Skip to content

Commit 6526860

Browse files
committed
[IDE] Split ResolvedCursorInfo into subclasses
This way, each kind of `ResolvedCursorInfo` can define its own set of properties and it’s obvious which properties are used for which kind. Also switch to getters and setters because that makes it easier to search for usages of properties by looking at the call hierarchy of the getter / setter.
1 parent 3443076 commit 6526860

File tree

5 files changed

+354
-184
lines changed

5 files changed

+354
-184
lines changed

include/swift/IDE/Utils.h

Lines changed: 171 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -128,71 +128,200 @@ enum class CursorInfoKind {
128128
StmtStart,
129129
};
130130

131+
/// Base class of more specialized \c ResolvedCursorInfos that also represents
132+
/// and \c Invalid cursor info.
133+
/// Subclasses of \c ResolvedCursorInfo cannot add new stored properies because
134+
/// \c ResolvedCursorInfo is being passed around as its base class and thus any
135+
/// properties in subclasses would get lost.
131136
struct ResolvedCursorInfo {
137+
protected:
132138
CursorInfoKind Kind = CursorInfoKind::Invalid;
133139
SourceFile *SF = nullptr;
134140
SourceLoc Loc;
135-
ValueDecl *ValueD = nullptr;
136-
TypeDecl *CtorTyRef = nullptr;
137-
ExtensionDecl *ExtTyRef = nullptr;
138-
/// Declarations that were shadowed by \c ValueD using a shorthand syntax that
139-
/// names both the newly declared variable and the referenced variable by the
140-
/// same identifier in the source text. This includes shorthand closure
141-
/// captures (`[foo]`) and shorthand if captures
142-
/// (`if let foo {`).
143-
/// Decls that are shadowed using shorthand syntax should be reported as
144-
/// additional cursor info results.
145-
SmallVector<ValueDecl *, 2> ShorthandShadowedDecls;
146-
ModuleEntity Mod;
147-
bool IsRef = true;
148-
bool IsKeywordArgument = false;
149-
Type Ty;
150-
Type ContainerType;
151-
Stmt *TrailingStmt = nullptr;
152-
Expr *TrailingExpr = nullptr;
153-
/// It this is a ref, whether it is "dynamic". See \c ide::isDynamicRef.
154-
bool IsDynamic = false;
155-
/// If this is a dynamic ref, the types of the base (multiple in the case of
156-
/// protocol composition).
157-
SmallVector<NominalTypeDecl *, 1> ReceiverTypes;
158141

142+
// Technically, these structs could form a union (because only one of them is
143+
// active at a time). But I had issues with C++ complaining about copy
144+
// constructors and gave up. At the moment it's only wasting 3 words for non
145+
// ValueRef data.
146+
struct {
147+
ValueDecl *ValueD = nullptr;
148+
TypeDecl *CtorTyRef = nullptr;
149+
ExtensionDecl *ExtTyRef = nullptr;
150+
bool IsRef = true;
151+
Type Ty;
152+
Type ContainerType;
153+
bool IsKeywordArgument = false;
154+
/// It this is a ref, whether it is "dynamic". See \c ide::isDynamicRef.
155+
bool IsDynamic = false;
156+
/// If this is a dynamic ref, the types of the base (multiple in the case of
157+
/// protocol composition).
158+
SmallVector<NominalTypeDecl *> ReceiverTypes;
159+
/// Declarations that were shadowed by \c ValueD using a shorthand syntax
160+
/// that names both the newly declared variable and the referenced variable
161+
/// by the same identifier in the source text. This includes shorthand
162+
/// closure captures (`[foo]`) and shorthand if captures
163+
/// (`if let foo {`).
164+
/// Decls that are shadowed using shorthand syntax should be reported as
165+
/// additional cursor info results.
166+
SmallVector<ValueDecl *> ShorthandShadowedDecls;
167+
} ValueRefInfo;
168+
struct {
169+
ModuleEntity Mod;
170+
} ModuleRefInfo;
171+
struct {
172+
Expr *TrailingExpr = nullptr;
173+
} ExprStartInfo;
174+
struct {
175+
Stmt *TrailingStmt = nullptr;
176+
} StmtStartInfo;
177+
178+
public:
159179
ResolvedCursorInfo() = default;
160180
ResolvedCursorInfo(SourceFile *SF) : SF(SF) {}
161181

162-
ValueDecl *typeOrValue() { return CtorTyRef ? CtorTyRef : ValueD; }
182+
CursorInfoKind getKind() const { return Kind; }
183+
184+
SourceFile *getSourceFile() const { return SF; }
185+
186+
SourceLoc getLoc() const { return Loc; }
187+
void setLoc(SourceLoc Loc) { this->Loc = Loc; }
163188

164189
friend bool operator==(const ResolvedCursorInfo &lhs,
165190
const ResolvedCursorInfo &rhs) {
166191
return lhs.SF == rhs.SF &&
167192
lhs.Loc.getOpaquePointerValue() == rhs.Loc.getOpaquePointerValue();
168193
}
169194

170-
void setValueRef(ValueDecl *ValueD, TypeDecl *CtorTyRef,
171-
ExtensionDecl *ExtTyRef, bool IsRef,
172-
Type Ty, Type ContainerType) {
195+
bool isValid() const { return !isInvalid(); }
196+
bool isInvalid() const { return Kind == CursorInfoKind::Invalid; }
197+
};
198+
199+
struct ResolvedValueRefCursorInfo : public ResolvedCursorInfo {
200+
// IMPORTANT: Don't add stored properties here. See comment on
201+
// ResolvedCursorInfo.
202+
203+
ResolvedValueRefCursorInfo() = default;
204+
explicit ResolvedValueRefCursorInfo(const ResolvedCursorInfo &Base,
205+
ValueDecl *ValueD, TypeDecl *CtorTyRef,
206+
ExtensionDecl *ExtTyRef, bool IsRef,
207+
Type Ty, Type ContainerType)
208+
: ResolvedCursorInfo(Base) {
209+
assert(Base.getKind() == CursorInfoKind::Invalid &&
210+
"Can only specialize from invalid");
173211
Kind = CursorInfoKind::ValueRef;
174-
this->ValueD = ValueD;
175-
this->CtorTyRef = CtorTyRef;
176-
this->ExtTyRef = ExtTyRef;
177-
this->IsRef = IsRef;
178-
this->Ty = Ty;
179-
this->ContainerType = ContainerType;
212+
ValueRefInfo.ValueD = ValueD;
213+
ValueRefInfo.CtorTyRef = CtorTyRef;
214+
ValueRefInfo.ExtTyRef = ExtTyRef;
215+
ValueRefInfo.IsRef = IsRef;
216+
ValueRefInfo.Ty = Ty;
217+
ValueRefInfo.ContainerType = ContainerType;
218+
}
219+
220+
ValueDecl *getValueD() const { return ValueRefInfo.ValueD; }
221+
void setValueD(ValueDecl *ValueD) { ValueRefInfo.ValueD = ValueD; }
222+
223+
ExtensionDecl *getExtTyRef() const { return ValueRefInfo.ExtTyRef; }
224+
225+
TypeDecl *getCtorTyRef() const { return ValueRefInfo.CtorTyRef; }
226+
227+
bool isRef() const { return ValueRefInfo.IsRef; }
228+
void setIsRef(bool IsRef) { ValueRefInfo.IsRef = IsRef; }
229+
230+
Type getType() const { return ValueRefInfo.Ty; }
231+
232+
Type getContainerType() const { return ValueRefInfo.ContainerType; }
233+
void setContainerType(Type Ty) { ValueRefInfo.ContainerType = Ty; }
234+
235+
bool isKeywordArgument() const { return ValueRefInfo.IsKeywordArgument; }
236+
void setIsKeywordArgument(bool IsKeywordArgument) {
237+
ValueRefInfo.IsKeywordArgument = IsKeywordArgument;
238+
}
239+
240+
bool isDynamic() const { return ValueRefInfo.IsDynamic; }
241+
void setIsDynamic(bool IsDynamic) { ValueRefInfo.IsDynamic = IsDynamic; }
242+
243+
ArrayRef<NominalTypeDecl *> getReceiverTypes() const {
244+
return ValueRefInfo.ReceiverTypes;
245+
}
246+
void setReceiverTypes(const SmallVector<NominalTypeDecl *> &ReceiverTypes) {
247+
ValueRefInfo.ReceiverTypes = ReceiverTypes;
248+
}
249+
250+
ArrayRef<ValueDecl *> getShorthandShadowedDecls() const {
251+
return ValueRefInfo.ShorthandShadowedDecls;
252+
};
253+
void setShorthandShadowedDecls(
254+
const SmallVector<ValueDecl *> &ShorthandShadowedDecls) {
255+
ValueRefInfo.ShorthandShadowedDecls = ShorthandShadowedDecls;
256+
};
257+
258+
ValueDecl *typeOrValue() {
259+
return ValueRefInfo.CtorTyRef ? ValueRefInfo.CtorTyRef
260+
: ValueRefInfo.ValueD;
180261
}
181-
void setModuleRef(ModuleEntity Mod) {
262+
263+
static bool classof(const ResolvedCursorInfo *Info) {
264+
return Info->getKind() == CursorInfoKind::ValueRef;
265+
}
266+
};
267+
268+
struct ResolvedModuleRefCursorInfo : public ResolvedCursorInfo {
269+
// IMPORTANT: Don't add stored properties here. See comment on
270+
// ResolvedCursorInfo.
271+
272+
ResolvedModuleRefCursorInfo(const ResolvedCursorInfo &Base, ModuleEntity Mod)
273+
: ResolvedCursorInfo(Base) {
274+
assert(Base.getKind() == CursorInfoKind::Invalid &&
275+
"Can only specialize from invalid");
182276
Kind = CursorInfoKind::ModuleRef;
183-
this->Mod = Mod;
277+
ModuleRefInfo.Mod = Mod;
184278
}
185-
void setTrailingStmt(Stmt *TrailingStmt) {
186-
Kind = CursorInfoKind::StmtStart;
187-
this->TrailingStmt = TrailingStmt;
279+
280+
ModuleEntity getMod() const { return ModuleRefInfo.Mod; }
281+
282+
static bool classof(const ResolvedCursorInfo *Info) {
283+
return Info->getKind() == CursorInfoKind::ModuleRef;
188284
}
189-
void setTrailingExpr(Expr* TrailingExpr) {
285+
};
286+
287+
struct ResolvedExprStartCursorInfo : public ResolvedCursorInfo {
288+
// IMPORTANT: Don't add stored properties here. See comment on
289+
// ResolvedCursorInfo.
290+
291+
ResolvedExprStartCursorInfo(const ResolvedCursorInfo &Base,
292+
Expr *TrailingExpr)
293+
: ResolvedCursorInfo(Base) {
294+
assert(Base.getKind() == CursorInfoKind::Invalid &&
295+
"Can only specialize from invalid");
190296
Kind = CursorInfoKind::ExprStart;
191-
this->TrailingExpr = TrailingExpr;
297+
ExprStartInfo.TrailingExpr = TrailingExpr;
192298
}
193299

194-
bool isValid() const { return !isInvalid(); }
195-
bool isInvalid() const { return Kind == CursorInfoKind::Invalid; }
300+
Expr *getTrailingExpr() const { return ExprStartInfo.TrailingExpr; }
301+
302+
static bool classof(const ResolvedCursorInfo *Info) {
303+
return Info->getKind() == CursorInfoKind::ExprStart;
304+
}
305+
};
306+
307+
struct ResolvedStmtStartCursorInfo : public ResolvedCursorInfo {
308+
// IMPORTANT: Don't add stored properties here. See comment on
309+
// ResolvedCursorInfo.
310+
311+
ResolvedStmtStartCursorInfo(const ResolvedCursorInfo &Base,
312+
Stmt *TrailingStmt)
313+
: ResolvedCursorInfo(Base) {
314+
assert(Base.getKind() == CursorInfoKind::Invalid &&
315+
"Can only specialize from invalid");
316+
Kind = CursorInfoKind::StmtStart;
317+
StmtStartInfo.TrailingStmt = TrailingStmt;
318+
}
319+
320+
Stmt *getTrailingStmt() const { return StmtStartInfo.TrailingStmt; }
321+
322+
static bool classof(const ResolvedCursorInfo *Info) {
323+
return Info->getKind() == CursorInfoKind::StmtStart;
324+
}
196325
};
197326

198327
void simple_display(llvm::raw_ostream &out, const ResolvedCursorInfo &info);

lib/IDE/IDERequests.cpp

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -125,20 +125,24 @@ bool CursorInfoResolver::tryResolve(ValueDecl *D, TypeDecl *CtorTyRef,
125125
}
126126
}
127127

128+
ResolvedValueRefCursorInfo ValueRefInfo(CursorInfo, D, CtorTyRef, ExtTyRef,
129+
IsRef, Ty, ContainerType);
128130
if (Expr *BaseE = getBase(ExprStack)) {
129131
if (isDynamicRef(BaseE, D)) {
130-
CursorInfo.IsDynamic = true;
131-
ide::getReceiverType(BaseE, CursorInfo.ReceiverTypes);
132+
ValueRefInfo.setIsDynamic(true);
133+
SmallVector<NominalTypeDecl *> ReceiverTypes;
134+
ide::getReceiverType(BaseE, ReceiverTypes);
135+
ValueRefInfo.setReceiverTypes(ReceiverTypes);
132136
}
133137
}
134138

135-
CursorInfo.setValueRef(D, CtorTyRef, ExtTyRef, IsRef, Ty, ContainerType);
139+
CursorInfo = ValueRefInfo;
136140
return true;
137141
}
138142

139143
bool CursorInfoResolver::tryResolve(ModuleEntity Mod, SourceLoc Loc) {
140144
if (Loc == LocToResolve) {
141-
CursorInfo.setModuleRef(Mod);
145+
CursorInfo = ResolvedModuleRefCursorInfo(CursorInfo, Mod);
142146
return true;
143147
}
144148
return false;
@@ -147,13 +151,13 @@ bool CursorInfoResolver::tryResolve(ModuleEntity Mod, SourceLoc Loc) {
147151
bool CursorInfoResolver::tryResolve(Stmt *St) {
148152
if (auto *LST = dyn_cast<LabeledStmt>(St)) {
149153
if (LST->getStartLoc() == LocToResolve) {
150-
CursorInfo.setTrailingStmt(St);
154+
CursorInfo = ResolvedStmtStartCursorInfo(CursorInfo, St);
151155
return true;
152156
}
153157
}
154158
if (auto *CS = dyn_cast<CaseStmt>(St)) {
155159
if (CS->getStartLoc() == LocToResolve) {
156-
CursorInfo.setTrailingStmt(St);
160+
CursorInfo = ResolvedStmtStartCursorInfo(CursorInfo, St);
157161
return true;
158162
}
159163
}
@@ -171,16 +175,21 @@ bool CursorInfoResolver::visitSubscriptReference(ValueDecl *D,
171175
ResolvedCursorInfo CursorInfoResolver::resolve(SourceLoc Loc) {
172176
assert(Loc.isValid());
173177
LocToResolve = Loc;
174-
CursorInfo.Loc = Loc;
178+
CursorInfo.setLoc(Loc);
175179

176180
walk(SrcFile);
177181

178-
if (!CursorInfo.IsRef) {
179-
// If we have a definition, add any decls that it potentially shadows
180-
auto ShorthandShadowedDecl = ShorthandShadowedDecls[CursorInfo.ValueD];
181-
while (ShorthandShadowedDecl) {
182-
CursorInfo.ShorthandShadowedDecls.push_back(ShorthandShadowedDecl);
183-
ShorthandShadowedDecl = ShorthandShadowedDecls[ShorthandShadowedDecl];
182+
if (auto ValueRefInfo = dyn_cast<ResolvedValueRefCursorInfo>(&CursorInfo)) {
183+
if (!ValueRefInfo->isRef()) {
184+
SmallVector<ValueDecl *> ShadowedDecls;
185+
// If we have a definition, add any decls that it potentially shadows
186+
auto ShorthandShadowedDecl =
187+
ShorthandShadowedDecls[ValueRefInfo->getValueD()];
188+
while (ShorthandShadowedDecl) {
189+
ShadowedDecls.push_back(ShorthandShadowedDecl);
190+
ShorthandShadowedDecl = ShorthandShadowedDecls[ShorthandShadowedDecl];
191+
}
192+
ValueRefInfo->setShorthandShadowedDecls(ShadowedDecls);
184193
}
185194
}
186195

@@ -307,7 +316,7 @@ bool CursorInfoResolver::walkToExprPost(Expr *E) {
307316
return false;
308317

309318
if (OutermostCursorExpr && isCursorOn(E, LocToResolve)) {
310-
CursorInfo.setTrailingExpr(OutermostCursorExpr);
319+
CursorInfo = ResolvedExprStartCursorInfo(CursorInfo, OutermostCursorExpr);
311320
return false;
312321
}
313322

@@ -328,8 +337,9 @@ bool CursorInfoResolver::visitCallArgName(Identifier Name,
328337
return true;
329338

330339
bool Found = tryResolve(D, nullptr, nullptr, Range.getStart(), /*IsRef=*/true);
331-
if (Found)
332-
CursorInfo.IsKeywordArgument = true;
340+
if (Found) {
341+
cast<ResolvedValueRefCursorInfo>(CursorInfo).setIsKeywordArgument(true);
342+
}
333343
return !Found;
334344
}
335345

@@ -383,9 +393,9 @@ void swift::ide::simple_display(llvm::raw_ostream &out,
383393
if (info.isInvalid())
384394
return;
385395
out << "Resolved cursor info at ";
386-
auto &SM = info.SF->getASTContext().SourceMgr;
387-
out << SM.getIdentifierForBuffer(*info.SF->getBufferID());
388-
auto LC = SM.getLineAndColumnInBuffer(info.Loc);
396+
auto &SM = info.getSourceFile()->getASTContext().SourceMgr;
397+
out << SM.getIdentifierForBuffer(*info.getSourceFile()->getBufferID());
398+
auto LC = SM.getLineAndColumnInBuffer(info.getLoc());
389399
out << ":" << LC.first << ":" << LC.second;
390400
}
391401

0 commit comments

Comments
 (0)