hokein created this revision.
hokein added a reviewer: kadircet.
Herald added a project: All.
hokein requested review of this revision.
Herald added a project: clang-tools-extra.

By special-casing them at the moment. The tooling stdlib lib doesn't
support these symbols (most important one is std::move).


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D143906

Files:
  clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
  clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp

Index: clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp
===================================================================
--- clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp
+++ clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp
@@ -278,25 +278,31 @@
 
 class HeadersForSymbolTest : public FindHeadersTest {
 protected:
-  llvm::SmallVector<Header> headersForFoo() {
+  llvm::SmallVector<Header> headersFor(llvm::StringRef Name) {
     struct Visitor : public RecursiveASTVisitor<Visitor> {
       const NamedDecl *Out = nullptr;
+      llvm::StringRef Name;
+      Visitor(llvm::StringRef Name) : Name(Name) {}
       bool VisitNamedDecl(const NamedDecl *ND) {
-        if (ND->getName() == "foo") {
+        if (auto *TD = ND->getDescribedTemplate())
+          ND = TD;
+
+        if (ND->getName() == Name) {
           EXPECT_TRUE(Out == nullptr || Out == ND->getCanonicalDecl())
-              << "Found multiple matches for foo.";
+              << "Found multiple matches for " << Name << ".";
           Out = cast<NamedDecl>(ND->getCanonicalDecl());
         }
         return true;
       }
     };
-    Visitor V;
+    Visitor V(Name);
     V.TraverseDecl(AST->context().getTranslationUnitDecl());
     if (!V.Out)
-      ADD_FAILURE() << "Couldn't find any decls named foo.";
+      ADD_FAILURE() << "Couldn't find any decls named " << Name << ".";
     assert(V.Out);
     return headersForSymbol(*V.Out, AST->sourceManager(), &PI);
   }
+  llvm::SmallVector<Header> headersForFoo() { return headersFor("foo"); }
 };
 
 TEST_F(HeadersForSymbolTest, Deduplicates) {
@@ -430,5 +436,54 @@
   EXPECT_THAT(headersForFoo(), ElementsAre(Header(StringRef("\"public.h\"")),
                                            physicalHeader("foo.h")));
 }
+
+TEST_F(HeadersForSymbolTest, AmbiguousStdSymbols) {
+  struct {
+    llvm::StringRef Code;
+    llvm::StringRef Name;
+
+    llvm::StringRef ExpectedHeader;
+  } TestCases[] = {
+      {
+          R"cpp(
+            namespace std {
+             template <typename InputIt, typename OutputIt>
+             constexpr OutputIt move(InputIt first, InputIt last, OutputIt dest);
+            })cpp",
+          "move",
+          "<algorithm>",
+      },
+      {
+          R"cpp(
+            namespace std {
+              template<typename T> constexpr T move(T&& t) noexcept;
+            })cpp",
+          "move",
+          "<utility>",
+      },
+      {
+          R"cpp(
+            namespace std {
+              template<class ForwardIt, class T>
+              ForwardIt remove(ForwardIt first, ForwardIt last, const T& value);
+            })cpp",
+          "remove",
+          "<algorithm>",
+      },
+      {
+          "namespace std { int remove(const char*); }",
+          "remove",
+          "<cstdio>",
+      },
+  };
+
+  for (const auto &T : TestCases) {
+    Inputs.Code = T.Code;
+    buildAST();
+    EXPECT_THAT(headersFor(T.Name),
+                UnorderedElementsAre(Header(T.ExpectedHeader)));
+  }
+}
+
 } // namespace
 } // namespace clang::include_cleaner
Index: clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
===================================================================
--- clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
+++ clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
@@ -82,6 +82,36 @@
   llvm_unreachable("unhandled Symbol kind!");
 }
 
+// Special-case the ambiguous standard library symbols (e.g. std::move) which
+// are not supported by the tooling stdlib lib.
+llvm::SmallVector<Header> specialStandardSymbols(const Symbol &S) {
+  if (S.kind() != Symbol::Declaration || !S.declaration().isInStdNamespace())
+    return {};
+
+  const auto *FD = S.declaration().getAsFunction();
+  if (!FD)
+    return {};
+
+  llvm::StringRef FName = FD->getName();
+  if (FName == "move") {
+    if (FD->getNumParams() == 1)
+      // move(T&& t)
+      return {Header("<utility>")};
+    if (FD->getNumParams() == 3)
+      // move(InputIt first, InputIt last, OutputIt dest);
+      return {Header("<algorithm>")};
+  }
+  if (FName == "remove") {
+    if (FD->getNumParams() == 1)
+      // remove(const char*);
+      return {Header("<cstdio>")};
+    if (FD->getNumParams() == 3)
+      // remove(ForwardIt first, ForwardIt last, const T& value);
+      return {Header("<algorithm>")};
+  }
+  return {};
+}
+
 } // namespace
 
 llvm::SmallVector<Hinted<Header>> findHeaders(const SymbolLocation &Loc,
@@ -141,6 +171,9 @@
 llvm::SmallVector<Header> headersForSymbol(const Symbol &S,
                                            const SourceManager &SM,
                                            const PragmaIncludes *PI) {
+  if (auto Headers = specialStandardSymbols(S); !Headers.empty())
+    return Headers;
+
   // Get headers for all the locations providing Symbol. Same header can be
   // reached through different traversals, deduplicate those into a single
   // Header by merging their hints.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to