jvikstrom updated this revision to Diff 213608. jvikstrom marked an inline comment as done. jvikstrom added a comment.
Added tests for making sure explicit specializations, explicit instantiations, partial instantiations, explicit declarations and template variables are in topLevelDecls. Also added a test to SemanticHighlightingTests to make sure that explicit instantiations are being traversed (so they aren't accidentaly removed from topLevelDecls). Also added comment for the two added functions in AST.h. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D65510/new/ https://reviews.llvm.org/D65510 Files: clang-tools-extra/clangd/AST.cpp clang-tools-extra/clangd/AST.h clang-tools-extra/clangd/ClangdUnit.cpp clang-tools-extra/clangd/CodeComplete.cpp clang-tools-extra/clangd/unittests/ClangdUnitTests.cpp clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
Index: clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp +++ clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp @@ -249,6 +249,12 @@ template<typename $TemplateParameter[[T]]> void $Function[[foo]]($TemplateParameter[[T]] ...); + )cpp", + R"cpp( + template <class $TemplateParameter[[T]]> + struct $Class[[Tmpl]] {$TemplateParameter[[T]] $Field[[x]] = 0;}; + extern template struct $Class[[Tmpl]]<float>; + template struct $Class[[Tmpl]]<double>; )cpp"}; for (const auto &TestCase : TestCases) { checkHighlightings(TestCase); Index: clang-tools-extra/clangd/unittests/ClangdUnitTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/ClangdUnitTests.cpp +++ clang-tools-extra/clangd/unittests/ClangdUnitTests.cpp @@ -103,6 +103,49 @@ EXPECT_THAT(AST.getLocalTopLevelDecls(), ElementsAre(DeclNamed("main"))); } +TEST(ClangdUnitTest, DoesNotGetImplicitTemplateTopDecls) { + TestTU TU; + TU.Code = R"cpp( + template<typename T> + void f(T) {} + void s() { + f(10UL); + } + )cpp"; + + auto AST = TU.build(); + EXPECT_THAT(AST.getLocalTopLevelDecls(), + ElementsAre(DeclNamed("f"), DeclNamed("s"))); +} + +TEST(ClangdUnitTest, + GetsExplicitInstantiationAndSpecializationTemplateTopDecls) { + TestTU TU; + TU.Code = R"cpp( + template <typename T> + void f(T) {} + template<> + void f(bool); + template void f(double); + + template <class T> + struct V {}; + template<class T> + struct V<T*> {}; + + template<class T> + T foo = T(10); + int i = foo<int>; + double d = foo<double>; + )cpp"; + + auto AST = TU.build(); + EXPECT_THAT(AST.getLocalTopLevelDecls(), + ElementsAre(DeclNamed("f"), DeclNamed("f"), DeclNamed("f"), + DeclNamed("V"), DeclNamed("V"), DeclNamed("foo"), + DeclNamed("i"), DeclNamed("d"))); +} + TEST(ClangdUnitTest, TokensAfterPreamble) { TestTU TU; TU.AdditionalFiles["foo.h"] = R"( Index: clang-tools-extra/clangd/CodeComplete.cpp =================================================================== --- clang-tools-extra/clangd/CodeComplete.cpp +++ clang-tools-extra/clangd/CodeComplete.cpp @@ -1674,13 +1674,6 @@ } }; -template <class T> bool isExplicitTemplateSpecialization(const NamedDecl &ND) { - if (const auto *TD = dyn_cast<T>(&ND)) - if (TD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) - return true; - return false; -} - } // namespace clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const { @@ -1783,9 +1776,7 @@ }; // We only complete symbol's name, which is the same as the name of the // *primary* template in case of template specializations. - if (isExplicitTemplateSpecialization<FunctionDecl>(ND) || - isExplicitTemplateSpecialization<CXXRecordDecl>(ND) || - isExplicitTemplateSpecialization<VarDecl>(ND)) + if (isExplicitTemplateSpecialization(&ND)) return false; if (InTopLevelScope(ND)) Index: clang-tools-extra/clangd/ClangdUnit.cpp =================================================================== --- clang-tools-extra/clangd/ClangdUnit.cpp +++ clang-tools-extra/clangd/ClangdUnit.cpp @@ -9,6 +9,7 @@ #include "ClangdUnit.h" #include "../clang-tidy/ClangTidyDiagnosticConsumer.h" #include "../clang-tidy/ClangTidyModuleRegistry.h" +#include "AST.h" #include "Compiler.h" #include "Diagnostics.h" #include "Headers.h" @@ -19,8 +20,11 @@ #include "index/CanonicalIncludes.h" #include "index/Index.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/Specifiers.h" #include "clang/Basic/TokenKinds.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" @@ -70,6 +74,9 @@ auto &SM = D->getASTContext().getSourceManager(); if (!isInsideMainFile(D->getLocation(), SM)) continue; + if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) + if (isImplicitTemplateInstantiation(ND)) + continue; // ObjCMethodDecl are not actually top-level decls. if (isa<ObjCMethodDecl>(D)) Index: clang-tools-extra/clangd/AST.h =================================================================== --- clang-tools-extra/clangd/AST.h +++ clang-tools-extra/clangd/AST.h @@ -80,9 +80,23 @@ /// take in to account using directives etc /// Example: shortenNamespace("ns1::MyClass<ns1::OtherClass>", "ns1") /// --> "MyClass<ns1::OtherClass>" -std::string shortenNamespace(const llvm::StringRef OriginalName, - const llvm::StringRef CurrentNamespace); - +std::string shortenNamespace(const llvm::StringRef OriginalName, + const llvm::StringRef CurrentNamespace); + +/// Indicates if \p D is a template instantiation implicitly generated by the +/// compiler, e.g. +/// template <class T> struct vector {}; +/// vector<int> v; // 'vector<int>' is an implicit instantiation +bool isImplicitTemplateInstantiation(const NamedDecl *D); +/// Indicates if \p D is an explicit template specialization, e.g. +/// template <class T> struct vector {}; +/// template <> struct vector<bool> {}; // <-- explicit specialization +/// +/// Note that explicit instantiations are NOT explicit specializations, albeit +/// they look similar. +/// template struct vector<bool>; // <-- explicit instantiation, NOT an +/// explicit specialization. +bool isExplicitTemplateSpecialization(const NamedDecl *D); } // namespace clangd } // namespace clang Index: clang-tools-extra/clangd/AST.cpp =================================================================== --- clang-tools-extra/clangd/AST.cpp +++ clang-tools-extra/clangd/AST.cpp @@ -14,6 +14,7 @@ #include "clang/AST/TemplateBase.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/Specifiers.h" #include "clang/Index/USRGeneration.h" #include "llvm/ADT/Optional.h" #include "llvm/Support/Casting.h" @@ -40,8 +41,32 @@ // contain TemplateArgumentLoc information. return llvm::None; } + +template <class T> +bool isTemplateSpecializationKind(const NamedDecl *D, + TemplateSpecializationKind Kind) { + if (const auto *TD = dyn_cast<T>(D)) + return TD->getTemplateSpecializationKind() == Kind; + return false; +} + +bool isTemplateSpecializationKind(const NamedDecl *D, + TemplateSpecializationKind Kind) { + return isTemplateSpecializationKind<FunctionDecl>(D, Kind) || + isTemplateSpecializationKind<CXXRecordDecl>(D, Kind) || + isTemplateSpecializationKind<VarDecl>(D, Kind); +} + } // namespace +bool isImplicitTemplateInstantiation(const NamedDecl *D) { + return isTemplateSpecializationKind(D, TSK_ImplicitInstantiation); +} + +bool isExplicitTemplateSpecialization(const NamedDecl *D) { + return isTemplateSpecializationKind(D, TSK_ExplicitSpecialization); +} + // Returns true if the complete name of decl \p D is spelled in the source code. // This is not the case for: // * symbols formed via macro concatenation, the spelling location will
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits