diff --git a/clang/include/clang/Tooling/Inclusions/StandardLibrary.h b/clang/include/clang/Tooling/Inclusions/StandardLibrary.h --- a/clang/include/clang/Tooling/Inclusions/StandardLibrary.h +++ b/clang/include/clang/Tooling/Inclusions/StandardLibrary.h @@ -37,6 +37,7 @@ // "" and "" (and their symbols) are treated differently. class Header { public: + static std::vector
all(); // Name should contain the angle brackets, e.g. "". static std::optional
named(llvm::StringRef Name); @@ -63,16 +64,18 @@ // for them. class Symbol { public: + static std::vector all(); /// \p Scope should have the trailing "::", for example: /// named("std::chrono::", "system_clock") static std::optional named(llvm::StringRef Scope, llvm::StringRef Name); friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Symbol &S) { - return OS << S.scope() << S.name(); + return OS << S.qualified_name(); } llvm::StringRef scope() const; llvm::StringRef name() const; + llvm::StringRef qualified_name() const; // The preferred header for this symbol (e.g. the suggested insertion). Header header() const; // Some symbols may be provided by multiple headers. diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -17203,6 +17203,10 @@ SkipBody->Previous = Def; return Def; } else { + llvm::errs() << "got here\n"; + Def->dump(); + Hidden->dump(); + NameLoc.dump(getSourceManager()); SkipBody->ShouldSkip = true; SkipBody->Previous = Def; makeMergedDefinitionVisible(Hidden); diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp --- a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp +++ b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp @@ -15,23 +15,34 @@ namespace tooling { namespace stdlib { +// Header::ID => header name static llvm::StringRef *HeaderNames; -static std::pair *SymbolNames; -static unsigned *SymbolHeaderIDs; +// Header name => Header::ID static llvm::DenseMap *HeaderIDs; -// Maps symbol name -> Symbol::ID, within a namespace. + +static unsigned SymbolCount = 0; +// Symbol::ID => symbol qualified_name/name/scope +static struct SymbolName { + const char *Data; // std::vector + unsigned ScopeLen; // ~~~~~ + unsigned NameLen; // ~~~~~~ +} *SymbolNames; +// Symbol name -> Symbol::ID, within a namespace. using NSSymbolMap = llvm::DenseMap; static llvm::DenseMap *NamespaceSymbols; +// Symbol::ID => Header::ID +static unsigned *SymbolHeaderIDs; static int initialize() { - unsigned SymCount = 0; -#define SYMBOL(Name, NS, Header) ++SymCount; + SymbolCount = 0; +#define SYMBOL(Name, NS, Header) ++SymbolCount; #include "clang/Tooling/Inclusions/CSymbolMap.inc" #include "clang/Tooling/Inclusions/StdSymbolMap.inc" #undef SYMBOL - SymbolNames = new std::remove_reference_t[SymCount]; + SymbolNames = + new std::remove_reference_t[SymbolCount]; SymbolHeaderIDs = - new std::remove_reference_t[SymCount]; + new std::remove_reference_t[SymbolCount]; NamespaceSymbols = new std::remove_reference_t; HeaderIDs = new std::remove_reference_t; @@ -46,20 +57,25 @@ return HeaderIDs->try_emplace(Header, HeaderIDs->size()).first->second; }; - auto Add = [&, SymIndex(0)](llvm::StringRef Name, llvm::StringRef NS, + auto Add = [&, SymIndex(0)](llvm::StringRef QName, unsigned NSLen, llvm::StringRef HeaderName) mutable { - if (NS == "None") - NS = ""; + // Correct "Nonefoo" => foo. + // FIXME: get rid of "None" from the generated mapping files. + if (QName.take_front(NSLen) == "None") { + QName = QName.drop_front(NSLen); + NSLen = 0; + } - SymbolNames[SymIndex] = {NS, Name}; + SymbolNames[SymIndex] = {QName.data(), NSLen, + static_cast(QName.size() - NSLen)}; SymbolHeaderIDs[SymIndex] = AddHeader(HeaderName); - NSSymbolMap &NSSymbols = AddNS(NS); - NSSymbols.try_emplace(Name, SymIndex); + NSSymbolMap &NSSymbols = AddNS(QName.take_front(NSLen)); + NSSymbols.try_emplace(QName.drop_front(NSLen), SymIndex); ++SymIndex; }; -#define SYMBOL(Name, NS, Header) Add(#Name, #NS, #Header); +#define SYMBOL(Name, NS, Header) Add(#NS #Name, strlen(#NS), #Header); #include "clang/Tooling/Inclusions/CSymbolMap.inc" #include "clang/Tooling/Inclusions/StdSymbolMap.inc" #undef SYMBOL @@ -76,6 +92,13 @@ (void)Dummy; } +std::vector
Header::all() { + std::vector
Result; + Result.reserve(HeaderIDs->size()); + for (unsigned I = 0, E = HeaderIDs->size(); I < E; ++I) + Result.push_back(Header(I)); + return Result; +} std::optional
Header::named(llvm::StringRef Name) { ensureInitialized(); auto It = HeaderIDs->find(Name); @@ -84,8 +107,26 @@ return Header(It->second); } llvm::StringRef Header::name() const { return HeaderNames[ID]; } -llvm::StringRef Symbol::scope() const { return SymbolNames[ID].first; } -llvm::StringRef Symbol::name() const { return SymbolNames[ID].second; } + +std::vector Symbol::all() { + std::vector Result; + Result.reserve(SymbolCount); + for (unsigned I = 0, E = SymbolCount; I < E; ++I) + Result.push_back(Symbol(I)); + return Result; +} +llvm::StringRef Symbol::scope() const { + SymbolName &S = SymbolNames[ID]; + return StringRef(S.Data, S.ScopeLen); +} +llvm::StringRef Symbol::name() const { + SymbolName &S = SymbolNames[ID]; + return StringRef(S.Data + S.ScopeLen, S.NameLen); +} +llvm::StringRef Symbol::qualified_name() const { + SymbolName &S = SymbolNames[ID]; + return StringRef(S.Data, S.ScopeLen + S.NameLen); +} std::optional Symbol::named(llvm::StringRef Scope, llvm::StringRef Name) { ensureInitialized(); diff --git a/clang/test/AST/dump.cpp b/clang/test/AST/dump.cpp --- a/clang/test/AST/dump.cpp +++ b/clang/test/AST/dump.cpp @@ -30,7 +30,7 @@ // CHECK-NEXT: | `-VarDecl {{.+}} col:40 implicit used omp_out 'char' // CHECK-NEXT: |-OMPDeclareReductionDecl {{.+}} col:37 fun 'float' combiner 0x{{.+}} initializer 0x{{.+}} // CHECK-NEXT: | |-CompoundAssignOperator {{.+}} 'float' lvalue '+=' ComputeLHSTy='float' ComputeResultTy='float' -// CHECK-NEXT: | | |-DeclRefExpr {{.+}} 'float' lvalue Var {{.+}} 'omp_out' 'float' +// CHECK-NEXT: | | |-BOOM{{.+}} 'float' lvalue Var {{.+}} 'omp_out' 'float' // CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} 'float' // CHECK-NEXT: | | `-DeclRefExpr {{.+}} 'float' lvalue Var {{.+}} 'omp_in' 'float' // CHECK-NEXT: | |-BinaryOperator {{.+}} 'float' '+' diff --git a/clang/unittests/Tooling/StandardLibraryTest.cpp b/clang/unittests/Tooling/StandardLibraryTest.cpp --- a/clang/unittests/Tooling/StandardLibraryTest.cpp +++ b/clang/unittests/Tooling/StandardLibraryTest.cpp @@ -18,6 +18,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +using ::testing::Contains; using ::testing::ElementsAre; namespace clang { @@ -35,17 +36,24 @@ TEST(StdlibTest, All) { auto VectorH = stdlib::Header::named(""); EXPECT_TRUE(VectorH); + EXPECT_EQ(VectorH->name(), ""); EXPECT_EQ(llvm::to_string(*VectorH), ""); EXPECT_FALSE(stdlib::Header::named("HeadersTests.cpp")); auto Vector = stdlib::Symbol::named("std::", "vector"); EXPECT_TRUE(Vector); + EXPECT_EQ(Vector->scope(), "std::"); + EXPECT_EQ(Vector->name(), "vector"); + EXPECT_EQ(Vector->qualified_name(), "std::vector"); EXPECT_EQ(llvm::to_string(*Vector), "std::vector"); EXPECT_FALSE(stdlib::Symbol::named("std::", "dongle")); EXPECT_FALSE(stdlib::Symbol::named("clang::", "ASTContext")); EXPECT_EQ(Vector->header(), *VectorH); EXPECT_THAT(Vector->headers(), ElementsAre(*VectorH)); + + EXPECT_THAT(stdlib::Header::all(), Contains(*VectorH)); + EXPECT_THAT(stdlib::Symbol::all(), Contains(*Vector)); } TEST(StdlibTest, Recognizer) {