Index: include-fixer/find-all-symbols/CMakeLists.txt =================================================================== --- include-fixer/find-all-symbols/CMakeLists.txt +++ include-fixer/find-all-symbols/CMakeLists.txt @@ -4,6 +4,7 @@ add_clang_library(findAllSymbols FindAllSymbols.cpp + PragmaCommentHandler.cpp SymbolInfo.cpp LINK_LIBS Index: include-fixer/find-all-symbols/FindAllSymbols.h =================================================================== --- include-fixer/find-all-symbols/FindAllSymbols.h +++ include-fixer/find-all-symbols/FindAllSymbols.h @@ -12,6 +12,9 @@ #include "SymbolInfo.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "llvm/ADT/StringRef.h" + +#include #include namespace clang { @@ -43,10 +46,15 @@ void registerMatchers(clang::ast_matchers::MatchFinder *MatchFinder); + void addPragmaHeader(FileID ID, llvm::StringRef FilePath); + + llvm::Optional getPragmaHeader(FileID ID) const; + void run(const clang::ast_matchers::MatchFinder::MatchResult &result) override; private: + std::map PragmaHeaderMap; ResultReporter *const Reporter; }; Index: include-fixer/find-all-symbols/FindAllSymbols.cpp =================================================================== --- include-fixer/find-all-symbols/FindAllSymbols.cpp +++ include-fixer/find-all-symbols/FindAllSymbols.cpp @@ -43,8 +43,8 @@ } } -bool SetCommonInfo(const MatchFinder::MatchResult &Result, - const NamedDecl *ND, SymbolInfo *Symbol) { +bool SetCommonInfo(const MatchFinder::MatchResult &Result, const NamedDecl *ND, + SymbolInfo *Symbol, const FindAllSymbols *Matcher) { SetContext(ND, Symbol); Symbol->Name = ND->getNameAsString(); @@ -60,6 +60,13 @@ Symbol->LineNumber = SM->getExpansionLineNumber(Loc); + // Check prgama header. + auto PragmaHeader = Matcher->getPragmaHeader(SM->getFileID(Loc)); + if (PragmaHeader) { + Symbol->FilePath = PragmaHeader.getValue(); + return true; + } + llvm::StringRef FilePath = SM->getFilename(Loc); if (FilePath.empty()) return false; @@ -163,6 +170,17 @@ this); } +void FindAllSymbols::addPragmaHeader(FileID ID, llvm::StringRef FilePath) { + PragmaHeaderMap[ID] = FilePath; +} + +llvm::Optional FindAllSymbols::getPragmaHeader(FileID ID) const { + auto It = PragmaHeaderMap.find(ID); + if (It == PragmaHeaderMap.end()) + return llvm::None; + return It->second; +} + void FindAllSymbols::run(const MatchFinder::MatchResult &Result) { // Ignore Results in failing TUs. if (Result.Context->getDiagnostics().hasErrorOccurred()) { @@ -174,7 +192,7 @@ const SourceManager *SM = Result.SourceManager; SymbolInfo Symbol; - if (!SetCommonInfo(Result, ND, &Symbol)) + if (!SetCommonInfo(Result, ND, &Symbol, this)) return; if (const auto *VD = llvm::dyn_cast(ND)) { Index: include-fixer/find-all-symbols/PragmaCommentHandler.h =================================================================== --- /dev/null +++ include-fixer/find-all-symbols/PragmaCommentHandler.h @@ -0,0 +1,34 @@ +//===-- PragmaCommentHandler.h - find all 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_FIND_ALL_SYMBOLS_PRAGMACOMMENTHANDLER_H +#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PRAGMACOMMENTHANDLER_H + +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Preprocessor.h" + +namespace clang { +namespace find_all_symbols { + +class FindAllSymbols; + +class PragmaCommentHandler : public clang::CommentHandler { +public: + PragmaCommentHandler(FindAllSymbols *Matcher) : Matcher(Matcher) {} + + bool HandleComment(Preprocessor &PP, SourceRange Range) override; + +private: + FindAllSymbols *const Matcher; +}; + +} // namespace find_all_symbols +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PRAGMACOMMENTHANDLER_H Index: include-fixer/find-all-symbols/PragmaCommentHandler.cpp =================================================================== --- /dev/null +++ include-fixer/find-all-symbols/PragmaCommentHandler.cpp @@ -0,0 +1,34 @@ +//===-- PragmaCommentHandler.cpp - find all symbols -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PragmaCommentHandler.h" +#include "FindAllSymbols.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/Support/Regex.h" + +namespace clang { +namespace find_all_symbols { +namespace { +const char IWYUPragma[] = "// IWYU pragma: private, include (.*)"; +} // namespace + +bool PragmaCommentHandler::HandleComment(Preprocessor &PP, SourceRange Range) { + StringRef Text = + Lexer::getSourceText(CharSourceRange::getCharRange(Range), + PP.getSourceManager(), PP.getLangOpts()); + SmallVector Matches; + if (!llvm::Regex(IWYUPragma).match(Text, &Matches)) + return false; + Matcher->addPragmaHeader(PP.getSourceManager().getFileID(Range.getBegin()), + Matches[1].trim("\"<>")); + return false; +} + +} // namespace find_all_symbols +} // namespace clang 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 @@ -8,9 +8,12 @@ //===----------------------------------------------------------------------===// #include "FindAllSymbols.h" +#include "PragmaCommentHandler.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" #include "llvm/Support/Path.h" @@ -74,6 +77,29 @@ std::map> Symbols; }; +class FindAllSymbolsAction : public clang::ASTFrontendAction { +public: + FindAllSymbolsAction() + : Reporter(), MatchFinder(), Matcher(&Reporter), Handler(&Matcher) { + Matcher.registerMatchers(&MatchFinder); + } + + std::unique_ptr + CreateASTConsumer(clang::CompilerInstance &Compiler, + StringRef InFile) override { + Compiler.getPreprocessor().addCommentHandler(&Handler); + return MatchFinder.newASTConsumer(); + } + + void EndSourceFileAction() override { Reporter.Write(OutputDir); } + +private: + YamlReporter Reporter; + clang::ast_matchers::MatchFinder MatchFinder; + FindAllSymbols Matcher; + PragmaCommentHandler Handler; +}; + bool Merge(llvm::StringRef MergeDir, llvm::StringRef OutputFile) { std::error_code EC; std::set UniqueSymbols; @@ -134,11 +160,8 @@ return 0; } - clang::find_all_symbols::YamlReporter Reporter; - clang::find_all_symbols::FindAllSymbols Matcher(&Reporter); - clang::ast_matchers::MatchFinder MatchFinder; - Matcher.registerMatchers(&MatchFinder); - Tool.run(newFrontendActionFactory(&MatchFinder).get()); - Reporter.Write(OutputDir); + Tool.run( + newFrontendActionFactory() + .get()); return 0; } 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 @@ -8,6 +8,8 @@ //===----------------------------------------------------------------------===// #include "FindAllSymbols.h" +#include "PragmaCommentHandler.h" +#include "clang/Frontend/CompilerInstance.h" #include "clang/Tooling/Tooling.h" #include "llvm/Support/YAMLTraits.h" #include "gtest/gtest.h" @@ -51,6 +53,39 @@ std::vector Symbols; }; +class MockFindAllSymbolsAction : public clang::ASTFrontendAction { +public: + MockFindAllSymbolsAction(FindAllSymbols::ResultReporter *Reporter) + : MatchFinder(), Matcher(Reporter), Handler(&Matcher) { + Matcher.registerMatchers(&MatchFinder); + } + + std::unique_ptr + CreateASTConsumer(clang::CompilerInstance &Compiler, + StringRef InFile) override { + Compiler.getPreprocessor().addCommentHandler(&Handler); + return MatchFinder.newASTConsumer(); + } + +private: + ast_matchers::MatchFinder MatchFinder; + FindAllSymbols Matcher; + PragmaCommentHandler Handler; +}; + +class MockFindAllSymbolsActionFactory + : public clang::tooling::FrontendActionFactory { +public: + MockFindAllSymbolsActionFactory(MockReporter *Reporter) + : Reporter(Reporter) {} + clang::FrontendAction *create() override { + return new MockFindAllSymbolsAction(Reporter); + } + +private: + MockReporter *const Reporter; +}; + class FindAllSymbolsTest : public ::testing::Test { public: bool hasSymbol(const SymbolInfo &Symbol) { @@ -62,18 +97,16 @@ } bool runFindAllSymbols(StringRef Code) { - FindAllSymbols matcher(&Reporter); - clang::ast_matchers::MatchFinder MatchFinder; - matcher.registerMatchers(&MatchFinder); - llvm::IntrusiveRefCntPtr InMemoryFileSystem( new vfs::InMemoryFileSystem); llvm::IntrusiveRefCntPtr Files( new FileManager(FileSystemOptions(), InMemoryFileSystem)); std::string FileName = "symbol.cc"; - std::unique_ptr Factory = - clang::tooling::newFrontendActionFactory(&MatchFinder); + + std::unique_ptr Factory( + new MockFindAllSymbolsActionFactory(&Reporter)); + tooling::ToolInvocation Invocation( {std::string("find_all_symbols"), std::string("-fsyntax-only"), FileName}, @@ -360,5 +393,20 @@ } } +TEST_F(FindAllSymbolsTest, IWYUPrivatePragmaTest) { + static const char Code[] = R"( + // IWYU pragma: private, include "bar.h" + struct Bar { + }; + )"; + runFindAllSymbols(Code); + + { + SymbolInfo Symbol = + CreateSymbolInfo("Bar", SymbolInfo::Class, "bar.h", 3, {}); + EXPECT_TRUE(hasSymbol(Symbol)); + } +} + } // namespace find_all_symbols } // namespace clang