16
16
#include " swift/AST/GenericEnvironment.h"
17
17
#include " swift/AST/NameLookup.h"
18
18
#include " swift/AST/USRGeneration.h"
19
+ #include " swift/IDE/SelectedOverloadInfo.h"
19
20
#include " swift/IDE/TypeCheckCompletionCallback.h"
20
21
#include " swift/Parse/IDEInspectionCallbacks.h"
21
22
#include " swift/Sema/ConstraintSystem.h"
@@ -47,21 +48,28 @@ void typeCheckDeclAndParentClosures(ValueDecl *VD) {
47
48
DC = DC->getParent ();
48
49
}
49
50
50
- typeCheckASTNodeAtLoc (
51
- TypeCheckASTNodeAtLocContext::declContext (VD->getDeclContext ()),
52
- VD->getLoc ());
51
+ if (!VD->getInterfaceType ()) {
52
+ // The decl has an interface time if it came from another module. In that
53
+ // case, there's nothing to do. Otherwise, type check the decl to get its
54
+ // type.
55
+ typeCheckASTNodeAtLoc (
56
+ TypeCheckASTNodeAtLocContext::declContext (VD->getDeclContext ()),
57
+ VD->getLoc ());
58
+ }
53
59
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 ();
60
+ if (VarD->hasAttachedPropertyWrapper ()) {
61
+ // Type check any attached property wrappers so the annotated declaration
62
+ // can refer to their USRs.
63
+ (void )VarD->getPropertyWrapperBackingPropertyType ();
64
+ }
57
65
// Visit emitted accessors so we generated accessors from property wrappers.
58
66
VarD->visitEmittedAccessors ([&](AccessorDecl *accessor) {});
59
67
}
60
68
}
61
69
62
70
// MARK: - NodeFinderResults
63
71
64
- enum class NodeFinderResultKind { Decl };
72
+ enum class NodeFinderResultKind { Decl, Expr };
65
73
66
74
class NodeFinderResult {
67
75
NodeFinderResultKind Kind;
@@ -87,6 +95,24 @@ class NodeFinderDeclResult : public NodeFinderResult {
87
95
}
88
96
};
89
97
98
+ class NodeFinderExprResult : public NodeFinderResult {
99
+ Expr *E;
100
+ // / The \c DeclContext in which \c E occurs.
101
+ DeclContext *DC;
102
+
103
+ public:
104
+ NodeFinderExprResult (Expr *E, DeclContext *DC)
105
+ : NodeFinderResult(NodeFinderResultKind::Expr), E(E), DC(DC) {}
106
+
107
+ Expr *getExpr () const { return E; }
108
+
109
+ DeclContext *getDeclContext () const { return DC; }
110
+
111
+ static bool classof (const NodeFinderResult *Res) {
112
+ return Res->getKind () == NodeFinderResultKind::Expr;
113
+ }
114
+ };
115
+
90
116
// MARK: - NodeFinder
91
117
92
118
// / Walks the AST, looking for a node at \c LocToResolve. While walking the
@@ -192,6 +218,23 @@ class NodeFinder : ASTWalker {
192
218
}
193
219
}
194
220
221
+ if (E->getLoc () != LocToResolve) {
222
+ return Action::Continue (E);
223
+ }
224
+
225
+ switch (E->getKind ()) {
226
+ case ExprKind::DeclRef:
227
+ case ExprKind::UnresolvedDot:
228
+ case ExprKind::UnresolvedDeclRef: {
229
+ assert (Result == nullptr );
230
+ Result =
231
+ std::make_unique<NodeFinderExprResult>(E, getCurrentDeclContext ());
232
+ return Action::Stop ();
233
+ }
234
+ default :
235
+ break ;
236
+ }
237
+
195
238
return Action::Continue (E);
196
239
}
197
240
@@ -215,6 +258,57 @@ class NodeFinder : ASTWalker {
215
258
}
216
259
};
217
260
261
+ // MARK: - Solver-based expression analysis
262
+
263
+ class CursorInfoTypeCheckSolutionCallback : public TypeCheckCompletionCallback {
264
+ public:
265
+ struct CursorInfoDeclReference {
266
+ // / If the referenced declaration is a member reference, the type of the
267
+ // / member's base, otherwise \c null.
268
+ Type BaseType;
269
+ // / Whether the reference is dynamic (see \c ide::isDynamicRef)
270
+ bool IsDynamicRef;
271
+ // / The declaration that is being referenced. Will never be \c nullptr.
272
+ ValueDecl *ReferencedDecl;
273
+ };
274
+
275
+ private:
276
+ // / The expression for which we want to provide cursor info results.
277
+ Expr *ResolveExpr;
278
+
279
+ SmallVector<CursorInfoDeclReference, 1 > Results;
280
+
281
+ void sawSolutionImpl (const Solution &S) override {
282
+ auto &CS = S.getConstraintSystem ();
283
+
284
+ auto Locator = CS.getConstraintLocator (ResolveExpr);
285
+ auto CalleeLocator = S.getCalleeLocator (Locator);
286
+ auto OverloadInfo = getSelectedOverloadInfo (S, CalleeLocator);
287
+ if (!OverloadInfo.Value ) {
288
+ // We could not resolve the referenced declaration. Skip the solution.
289
+ return ;
290
+ }
291
+
292
+ bool IsDynamicRef = false ;
293
+ auto BaseLocator =
294
+ CS.getConstraintLocator (Locator, ConstraintLocator::MemberRefBase);
295
+ if (auto BaseExpr =
296
+ simplifyLocatorToAnchor (BaseLocator).dyn_cast <Expr *>()) {
297
+ IsDynamicRef =
298
+ ide::isDynamicRef (BaseExpr, OverloadInfo.Value ,
299
+ [&S](Expr *E) { return S.getResolvedType (E); });
300
+ }
301
+
302
+ Results.push_back ({OverloadInfo.BaseTy , IsDynamicRef, OverloadInfo.Value });
303
+ }
304
+
305
+ public:
306
+ CursorInfoTypeCheckSolutionCallback (Expr *ResolveExpr)
307
+ : ResolveExpr(ResolveExpr) {}
308
+
309
+ ArrayRef<CursorInfoDeclReference> getResults () const { return Results; }
310
+ };
311
+
218
312
// MARK: - CursorInfoDoneParsingCallback
219
313
220
314
class CursorInfoDoneParsingCallback : public IDEInspectionCallbacks {
@@ -242,6 +336,59 @@ class CursorInfoDoneParsingCallback : public IDEInspectionCallbacks {
242
336
return CursorInfo;
243
337
}
244
338
339
+ std::unique_ptr<ResolvedCursorInfo>
340
+ getExprResult (NodeFinderExprResult *ExprResult, SourceFile *SrcFile,
341
+ NodeFinder &Finder) const {
342
+ Expr *E = ExprResult->getExpr ();
343
+ DeclContext *DC = ExprResult->getDeclContext ();
344
+
345
+ // Type check the statemnt containing E and listen for solutions.
346
+ CursorInfoTypeCheckSolutionCallback Callback (E);
347
+ llvm::SaveAndRestore<TypeCheckCompletionCallback *> CompletionCollector (
348
+ DC->getASTContext ().SolutionCallback , &Callback);
349
+ typeCheckASTNodeAtLoc (TypeCheckASTNodeAtLocContext::declContext (DC),
350
+ E->getLoc ());
351
+
352
+ if (Callback.getResults ().empty ()) {
353
+ // No results.
354
+ return nullptr ;
355
+ }
356
+
357
+ for (auto Info : Callback.getResults ()) {
358
+ // Type check the referenced decls so that all their parent closures are
359
+ // type-checked (see comment in typeCheckDeclAndParentClosures).
360
+ typeCheckDeclAndParentClosures (Info.ReferencedDecl );
361
+ }
362
+
363
+ if (Callback.getResults ().size () != 1 ) {
364
+ // FIXME: We need to be able to report multiple results.
365
+ return nullptr ;
366
+ }
367
+
368
+ // Deliver results
369
+
370
+ auto Res = Callback.getResults ()[0 ];
371
+ auto CursorInfo = std::make_unique<ResolvedValueRefCursorInfo>(
372
+ ResolvedCursorInfo (SrcFile), Res.ReferencedDecl , /* CtorTyRef=*/ nullptr ,
373
+ /* ExtTyRef=*/ nullptr , /* IsRef=*/ true , /* Ty=*/ Type (),
374
+ /* ContainerType=*/ Res.BaseType );
375
+ CursorInfo->setLoc (RequestedLoc);
376
+ CursorInfo->setIsDynamic (Res.IsDynamicRef );
377
+ if (Res.IsDynamicRef && Res.BaseType ) {
378
+ if (auto ReceiverType = Res.BaseType ->getAnyNominal ()) {
379
+ CursorInfo->setReceiverTypes ({ReceiverType});
380
+ } else if (auto MT = Res.BaseType ->getAs <AnyMetatypeType>()) {
381
+ // Look through metatypes to get the nominal type decl.
382
+ if (auto ReceiverType = MT->getInstanceType ()->getAnyNominal ()) {
383
+ CursorInfo->setReceiverTypes ({ReceiverType});
384
+ }
385
+ }
386
+ }
387
+ CursorInfo->setShorthandShadowedDecls (
388
+ Finder.getShorthandShadowedDecls (Res.ReferencedDecl ));
389
+ return CursorInfo;
390
+ }
391
+
245
392
void doneParsing (SourceFile *SrcFile) override {
246
393
if (!SrcFile) {
247
394
return ;
@@ -258,6 +405,10 @@ class CursorInfoDoneParsingCallback : public IDEInspectionCallbacks {
258
405
CursorInfo = getDeclResult (cast<NodeFinderDeclResult>(Result.get ()),
259
406
SrcFile, Finder);
260
407
break ;
408
+ case NodeFinderResultKind::Expr:
409
+ CursorInfo = getExprResult (cast<NodeFinderExprResult>(Result.get ()),
410
+ SrcFile, Finder);
411
+ break ;
261
412
}
262
413
if (Result) {
263
414
Consumer.handleResults (*CursorInfo);
0 commit comments