Skip to content

Commit 8948a03

Browse files
authored
Merge pull request swiftlang#36508 from bnbarham/static-dynamic-flag
[SourceKit/CursorInfo] Mark dynamic calls
2 parents 972dc99 + 19f2313 commit 8948a03

File tree

11 files changed

+418
-199
lines changed

11 files changed

+418
-199
lines changed

include/swift/IDE/Utils.h

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,11 @@ struct ResolvedCursorInfo {
164164
Type ContainerType;
165165
Stmt *TrailingStmt = nullptr;
166166
Expr *TrailingExpr = nullptr;
167+
/// If this is a call, whether it is "dynamic", see ide::isDynamicCall.
168+
bool IsDynamic = false;
169+
/// If this is a call, the types of the base (multiple in the case of
170+
/// protocol composition).
171+
SmallVector<NominalTypeDecl *, 1> ReceiverTypes;
167172

168173
ResolvedCursorInfo() = default;
169174
ResolvedCursorInfo(SourceFile *SF) : SF(SF) {}
@@ -174,12 +179,9 @@ struct ResolvedCursorInfo {
174179
lhs.Loc.getOpaquePointerValue() == rhs.Loc.getOpaquePointerValue();
175180
}
176181

177-
void setValueRef(ValueDecl *ValueD,
178-
TypeDecl *CtorTyRef,
179-
ExtensionDecl *ExtTyRef,
180-
bool IsRef,
181-
Type Ty,
182-
Type ContainerType) {
182+
void setValueRef(ValueDecl *ValueD, TypeDecl *CtorTyRef,
183+
ExtensionDecl *ExtTyRef, bool IsRef,
184+
Type Ty, Type ContainerType) {
183185
Kind = CursorInfoKind::ValueRef;
184186
this->ValueD = ValueD;
185187
this->CtorTyRef = CtorTyRef;
@@ -621,6 +623,23 @@ ClangNode extensionGetClangNode(const ExtensionDecl *ext);
621623
/// or a curry thunk, etc.
622624
std::pair<Type, ConcreteDeclRef> getReferencedDecl(Expr *expr);
623625

626+
/// Whether the last expression in \p ExprStack is being called.
627+
bool isBeingCalled(ArrayRef<Expr*> ExprStack);
628+
629+
/// The base of the last expression in \p ExprStack (which may look up the
630+
/// stack in eg. the case of a `DotSyntaxCallExpr`).
631+
Expr *getBase(ArrayRef<Expr *> ExprStack);
632+
633+
/// Assuming that we have a call, returns whether or not it is "dynamic" based
634+
/// on its base expression and decl of the callee. Note that this is not
635+
/// Swift's "dynamic" modifier (`ValueDecl::isDynamic`), but rathar "can call a
636+
/// function in a conformance/subclass".
637+
bool isDynamicCall(Expr *Base, ValueDecl *D);
638+
639+
/// Adds the resolved nominal types of \p Base to \p Types.
640+
void getReceiverType(Expr *Base,
641+
SmallVectorImpl<NominalTypeDecl *> &Types);
642+
624643
} // namespace ide
625644
} // namespace swift
626645

lib/IDE/IDERequests.cpp

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,12 @@ class CursorInfoResolver : public SourceEntityWalker {
5959
SourceLoc LocToResolve;
6060
ResolvedCursorInfo CursorInfo;
6161
Type ContainerType;
62-
llvm::SmallVector<Expr*, 4> TrailingExprStack;
62+
Expr *OutermostCursorExpr;
63+
llvm::SmallVector<Expr*, 8> ExprStack;
6364

6465
public:
6566
explicit CursorInfoResolver(SourceFile &SrcFile) :
66-
SrcFile(SrcFile), CursorInfo(&SrcFile) {}
67+
SrcFile(SrcFile), CursorInfo(&SrcFile), OutermostCursorExpr(nullptr) {}
6768
ResolvedCursorInfo resolve(SourceLoc Loc);
6869
SourceManager &getSourceMgr() const;
6970
private:
@@ -99,8 +100,8 @@ SourceManager &CursorInfoResolver::getSourceMgr() const
99100
}
100101

101102
bool CursorInfoResolver::tryResolve(ValueDecl *D, TypeDecl *CtorTyRef,
102-
ExtensionDecl *ExtTyRef, SourceLoc Loc,
103-
bool IsRef, Type Ty) {
103+
ExtensionDecl *ExtTyRef, SourceLoc Loc,
104+
bool IsRef, Type Ty) {
104105
if (!D->hasName())
105106
return false;
106107

@@ -116,6 +117,14 @@ bool CursorInfoResolver::tryResolve(ValueDecl *D, TypeDecl *CtorTyRef,
116117
}
117118
}
118119
}
120+
121+
if (isBeingCalled(ExprStack)) {
122+
if (Expr *BaseE = getBase(ExprStack)) {
123+
CursorInfo.IsDynamic = isDynamicCall(BaseE, D);
124+
ide::getReceiverType(BaseE, CursorInfo.ReceiverTypes);
125+
}
126+
}
127+
119128
CursorInfo.setValueRef(D, CtorTyRef, ExtTyRef, IsRef, Ty, ContainerType);
120129
return true;
121130
}
@@ -221,44 +230,55 @@ bool CursorInfoResolver::visitDeclReference(ValueDecl *D,
221230
return !tryResolve(D, CtorTyRef, ExtTyRef, Range.getStart(), /*IsRef=*/true, T);
222231
}
223232

