1616#include " swift/AST/GenericEnvironment.h"
1717#include " swift/AST/NameLookup.h"
1818#include " swift/AST/USRGeneration.h"
19+ #include " swift/IDE/SelectedOverloadInfo.h"
1920#include " swift/IDE/TypeCheckCompletionCallback.h"
2021#include " swift/Parse/IDEInspectionCallbacks.h"
2122#include " swift/Sema/ConstraintSystem.h"
@@ -51,17 +52,19 @@ void typeCheckDeclAndParentClosures(ValueDecl *VD) {
5152 TypeCheckASTNodeAtLocContext::declContext (VD->getDeclContext ()),
5253 VD->getLoc ());
5354 if (auto VarD = dyn_cast<VarDecl>(VD)) {
54- // Type check any attached property wrappers so the annotated declaration
55- // can refer to their USRs.
56- (void )VarD->getPropertyWrapperBackingPropertyType ();
55+ if (VarD->hasAttachedPropertyWrapper ()) {
56+ // Type check any attached property wrappers so the annotated declaration
57+ // can refer to their USRs.
58+ (void )VarD->getPropertyWrapperBackingPropertyType ();
59+ }
5760 // Visit emitted accessors so we generated accessors from property wrappers.
5861 VarD->visitEmittedAccessors ([&](AccessorDecl *accessor) {});
5962 }
6063}
6164
6265// MARK: - NodeFinderResults
6366
64- enum class NodeFinderResultKind { Decl };
67+ enum class NodeFinderResultKind { Decl, Expr };
6568
6669class NodeFinderResult {
6770 NodeFinderResultKind Kind;
@@ -87,6 +90,24 @@ class NodeFinderDeclResult : public NodeFinderResult {
8790 }
8891};
8992
93+ class NodeFinderExprResult : public NodeFinderResult {
94+ Expr *E;
95+ // / The \c DeclContext in which \c E occurs.
96+ DeclContext *DC;
97+
98+ public:
99+ NodeFinderExprResult (Expr *E, DeclContext *DC)
100+ : NodeFinderResult(NodeFinderResultKind::Expr), E(E), DC(DC) {}
101+
102+ Expr *getExpr () const { return E; }
103+
104+ DeclContext *getDeclContext () const { return DC; }
105+
106+ static bool classof (const NodeFinderResult *Res) {
107+ return Res->getKind () == NodeFinderResultKind::Expr;
108+ }
109+ };
110+
90111// MARK: - NodeFinder
91112
92113// / Walks the AST, looking for a node at \c LocToResolve. While walking the
@@ -192,6 +213,23 @@ class NodeFinder : ASTWalker {
192213 }
193214 }
194215
216+ if (E->getLoc () != LocToResolve) {
217+ return Action::Continue (E);
218+ }
219+
220+ switch (E->getKind ()) {
221+ case ExprKind::DeclRef:
222+ case ExprKind::UnresolvedDot:
223+ case ExprKind::UnresolvedDeclRef: {
224+ assert (Result == nullptr );
225+ Result =
226+ std::make_unique<NodeFinderExprResult>(E, getCurrentDeclContext ());
227+ return Action::Stop ();
228+ }
229+ default :
230+ break ;
231+ }
232+
195233 return Action::Continue (E);
196234 }
197235
@@ -215,6 +253,57 @@ class NodeFinder : ASTWalker {
215253 }
216254};
217255
256+ // MARK: - Solver-based expression analysis
257+
258+ class CursorInfoTypeCheckSolutionCallback : public TypeCheckCompletionCallback {
259+ public:
260+ struct CursorInfoDeclReference {
261+ // / If the referenced declaration is a member reference, the type of the
262+ // / member's base, otherwise \c null.
263+ Type BaseType;
264+ // / Whether the reference is dynamic (see \c ide::isDynamicRef)
265+ bool IsDynamicRef;
266+ // / The declaration that is being referenced. Will never be \c nullptr.
267+ ValueDecl *ReferencedDecl;
268+ };
269+
270+ private:
271+ // / The expression for which we want to provide cursor info results.
272+ Expr *ResolveExpr;
273+
274+ SmallVector<CursorInfoDeclReference, 1 > Results;
275+
276+ void sawSolutionImpl (const Solution &S) override {
277+ auto &CS = S.getConstraintSystem ();
278+
279+ auto Locator = CS.getConstraintLocator (ResolveExpr);
280+ auto CalleeLocator = S.getCalleeLocator (Locator);
281+ auto OverloadInfo = getSelectedOverloadInfo (S, CalleeLocator);
282+ if (!OverloadInfo.Value ) {
283+ // We could not resolve the referenced declaration. Skip the solution.
284+ return ;
285+ }
286+
287+ bool IsDynamicRef = false ;
288+ auto BaseLocator =
289+ CS.getConstraintLocator (Locator, ConstraintLocator::MemberRefBase);
290+ if (auto BaseExpr =
291+ simplifyLocatorToAnchor (BaseLocator).dyn_cast <Expr *>()) {
292+ IsDynamicRef =
293+ ide::isDynamicRef (BaseExpr, OverloadInfo.Value ,
294+ [&S](Expr *E) { return S.getResolvedType (E); });
295+ }
296+
297+ Results.push_back ({OverloadInfo.BaseTy , IsDynamicRef, OverloadInfo.Value });
298+ }
299+
300+ public:
301+ CursorInfoTypeCheckSolutionCallback (Expr *ResolveExpr)
302+ : ResolveExpr(ResolveExpr) {}
303+
304+ ArrayRef<CursorInfoDeclReference> getResults () const { return Results; }
305+ };
306+
218307// MARK: - CursorInfoDoneParsingCallback
219308
220309class CursorInfoDoneParsingCallback : public IDEInspectionCallbacks {
@@ -242,6 +331,59 @@ class CursorInfoDoneParsingCallback : public IDEInspectionCallbacks {
242331 return CursorInfo;
243332 }
244333
334+ std::unique_ptr<ResolvedCursorInfo>
335+ getExprResult (NodeFinderExprResult *ExprResult, SourceFile *SrcFile,
336+ NodeFinder &Finder) const {
337+ Expr *E = ExprResult->getExpr ();
338+ DeclContext *DC = ExprResult->getDeclContext ();
339+
340+ // Type check the statemnt containing E and listen for solutions.
341+ CursorInfoTypeCheckSolutionCallback Callback (E);
342+ llvm::SaveAndRestore<TypeCheckCompletionCallback *> CompletionCollector (
343+ DC->getASTContext ().SolutionCallback , &Callback);
344+ typeCheckASTNodeAtLoc (TypeCheckASTNodeAtLocContext::declContext (DC),
345+ E->getLoc ());
346+
347+ if (Callback.getResults ().empty ()) {
348+ // No results.
349+ return nullptr ;
350+ }
351+
352+ for (auto Info : Callback.getResults ()) {
353+ // Type check the referenced decls so that all their parent closures are
354+ // type-checked (see comment in typeCheckDeclAndParentClosures).
355+ typeCheckDeclAndParentClosures (Info.ReferencedDecl );
356+ }
357+
358+ if (Callback.getResults ().size () != 1 ) {
359+ // FIXME: We need to be able to report multiple results.
360+ return nullptr ;
361+ }
362+
363+ // Deliver results
364+
365+ auto Res = Callback.getResults ()[0 ];
366+ auto CursorInfo = std::make_unique<ResolvedValueRefCursorInfo>(
367+ ResolvedCursorInfo (SrcFile), Res.ReferencedDecl , /* CtorTyRef=*/ nullptr ,
368+ /* ExtTyRef=*/ nullptr , /* IsRef=*/ true , /* Ty=*/ Type (),
369+ /* ContainerType=*/ Res.BaseType );
370+ CursorInfo->setLoc (RequestedLoc);
371+ CursorInfo->setIsDynamic (Res.IsDynamicRef );
372+ if (Res.IsDynamicRef && Res.BaseType ) {
373+ if (auto ReceiverType = Res.BaseType ->getAnyNominal ()) {
374+ CursorInfo->setReceiverTypes ({ReceiverType});
375+ } else if (auto MT = Res.BaseType ->getAs <AnyMetatypeType>()) {
376+ // Look through metatypes to get the nominal type decl.
377+ if (auto ReceiverType = MT->getInstanceType ()->getAnyNominal ()) {
378+ CursorInfo->setReceiverTypes ({ReceiverType});
379+ }
380+ }
381+ }
382+ CursorInfo->setShorthandShadowedDecls (
383+ Finder.getShorthandShadowedDecls (Res.ReferencedDecl ));
384+ return CursorInfo;
385+ }
386+
245387 void doneParsing (SourceFile *SrcFile) override {
246388 if (!SrcFile) {
247389 return ;
@@ -258,6 +400,10 @@ class CursorInfoDoneParsingCallback : public IDEInspectionCallbacks {
258400 CursorInfo = getDeclResult (cast<NodeFinderDeclResult>(Result.get ()),
259401 SrcFile, Finder);
260402 break ;
403+ case NodeFinderResultKind::Expr:
404+ CursorInfo = getExprResult (cast<NodeFinderExprResult>(Result.get ()),
405+ SrcFile, Finder);
406+ break ;
261407 }
262408 if (Result) {
263409 Consumer.handleResults (*CursorInfo);
0 commit comments