Index: include-fixer/CMakeLists.txt =================================================================== --- include-fixer/CMakeLists.txt +++ include-fixer/CMakeLists.txt @@ -23,3 +23,4 @@ add_subdirectory(tool) add_subdirectory(find-all-symbols) +add_subdirectory(find-stl-symbols) Index: include-fixer/find-all-symbols/CMakeLists.txt =================================================================== --- include-fixer/find-all-symbols/CMakeLists.txt +++ include-fixer/find-all-symbols/CMakeLists.txt @@ -13,6 +13,7 @@ clangASTMatchers clangBasic clangLex + clangTooling ) add_subdirectory(tool) Index: include-fixer/find-all-symbols/FindAllMacros.h =================================================================== --- include-fixer/find-all-symbols/FindAllMacros.h +++ include-fixer/find-all-symbols/FindAllMacros.h @@ -32,7 +32,9 @@ void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD) override; -private: +protected: + virtual void reportMacro(const Token &MacroNameTok, const SymbolInfo &Info); + // Reporter for SymbolInfo. SymbolReporter *const Reporter; SourceManager *const SM; Index: include-fixer/find-all-symbols/FindAllMacros.cpp =================================================================== --- include-fixer/find-all-symbols/FindAllMacros.cpp +++ include-fixer/find-all-symbols/FindAllMacros.cpp @@ -17,9 +17,14 @@ namespace clang { namespace find_all_symbols { +void FindAllMacros::reportMacro(const Token &, const SymbolInfo &Symbol) { + Reporter->reportSymbol(SM->getFileEntryForID(SM->getMainFileID())->getName(), + Symbol); +} + void FindAllMacros::MacroDefined(const Token &MacroNameTok, const MacroDirective *MD) { - SourceLocation Loc = SM->getExpansionLoc(MacroNameTok.getLocation()); + SourceLocation Loc = MacroNameTok.getLocation(); if (Loc.isInvalid() || SM->isInMainFile(Loc)) return; @@ -38,8 +43,7 @@ SymbolInfo::SymbolKind::Macro, FilePath.str(), SM->getSpellingLineNumber(Loc), {}); - Reporter->reportSymbol(SM->getFileEntryForID(SM->getMainFileID())->getName(), - Symbol); + reportMacro(MacroNameTok, Symbol); } } // namespace find_all_symbols Index: include-fixer/find-all-symbols/FindAllSymbols.h =================================================================== --- include-fixer/find-all-symbols/FindAllSymbols.h +++ include-fixer/find-all-symbols/FindAllSymbols.h @@ -43,7 +43,11 @@ void run(const clang::ast_matchers::MatchFinder::MatchResult &result) override; -private: +protected: + // The way SymbolInfo of a decl is reported can be overrided. + virtual void reportDecl(const SourceManager &SM, const clang::NamedDecl *ND, + const SymbolInfo &Info); + // Reporter for SymbolInfo. SymbolReporter *const Reporter; // A remapping header file collector allowing clients include a different Index: include-fixer/find-all-symbols/FindAllSymbols.cpp =================================================================== --- include-fixer/find-all-symbols/FindAllSymbols.cpp +++ include-fixer/find-all-symbols/FindAllSymbols.cpp @@ -206,6 +206,13 @@ this); } +void FindAllSymbols::reportDecl(const SourceManager &SM, + const clang::NamedDecl *ND, + const SymbolInfo &Symbol) { + Reporter->reportSymbol(SM.getFileEntryForID(SM.getMainFileID())->getName(), + Symbol); +} + void FindAllSymbols::run(const MatchFinder::MatchResult &Result) { // Ignore Results in failing TUs. if (Result.Context->getDiagnostics().hasErrorOccurred()) { @@ -214,13 +221,11 @@ const NamedDecl *ND = Result.Nodes.getNodeAs("decl"); assert(ND && "Matched declaration must be a NamedDecl!"); - const SourceManager *SM = Result.SourceManager; - llvm::Optional Symbol = - CreateSymbolInfo(ND, *SM, Collector); + SourceManager &SM = *Result.SourceManager; + llvm::Optional Symbol = CreateSymbolInfo(ND, SM, Collector); if (Symbol) - Reporter->reportSymbol( - SM->getFileEntryForID(SM->getMainFileID())->getName(), *Symbol); + reportDecl(SM, ND, *Symbol); } } // namespace find_all_symbols Index: include-fixer/find-all-symbols/SymbolReporter.h =================================================================== --- include-fixer/find-all-symbols/SymbolReporter.h +++ include-fixer/find-all-symbols/SymbolReporter.h @@ -20,8 +20,13 @@ public: virtual ~SymbolReporter() = default; - virtual void reportSymbol(llvm::StringRef FileName, - const SymbolInfo &Symbol) = 0; + // A struct for carrying optional extra arguments for reportSymbol. + struct Args { + int Arg1; + }; + + virtual void reportSymbol(llvm::StringRef FileName, const SymbolInfo &Symbol, + const Args *ExtraArgs = nullptr) = 0; }; } // namespace find_all_symbols Index: include-fixer/find-all-symbols/tool/FindAllSymbolsMain.cpp =================================================================== --- include-fixer/find-all-symbols/tool/FindAllSymbolsMain.cpp +++ include-fixer/find-all-symbols/tool/FindAllSymbolsMain.cpp @@ -65,11 +65,12 @@ namespace clang { namespace find_all_symbols { -class YamlReporter : public clang::find_all_symbols::SymbolReporter { +class YamlReporter : public SymbolReporter { public: ~YamlReporter() override {} - void reportSymbol(StringRef FileName, const SymbolInfo &Symbol) override { + void reportSymbol(StringRef FileName, const SymbolInfo &Symbol, + const Args *) override { Symbols[FileName].insert(Symbol); } Index: include-fixer/find-stl-symbols/CMakeLists.txt =================================================================== --- /dev/null +++ include-fixer/find-stl-symbols/CMakeLists.txt @@ -0,0 +1,16 @@ +set(LLVM_LINK_COMPONENTS + Support + ) + +add_clang_library(findSTLSymbols + FindSTLSymbolsAction.cpp + STLSymbolsFinder.cpp + + LINK_LIBS + clangBasic + clangLex + clangTooling + findAllSymbols + ) + +add_subdirectory(tool) Index: include-fixer/find-stl-symbols/FindSTLSymbolsAction.h =================================================================== --- /dev/null +++ include-fixer/find-stl-symbols/FindSTLSymbolsAction.h @@ -0,0 +1,68 @@ +//===-- FindSTLSymbolsAction.h - find libc++ symbols ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FIND_STL_SYMBOLS_FIND_STL_SYMBOLS_ACTION_H +#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FIND_STL_SYMBOLS_FIND_STL_SYMBOLS_ACTION_H + +#include "../find-all-symbols/FindAllMacros.h" +#include "../find-all-symbols/FindAllSymbols.h" +#include "../find-all-symbols/SymbolInfo.h" +#include "../find-all-symbols/SymbolReporter.h" +#include "clang/Frontend/FrontendAction.h" + +namespace clang { +namespace find_stl_symbols { + +class FindSTLSymbolsAction : public clang::ASTFrontendAction { +public: + FindSTLSymbolsAction(find_all_symbols::SymbolReporter *Reporter) + : Reporter(Reporter), MatchFinder(), Matcher(Reporter) { + Matcher.registerMatchers(&MatchFinder); + } + + std::unique_ptr + CreateASTConsumer(clang::CompilerInstance &Compiler, + StringRef InFile) override; + +private: + // Overrides reportDecl so that the IncludeDepth can be retrieved. + // + // See comments for STLSymbolsFinder for what IncludeDepth is and the reason + // why we need it. + class FindSTLSymbols : public find_all_symbols::FindAllSymbols { + public: + explicit FindSTLSymbols(find_all_symbols::SymbolReporter *Reporter) + : FindAllSymbols(Reporter) {} + + private: + void reportDecl(const SourceManager &SM, const clang::NamedDecl *ND, + const find_all_symbols::SymbolInfo &Symbol) override; + }; + + // Overrides reportMacros so that the IncludeDepth can be retrieved. + class FindSTLMacros : public find_all_symbols::FindAllMacros { + public: + explicit FindSTLMacros(find_all_symbols::SymbolReporter *Reporter, + SourceManager *SM) + : FindAllMacros(Reporter, SM) {} + + private: + void reportMacro(const Token &MacroNameTok, + const find_all_symbols::SymbolInfo &Symbol) override; + }; + + find_all_symbols::SymbolReporter *const Reporter; + clang::ast_matchers::MatchFinder MatchFinder; + FindSTLSymbols Matcher; +}; + +} // namespace find_stl_symbols +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FIND_STL_SYMBOLS_FIND_STL_SYMBOLS_ACTION_H Index: include-fixer/find-stl-symbols/FindSTLSymbolsAction.cpp =================================================================== --- /dev/null +++ include-fixer/find-stl-symbols/FindSTLSymbolsAction.cpp @@ -0,0 +1,56 @@ +//===-- FindSTLSymbolsAction.cpp - find libc++ symbols ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "FindSTLSymbolsAction.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/Preprocessor.h" + +using namespace clang::find_all_symbols; + +namespace clang { +namespace find_stl_symbols { + +std::unique_ptr +FindSTLSymbolsAction::CreateASTConsumer(clang::CompilerInstance &Compiler, + StringRef InFile) { + Compiler.getPreprocessor().addPPCallbacks( + llvm::make_unique(Reporter, &Compiler.getSourceManager())); + return MatchFinder.newASTConsumer(); +} + +static int calculateIncludeDepth(const SourceManager &SM, SourceLocation Loc) { + int Result = 0; + while (true) { + auto Fid = SM.getFileID(Loc); + Loc = SM.getIncludeLoc(Fid); + if (!Loc.isValid()) break; + Result++; + } + return Result; +} + +void FindSTLSymbolsAction::FindSTLSymbols::reportDecl( + const SourceManager &SM, const clang::NamedDecl *ND, + const SymbolInfo &Symbol) { + int IncludeDepth = calculateIncludeDepth(SM, ND->getLocation()); + SymbolReporter::Args ExtraArgs{IncludeDepth}; + Reporter->reportSymbol(SM.getFileEntryForID(SM.getMainFileID())->getName(), + Symbol, &ExtraArgs); +} + +void FindSTLSymbolsAction::FindSTLMacros::reportMacro( + const Token &MacroNameTok, const SymbolInfo &Symbol) { + int IncludeDepth = calculateIncludeDepth(*SM, MacroNameTok.getLocation()); + SymbolReporter::Args ExtraArgs{IncludeDepth}; + Reporter->reportSymbol(SM->getFileEntryForID(SM->getMainFileID())->getName(), + Symbol, &ExtraArgs); +} + +} // namespace find_all_symbols +} // namespace clang Index: include-fixer/find-stl-symbols/STLSymbolsFinder.h =================================================================== --- /dev/null +++ include-fixer/find-stl-symbols/STLSymbolsFinder.h @@ -0,0 +1,72 @@ +//===-- STLSymbolsFinder.h - find libc++ symbols ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FIND_STL_SYMBOLS_STL_SYMBOLS_FINDER_H +#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FIND_STL_SYMBOLS_STL_SYMBOLS_FINDER_H + +#include "../find-all-symbols/SymbolInfo.h" +#include "../find-all-symbols/SymbolReporter.h" + +namespace clang { + +class FileManager; + +namespace vfs { +class FileSystem; +} // namespace vfs + +namespace find_stl_symbols { + +class STLSymbolsFinder { +public: + STLSymbolsFinder(FileManager &Files, const std::string &CXXIncludePath); + + void run(find_all_symbols::SymbolReporter *OutputReporter); + +private: + bool findSymbolsInHeader(llvm::StringRef Header); + + // Stores all symbols and their include_depth. Only outputs symbol information + // after processing all headers from C++ standard library - for each symbol, + // the header that has the smallest include depth is chosen to be its + // FilePath. + // The result symbols are redirected to the OutputReporter in the end. + class STLReporter : public find_all_symbols::SymbolReporter { + public: + // A map from SymbolInfo to
pair. + // We always stores the header with the smallest include depth for each + // symbol. + typedef std::map> + SymbolToHeaderMap; + + void setCurrentHeader(llvm::StringRef Header) { this->Header = Header; } + + void reportSymbol(llvm::StringRef FileName, + const find_all_symbols::SymbolInfo &Symbol, + const Args *ExtraArgs = nullptr) override; + + void calculateHeadersAndReportAll( + find_all_symbols::SymbolReporter *OutputReporter); + + private: + SymbolToHeaderMap SymbolMap; + // The standard library header from which the symbol is included. This will + // be updated for each header run. + std::string Header; + }; + + FileManager &Files; + std::string CXXIncludePath; + STLReporter Reporter; +}; + +} // namespace find_stl_symbols +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FIND_STL_SYMBOLS_STL_SYMBOLS_FINDER_H Index: include-fixer/find-stl-symbols/STLSymbolsFinder.cpp =================================================================== --- /dev/null +++ include-fixer/find-stl-symbols/STLSymbolsFinder.cpp @@ -0,0 +1,102 @@ +//===-- STLSymbolsFinder.cpp - find libc++ symbols --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "STLSymbolsFinder.h" +#include "FindSTLSymbolsAction.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/CompilationDatabase.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/Support/Debug.h" +#include + +#define DEBUG_TYPE "find-stl-symbols" + +using namespace clang::find_all_symbols; +using namespace clang::tooling; +using namespace llvm; + +namespace clang { +namespace find_stl_symbols { + +STLSymbolsFinder::STLSymbolsFinder(FileManager &Files, + const std::string &CXXIncludePath) + : Files(Files), CXXIncludePath(CXXIncludePath) { + if (*CXXIncludePath.rbegin() != '/') + this->CXXIncludePath.push_back('/'); +} + +void STLSymbolsFinder::STLReporter::reportSymbol( + llvm::StringRef FileName, const SymbolInfo &Symbol, + const SymbolReporter::Args *ExtraArgs) { + assert(ExtraArgs && "Expecting include depth in extra args."); + int IncludeDepth = ExtraArgs->Arg1; + auto Iter = SymbolMap.find(Symbol); + if (Iter == SymbolMap.end() || (IncludeDepth < Iter->second.second)) { + SymbolMap[Symbol] = std::make_pair(Header, IncludeDepth); + } +} + +void STLSymbolsFinder::STLReporter::calculateHeadersAndReportAll( + SymbolReporter *OutputReporter) { + std::set Results; + for (const auto &Entry : SymbolMap) { + const auto &Symbol = Entry.first; + SymbolInfo NewSymbol(Symbol.getName(), Symbol.getSymbolKind(), + Entry.second.first, Symbol.getLineNumber(), + Symbol.getContexts()); + OutputReporter->reportSymbol(NewSymbol.getFilePath(), NewSymbol); + } +} + +bool STLSymbolsFinder::findSymbolsInHeader(llvm::StringRef Header) { + Reporter.setCurrentHeader(Header); + const std::string kIncludePathOption = "-I" + CXXIncludePath; + DEBUG(llvm::errs() << "Processing header " << Header << "(" << HeaderPath + << ")\n"); + + auto FS = Files.getVirtualFileSystem(); + std::string MainFile = (Header + ".cc").str(); + std::vector Args = { + std::string("FindSTLSymbols"), std::string("-fsyntax-only"), + std::string("-std=c++11"), kIncludePathOption, MainFile}; + tooling::ToolInvocation Invocation(Args, new FindSTLSymbolsAction(&Reporter), + &Files); + std::string Code = + ("#include <" + Header + ">\nint main() { return 0; }").str(); + Invocation.mapVirtualFile(MainFile, Code); + return Invocation.run(); +} + +void STLSymbolsFinder::run(SymbolReporter *OutputReporter) { + std::error_code EC; + IntrusiveRefCntPtr FS = Files.getVirtualFileSystem(); + DEBUG(llvm::errs() << "Checking CXXIncludePath " << CXXIncludePath << "\n";); + auto File = FS->dir_begin(CXXIncludePath, EC); + vfs::directory_iterator FileEnd; + while (File != FileEnd && !EC) { + DEBUG(llvm::errs() << "Checking " << File->getName() << "\n";); + if (File->getType() == sys::fs::file_type::regular_file) { + if (!findSymbolsInHeader(sys::path::filename(File->getName()))) { + llvm::errs() << "Failed processing " << File->getName() << "\n"; + } + } + + File.increment(EC); + } + if (EC) { + llvm::errs() << EC.message() << "\n"; + return; + } + Reporter.calculateHeadersAndReportAll(OutputReporter); +} + +} // namespace find_stl_symbols +} // namespace clang Index: include-fixer/find-stl-symbols/tool/CMakeLists.txt =================================================================== --- /dev/null +++ include-fixer/find-stl-symbols/tool/CMakeLists.txt @@ -0,0 +1,11 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) + +add_clang_executable(find-stl-symbols FindSTLSymbolsMain.cpp) +target_link_libraries(find-stl-symbols + + clangBasic + clangFrontend + clangLex + clangTooling + findSTLSymbols + ) Index: include-fixer/find-stl-symbols/tool/FindSTLSymbolsMain.cpp =================================================================== --- /dev/null +++ include-fixer/find-stl-symbols/tool/FindSTLSymbolsMain.cpp @@ -0,0 +1,74 @@ +//===-- FindSTLSymbolsMain.cpp - find stl symbols tool ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "STLSymbolsFinder.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/FileSystemOptions.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" + +using namespace llvm; +using namespace clang; +using SymbolInfo = clang::find_all_symbols::SymbolInfo; + +static cl::opt + CXXIncludePath("i", cl::desc("C++ standard library include path."), + cl::init(""), cl::value_desc("libc++ include path")); + +static cl::opt + OutputFile("o", cl::desc("The file path for saving the results."), + cl::init("stl-symbols.yaml"), + cl::value_desc("output-file.yaml")); + +namespace clang { +namespace find_stl_symbols { + +class STLYamlReporter : public find_all_symbols::SymbolReporter { +public: + explicit STLYamlReporter(StringRef OutputFile) : OutputFile(OutputFile) {} + + ~STLYamlReporter() override { + int FD; + auto ErrCode = + llvm::sys::fs::openFileForWrite(OutputFile, FD, sys::fs::F_None); + if (ErrCode) { + llvm::errs() << ErrCode.message(); + return; + } + llvm::raw_fd_ostream OS(FD, /*shouldClose*/ true); + WriteSymbolInfosToStream(OS, Symbols); + } + + void reportSymbol(StringRef, const SymbolInfo &Symbol, + const Args *) override { + Symbols.insert(Symbol); + } + +private: + std::string OutputFile; + std::set Symbols; +}; + +} // namespace find_stl_symbols +} // namespace clang + +int main(int argc, const char **argv) { + cl::ParseCommandLineOptions(argc, argv); + if (CXXIncludePath.empty()) { + llvm::errs() << "C++ standard library include path is not provided.\n"; + return 1; + } + find_stl_symbols::STLYamlReporter Reporter(OutputFile); + + llvm::IntrusiveRefCntPtr Files( + new FileManager(FileSystemOptions())); + find_stl_symbols::STLSymbolsFinder Finder(*Files, CXXIncludePath); + Finder.run(&Reporter); + return 0; +} Index: unittests/include-fixer/CMakeLists.txt =================================================================== --- unittests/include-fixer/CMakeLists.txt +++ unittests/include-fixer/CMakeLists.txt @@ -26,3 +26,4 @@ ) add_subdirectory(find-all-symbols) +add_subdirectory(find-stl-symbols) Index: unittests/include-fixer/find-all-symbols/FindAllSymbolsTests.cpp =================================================================== --- unittests/include-fixer/find-all-symbols/FindAllSymbolsTests.cpp +++ unittests/include-fixer/find-all-symbols/FindAllSymbolsTests.cpp @@ -33,12 +33,12 @@ static const char HeaderName[] = "symbols.h"; -class TestSymbolReporter : public clang::find_all_symbols::SymbolReporter { +class TestSymbolReporter : public SymbolReporter { public: ~TestSymbolReporter() override {} - void reportSymbol(llvm::StringRef FileName, - const SymbolInfo &Symbol) override { + void reportSymbol(llvm::StringRef FileName, const SymbolInfo &Symbol, + const Args *) override { Symbols.push_back(Symbol); } Index: unittests/include-fixer/find-stl-symbols/CMakeLists.txt =================================================================== --- /dev/null +++ unittests/include-fixer/find-stl-symbols/CMakeLists.txt @@ -0,0 +1,21 @@ +set(LLVM_LINK_COMPONENTS + support + ) + +get_filename_component(INCLUDE_FIXER_SOURCE_DIR + ${CMAKE_CURRENT_SOURCE_DIR}/../../../include-fixer/find-stl-symbols REALPATH) +include_directories( + ${INCLUDE_FIXER_SOURCE_DIR} + ) + +add_extra_unittest(FindSTLSymbolsTests + STLSymbolsFinderTests.cpp + ) + +target_link_libraries(FindSTLSymbolsTests + clangBasic + clangFrontend + clangLex + clangTooling + findSTLSymbols + ) Index: unittests/include-fixer/find-stl-symbols/STLSymbolsFinderTests.cpp =================================================================== --- /dev/null +++ unittests/include-fixer/find-stl-symbols/STLSymbolsFinderTests.cpp @@ -0,0 +1,118 @@ +//===-- STLSymbolsFinderTests.cpp - STLSymbolsFinder unittests---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "FindSTLSymbolsAction.h" +#include "STLSymbolsFinder.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/MemoryBuffer.h" +#include "gtest/gtest.h" +#include +#include + +using namespace clang::find_all_symbols; + +namespace clang { +namespace find_stl_symbols { +namespace { + +class TestSymbolReporter : public SymbolReporter { +public: + ~TestSymbolReporter() override {} + + void reportSymbol(llvm::StringRef, const SymbolInfo &Symbol, + const Args *) override { + // TODO: remove. + llvm::errs() << "Reporting " << Symbol.getName() << " " + << Symbol.getFilePath() << "\n"; + Symbols.push_back(Symbol); + } + + bool hasSymbol(const SymbolInfo &Symbol) const { + for (const auto &S : Symbols) { + if (S == Symbol) + return true; + } + return false; + } + +private: + std::vector Symbols; +}; + +class STLSymbolsFinderTest : public ::testing::Test { +public: + STLSymbolsFinderTest() + : InMemoryFS(new vfs::InMemoryFileSystem), + Files(new FileManager(FileSystemOptions(), InMemoryFS)) {} + +protected: + bool hasSymbol(const SymbolInfo &Symbol) { + return Reporter.hasSymbol(Symbol); + } + + bool runSTLSymbolsFinder( + const std::vector> &Contents) { + llvm::IntrusiveRefCntPtr InMemoryFileSystem( + new vfs::InMemoryFileSystem); + llvm::IntrusiveRefCntPtr Files( + new FileManager(FileSystemOptions(), InMemoryFileSystem)); + + // Add headers into InMemoryFileSystem so that Finder and ClangTool can read + // files from the (virtual) include directory. + for (const auto &Pair : Contents) { + InMemoryFileSystem->addFile( + Pair.first, 0, llvm::MemoryBuffer::getMemBuffer(Pair.second)); + } + + STLSymbolsFinder Finder(*Files, kIncludePath); + Finder.run(&Reporter); + return true; + } + + TestSymbolReporter Reporter; + llvm::IntrusiveRefCntPtr InMemoryFS; + llvm::IntrusiveRefCntPtr Files; + std::string kIncludePath = "/include/"; +}; + +TEST_F(STLSymbolsFinderTest, FindInFakeLibrary) { + std::vector> Contents; + Contents.emplace_back(kIncludePath + "a", + "#include \nclass A {};"); + Contents.emplace_back(kIncludePath + "b", "#include "); + Contents.emplace_back(kIncludePath + "internal/a_1.h", + "#include "); + Contents.emplace_back(kIncludePath + "internal/a_2.h", + "#include "); + Contents.emplace_back(kIncludePath + "internal/b_1.h", + "#include \nclass B{};"); + // struct Common is included by both a.h and b.h, but b.h has smaller + // include depth, so the file path for struct Common will be b.h. + Contents.emplace_back(kIncludePath + "internal/common.h", + "struct Common {};"); + + runSTLSymbolsFinder(Contents); + + SymbolInfo Symbol = + SymbolInfo("A", SymbolInfo::SymbolKind::Class, "a", 2, {}); + EXPECT_TRUE(hasSymbol(Symbol)); + + Symbol = SymbolInfo("B", SymbolInfo::SymbolKind::Class, "b", 2, {}); + EXPECT_TRUE(hasSymbol(Symbol)); + + Symbol = SymbolInfo("Common", SymbolInfo::SymbolKind::Class, "b", 1, {}); + EXPECT_TRUE(hasSymbol(Symbol)); +} + +} // anonymous namespace +} // namespace find_stl_symbols +} // namespace clang