233+
static bool isCursorOn(Expr *E, SourceLoc Loc) {
234+
if (E->isImplicit())
235+
return false;
236+
237+
bool IsCursorOnLoc = E->getStartLoc() == Loc;
238+
// Handle cursor placement after `try` in (ForceTry|OptionalTry)Expr
239+
if (auto *FTE = dyn_cast<ForceTryExpr>(E)) {
240+
IsCursorOnLoc |= FTE->getExclaimLoc() == Loc;
241+
}
242+
if (auto *OTE = dyn_cast<OptionalTryExpr>(E)) {
243+
IsCursorOnLoc |= OTE->getQuestionLoc() == Loc;
244+
}
245+
return IsCursorOnLoc;
246+
}
247+
224248
bool CursorInfoResolver::walkToExprPre(Expr *E) {
225-
if (!isDone()) {
226-
if (auto SAE = dyn_cast<SelfApplyExpr>(E)) {
227-
if (SAE->getFn()->getStartLoc() == LocToResolve) {
228-
ContainerType = SAE->getBase()->getType();
229-
}
230-
} else if (auto ME = dyn_cast<MemberRefExpr>(E)) {
231-
SourceLoc MemberLoc = ME->getNameLoc().getBaseNameLoc();
232-
if (MemberLoc.isValid() && MemberLoc == LocToResolve) {
233-
ContainerType = ME->getBase()->getType();
234-
}
235-
}
236-
auto IsProperCursorLocation = E->getStartLoc() == LocToResolve;
237-
// Handle cursor placement after `try` in ForceTry and OptionalTry Expr.
238-
auto CheckLocation = [&IsProperCursorLocation, this](SourceLoc Loc) {
239-
IsProperCursorLocation = Loc == LocToResolve || IsProperCursorLocation;
240-
};
241-
if (auto *FTE = dyn_cast<ForceTryExpr>(E)) {
242-
CheckLocation(FTE->getExclaimLoc());
249+
if (isDone())
250+
return true;
251+
252+
if (auto SAE = dyn_cast<SelfApplyExpr>(E)) {
253+
if (SAE->getFn()->getStartLoc() == LocToResolve) {
254+
ContainerType = SAE->getBase()->getType();
243255
}
244-
if (auto *OTE = dyn_cast<OptionalTryExpr>(E)) {
245-
CheckLocation(OTE->getQuestionLoc());
256+
} else if (auto ME = dyn_cast<MemberRefExpr>(E)) {
257+
SourceLoc MemberLoc = ME->getNameLoc().getBaseNameLoc();
258+
if (MemberLoc.isValid() && MemberLoc == LocToResolve) {
259+
ContainerType = ME->getBase()->getType();
246260
}
247-
// Keep track of trailing expressions.
248-
if (!E->isImplicit() && IsProperCursorLocation)
249-
TrailingExprStack.push_back(E);
250261
}
262+
263+
if (!OutermostCursorExpr && isCursorOn(E, LocToResolve))
264+
OutermostCursorExpr = E;
265+
266+
ExprStack.push_back(E);
267+
251268
return true;
252269
}
253270

254271
bool CursorInfoResolver::walkToExprPost(Expr *E) {
255272
if (isDone())
256273
return false;
257-
if (!TrailingExprStack.empty() && TrailingExprStack.back() == E) {
258-
// We return the outtermost expression in the token info.
259-
CursorInfo.setTrailingExpr(TrailingExprStack.front());
274+
275+
if (OutermostCursorExpr && isCursorOn(E, LocToResolve)) {
276+
CursorInfo.setTrailingExpr(OutermostCursorExpr);
260277
return false;
261278
}
279+
280+
ExprStack.pop_back();
281+
262282
return true;
263283
}
264284

lib/IDE/Utils.cpp

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,3 +1181,111 @@ std::pair<Type, ConcreteDeclRef> swift::ide::getReferencedDecl(Expr *expr) {
11811181

11821182
return std::make_pair(exprTy, refDecl);
11831183
}
1184+
1185+
bool swift::ide::isBeingCalled(ArrayRef<Expr *> ExprStack) {
1186+
if (ExprStack.empty())
1187+
return false;
1188+
1189+
Expr *Target = ExprStack.back();
1190+
auto UnderlyingDecl = getReferencedDecl(Target).second;
1191+
for (Expr *E: reverse(ExprStack)) {
1192+
auto *AE = dyn_cast<ApplyExpr>(E);
1193+
if (!AE || AE->isImplicit())
1194+
continue;
1195+
if (isa<ConstructorRefCallExpr>(AE) && AE->getArg() == Target)
1196+
return true;
1197+
if (isa<SelfApplyExpr>(AE))
1198+
continue;
1199+
if (getReferencedDecl(AE->getFn()).second == UnderlyingDecl)
1200+
return true;
1201+
}
1202+
return false;
1203+
}
1204+
1205+
static Expr *getContainingExpr(ArrayRef<Expr *> ExprStack, size_t index) {
1206+
if (ExprStack.size() > index)
1207+
return ExprStack.end()[-std::ptrdiff_t(index + 1)];
1208+
return nullptr;
1209+
}
1210+
1211+
Expr *swift::ide::getBase(ArrayRef<Expr *> ExprStack) {
1212+
if (ExprStack.empty())
1213+
return nullptr;
1214+
1215+
Expr *CurrentE = ExprStack.back();
1216+
Expr *ParentE = getContainingExpr(ExprStack, 1);
1217+
Expr *Base = nullptr;
1218+
if (auto DSE = dyn_cast_or_null<DotSyntaxCallExpr>(ParentE))
1219+
Base = DSE->getBase();
1220+
else if (auto MRE = dyn_cast<MemberRefExpr>(CurrentE))
1221+
Base = MRE->getBase();
1222+
else if (auto SE = dyn_cast<SubscriptExpr>(CurrentE))
1223+
Base = SE->getBase();
1224+
1225+
if (Base) {
1226+
while (auto ICE = dyn_cast<ImplicitConversionExpr>(Base))
1227+
Base = ICE->getSubExpr();
1228+
// DotSyntaxCallExpr with getBase() == CurrentE (ie. the current call is
1229+
// the base of another expression)
1230+
if (Base == CurrentE)
1231+
return nullptr;
1232+
}
1233+
return Base;
1234+
}
1235+
1236+
bool swift::ide::isDynamicCall(Expr *Base, ValueDecl *D) {
1237+
auto TyD = D->getDeclContext()->getSelfNominalTypeDecl();
1238+
if (!TyD)
1239+
return false;
1240+
1241+
if (isa<StructDecl>(TyD) || isa<EnumDecl>(TyD) || D->isFinal())
1242+
return false;
1243+
1244+
// super.method()
1245+
// TODO: Should be dynamic if `D` is marked as dynamic and @objc, but in
1246+
// that case we really need to change the role the index outputs as
1247+
// well - the overrides we'd want to include are from the type of
1248+
// super up to `D`
1249+
if (Base->isSuperExpr())
1250+
return false;
1251+
1252+
// `SomeType.staticOrClassMethod()`
1253+
if (isa<TypeExpr>(Base))
1254+
return false;
1255+
1256+
// `type(of: foo).staticOrClassMethod()`, not "dynamic" if the instance type
1257+
// is a struct/enum or if it is a class and the function is a static method
1258+
// (rather than a class method).
1259+
if (auto IT = Base->getType()->getAs<MetatypeType>()) {
1260+
auto InstanceType = IT->getInstanceType();
1261+
if (InstanceType->getStructOrBoundGenericStruct() ||
1262+
InstanceType->getEnumOrBoundGenericEnum())
1263+
return false;
1264+
if (InstanceType->getClassOrBoundGenericClass() && D->isFinal())
1265+
return false;
1266+
}
1267+
1268+
return true;
1269+
}
1270+
1271+
void swift::ide::getReceiverType(Expr *Base,
1272+
SmallVectorImpl<NominalTypeDecl *> &Types) {
1273+
Type ReceiverTy = Base->getType();
1274+
if (!ReceiverTy)
1275+
return;
1276+
1277+
if (auto LVT = ReceiverTy->getAs<LValueType>())
1278+
ReceiverTy = LVT->getObjectType();
1279+
else if (auto MetaT = ReceiverTy->getAs<MetatypeType>())
1280+
ReceiverTy = MetaT->getInstanceType();
1281+
else if (auto SelfT = ReceiverTy->getAs<DynamicSelfType>())
1282+
ReceiverTy = SelfT->getSelfType();
1283+
1284+
// TODO: Handle generics and composed protocols
1285+
if (auto OpenedTy = ReceiverTy->getAs<OpenedArchetypeType>())
1286+
ReceiverTy = OpenedTy->getOpenedExistentialType();
1287+
1288+
if (auto TyD = ReceiverTy->getAnyNominal()) {
1289+
Types.push_back(TyD);
1290+
}
1291+
}

0 commit comments

Comments
 (0)