From 6d3ec86383860d5c48a026ae32b2d5483585b920 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Mon, 24 Apr 2017 14:04:58 +0000 Subject: [PATCH] [index] The relation between the declarations in template specializations that 'override' declarations in the base template should be recorded This can be used for improved "go to definition" feature in Xcode. rdar://31604739 Differential Revision: https://reviews.llvm.org/D32020 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@301180 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Index/IndexDecl.cpp | 64 ++++++++++++++++-- lib/Index/IndexingContext.cpp | 4 ++ lib/Index/IndexingContext.h | 2 + test/Index/Core/index-source.cpp | 109 +++++++++++++++++++++++++++++++ 4 files changed, 175 insertions(+), 4 deletions(-) diff --git a/lib/Index/IndexDecl.cpp b/lib/Index/IndexDecl.cpp index 8028f8892f..ba65889a6f 100644 --- a/lib/Index/IndexDecl.cpp +++ b/lib/Index/IndexDecl.cpp @@ -144,6 +144,53 @@ public: return true; } + /// Gather the declarations which the given declaration \D overrides in a + /// pseudo-override manner. + /// + /// Pseudo-overrides occur when a class template specialization declares + /// a declaration that has the same name as a similar declaration in the + /// non-specialized template. + void + gatherTemplatePseudoOverrides(const NamedDecl *D, + SmallVectorImpl &Relations) { + if (!IndexCtx.getLangOpts().CPlusPlus) + return; + const auto *CTSD = + dyn_cast(D->getLexicalDeclContext()); + if (!CTSD) + return; + llvm::PointerUnion + Template = CTSD->getSpecializedTemplateOrPartial(); + if (const auto *CTD = Template.dyn_cast()) { + const CXXRecordDecl *Pattern = CTD->getTemplatedDecl(); + bool TypeOverride = isa(D); + for (const NamedDecl *ND : Pattern->lookup(D->getDeclName())) { + if (const auto *CTD = dyn_cast(ND)) + ND = CTD->getTemplatedDecl(); + if (ND->isImplicit()) + continue; + // Types can override other types. + if (!TypeOverride) { + if (ND->getKind() != D->getKind()) + continue; + } else if (!isa(ND)) + continue; + if (const auto *FD = dyn_cast(ND)) { + const auto *DFD = cast(D); + // Function overrides are approximated using the number of parameters. + if (FD->getStorageClass() != DFD->getStorageClass() || + FD->getNumParams() != DFD->getNumParams()) + continue; + } + Relations.emplace_back( + SymbolRoleSet(SymbolRole::RelationOverrideOf) | + SymbolRoleSet(SymbolRole::RelationSpecializationOf), + ND); + } + } + } + bool VisitFunctionDecl(const FunctionDecl *D) { if (D->isDeleted()) return true; @@ -158,6 +205,7 @@ public: Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, *I); } } + gatherTemplatePseudoOverrides(D, Relations); TRY_DECL(D, IndexCtx.handleDecl(D, Roles, Relations)); handleDeclarator(D); @@ -194,14 +242,18 @@ public: } bool VisitVarDecl(const VarDecl *D) { - TRY_DECL(D, IndexCtx.handleDecl(D)); + SmallVector Relations; + gatherTemplatePseudoOverrides(D, Relations); + TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations)); handleDeclarator(D); IndexCtx.indexBody(D->getInit(), D); return true; } bool VisitFieldDecl(const FieldDecl *D) { - TRY_DECL(D, IndexCtx.handleDecl(D)); + SmallVector Relations; + gatherTemplatePseudoOverrides(D, Relations); + TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations)); handleDeclarator(D); if (D->isBitField()) IndexCtx.indexBody(D->getBitWidth(), D); @@ -233,7 +285,9 @@ public: bool VisitTypedefNameDecl(const TypedefNameDecl *D) { if (!D->isTransparentTag()) { - TRY_DECL(D, IndexCtx.handleDecl(D)); + SmallVector Relations; + gatherTemplatePseudoOverrides(D, Relations); + TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations)); IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); } return true; @@ -243,7 +297,9 @@ public: // Non-free standing tags are handled in indexTypeSourceInfo. if (D->isFreeStanding()) { if (D->isThisDeclarationADefinition()) { - IndexCtx.indexTagDecl(D); + SmallVector Relations; + gatherTemplatePseudoOverrides(D, Relations); + IndexCtx.indexTagDecl(D, Relations); } else { auto *Parent = dyn_cast(D->getDeclContext()); return IndexCtx.handleReference(D, D->getLocation(), Parent, diff --git a/lib/Index/IndexingContext.cpp b/lib/Index/IndexingContext.cpp index 254abecd4e..709a23657b 100644 --- a/lib/Index/IndexingContext.cpp +++ b/lib/Index/IndexingContext.cpp @@ -28,6 +28,10 @@ bool IndexingContext::shouldIndex(const Decl *D) { return !isGeneratedDecl(D); } +const LangOptions &IndexingContext::getLangOpts() const { + return Ctx->getLangOpts(); +} + bool IndexingContext::shouldIndexFunctionLocalSymbols() const { return IndexOpts.IndexFunctionLocals; } diff --git a/lib/Index/IndexingContext.h b/lib/Index/IndexingContext.h index c70cb0a827..566651c83a 100644 --- a/lib/Index/IndexingContext.h +++ b/lib/Index/IndexingContext.h @@ -50,6 +50,8 @@ public: bool shouldIndex(const Decl *D); + const LangOptions &getLangOpts() const; + bool shouldSuppressRefs() const { return false; } diff --git a/test/Index/Core/index-source.cpp b/test/Index/Core/index-source.cpp index 5d4a1be456..76b8a150ed 100644 --- a/test/Index/Core/index-source.cpp +++ b/test/Index/Core/index-source.cpp @@ -111,3 +111,112 @@ template<> class PartialSpecilizationClass { }; // CHECK: [[@LINE-1]]:7 | class(Gen,TS)/C++ | PartialSpecilizationClass | c:@S@PartialSpecilizationClass>#I#I | | Def,RelSpecialization | rel: 1 // CHECK-NEXT: RelSpecialization | PartialSpecilizationClass | c:@ST>2#T#T@PartialSpecilizationClass + +template +class PseudoOverridesInSpecializations { + void function() { } + void function(int) { } + + static void staticFunction() { } + + int field; + static int variable; + + typedef T TypeDef; + using TypeAlias = T; + + enum anEnum { }; + + struct Struct { }; + union Union { }; + + using TypealiasOrRecord = void; + + template struct InnerTemplate { }; + template struct InnerTemplate { }; +}; + +template<> +class PseudoOverridesInSpecializations { + void function() { } +// CHECK: [[@LINE-1]]:8 | instance-method/C++ | function | c:@S@PseudoOverridesInSpecializations>#d#I@F@function# | __ZN32PseudoOverridesInSpecializationsIdiE8functionEv | Def,RelChild,RelOver,RelSpecialization | rel: 2 +// CHECK-NEXT: RelChild +// CHECK-NEXT: RelOver,RelSpecialization | function | c:@ST>2#T#T@PseudoOverridesInSpecializations@F@function# + + void staticFunction() { } +// CHECK: [[@LINE-1]]:8 | instance-method/C++ | staticFunction | c:@S@PseudoOverridesInSpecializations>#d#I@F@staticFunction# | __ZN32PseudoOverridesInSpecializationsIdiE14staticFunctionEv | Def,RelChild | rel: 1 +// CHECK-NOT: RelOver + + int notOverridingField = 0; + +// CHECK-LABEL: checLabelBreak + int checLabelBreak = 0; + + int field = 0; +// CHECK: [[@LINE-1]]:7 | field/C++ | field | c:@S@PseudoOverridesInSpecializations>#d#I@FI@field | | Def,RelChild,RelOver,RelSpecialization | rel: 2 +// CHECK-NEXT: RelChild +// CHECK-NEXT: RelOver,RelSpecialization | field | c:@ST>2#T#T@PseudoOverridesInSpecializations@FI@field + + static double variable; +// CHECK: [[@LINE-1]]:17 | static-property/C++ | variable | c:@S@PseudoOverridesInSpecializations>#d#I@variable | __ZN32PseudoOverridesInSpecializationsIdiE8variableE | Decl,RelChild,RelOver,RelSpecialization | rel: 2 +// CHECK-NEXT: RelChild +// CHECK-NEXT: RelOver,RelSpecialization | variable | c:@ST>2#T#T@PseudoOverridesInSpecializations@variable + + typedef double TypeDef; +// CHECK: [[@LINE-1]]:18 | type-alias/C | TypeDef | c:index-source.cpp@S@PseudoOverridesInSpecializations>#d#I@T@TypeDef | | Def,RelChild,RelOver,RelSpecialization | rel: 2 +// CHECK-NEXT: RelChild +// CHECK-NEXT: RelOver,RelSpecialization | TypeDef | c:index-source.cpp@ST>2#T#T@PseudoOverridesInSpecializations@T@TypeDef + + using TypeAlias = int; +// CHECK: [[@LINE-1]]:9 | type-alias/C++ | TypeAlias | c:@S@PseudoOverridesInSpecializations>#d#I@TypeAlias | | Def,RelChild,RelOver,RelSpecialization | rel: 2 +// CHECK-NEXT: RelChild +// CHECK-NEXT: RelOver,RelSpecialization | TypeAlias | c:@ST>2#T#T@PseudoOverridesInSpecializations@TypeAlias + + enum anEnum { }; +// CHECK: [[@LINE-1]]:8 | enum/C | anEnum | c:@S@PseudoOverridesInSpecializations>#d#I@E@anEnum | | Def,RelChild,RelOver,RelSpecialization | rel: 2 +// CHECK-NEXT: RelChild +// CHECK-NEXT: RelOver,RelSpecialization | anEnum | c:@ST>2#T#T@PseudoOverridesInSpecializations@E@anEnum + class Struct { }; +// CHECK: [[@LINE-1]]:9 | class/C++ | Struct | c:@S@PseudoOverridesInSpecializations>#d#I@S@Struct | | Def,RelChild,RelOver,RelSpecialization | rel: 2 +// CHECK-NEXT: RelChild +// CHECK-NEXT: RelOver,RelSpecialization | Struct | c:@ST>2#T#T@PseudoOverridesInSpecializations@S@Struct + union Union { }; +// CHECK: [[@LINE-1]]:9 | union/C | Union | c:@S@PseudoOverridesInSpecializations>#d#I@U@Union | | Def,RelChild,RelOver,RelSpecialization | rel: 2 +// CHECK-NEXT: RelChild +// CHECK-NEXT: RelOver,RelSpecialization | Union | c:@ST>2#T#T@PseudoOverridesInSpecializations@U@Union + + struct TypealiasOrRecord { }; +// CHECK: [[@LINE-1]]:10 | struct/C | TypealiasOrRecord | c:@S@PseudoOverridesInSpecializations>#d#I@S@TypealiasOrRecord | | Def,RelChild,RelOver,RelSpecialization | rel: 2 +// CHECK-NEXT: RelChild +// CHECK-NEXT: RelOver,RelSpecialization | TypealiasOrRecord | c:@ST>2#T#T@PseudoOverridesInSpecializations@TypealiasOrRecord + + template struct InnerTemplate { }; +// CHECK: [[@LINE-1]]:31 | struct(Gen)/C++ | InnerTemplate | c:@S@PseudoOverridesInSpecializations>#d#I@ST>1#T@InnerTemplate | | Def,RelChild,RelOver,RelSpecialization | rel: 2 +// CHECK-NEXT: RelChild +// CHECK-NEXT: RelOver,RelSpecialization | InnerTemplate | c:@ST>2#T#T@PseudoOverridesInSpecializations@ST>1#T@InnerTemplate + template struct InnerTemplate { }; +// CHECK-NOT: RelOver +}; + +template +class PseudoOverridesInSpecializations { + typedef float TypealiasOrRecord; +// CHECK: [[@LINE-1]]:17 | type-alias/C | TypealiasOrRecord | c:index-source.cpp@SP>1#T@PseudoOverridesInSpecializations>#f#t0.0@T@TypealiasOrRecord | | Def,RelChild,RelOver,RelSpecialization | rel: 2 +// CHECK-NEXT: RelChild +// CHECK-NEXT: RelOver,RelSpecialization | TypealiasOrRecord | c:@ST>2#T#T@PseudoOverridesInSpecializations@TypealiasOrRecord +}; + +template +class ConflictingPseudoOverridesInSpecialization { + void foo(T x); + void foo(U x); +}; + +template +class ConflictingPseudoOverridesInSpecialization { + void foo(T x); +// CHECK: [[@LINE-1]]:8 | instance-method/C++ | foo | c:@SP>1#T@ConflictingPseudoOverridesInSpecialization>#I#t0.0@F@foo#S0_# | | Decl,RelChild,RelOver,RelSpecialization | rel: 3 +// CHECK-NEXT: RelChild +// CHECK-NEXT: RelOver,RelSpecialization | foo | c:@ST>2#T#T@ConflictingPseudoOverridesInSpecialization@F@foo#t0.0# +// CHECK-NEXT: RelOver,RelSpecialization | foo | c:@ST>2#T#T@ConflictingPseudoOverridesInSpecialization@F@foo#t0.1# +}; -- 2.40.0