Skip to content

Commit 721e3e9

Browse files
authored
Merge pull request #63127 from bnbarham/fix-shadowed-decls
[Index] Resolve any shadowed references to the decl they shadow
2 parents fa1f536 + 7b4ab8d commit 721e3e9

File tree

3 files changed

+134
-55
lines changed

3 files changed

+134
-55
lines changed

lib/IDE/IDETypeChecking.cpp

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -918,35 +918,30 @@ SmallVector<std::pair<ValueDecl *, ValueDecl *>, 1>
918918
swift::getShorthandShadows(CaptureListExpr *CaptureList, DeclContext *DC) {
919919
SmallVector<std::pair<ValueDecl *, ValueDecl *>, 1> Result;
920920
for (auto Capture : CaptureList->getCaptureList()) {
921-
if (Capture.PBD->getPatternList().size() != 1) {
921+
if (Capture.PBD->getPatternList().size() != 1)
922922
continue;
923-
}
923+
924924
Expr *Init = Capture.PBD->getInit(0);
925-
if (!Init) {
926-
continue;
927-
}
928-
if (auto UDRE = dyn_cast<UnresolvedDeclRefExpr>(Init)) {
929-
if (DC) {
930-
Init = resolveDeclRefExpr(UDRE, DC, /*replaceInvalidRefsWithErrors=*/false);
931-
}
932-
}
933-
auto *DRE = dyn_cast_or_null<DeclRefExpr>(Init);
934-
if (!DRE) {
925+
if (!Init)
935926
continue;
936-
}
937927

938928
auto DeclaredVar = Capture.getVar();
939-
if (DeclaredVar->getLoc() != DRE->getLoc()) {
929+
if (DeclaredVar->getLoc() != Init->getLoc()) {
940930
// We have a capture like `[foo]` if the declared var and the
941931
// reference share the same location.
942932
continue;
943933
}
944934

945-
auto *ReferencedVar = dyn_cast_or_null<VarDecl>(DRE->getDecl());
946-
if (!ReferencedVar) {
947-
continue;
935+
if (auto UDRE = dyn_cast<UnresolvedDeclRefExpr>(Init)) {
936+
if (DC) {
937+
Init = resolveDeclRefExpr(UDRE, DC, /*replaceInvalidRefsWithErrors=*/false);
938+
}
948939
}
949940

941+
auto *ReferencedVar = Init->getReferencedDecl().getDecl();
942+
if (!ReferencedVar)
943+
continue;
944+
950945
assert(DeclaredVar->getName() == ReferencedVar->getName());
951946

952947
Result.emplace_back(std::make_pair(DeclaredVar, ReferencedVar));
@@ -958,28 +953,23 @@ SmallVector<std::pair<ValueDecl *, ValueDecl *>, 1>
958953
swift::getShorthandShadows(LabeledConditionalStmt *CondStmt, DeclContext *DC) {
959954
SmallVector<std::pair<ValueDecl *, ValueDecl *>, 1> Result;
960955
for (const StmtConditionElement &Cond : CondStmt->getCond()) {
961-
if (Cond.getKind() != StmtConditionElement::CK_PatternBinding) {
956+
if (Cond.getKind() != StmtConditionElement::CK_PatternBinding)
962957
continue;
963-
}
958+
964959
Expr *Init = Cond.getInitializer();
965960
if (auto UDRE = dyn_cast<UnresolvedDeclRefExpr>(Init)) {
966961
if (DC) {
967962
Init = resolveDeclRefExpr(UDRE, DC, /*replaceInvalidRefsWithErrors=*/false);
968963
}
969964
}
970-
auto InitDeclRef = dyn_cast<DeclRefExpr>(Init);
971-
if (!InitDeclRef) {
972-
continue;
973-
}
974-
auto ReferencedVar = dyn_cast_or_null<VarDecl>(InitDeclRef->getDecl());
975-
if (!ReferencedVar) {
965+
966+
auto ReferencedVar = Init->getReferencedDecl().getDecl();
967+
if (!ReferencedVar)
976968
continue;
977-
}
978969

979970
Cond.getPattern()->forEachVariable([&](VarDecl *DeclaredVar) {
980-
if (DeclaredVar->getLoc() != Init->getLoc()) {
971+
if (DeclaredVar->getLoc() != Init->getLoc())
981972
return;
982-
}
983973
assert(DeclaredVar->getName() == ReferencedVar->getName());
984974
Result.emplace_back(std::make_pair(DeclaredVar, ReferencedVar));
985975
});

lib/Index/Index.cpp

Lines changed: 56 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/AST/Pattern.h"
2323
#include "swift/AST/ProtocolConformance.h"
2424
#include "swift/AST/SourceFile.h"
25+
#include "swift/AST/Stmt.h"
2526
#include "swift/AST/TypeRepr.h"
2627
#include "swift/AST/Types.h"
2728
#include "swift/AST/USRGeneration.h"
@@ -449,8 +450,9 @@ class IndexSwiftASTWalker : public SourceEntityWalker {
449450
ContainerTracker Containers;
450451

451452
// Contains a mapping for captures of the form [x], from the declared "x"
452-
// to the captured "x" in the enclosing scope.
453-
llvm::DenseMap<VarDecl *, VarDecl *> sameNamedCaptures;
453+
// to the captured "x" in the enclosing scope. Also includes shorthand if
454+
// let bindings.
455+
llvm::DenseMap<ValueDecl *, ValueDecl *> sameNamedCaptures;
454456

455457
bool getNameAndUSR(ValueDecl *D, ExtensionDecl *ExtD,
456458
StringRef &name, StringRef &USR) {
@@ -559,6 +561,16 @@ class IndexSwiftASTWalker : public SourceEntityWalker {
559561
return false;
560562
}
561563

564+
ValueDecl *firstDecl(ValueDecl *D) {
565+
while (true) {
566+
auto captured = sameNamedCaptures.find(D);
567+
if (captured == sameNamedCaptures.end())
568+
break;
569+
D = captured->second;
570+
}
571+
return D;
572+
}
573+
562574
public:
563575
IndexSwiftASTWalker(IndexDataConsumer &IdxConsumer, ASTContext &Ctx,
564576
SourceFile *SF = nullptr)
@@ -706,22 +718,11 @@ class IndexSwiftASTWalker : public SourceEntityWalker {
706718
if (Cancelled)
707719
return false;
708720

709-
// Record any captures of the form [x], herso we can treat
710-
if (auto captureList = dyn_cast<CaptureListExpr>(E)) {
711-
for (const auto &capture : captureList->getCaptureList()) {
712-
auto declaredVar = capture.getVar();
713-
if (capture.PBD->getEqualLoc(0).isValid())
714-
continue;
715-
716-
VarDecl *capturedVar = nullptr;
717-
if (auto init = capture.PBD->getInit(0)) {
718-
if (auto declRef = dyn_cast<DeclRefExpr>(init))
719-
capturedVar = dyn_cast_or_null<VarDecl>(declRef->getDecl());
720-
}
721-
722-
if (capturedVar) {
723-
sameNamedCaptures[declaredVar] = capturedVar;
724-
}
721+
// Record any same named captures/shorthand if let bindings so we can
722+
// treat their references as references to the original decl.
723+
if (auto *captureList = dyn_cast<CaptureListExpr>(E)) {
724+
for (auto shadows : getShorthandShadows(captureList)) {
725+
sameNamedCaptures[shadows.first] = shadows.second;
725726
}
726727
}
727728

@@ -739,6 +740,20 @@ class IndexSwiftASTWalker : public SourceEntityWalker {
739740
return true;
740741
}
741742

743+
bool walkToStmtPre(Stmt *stmt) override {
744+
if (Cancelled)
745+
return false;
746+
747+
// Record any same named captures/shorthand if let bindings so we can
748+
// treat their references as references to the original decl.
749+
if (auto *condition = dyn_cast<LabeledConditionalStmt>(stmt)) {
750+
for (auto shadows : getShorthandShadows(condition)) {
751+
sameNamedCaptures[shadows.first] = shadows.second;
752+
}
753+
}
754+
return true;
755+
}
756+
742757
bool walkToTypeReprPre(TypeRepr *T) override {
743758
if (Cancelled)
744759
return false;
@@ -820,6 +835,11 @@ class IndexSwiftASTWalker : public SourceEntityWalker {
820835
if (isRepressed(Loc) || Loc.isInvalid())
821836
return true;
822837

838+
// Dig back to the original captured variable
839+
if (auto *VD = dyn_cast<VarDecl>(D)) {
840+
D = firstDecl(D);
841+
}
842+
823843
IndexSymbol Info;
824844

825845
if (Data.isImplicit)
@@ -1459,6 +1479,24 @@ bool IndexSwiftASTWalker::reportExtension(ExtensionDecl *D) {
14591479
}
14601480

14611481
bool IndexSwiftASTWalker::report(ValueDecl *D) {
1482+
auto *shadowedDecl = firstDecl(D);
1483+
if (D != shadowedDecl) {
1484+
// Report a reference to the shadowed decl
1485+
SourceLoc loc = D->getNameLoc();
1486+
1487+
IndexSymbol info;
1488+
if (!reportRef(shadowedDecl, loc, info, AccessKind::Read))
1489+
return false;
1490+
1491+
// Suppress the reference if there is any (it is implicit and hence
1492+
// already skipped in the shorthand if let case, but explicit in the
1493+
// captured case).
1494+
repressRefAtLoc(loc);
1495+
1496+
// Skip the definition of a shadowed decl
1497+
return true;
1498+
}
1499+
14621500
if (startEntityDecl(D)) {
14631501
// Pass accessors.
14641502
if (auto StoreD = dyn_cast<AbstractStorageDecl>(D)) {
@@ -1632,15 +1670,6 @@ bool IndexSwiftASTWalker::initIndexSymbol(ValueDecl *D, SourceLoc Loc,
16321670
if (auto *VD = dyn_cast<VarDecl>(D)) {
16331671
// Always base the symbol information on the canonical VarDecl
16341672
D = VD->getCanonicalVarDecl();
1635-
1636-
// Dig back to the original captured variable.
1637-
while (true) {
1638-
auto captured = sameNamedCaptures.find(cast<VarDecl>(D));
1639-
if (captured == sameNamedCaptures.end())
1640-
break;
1641-
1642-
D = captured->second;
1643-
}
16441673
}
16451674

16461675
Info.decl = D;

test/Index/index_shadow.swift

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-ide-test -print-indexed-symbols -source-filename %s --include-locals | %FileCheck %s
3+
4+
// The index will output references to the shadowed-declaration rather than
5+
// the one defined by the shorthand if-let or capture. It also skips
6+
// outputting the shadowing-definiiton since it would then have no references.
7+
8+
struct ShadowedTest {
9+
// CHECK: [[@LINE+1]]:7 {{.*}} s:14swift_ide_test12ShadowedTestV11shadowedVarSiSgSgvp {{.*}}Def
10+
let shadowedVar: Int?? = 1
11+
12+
func localShadowTest() {
13+
// CHECK: [[@LINE+1]]:9 {{.*}} s:14swift_ide_test12ShadowedTestV011localShadowE0yyF0fD3VarL_SiSgvp {{.*}}Def
14+
let localShadowedVar: Int? = 2
15+
16+
// CHECK-NOT: [[@LINE+2]]:12 {{.*}} localShadowedVar {{.*}}Def
17+
// CHECK: [[@LINE+1]]:12 {{.*}} s:14swift_ide_test12ShadowedTestV011localShadowE0yyF0fD3VarL_SiSgvp {{.*}}Ref
18+
if let localShadowedVar {
19+
// CHECK: [[@LINE+1]]:11 {{.*}} s:14swift_ide_test12ShadowedTestV011localShadowE0yyF0fD3VarL_SiSgvp {{.*}}Ref
20+
_ = localShadowedVar
21+
}
22+
23+
// CHECK-NOT: [[@LINE+2]]:12 {{.*}} localShadowedVar {{.*}}Def
24+
// CHECK: [[@LINE+1]]:12 {{.*}} s:14swift_ide_test12ShadowedTestV011localShadowE0yyF0fD3VarL_SiSgvp {{.*}}Ref
25+
_ = { [localShadowedVar] in
26+
// CHECK: [[@LINE+1]]:11 {{.*}} s:14swift_ide_test12ShadowedTestV011localShadowE0yyF0fD3VarL_SiSgvp {{.*}}Ref
27+
_ = localShadowedVar
28+
}
29+
}
30+
31+
func shadowTest() {
32+
// CHECK-NOT: [[@LINE+2]]:12 {{.*}} shadowedVar {{.*}}Def
33+
// CHECK: [[@LINE+1]]:12 {{.*}} s:14swift_ide_test12ShadowedTestV11shadowedVarSiSgSgvp {{.*}}Ref
34+
if let shadowedVar {
35+
// CHECK: [[@LINE+1]]:11 {{.*}} s:14swift_ide_test12ShadowedTestV11shadowedVarSiSgSgvp {{.*}}Ref
36+
_ = shadowedVar
37+
38+
// CHECK-NOT: [[@LINE+2]]:14 {{.*}} shadowedVar {{.*}}Def
39+
// CHECK: [[@LINE+1]]:14 {{.*}} s:14swift_ide_test12ShadowedTestV11shadowedVarSiSgSgvp {{.*}}Ref
40+
if let shadowedVar {
41+
// CHECK: [[@LINE+1]]:13 {{.*}} s:14swift_ide_test12ShadowedTestV11shadowedVarSiSgSgvp {{.*}}Ref
42+
_ = shadowedVar
43+
}
44+
}
45+
46+
// CHECK-NOT: [[@LINE+2]]:12 {{.*}} shadowedVar {{.*}}Def
47+
// CHECK: [[@LINE+1]]:12 {{.*}} s:14swift_ide_test12ShadowedTestV11shadowedVarSiSgSgvp {{.*}}Ref
48+
_ = { [shadowedVar] in
49+
// CHECK: [[@LINE+1]]:11 {{.*}} s:14swift_ide_test12ShadowedTestV11shadowedVarSiSgSgvp {{.*}}Ref
50+
_ = shadowedVar
51+
52+
// CHECK-NOT: [[@LINE+2]]:14 {{.*}} shadowedVar {{.*}}Def
53+
// CHECK: [[@LINE+1]]:14 {{.*}} s:14swift_ide_test12ShadowedTestV11shadowedVarSiSgSgvp {{.*}}Ref
54+
_ = { [shadowedVar] in
55+
// CHECK: [[@LINE+1]]:13 {{.*}} s:14swift_ide_test12ShadowedTestV11shadowedVarSiSgSgvp {{.*}}Ref
56+
_ = shadowedVar
57+
}
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)