jvikstrom updated this revision to Diff 213808.
jvikstrom marked 4 inline comments as done.
jvikstrom added a comment.

Added more ways to specialize/instantiate templates to test.


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
@@ -21,6 +21,8 @@
 namespace {
 
 using ::testing::ElementsAre;
+using ::testing::ElementsAreArray;
+
 
 TEST(ClangdUnitTest, GetBeginningOfIdentifier) {
   std::string Preamble = R"cpp(
@@ -103,6 +105,57 @@
   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 <>
+    struct V<bool> {};
+
+    template<class T>
+    T foo = T(10);
+    int i = foo<int>;
+    double d = foo<double>;
+    template <class T>
+    int foo<T*> = 0;
+    template <>
+    int foo<bool> = 0;
+  )cpp";
+
+  auto AST = TU.build();
+  EXPECT_THAT(
+      AST.getLocalTopLevelDecls(),
+      ElementsAreArray({DeclNamed("f"), DeclNamed("f"), DeclNamed("f"),
+                        DeclNamed("V"), DeclNamed("V"), DeclNamed("V"),
+                        DeclNamed("foo"), DeclNamed("i"), DeclNamed("d"),
+                        DeclNamed("foo"), DeclNamed("foo")}));
+}
+
 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

Reply via email to