diff options
Diffstat (limited to 'clang-tools-extra/clang-include-fixer/find-all-symbols')
21 files changed, 2118 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/CMakeLists.txt b/clang-tools-extra/clang-include-fixer/find-all-symbols/CMakeLists.txt new file mode 100644 index 00000000000..c5fe19bfdbd --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/CMakeLists.txt @@ -0,0 +1,24 @@ +set(LLVM_LINK_COMPONENTS + Support + ) + +add_clang_library(findAllSymbols + FindAllSymbols.cpp + FindAllSymbolsAction.cpp + FindAllMacros.cpp + HeaderMapCollector.cpp + PathConfig.cpp + PragmaCommentHandler.cpp + STLPostfixHeaderMap.cpp + SymbolInfo.cpp + + LINK_LIBS + clangAST + clangASTMatchers + clangBasic + clangFrontend + clangLex + clangTooling + ) + +add_subdirectory(tool) diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllMacros.cpp b/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllMacros.cpp new file mode 100644 index 00000000000..ed1bc2f490a --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllMacros.cpp @@ -0,0 +1,69 @@ +//===-- FindAllMacros.cpp - find all macros ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "FindAllMacros.h" +#include "HeaderMapCollector.h" +#include "PathConfig.h" +#include "SymbolInfo.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/Token.h" +#include "llvm/Support/Path.h" + +namespace clang { +namespace find_all_symbols { + +llvm::Optional<SymbolInfo> +FindAllMacros::CreateMacroSymbol(const Token &MacroNameTok, + const MacroInfo *info) { + std::string FilePath = + getIncludePath(*SM, info->getDefinitionLoc(), Collector); + if (FilePath.empty()) + return llvm::None; + return SymbolInfo(MacroNameTok.getIdentifierInfo()->getName(), + SymbolInfo::SymbolKind::Macro, FilePath, {}); +} + +void FindAllMacros::MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) { + if (auto Symbol = CreateMacroSymbol(MacroNameTok, MD->getMacroInfo())) + ++FileSymbols[*Symbol].Seen; +} + +void FindAllMacros::MacroUsed(const Token &Name, const MacroDefinition &MD) { + if (!MD || !SM->isInMainFile(SM->getExpansionLoc(Name.getLocation()))) + return; + if (auto Symbol = CreateMacroSymbol(Name, MD.getMacroInfo())) + ++FileSymbols[*Symbol].Used; +} + +void FindAllMacros::MacroExpands(const Token &MacroNameTok, + const MacroDefinition &MD, SourceRange Range, + const MacroArgs *Args) { + MacroUsed(MacroNameTok, MD); +} + +void FindAllMacros::Ifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) { + MacroUsed(MacroNameTok, MD); +} + +void FindAllMacros::Ifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) { + MacroUsed(MacroNameTok, MD); +} + +void FindAllMacros::EndOfMainFile() { + Reporter->reportSymbols(SM->getFileEntryForID(SM->getMainFileID())->getName(), + FileSymbols); + FileSymbols.clear(); +} + +} // namespace find_all_symbols +} // namespace clang diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllMacros.h b/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllMacros.h new file mode 100644 index 00000000000..5aaf388456e --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllMacros.h @@ -0,0 +1,64 @@ +//===-- FindAllMacros.h - find all macros -----------------------*- C++ -*-===// +// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_FIND_ALL_MACROS_H +#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_FIND_ALL_MACROS_H + +#include "SymbolInfo.h" +#include "SymbolReporter.h" +#include "clang/Lex/PPCallbacks.h" + +namespace clang { +class MacroInfo; +namespace find_all_symbols { + +class HeaderMapCollector; + +/// \brief A preprocessor that collects all macro symbols. +/// The contexts of a macro will be ignored since they are not available during +/// preprocessing period. +class FindAllMacros : public clang::PPCallbacks { +public: + explicit FindAllMacros(SymbolReporter *Reporter, SourceManager *SM, + HeaderMapCollector *Collector = nullptr) + : Reporter(Reporter), SM(SM), Collector(Collector) {} + + void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override; + + void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, + SourceRange Range, const MacroArgs *Args) override; + + void Ifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override; + + void Ifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override; + + void EndOfMainFile() override; + +private: + llvm::Optional<SymbolInfo> CreateMacroSymbol(const Token &MacroNameTok, + const MacroInfo *MD); + // Not a callback, just a common path for all usage types. + void MacroUsed(const Token &Name, const MacroDefinition &MD); + + SymbolInfo::SignalMap FileSymbols; + // Reporter for SymbolInfo. + SymbolReporter *const Reporter; + SourceManager *const SM; + // A remapping header file collector allowing clients to include a different + // header. + HeaderMapCollector *const Collector; +}; + +} // namespace find_all_symbols +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_FIND_ALL_MACROS_H diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp b/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp new file mode 100644 index 00000000000..bb6a3fa9f16 --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp @@ -0,0 +1,268 @@ +//===-- FindAllSymbols.cpp - find all symbols--------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "FindAllSymbols.h" +#include "HeaderMapCollector.h" +#include "PathConfig.h" +#include "SymbolInfo.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Type.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Support/FileSystem.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace find_all_symbols { +namespace { + +AST_MATCHER(EnumConstantDecl, isInScopedEnum) { + if (const auto *ED = dyn_cast<EnumDecl>(Node.getDeclContext())) + return ED->isScoped(); + return false; +} + +AST_POLYMORPHIC_MATCHER(isFullySpecialized, + AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl, VarDecl, + CXXRecordDecl)) { + if (Node.getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { + bool IsPartialSpecialization = + llvm::isa<VarTemplatePartialSpecializationDecl>(Node) || + llvm::isa<ClassTemplatePartialSpecializationDecl>(Node); + return !IsPartialSpecialization; + } + return false; +} + +std::vector<SymbolInfo::Context> GetContexts(const NamedDecl *ND) { + std::vector<SymbolInfo::Context> Contexts; + for (const auto *Context = ND->getDeclContext(); Context; + Context = Context->getParent()) { + if (llvm::isa<TranslationUnitDecl>(Context) || + llvm::isa<LinkageSpecDecl>(Context)) + break; + + assert(llvm::isa<NamedDecl>(Context) && + "Expect Context to be a NamedDecl"); + if (const auto *NSD = dyn_cast<NamespaceDecl>(Context)) { + if (!NSD->isInlineNamespace()) + Contexts.emplace_back(SymbolInfo::ContextType::Namespace, + NSD->getName().str()); + } else if (const auto *ED = dyn_cast<EnumDecl>(Context)) { + Contexts.emplace_back(SymbolInfo::ContextType::EnumDecl, + ED->getName().str()); + } else { + const auto *RD = cast<RecordDecl>(Context); + Contexts.emplace_back(SymbolInfo::ContextType::Record, + RD->getName().str()); + } + } + return Contexts; +} + +llvm::Optional<SymbolInfo> +CreateSymbolInfo(const NamedDecl *ND, const SourceManager &SM, + const HeaderMapCollector *Collector) { + SymbolInfo::SymbolKind Type; + if (llvm::isa<VarDecl>(ND)) { + Type = SymbolInfo::SymbolKind::Variable; + } else if (llvm::isa<FunctionDecl>(ND)) { + Type = SymbolInfo::SymbolKind::Function; + } else if (llvm::isa<TypedefNameDecl>(ND)) { + Type = SymbolInfo::SymbolKind::TypedefName; + } else if (llvm::isa<EnumConstantDecl>(ND)) { + Type = SymbolInfo::SymbolKind::EnumConstantDecl; + } else if (llvm::isa<EnumDecl>(ND)) { + Type = SymbolInfo::SymbolKind::EnumDecl; + // Ignore anonymous enum declarations. + if (ND->getName().empty()) + return llvm::None; + } else { + assert(llvm::isa<RecordDecl>(ND) && + "Matched decl must be one of VarDecl, " + "FunctionDecl, TypedefNameDecl, EnumConstantDecl, " + "EnumDecl and RecordDecl!"); + // C-style record decl can have empty name, e.g "struct { ... } var;". + if (ND->getName().empty()) + return llvm::None; + Type = SymbolInfo::SymbolKind::Class; + } + + SourceLocation Loc = SM.getExpansionLoc(ND->getLocation()); + if (!Loc.isValid()) { + llvm::errs() << "Declaration " << ND->getNameAsString() << "(" + << ND->getDeclKindName() + << ") has invalid declaration location."; + return llvm::None; + } + + std::string FilePath = getIncludePath(SM, Loc, Collector); + if (FilePath.empty()) return llvm::None; + + return SymbolInfo(ND->getNameAsString(), Type, FilePath, GetContexts(ND)); +} + +} // namespace + +void FindAllSymbols::registerMatchers(MatchFinder *MatchFinder) { + // FIXME: Handle specialization. + auto IsInSpecialization = hasAncestor( + decl(anyOf(cxxRecordDecl(isExplicitTemplateSpecialization()), + functionDecl(isExplicitTemplateSpecialization())))); + + // Matchers for both C and C++. + // We only match symbols from header files, i.e. not from main files (see + // function's comment for detailed explanation). + auto CommonFilter = + allOf(unless(isImplicit()), unless(isExpansionInMainFile())); + + auto HasNSOrTUCtxMatcher = + hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl())); + + // We need seperate rules for C record types and C++ record types since some + // template related matchers are inapplicable on C record declarations. + // + // Matchers specific to C++ code. + // All declarations should be in namespace or translation unit. + auto CCMatcher = + allOf(HasNSOrTUCtxMatcher, unless(IsInSpecialization), + unless(ast_matchers::isTemplateInstantiation()), + unless(isInstantiated()), unless(isFullySpecialized())); + + // Matchers specific to code in extern "C" {...}. + auto ExternCMatcher = hasDeclContext(linkageSpecDecl()); + + // Matchers for variable declarations. + // + // In most cases, `ParmVarDecl` is filtered out by hasDeclContext(...) + // matcher since the declaration context is usually `MethodDecl`. However, + // this assumption does not hold for parameters of a function pointer + // parameter. + // For example, consider a function declaration: + // void Func(void (*)(float), int); + // The float parameter of the function pointer has an empty name, and its + // declaration context is an anonymous namespace; therefore, it won't be + // filtered out by our matchers above. + auto Vars = varDecl(CommonFilter, anyOf(ExternCMatcher, CCMatcher), + unless(parmVarDecl())); + + // Matchers for C-style record declarations in extern "C" {...}. + auto CRecords = recordDecl(CommonFilter, ExternCMatcher, isDefinition()); + // Matchers for C++ record declarations. + auto CXXRecords = cxxRecordDecl(CommonFilter, CCMatcher, isDefinition()); + + // Matchers for function declarations. + // We want to exclude friend declaration, but the `DeclContext` of a friend + // function declaration is not the class in which it is declared, so we need + // to explicitly check if the parent is a `friendDecl`. + auto Functions = functionDecl(CommonFilter, unless(hasParent(friendDecl())), + anyOf(ExternCMatcher, CCMatcher)); + + // Matcher for typedef and type alias declarations. + // + // typedef and type alias can come from C-style headers and C++ headers. + // For C-style headers, `DeclContxet` can be either `TranslationUnitDecl` + // or `LinkageSpecDecl`. + // For C++ headers, `DeclContext ` can be either `TranslationUnitDecl` + // or `NamespaceDecl`. + // With the following context matcher, we can match `typedefNameDecl` from + // both C-style headers and C++ headers (except for those in classes). + // "cc_matchers" are not included since template-related matchers are not + // applicable on `TypedefNameDecl`. + auto Typedefs = + typedefNameDecl(CommonFilter, anyOf(HasNSOrTUCtxMatcher, + hasDeclContext(linkageSpecDecl()))); + + // Matchers for enum declarations. + auto Enums = enumDecl(CommonFilter, isDefinition(), + anyOf(HasNSOrTUCtxMatcher, ExternCMatcher)); + + // Matchers for enum constant declarations. + // We only match the enum constants in non-scoped enum declarations which are + // inside toplevel translation unit or a namespace. + auto EnumConstants = enumConstantDecl( + CommonFilter, unless(isInScopedEnum()), + anyOf(hasDeclContext(enumDecl(HasNSOrTUCtxMatcher)), ExternCMatcher)); + + // Most of the time we care about all matchable decls, or all types. + auto Types = namedDecl(anyOf(CRecords, CXXRecords, Enums)); + auto Decls = namedDecl(anyOf(CRecords, CXXRecords, Enums, Typedefs, Vars, + EnumConstants, Functions)); + + // We want eligible decls bound to "decl"... + MatchFinder->addMatcher(Decls.bind("decl"), this); + + // ... and all uses of them bound to "use". These have many cases: + // Uses of values/functions: these generate a declRefExpr. + MatchFinder->addMatcher( + declRefExpr(isExpansionInMainFile(), to(Decls.bind("use"))), this); + // Uses of function templates: + MatchFinder->addMatcher( + declRefExpr(isExpansionInMainFile(), + to(functionDecl(hasParent( + functionTemplateDecl(has(Functions.bind("use"))))))), + this); + + // Uses of most types: just look at what the typeLoc refers to. + MatchFinder->addMatcher( + typeLoc(isExpansionInMainFile(), + loc(qualType(hasDeclaration(Types.bind("use"))))), + this); + // Uses of typedefs: these are often transparent to hasDeclaration, so we need + // to handle them explicitly. + MatchFinder->addMatcher( + typeLoc(isExpansionInMainFile(), + loc(typedefType(hasDeclaration(Typedefs.bind("use"))))), + this); + // Uses of class templates: + // The typeLoc names the templateSpecializationType. Its declaration is the + // ClassTemplateDecl, which contains the CXXRecordDecl we want. + MatchFinder->addMatcher( + typeLoc(isExpansionInMainFile(), + loc(templateSpecializationType(hasDeclaration( + classTemplateSpecializationDecl(hasSpecializedTemplate( + classTemplateDecl(has(CXXRecords.bind("use"))))))))), + this); +} + +void FindAllSymbols::run(const MatchFinder::MatchResult &Result) { + // Ignore Results in failing TUs. + if (Result.Context->getDiagnostics().hasErrorOccurred()) { + return; + } + + SymbolInfo::Signals Signals; + const NamedDecl *ND; + if ((ND = Result.Nodes.getNodeAs<NamedDecl>("use"))) + Signals.Used = 1; + else if ((ND = Result.Nodes.getNodeAs<NamedDecl>("decl"))) + Signals.Seen = 1; + else + assert(false && "Must match a NamedDecl!"); + + const SourceManager *SM = Result.SourceManager; + if (auto Symbol = CreateSymbolInfo(ND, *SM, Collector)) { + Filename = SM->getFileEntryForID(SM->getMainFileID())->getName(); + FileSymbols[*Symbol] += Signals; + } +} + +void FindAllSymbols::onEndOfTranslationUnit() { + if (Filename != "") { + Reporter->reportSymbols(Filename, FileSymbols); + FileSymbols.clear(); + Filename = ""; + } +} + +} // namespace find_all_symbols +} // namespace clang diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbols.h b/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbols.h new file mode 100644 index 00000000000..d78da668ee4 --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbols.h @@ -0,0 +1,62 @@ +//===-- FindAllSymbols.h - find all symbols----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_SYMBOL_MATCHER_H +#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_SYMBOL_MATCHER_H + +#include "SymbolInfo.h" +#include "SymbolReporter.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include <string> + +namespace clang { +namespace find_all_symbols { + +class HeaderMapCollector; + +/// \brief FindAllSymbols collects all classes, free standing functions and +/// global variables with some extra information such as the path of the header +/// file, the namespaces they are contained in, the type of variables and the +/// parameter types of functions. +/// +/// NOTE: +/// - Symbols declared in main files are not collected since they can not be +/// included. +/// - Member functions are not collected because accessing them must go +/// through the class. #include fixer only needs the class name to find +/// headers. +/// +class FindAllSymbols : public ast_matchers::MatchFinder::MatchCallback { +public: + explicit FindAllSymbols(SymbolReporter *Reporter, + HeaderMapCollector *Collector = nullptr) + : Reporter(Reporter), Collector(Collector) {} + + void registerMatchers(ast_matchers::MatchFinder *MatchFinder); + + void run(const ast_matchers::MatchFinder::MatchResult &result) override; + +protected: + void onEndOfTranslationUnit() override; + +private: + // Current source file being processed, filled by first symbol found. + std::string Filename; + // Findings for the current source file, flushed on onEndOfTranslationUnit. + SymbolInfo::SignalMap FileSymbols; + // Reporter for SymbolInfo. + SymbolReporter *const Reporter; + // A remapping header file collector allowing clients include a different + // header. + HeaderMapCollector *const Collector; +}; + +} // namespace find_all_symbols +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_SYMBOL_MATCHER_H diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbolsAction.cpp b/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbolsAction.cpp new file mode 100644 index 00000000000..9f1d31dc38a --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbolsAction.cpp @@ -0,0 +1,36 @@ +//===-- FindAllSymbolsAction.cpp - find all symbols action --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "FindAllSymbolsAction.h" +#include "FindAllMacros.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/STLExtras.h" + +namespace clang { +namespace find_all_symbols { + +FindAllSymbolsAction::FindAllSymbolsAction( + SymbolReporter *Reporter, + const HeaderMapCollector::RegexHeaderMap *RegexHeaderMap) + : Reporter(Reporter), Collector(RegexHeaderMap), Handler(&Collector), + Matcher(Reporter, &Collector) { + Matcher.registerMatchers(&MatchFinder); +} + +std::unique_ptr<ASTConsumer> +FindAllSymbolsAction::CreateASTConsumer(CompilerInstance &Compiler, + StringRef InFile) { + Compiler.getPreprocessor().addCommentHandler(&Handler); + Compiler.getPreprocessor().addPPCallbacks(llvm::make_unique<FindAllMacros>( + Reporter, &Compiler.getSourceManager(), &Collector)); + return MatchFinder.newASTConsumer(); +} + +} // namespace find_all_symbols +} // namespace clang diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbolsAction.h b/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbolsAction.h new file mode 100644 index 00000000000..ccffa4b3c9d --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbolsAction.h @@ -0,0 +1,62 @@ +//===-- FindAllSymbolsAction.h - find all symbols action --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_FIND_ALL_SYMBOLS_ACTION_H +#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_FIND_ALL_SYMBOLS_ACTION_H + +#include "FindAllSymbols.h" +#include "HeaderMapCollector.h" +#include "PragmaCommentHandler.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/StringRef.h" +#include <memory> + +namespace clang { +namespace find_all_symbols { + +class FindAllSymbolsAction : public clang::ASTFrontendAction { +public: + explicit FindAllSymbolsAction( + SymbolReporter *Reporter, + const HeaderMapCollector::RegexHeaderMap *RegexHeaderMap = nullptr); + + std::unique_ptr<clang::ASTConsumer> + CreateASTConsumer(clang::CompilerInstance &Compiler, + StringRef InFile) override; + +private: + SymbolReporter *const Reporter; + clang::ast_matchers::MatchFinder MatchFinder; + HeaderMapCollector Collector; + PragmaCommentHandler Handler; + FindAllSymbols Matcher; +}; + +class FindAllSymbolsActionFactory : public tooling::FrontendActionFactory { +public: + FindAllSymbolsActionFactory( + SymbolReporter *Reporter, + const HeaderMapCollector::RegexHeaderMap *RegexHeaderMap = nullptr) + : Reporter(Reporter), RegexHeaderMap(RegexHeaderMap) {} + + clang::FrontendAction *create() override { + return new FindAllSymbolsAction(Reporter, RegexHeaderMap); + } + +private: + SymbolReporter *const Reporter; + const HeaderMapCollector::RegexHeaderMap *const RegexHeaderMap; +}; + +} // namespace find_all_symbols +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_FIND_ALL_SYMBOLS_ACTION_H diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/HeaderMapCollector.cpp b/clang-tools-extra/clang-include-fixer/find-all-symbols/HeaderMapCollector.cpp new file mode 100644 index 00000000000..6ec49cae2a6 --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/HeaderMapCollector.cpp @@ -0,0 +1,44 @@ +//===-- HeaderMapCoolector.h - find all symbols------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "HeaderMapCollector.h" +#include "llvm/Support/Regex.h" + +namespace clang { +namespace find_all_symbols { + +HeaderMapCollector::HeaderMapCollector( + const RegexHeaderMap *RegexHeaderMappingTable) { + assert(RegexHeaderMappingTable); + this->RegexHeaderMappingTable.reserve(RegexHeaderMappingTable->size()); + for (const auto &Entry : *RegexHeaderMappingTable) { + this->RegexHeaderMappingTable.emplace_back(llvm::Regex(Entry.first), + Entry.second); + } +} + +llvm::StringRef +HeaderMapCollector::getMappedHeader(llvm::StringRef Header) const { + auto Iter = HeaderMappingTable.find(Header); + if (Iter != HeaderMappingTable.end()) + return Iter->second; + // If there is no complete header name mapping for this header, check the + // regex header mapping. + for (auto &Entry : RegexHeaderMappingTable) { +#ifndef NDEBUG + std::string Dummy; + assert(Entry.first.isValid(Dummy) && "Regex should never be invalid!"); +#endif + if (Entry.first.match(Header)) + return Entry.second; + } + return Header; +} + +} // namespace find_all_symbols +} // namespace clang diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/HeaderMapCollector.h b/clang-tools-extra/clang-include-fixer/find-all-symbols/HeaderMapCollector.h new file mode 100644 index 00000000000..2135827561d --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/HeaderMapCollector.h @@ -0,0 +1,56 @@ +//===-- HeaderMapCoolector.h - find all symbols------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_HEADER_MAP_COLLECTOR_H +#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_HEADER_MAP_COLLECTOR_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Regex.h" +#include <string> +#include <vector> + +namespace clang { +namespace find_all_symbols { + +/// \brief HeaderMappCollector collects all remapping header files. This maps +/// complete header names or header name regex patterns to header names. +class HeaderMapCollector { +public: + typedef llvm::StringMap<std::string> HeaderMap; + typedef std::vector<std::pair<const char *, const char *>> RegexHeaderMap; + + HeaderMapCollector() = default; + explicit HeaderMapCollector(const RegexHeaderMap *RegexHeaderMappingTable); + + void addHeaderMapping(llvm::StringRef OrignalHeaderPath, + llvm::StringRef MappingHeaderPath) { + HeaderMappingTable[OrignalHeaderPath] = MappingHeaderPath; + }; + + /// Check if there is a mapping from \p Header or a regex pattern that matches + /// it to another header name. + /// \param Header A header name. + /// \return \p Header itself if there is no mapping for it; otherwise, return + /// a mapped header name. + llvm::StringRef getMappedHeader(llvm::StringRef Header) const; + +private: + /// A string-to-string map saving the mapping relationship. + HeaderMap HeaderMappingTable; + + // A map from header patterns to header names. + // The header names are not owned. This is only threadsafe because the regexes + // never fail. + mutable std::vector<std::pair<llvm::Regex, const char *>> + RegexHeaderMappingTable; +}; + +} // namespace find_all_symbols +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_HEADER_MAP_COLLECTOR_H diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/PathConfig.cpp b/clang-tools-extra/clang-include-fixer/find-all-symbols/PathConfig.cpp new file mode 100644 index 00000000000..4f1ebc7732a --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/PathConfig.cpp @@ -0,0 +1,41 @@ +//===-- PathConfig.cpp - Process paths of symbols ---------------*- C++ -*-===// +// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PathConfig.h" +#include "llvm/Support/Path.h" + +namespace clang { +namespace find_all_symbols { + +std::string getIncludePath(const SourceManager &SM, SourceLocation Loc, + const HeaderMapCollector *Collector) { + llvm::StringRef FilePath; + // Walk up the include stack to skip .inc files. + while (true) { + if (!Loc.isValid() || SM.isInMainFile(Loc)) + return ""; + FilePath = SM.getFilename(Loc); + if (FilePath.empty()) + return ""; + if (!FilePath.endswith(".inc")) + break; + FileID ID = SM.getFileID(Loc); + Loc = SM.getIncludeLoc(ID); + } + + if (Collector) + FilePath = Collector->getMappedHeader(FilePath); + SmallString<256> CleanedFilePath = FilePath; + llvm::sys::path::remove_dots(CleanedFilePath, /*remove_dot_dot=*/false); + + return CleanedFilePath.str(); +} + +} // namespace find_all_symbols +} // namespace clang diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/PathConfig.h b/clang-tools-extra/clang-include-fixer/find-all-symbols/PathConfig.h new file mode 100644 index 00000000000..9c430f2526a --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/PathConfig.h @@ -0,0 +1,36 @@ +//===-- PathConfig.h - Process paths of symbols -----------------*- C++ -*-===// +// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PATH_CONFIG_H +#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PATH_CONFIG_H + +#include "HeaderMapCollector.h" +#include "clang/Basic/SourceManager.h" +#include <string> + +namespace clang { +namespace find_all_symbols { + +/// \brief This calculates the include path for \p Loc. +/// +/// \param SM SourceManager. +/// \param Loc A SourceLocation. +/// \param Collector An optional header mapping collector. +/// +/// \return The file path (or mapped file path if Collector is provided) of the +/// header that includes \p Loc. If \p Loc comes from .inc header file, \p Loc +/// is set to the location from which the .inc header file is included. If \p +/// Loc is invalid or comes from a main file, this returns an empty string. +std::string getIncludePath(const SourceManager &SM, SourceLocation Loc, + const HeaderMapCollector *Collector = nullptr); + +} // namespace find_all_symbols +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PATH_CONFIG_H diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/PragmaCommentHandler.cpp b/clang-tools-extra/clang-include-fixer/find-all-symbols/PragmaCommentHandler.cpp new file mode 100644 index 00000000000..494897529e2 --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/PragmaCommentHandler.cpp @@ -0,0 +1,36 @@ +//===-- PragmaCommentHandler.cpp - find all symbols -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PragmaCommentHandler.h" +#include "FindAllSymbols.h" +#include "HeaderMapCollector.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()); + size_t Pos = Text.find(IWYUPragma); + if (Pos == StringRef::npos) + return false; + StringRef RemappingFilePath = Text.substr(Pos + std::strlen(IWYUPragma)); + Collector->addHeaderMapping( + PP.getSourceManager().getFilename(Range.getBegin()), + RemappingFilePath.trim("\"<>")); + return false; +} + +} // namespace find_all_symbols +} // namespace clang diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/PragmaCommentHandler.h b/clang-tools-extra/clang-include-fixer/find-all-symbols/PragmaCommentHandler.h new file mode 100644 index 00000000000..752c82f5a06 --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/PragmaCommentHandler.h @@ -0,0 +1,40 @@ +//===-- PragmaCommentHandler.h - find all symbols----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PRAGMA_COMMENT_HANDLER_H +#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PRAGMA_COMMENT_HANDLER_H + +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Preprocessor.h" +#include <map> + +namespace clang { +namespace find_all_symbols { + +class HeaderMapCollector; + +/// \brief PragmaCommentHandler parses pragma comment on include files to +/// determine when we should include a different header from the header that +/// directly defines a symbol. +/// +/// Currently it only supports IWYU private pragma: +/// https://github.com/include-what-you-use/include-what-you-use/blob/master/docs/IWYUPragmas.md#iwyu-pragma-private +class PragmaCommentHandler : public clang::CommentHandler { +public: + PragmaCommentHandler(HeaderMapCollector *Collector) : Collector(Collector) {} + + bool HandleComment(Preprocessor &PP, SourceRange Range) override; + +private: + HeaderMapCollector *const Collector; +}; + +} // namespace find_all_symbols +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PRAGMA_COMMENT_HANDLER_H diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp b/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp new file mode 100644 index 00000000000..0d0bbd9f055 --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp @@ -0,0 +1,653 @@ +//===-- STLPostfixHeaderMap.h - hardcoded STL header map --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "STLPostfixHeaderMap.h" + +namespace clang { +namespace find_all_symbols { + +const HeaderMapCollector::RegexHeaderMap *getSTLPostfixHeaderMap() { + static const HeaderMapCollector::RegexHeaderMap STLPostfixHeaderMap = { + {"include/__stddef_max_align_t.h$", "<cstddef>"}, + {"include/__wmmintrin_aes.h$", "<wmmintrin.h>"}, + {"include/__wmmintrin_pclmul.h$", "<wmmintrin.h>"}, + {"include/adxintrin.h$", "<immintrin.h>"}, + {"include/ammintrin.h$", "<ammintrin.h>"}, + {"include/avx2intrin.h$", "<immintrin.h>"}, + {"include/avx512bwintrin.h$", "<immintrin.h>"}, + {"include/avx512cdintrin.h$", "<immintrin.h>"}, + {"include/avx512dqintrin.h$", "<immintrin.h>"}, + {"include/avx512erintrin.h$", "<immintrin.h>"}, + {"include/avx512fintrin.h$", "<immintrin.h>"}, + {"include/avx512ifmaintrin.h$", "<immintrin.h>"}, + {"include/avx512ifmavlintrin.h$", "<immintrin.h>"}, + {"include/avx512pfintrin.h$", "<immintrin.h>"}, + {"include/avx512vbmiintrin.h$", "<immintrin.h>"}, + {"include/avx512vbmivlintrin.h$", "<immintrin.h>"}, + {"include/avx512vlbwintrin.h$", "<immintrin.h>"}, + {"include/avx512vlcdintrin.h$", "<immintrin.h>"}, + {"include/avx512vldqintrin.h$", "<immintrin.h>"}, + {"include/avx512vlintrin.h$", "<immintrin.h>"}, + {"include/avxintrin.h$", "<immintrin.h>"}, + {"include/bmi2intrin.h$", "<x86intrin.h>"}, + {"include/bmiintrin.h$", "<x86intrin.h>"}, + {"include/emmintrin.h$", "<emmintrin.h>"}, + {"include/f16cintrin.h$", "<emmintrin.h>"}, + {"include/float.h$", "<cfloat>"}, + {"include/fma4intrin.h$", "<x86intrin.h>"}, + {"include/fmaintrin.h$", "<immintrin.h>"}, + {"include/fxsrintrin.h$", "<immintrin.h>"}, + {"include/ia32intrin.h$", "<x86intrin.h>"}, + {"include/immintrin.h$", "<immintrin.h>"}, + {"include/inttypes.h$", "<cinttypes>"}, + {"include/limits.h$", "<climits>"}, + {"include/lzcntintrin.h$", "<x86intrin.h>"}, + {"include/mm3dnow.h$", "<mm3dnow.h>"}, + {"include/mm_malloc.h$", "<mm_malloc.h>"}, + {"include/mmintrin.h$", "<mmintrin>"}, + {"include/mwaitxintrin.h$", "<x86intrin.h>"}, + {"include/pkuintrin.h$", "<immintrin.h>"}, + {"include/pmmintrin.h$", "<pmmintrin.h>"}, + {"include/popcntintrin.h$", "<popcntintrin.h>"}, + {"include/prfchwintrin.h$", "<x86intrin.h>"}, + {"include/rdseedintrin.h$", "<x86intrin.h>"}, + {"include/rtmintrin.h$", "<immintrin.h>"}, + {"include/shaintrin.h$", "<immintrin.h>"}, + {"include/smmintrin.h$", "<smmintrin.h>"}, + {"include/stdalign.h$", "<cstdalign>"}, + {"include/stdarg.h$", "<cstdarg>"}, + {"include/stdbool.h$", "<cstdbool>"}, + {"include/stddef.h$", "<cstddef>"}, + {"include/stdint.h$", "<cstdint>"}, + {"include/tbmintrin.h$", "<x86intrin.h>"}, + {"include/tmmintrin.h$", "<tmmintrin.h>"}, + {"include/wmmintrin.h$", "<wmmintrin.h>"}, + {"include/x86intrin.h$", "<x86intrin.h>"}, + {"include/xmmintrin.h$", "<xmmintrin.h>"}, + {"include/xopintrin.h$", "<x86intrin.h>"}, + {"include/xsavecintrin.h$", "<immintrin.h>"}, + {"include/xsaveintrin.h$", "<immintrin.h>"}, + {"include/xsaveoptintrin.h$", "<immintrin.h>"}, + {"include/xsavesintrin.h$", "<immintrin.h>"}, + {"include/xtestintrin.h$", "<immintrin.h>"}, + {"include/_G_config.h$", "<cstdio>"}, + {"include/assert.h$", "<cassert>"}, + {"algorithm$", "<algorithm>"}, + {"array$", "<array>"}, + {"atomic$", "<atomic>"}, + {"backward/auto_ptr.h$", "<memory>"}, + {"backward/binders.h$", "<string>"}, + {"bits/algorithmfwd.h$", "<algorithm>"}, + {"bits/alloc_traits.h$", "<unordered_set>"}, + {"bits/allocator.h$", "<string>"}, + {"bits/atomic_base.h$", "<atomic>"}, + {"bits/atomic_lockfree_defines.h$", "<exception>"}, + {"bits/basic_ios.h$", "<ios>"}, + {"bits/basic_ios.tcc$", "<ios>"}, + {"bits/basic_string.h$", "<string>"}, + {"bits/basic_string.tcc$", "<string>"}, + {"bits/char_traits.h$", "<string>"}, + {"bits/codecvt.h$", "<locale>"}, + {"bits/concept_check.h$", "<numeric>"}, + {"bits/cpp_type_traits.h$", "<cmath>"}, + {"bits/cxxabi_forced.h$", "<cxxabi.h>"}, + {"bits/deque.tcc$", "<deque>"}, + {"bits/exception_defines.h$", "<exception>"}, + {"bits/exception_ptr.h$", "<exception>"}, + {"bits/forward_list.h$", "<forward_list>"}, + {"bits/forward_list.tcc$", "<forward_list>"}, + {"bits/fstream.tcc$", "<fstream>"}, + {"bits/functexcept.h$", "<list>"}, + {"bits/functional_hash.h$", "<string>"}, + {"bits/gslice.h$", "<valarray>"}, + {"bits/gslice_array.h$", "<valarray>"}, + {"bits/hash_bytes.h$", "<typeinfo>"}, + {"bits/hashtable.h$", "<unordered_set>"}, + {"bits/hashtable_policy.h$", "<unordered_set>"}, + {"bits/indirect_array.h$", "<valarray>"}, + {"bits/ios_base.h$", "<ios>"}, + {"bits/istream.tcc$", "<istream>"}, + {"bits/list.tcc$", "<list>"}, + {"bits/locale_classes.h$", "<locale>"}, + {"bits/locale_classes.tcc$", "<locale>"}, + {"bits/locale_facets.h$", "<locale>"}, + {"bits/locale_facets.tcc$", "<locale>"}, + {"bits/locale_facets_nonio.h$", "<locale>"}, + {"bits/locale_facets_nonio.tcc$", "<locale>"}, + {"bits/localefwd.h$", "<locale>"}, + {"bits/mask_array.h$", "<valarray>"}, + {"bits/memoryfwd.h$", "<memory>"}, + {"bits/move.h$", "<utility>"}, + {"bits/nested_exception.h$", "<exception>"}, + {"bits/ostream.tcc$", "<ostream>"}, + {"bits/ostream_insert.h$", "<ostream>"}, + {"bits/postypes.h$", "<iosfwd>"}, + {"bits/ptr_traits.h$", "<memory>"}, + {"bits/random.h$", "<random>"}, + {"bits/random.tcc$", "<random>"}, + {"bits/range_access.h$", "<iterator>"}, + {"bits/regex.h$", "<regex>"}, + {"bits/regex_compiler.h$", "<regex>"}, + {"bits/regex_constants.h$", "<regex>"}, + {"bits/regex_cursor.h$", "<regex>"}, + {"bits/regex_error.h$", "<regex>"}, + {"bits/regex_grep_matcher.h$", "<regex>"}, + {"bits/regex_grep_matcher.tcc$", "<regex>"}, + {"bits/regex_nfa.h$", "<regex>"}, + {"bits/shared_ptr.h$", "<memory>"}, + {"bits/shared_ptr_base.h$", "<memory>"}, + {"bits/slice_array.h$", "<valarray>"}, + {"bits/sstream.tcc$", "<sstream>"}, + {"bits/stl_algo.h$", "<algorithm>"}, + {"bits/stl_algobase.h$", "<list>"}, + {"bits/stl_bvector.h$", "<vector>"}, + {"bits/stl_construct.h$", "<deque>"}, + {"bits/stl_deque.h$", "<deque>"}, + {"bits/stl_function.h$", "<string>"}, + {"bits/stl_heap.h$", "<queue>"}, + {"bits/stl_iterator.h$", "<iterator>"}, + {"bits/stl_iterator_base_funcs.h$", "<iterator>"}, + {"bits/stl_iterator_base_types.h$", "<numeric>"}, + {"bits/stl_list.h$", "<list>"}, + {"bits/stl_map.h$", "<map>"}, + {"bits/stl_multimap.h$", "<map>"}, + {"bits/stl_multiset.h$", "<set>"}, + {"bits/stl_numeric.h$", "<numeric>"}, + {"bits/stl_pair.h$", "<utility>"}, + {"bits/stl_queue.h$", "<queue>"}, + {"bits/stl_raw_storage_iter.h$", "<memory>"}, + {"bits/stl_relops.h$", "<utility>"}, + {"bits/stl_set.h$", "<set>"}, + {"bits/stl_stack.h$", "<stack>"}, + {"bits/stl_tempbuf.h$", "<memory>"}, + {"bits/stl_tree.h$", "<map>"}, + {"bits/stl_uninitialized.h$", "<deque>"}, + {"bits/stl_vector.h$", "<vector>"}, + {"bits/stream_iterator.h$", "<iterator>"}, + {"bits/streambuf.tcc$", "<streambuf>"}, + {"bits/streambuf_iterator.h$", "<iterator>"}, + {"bits/stringfwd.h$", "<string>"}, + {"bits/unique_ptr.h$", "<memory>"}, + {"bits/unordered_map.h$", "<unordered_map>"}, + {"bits/unordered_set.h$", "<unordered_set>"}, + {"bits/uses_allocator.h$", "<tuple>"}, + {"bits/valarray_after.h$", "<valarray>"}, + {"bits/valarray_array.h$", "<valarray>"}, + {"bits/valarray_array.tcc$", "<valarray>"}, + {"bits/valarray_before.h$", "<valarray>"}, + {"bits/vector.tcc$", "<vector>"}, + {"bitset$", "<bitset>"}, + {"ccomplex$", "<ccomplex>"}, + {"cctype$", "<cctype>"}, + {"cerrno$", "<cerrno>"}, + {"cfenv$", "<cfenv>"}, + {"cfloat$", "<cfloat>"}, + {"chrono$", "<chrono>"}, + {"cinttypes$", "<cinttypes>"}, + {"climits$", "<climits>"}, + {"clocale$", "<clocale>"}, + {"cmath$", "<cmath>"}, + {"complex$", "<complex>"}, + {"complex.h$", "<complex.h>"}, + {"condition_variable$", "<condition_variable>"}, + {"csetjmp$", "<csetjmp>"}, + {"csignal$", "<csignal>"}, + {"cstdalign$", "<cstdalign>"}, + {"cstdarg$", "<cstdarg>"}, + {"cstdbool$", "<cstdbool>"}, + {"cstdint$", "<cstdint>"}, + {"cstdio$", "<cstdio>"}, + {"cstdlib$", "<cstdlib>"}, + {"cstring$", "<cstring>"}, + {"ctgmath$", "<ctgmath>"}, + {"ctime$", "<ctime>"}, + {"cwchar$", "<cwchar>"}, + {"cwctype$", "<cwctype>"}, + {"cxxabi.h$", "<cxxabi.h>"}, + {"debug/debug.h$", "<numeric>"}, + {"debug/map.h$", "<map>"}, + {"debug/multimap.h$", "<multimap>"}, + {"debug/multiset.h$", "<multiset>"}, + {"debug/set.h$", "<set>"}, + {"deque$", "<deque>"}, + {"exception$", "<exception>"}, + {"ext/alloc_traits.h$", "<deque>"}, + {"ext/atomicity.h$", "<memory>"}, + {"ext/concurrence.h$", "<memory>"}, + {"ext/new_allocator.h$", "<string>"}, + {"ext/numeric_traits.h$", "<list>"}, + {"ext/string_conversions.h$", "<string>"}, + {"ext/type_traits.h$", "<cmath>"}, + {"fenv.h$", "<fenv.h>"}, + {"forward_list$", "<forward_list>"}, + {"fstream$", "<fstream>"}, + {"functional$", "<functional>"}, + {"future$", "<future>"}, + {"initializer_list$", "<initializer_list>"}, + {"iomanip$", "<iomanip>"}, + {"ios$", "<ios>"}, + {"iosfwd$", "<iosfwd>"}, + {"iostream$", "<iostream>"}, + {"istream$", "<istream>"}, + {"iterator$", "<iterator>"}, + {"limits$", "<limits>"}, + {"list$", "<list>"}, + {"locale$", "<locale>"}, + {"map$", "<map>"}, + {"memory$", "<memory>"}, + {"mutex$", "<mutex>"}, + {"new$", "<new>"}, + {"numeric$", "<numeric>"}, + {"ostream$", "<ostream>"}, + {"queue$", "<queue>"}, + {"random$", "<random>"}, + {"ratio$", "<ratio>"}, + {"regex$", "<regex>"}, + {"scoped_allocator$", "<scoped_allocator>"}, + {"set$", "<set>"}, + {"sstream$", "<sstream>"}, + {"stack$", "<stack>"}, + {"stdexcept$", "<stdexcept>"}, + {"streambuf$", "<streambuf>"}, + {"string$", "<string>"}, + {"system_error$", "<system_error>"}, + {"tgmath.h$", "<tgmath.h>"}, + {"thread$", "<thread>"}, + {"tuple$", "<tuple>"}, + {"type_traits$", "<type_traits>"}, + {"typeindex$", "<typeindex>"}, + {"typeinfo$", "<typeinfo>"}, + {"unordered_map$", "<unordered_map>"}, + {"unordered_set$", "<unordered_set>"}, + {"utility$", "<utility>"}, + {"valarray$", "<valarray>"}, + {"vector$", "<vector>"}, + {"include/complex.h$", "<complex.h>"}, + {"include/ctype.h$", "<cctype>"}, + {"include/errno.h$", "<cerrno>"}, + {"include/fenv.h$", "<fenv.h>"}, + {"include/inttypes.h$", "<cinttypes>"}, + {"include/libio.h$", "<cstdio>"}, + {"include/limits.h$", "<climits>"}, + {"include/locale.h$", "<clocale>"}, + {"include/math.h$", "<cmath>"}, + {"include/setjmp.h$", "<csetjmp>"}, + {"include/signal.h$", "<csignal>"}, + {"include/stdint.h$", "<cstdint>"}, + {"include/stdio.h$", "<cstdio>"}, + {"include/stdlib.h$", "<cstdlib>"}, + {"include/string.h$", "<cstring>"}, + {"include/time.h$", "<ctime>"}, + {"include/wchar.h$", "<cwchar>"}, + {"include/wctype.h$", "<cwctype>"}, + {"bits/cmathcalls.h$", "<complex.h>"}, + {"bits/errno.h$", "<cerrno>"}, + {"bits/fenv.h$", "<fenv.h>"}, + {"bits/huge_val.h$", "<cmath>"}, + {"bits/huge_valf.h$", "<cmath>"}, + {"bits/huge_vall.h$", "<cmath>"}, + {"bits/inf.h$", "<cmath>"}, + {"bits/local_lim.h$", "<climits>"}, + {"bits/locale.h$", "<clocale>"}, + {"bits/mathcalls.h$", "<math.h>"}, + {"bits/mathdef.h$", "<cmath>"}, + {"bits/nan.h$", "<cmath>"}, + {"bits/posix1_lim.h$", "<climits>"}, + {"bits/posix2_lim.h$", "<climits>"}, + {"bits/setjmp.h$", "<csetjmp>"}, + {"bits/sigaction.h$", "<csignal>"}, + {"bits/sigcontext.h$", "<csignal>"}, + {"bits/siginfo.h$", "<csignal>"}, + {"bits/signum.h$", "<csignal>"}, + {"bits/sigset.h$", "<csignal>"}, + {"bits/sigstack.h$", "<csignal>"}, + {"bits/stdio_lim.h$", "<cstdio>"}, + {"bits/sys_errlist.h$", "<cstdio>"}, + {"bits/time.h$", "<ctime>"}, + {"bits/timex.h$", "<ctime>"}, + {"bits/typesizes.h$", "<cstdio>"}, + {"bits/wchar.h$", "<cwchar>"}, + {"bits/wordsize.h$", "<csetjmp>"}, + {"bits/xopen_lim.h$", "<climits>"}, + {"include/xlocale.h$", "<cstring>"}, + {"bits/atomic_word.h$", "<memory>"}, + {"bits/basic_file.h$", "<fstream>"}, + {"bits/c\\+\\+allocator.h$", "<string>"}, + {"bits/c\\+\\+config.h$", "<iosfwd>"}, + {"bits/c\\+\\+io.h$", "<ios>"}, + {"bits/c\\+\\+locale.h$", "<locale>"}, + {"bits/cpu_defines.h$", "<iosfwd>"}, + {"bits/ctype_base.h$", "<locale>"}, + {"bits/cxxabi_tweaks.h$", "<cxxabi.h>"}, + {"bits/error_constants.h$", "<system_error>"}, + {"bits/gthr-default.h$", "<memory>"}, + {"bits/gthr.h$", "<memory>"}, + {"bits/opt_random.h$", "<random>"}, + {"bits/os_defines.h$", "<iosfwd>"}, + // GNU C headers + {"include/aio.h$", "<aio.h>"}, + {"include/aliases.h$", "<aliases.h>"}, + {"include/alloca.h$", "<alloca.h>"}, + {"include/ar.h$", "<ar.h>"}, + {"include/argp.h$", "<argp.h>"}, + {"include/argz.h$", "<argz.h>"}, + {"include/arpa/nameser.h$", "<resolv.h>"}, + {"include/arpa/nameser_compat.h$", "<resolv.h>"}, + {"include/byteswap.h$", "<byteswap.h>"}, + {"include/cpio.h$", "<cpio.h>"}, + {"include/crypt.h$", "<crypt.h>"}, + {"include/dirent.h$", "<dirent.h>"}, + {"include/dlfcn.h$", "<dlfcn.h>"}, + {"include/elf.h$", "<elf.h>"}, + {"include/endian.h$", "<endian.h>"}, + {"include/envz.h$", "<envz.h>"}, + {"include/err.h$", "<err.h>"}, + {"include/error.h$", "<error.h>"}, + {"include/execinfo.h$", "<execinfo.h>"}, + {"include/fcntl.h$", "<fcntl.h>"}, + {"include/features.h$", "<features.h>"}, + {"include/fenv.h$", "<fenv.h>"}, + {"include/fmtmsg.h$", "<fmtmsg.h>"}, + {"include/fnmatch.h$", "<fnmatch.h>"}, + {"include/fstab.h$", "<fstab.h>"}, + {"include/fts.h$", "<fts.h>"}, + {"include/ftw.h$", "<ftw.h>"}, + {"include/gconv.h$", "<gconv.h>"}, + {"include/getopt.h$", "<getopt.h>"}, + {"include/glob.h$", "<glob.h>"}, + {"include/grp.h$", "<grp.h>"}, + {"include/gshadow.h$", "<gshadow.h>"}, + {"include/iconv.h$", "<iconv.h>"}, + {"include/ifaddrs.h$", "<ifaddrs.h>"}, + {"include/kdb.h$", "<kdb.h>"}, + {"include/langinfo.h$", "<langinfo.h>"}, + {"include/libgen.h$", "<libgen.h>"}, + {"include/libintl.h$", "<libintl.h>"}, + {"include/link.h$", "<link.h>"}, + {"include/malloc.h$", "<malloc.h>"}, + {"include/mcheck.h$", "<mcheck.h>"}, + {"include/memory.h$", "<memory.h>"}, + {"include/mntent.h$", "<mntent.h>"}, + {"include/monetary.h$", "<monetary.h>"}, + {"include/mqueue.h$", "<mqueue.h>"}, + {"include/netdb.h$", "<netdb.h>"}, + {"include/netinet/in.h$", "<netinet/in.h>"}, + {"include/nl_types.h$", "<nl_types.h>"}, + {"include/nss.h$", "<nss.h>"}, + {"include/obstack.h$", "<obstack.h>"}, + {"include/panel.h$", "<panel.h>"}, + {"include/paths.h$", "<paths.h>"}, + {"include/printf.h$", "<printf.h>"}, + {"include/profile.h$", "<profile.h>"}, + {"include/pthread.h$", "<pthread.h>"}, + {"include/pty.h$", "<pty.h>"}, + {"include/pwd.h$", "<pwd.h>"}, + {"include/re_comp.h$", "<re_comp.h>"}, + {"include/regex.h$", "<regex.h>"}, + {"include/regexp.h$", "<regexp.h>"}, + {"include/resolv.h$", "<resolv.h>"}, + {"include/rpc/netdb.h$", "<netdb.h>"}, + {"include/sched.h$", "<sched.h>"}, + {"include/search.h$", "<search.h>"}, + {"include/semaphore.h$", "<semaphore.h>"}, + {"include/sgtty.h$", "<sgtty.h>"}, + {"include/shadow.h$", "<shadow.h>"}, + {"include/spawn.h$", "<spawn.h>"}, + {"include/stab.h$", "<stab.h>"}, + {"include/stdc-predef.h$", "<stdc-predef.h>"}, + {"include/stdio_ext.h$", "<stdio_ext.h>"}, + {"include/strings.h$", "<strings.h>"}, + {"include/stropts.h$", "<stropts.h>"}, + {"include/sudo_plugin.h$", "<sudo_plugin.h>"}, + {"include/sysexits.h$", "<sysexits.h>"}, + {"include/tar.h$", "<tar.h>"}, + {"include/tcpd.h$", "<tcpd.h>"}, + {"include/term.h$", "<term.h>"}, + {"include/term_entry.h$", "<term_entry.h>"}, + {"include/termcap.h$", "<termcap.h>"}, + {"include/termios.h$", "<termios.h>"}, + {"include/thread_db.h$", "<thread_db.h>"}, + {"include/tic.h$", "<tic.h>"}, + {"include/ttyent.h$", "<ttyent.h>"}, + {"include/uchar.h$", "<uchar.h>"}, + {"include/ucontext.h$", "<ucontext.h>"}, + {"include/ulimit.h$", "<ulimit.h>"}, + {"include/unctrl.h$", "<unctrl.h>"}, + {"include/unistd.h$", "<unistd.h>"}, + {"include/utime.h$", "<utime.h>"}, + {"include/utmp.h$", "<utmp.h>"}, + {"include/utmpx.h$", "<utmpx.h>"}, + {"include/values.h$", "<values.h>"}, + {"include/wordexp.h$", "<wordexp.h>"}, + {"fpu_control.h$", "<fpu_control.h>"}, + {"ieee754.h$", "<ieee754.h>"}, + {"include/xlocale.h$", "<xlocale.h>"}, + {"gnu/lib-names.h$", "<gnu/lib-names.h>"}, + {"gnu/libc-version.h$", "<gnu/libc-version.h>"}, + {"gnu/option-groups.h$", "<gnu/option-groups.h>"}, + {"gnu/stubs-32.h$", "<gnu/stubs-32.h>"}, + {"gnu/stubs-64.h$", "<gnu/stubs-64.h>"}, + {"gnu/stubs-x32.h$", "<gnu/stubs-x32.h>"}, + {"include/rpc/auth_des.h$", "<rpc/auth_des.h>"}, + {"include/rpc/rpc_msg.h$", "<rpc/rpc_msg.h>"}, + {"include/rpc/pmap_clnt.h$", "<rpc/pmap_clnt.h>"}, + {"include/rpc/rpc.h$", "<rpc/rpc.h>"}, + {"include/rpc/types.h$", "<rpc/types.h>"}, + {"include/rpc/auth_unix.h$", "<rpc/auth_unix.h>"}, + {"include/rpc/key_prot.h$", "<rpc/key_prot.h>"}, + {"include/rpc/pmap_prot.h$", "<rpc/pmap_prot.h>"}, + {"include/rpc/auth.h$", "<rpc/auth.h>"}, + {"include/rpc/svc_auth.h$", "<rpc/svc_auth.h>"}, + {"include/rpc/xdr.h$", "<rpc/xdr.h>"}, + {"include/rpc/pmap_rmt.h$", "<rpc/pmap_rmt.h>"}, + {"include/rpc/des_crypt.h$", "<rpc/des_crypt.h>"}, + {"include/rpc/svc.h$", "<rpc/svc.h>"}, + {"include/rpc/rpc_des.h$", "<rpc/rpc_des.h>"}, + {"include/rpc/clnt.h$", "<rpc/clnt.h>"}, + {"include/scsi/scsi.h$", "<scsi/scsi.h>"}, + {"include/scsi/sg.h$", "<scsi/sg.h>"}, + {"include/scsi/scsi_ioctl.h$", "<scsi/scsi_ioctl>"}, + {"include/netrose/rose.h$", "<netrose/rose.h>"}, + {"include/nfs/nfs.h$", "<nfs/nfs.h>"}, + {"include/netatalk/at.h$", "<netatalk/at.h>"}, + {"include/netinet/ether.h$", "<netinet/ether.h>"}, + {"include/netinet/icmp6.h$", "<netinet/icmp6.h>"}, + {"include/netinet/if_ether.h$", "<netinet/if_ether.h>"}, + {"include/netinet/if_fddi.h$", "<netinet/if_fddi.h>"}, + {"include/netinet/if_tr.h$", "<netinet/if_tr.h>"}, + {"include/netinet/igmp.h$", "<netinet/igmp.h>"}, + {"include/netinet/in.h$", "<netinet/in.h>"}, + {"include/netinet/in_systm.h$", "<netinet/in_systm.h>"}, + {"include/netinet/ip.h$", "<netinet/ip.h>"}, + {"include/netinet/ip6.h$", "<netinet/ip6.h>"}, + {"include/netinet/ip_icmp.h$", "<netinet/ip_icmp.h>"}, + {"include/netinet/tcp.h$", "<netinet/tcp.h>"}, + {"include/netinet/udp.h$", "<netinet/udp.h>"}, + {"include/netrom/netrom.h$", "<netrom/netrom.h>"}, + {"include/protocols/routed.h$", "<protocols/routed.h>"}, + {"include/protocols/rwhod.h$", "<protocols/rwhod.h>"}, + {"include/protocols/talkd.h$", "<protocols/talkd.h>"}, + {"include/protocols/timed.h$", "<protocols/timed.h>"}, + {"include/rpcsvc/klm_prot.x$", "<rpcsvc/klm_prot.x>"}, + {"include/rpcsvc/rstat.h$", "<rpcsvc/rstat.h>"}, + {"include/rpcsvc/spray.x$", "<rpcsvc/spray.x>"}, + {"include/rpcsvc/nlm_prot.x$", "<rpcsvc/nlm_prot.x>"}, + {"include/rpcsvc/nis_callback.x$", "<rpcsvc/nis_callback.x>"}, + {"include/rpcsvc/yp.h$", "<rpcsvc/yp.h>"}, + {"include/rpcsvc/yp.x$", "<rpcsvc/yp.x>"}, + {"include/rpcsvc/nfs_prot.h$", "<rpcsvc/nfs_prot.h>"}, + {"include/rpcsvc/rex.h$", "<rpcsvc/rex.h>"}, + {"include/rpcsvc/yppasswd.h$", "<rpcsvc/yppasswd.h>"}, + {"include/rpcsvc/rex.x$", "<rpcsvc/rex.x>"}, + {"include/rpcsvc/nis_tags.h$", "<rpcsvc/nis_tags.h>"}, + {"include/rpcsvc/nis_callback.h$", "<rpcsvc/nis_callback.h>"}, + {"include/rpcsvc/nfs_prot.x$", "<rpcsvc/nfs_prot.x>"}, + {"include/rpcsvc/bootparam_prot.x$", "<rpcsvc/bootparam_prot.x>"}, + {"include/rpcsvc/rusers.x$", "<rpcsvc/rusers.x>"}, + {"include/rpcsvc/rquota.x$", "<rpcsvc/rquota.x>"}, + {"include/rpcsvc/nis.h$", "<rpcsvc/nis.h>"}, + {"include/rpcsvc/nislib.h$", "<rpcsvc/nislib.h>"}, + {"include/rpcsvc/ypupd.h$", "<rpcsvc/ypupd.h>"}, + {"include/rpcsvc/bootparam.h$", "<rpcsvc/bootparam.h>"}, + {"include/rpcsvc/spray.h$", "<rpcsvc/spray.h>"}, + {"include/rpcsvc/key_prot.h$", "<rpcsvc/key_prot.h>"}, + {"include/rpcsvc/klm_prot.h$", "<rpcsvc/klm_prot.h>"}, + {"include/rpcsvc/sm_inter.h$", "<rpcsvc/sm_inter.h>"}, + {"include/rpcsvc/nlm_prot.h$", "<rpcsvc/nlm_prot.h>"}, + {"include/rpcsvc/yp_prot.h$", "<rpcsvc/yp_prot.h>"}, + {"include/rpcsvc/ypclnt.h$", "<rpcsvc/ypclnt.h>"}, + {"include/rpcsvc/rstat.x$", "<rpcsvc/rstat.x>"}, + {"include/rpcsvc/rusers.h$", "<rpcsvc/rusers.h>"}, + {"include/rpcsvc/key_prot.x$", "<rpcsvc/key_prot.x>"}, + {"include/rpcsvc/sm_inter.x$", "<rpcsvc/sm_inter.x>"}, + {"include/rpcsvc/rquota.h$", "<rpcsvc/rquota.h>"}, + {"include/rpcsvc/nis.x$", "<rpcsvc/nis.x>"}, + {"include/rpcsvc/bootparam_prot.h$", "<rpcsvc/bootparam_prot.h>"}, + {"include/rpcsvc/mount.h$", "<rpcsvc/mount.h>"}, + {"include/rpcsvc/mount.x$", "<rpcsvc/mount.x>"}, + {"include/rpcsvc/nis_object.x$", "<rpcsvc/nis_object.x>"}, + {"include/rpcsvc/yppasswd.x$", "<rpcsvc/yppasswd.x>"}, + {"sys/acct.h$", "<sys/acct.h>"}, + {"sys/auxv.h$", "<sys/auxv.h>"}, + {"sys/cdefs.h$", "<sys/cdefs.h>"}, + {"sys/debugreg.h$", "<sys/debugreg.h>"}, + {"sys/dir.h$", "<sys/dir.h>"}, + {"sys/elf.h$", "<sys/elf.h>"}, + {"sys/epoll.h$", "<sys/epoll.h>"}, + {"sys/eventfd.h$", "<sys/eventfd.h>"}, + {"sys/fanotify.h$", "<sys/fanotify.h>"}, + {"sys/file.h$", "<sys/file.h>"}, + {"sys/fsuid.h$", "<sys/fsuid.h>"}, + {"sys/gmon.h$", "<sys/gmon.h>"}, + {"sys/gmon_out.h$", "<sys/gmon_out.h>"}, + {"sys/inotify.h$", "<sys/inotify.h>"}, + {"sys/io.h$", "<sys/io.h>"}, + {"sys/ioctl.h$", "<sys/ioctl.h>"}, + {"sys/ipc.h$", "<sys/ipc.h>"}, + {"sys/kd.h$", "<sys/kd.h>"}, + {"sys/kdaemon.h$", "<sys/kdaemon.h>"}, + {"sys/klog.h$", "<sys/klog.h>"}, + {"sys/mman.h$", "<sys/mman.h>"}, + {"sys/mount.h$", "<sys/mount.h>"}, + {"sys/msg.h$", "<sys/msg.h>"}, + {"sys/mtio.h$", "<sys/mtio.h>"}, + {"sys/param.h$", "<sys/param.h>"}, + {"sys/pci.h$", "<sys/pci.h>"}, + {"sys/perm.h$", "<sys/perm.h>"}, + {"sys/personality.h$", "<sys/personality.h>"}, + {"sys/poll.h$", "<sys/poll.h>"}, + {"sys/prctl.h$", "<sys/prctl.h>"}, + {"sys/procfs.h$", "<sys/procfs.h>"}, + {"sys/profil.h$", "<sys/profil.h>"}, + {"sys/ptrace.h$", "<sys/ptrace.h>"}, + {"sys/queue.h$", "<sys/queue.h>"}, + {"sys/quota.h$", "<sys/quota.h>"}, + {"sys/raw.h$", "<sys/raw.h>"}, + {"sys/reboot.h$", "<sys/reboot.h>"}, + {"sys/reg.h$", "<sys/reg.h>"}, + {"sys/resource.h$", "<sys/resource.h>"}, + {"sys/select.h$", "<sys/select.h>"}, + {"sys/sem.h$", "<sys/sem.h>"}, + {"sys/sendfile.h$", "<sys/sendfile.h>"}, + {"sys/shm.h$", "<sys/shm.h>"}, + {"sys/signalfd.h$", "<sys/signalfd.h>"}, + {"sys/socket.h$", "<sys/socket.h>"}, + {"sys/stat.h$", "<sys/stat.h>"}, + {"sys/statfs.h$", "<sys/statfs.h>"}, + {"sys/statvfs.h$", "<sys/statvfs.h>"}, + {"sys/swap.h$", "<sys/swap.h>"}, + {"sys/syscall.h$", "<sys/syscall.h>"}, + {"sys/sysctl.h$", "<sys/sysctl.h>"}, + {"sys/sysinfo.h$", "<sys/sysinfo.h>"}, + {"sys/syslog.h$", "<sys/syslog.h>"}, + {"sys/sysmacros.h$", "<sys/sysmacros.h>"}, + {"sys/termios.h$", "<sys/termios.h>"}, + {"sys/time.h$", "<sys/select.h>"}, + {"sys/timeb.h$", "<sys/timeb.h>"}, + {"sys/timerfd.h$", "<sys/timerfd.h>"}, + {"sys/times.h$", "<sys/times.h>"}, + {"sys/timex.h$", "<sys/timex.h>"}, + {"sys/ttychars.h$", "<sys/ttychars.h>"}, + {"sys/ttydefaults.h$", "<sys/ttydefaults.h>"}, + {"sys/types.h$", "<sys/types.h>"}, + {"sys/ucontext.h$", "<sys/ucontext.h>"}, + {"sys/uio.h$", "<sys/uio.h>"}, + {"sys/un.h$", "<sys/un.h>"}, + {"sys/user.h$", "<sys/user.h>"}, + {"sys/ustat.h$", "<sys/ustat.h>"}, + {"sys/utsname.h$", "<sys/utsname.h>"}, + {"sys/vlimit.h$", "<sys/vlimit.h>"}, + {"sys/vm86.h$", "<sys/vm86.h>"}, + {"sys/vtimes.h$", "<sys/vtimes.h>"}, + {"sys/wait.h$", "<sys/wait.h>"}, + {"sys/xattr.h$", "<sys/xattr.h>"}, + {"bits/epoll.h$", "<sys/epoll.h>"}, + {"bits/eventfd.h$", "<sys/eventfd.h>"}, + {"bits/inotify.h$", "<sys/inotify.h>"}, + {"bits/ipc.h$", "<sys/ipc.h>"}, + {"bits/ipctypes.h$", "<sys/ipc.h>"}, + {"bits/mman-linux.h$", "<sys/mman.h>"}, + {"bits/mman.h$", "<sys/mman.h>"}, + {"bits/msq.h$", "<sys/msg.h>"}, + {"bits/resource.h$", "<sys/resource.h>"}, + {"bits/sem.h$", "<sys/sem.h>"}, + {"bits/shm.h$", "<sys/shm.h>"}, + {"bits/signalfd.h$", "<sys/signalfd.h>"}, + {"bits/statfs.h$", "<sys/statfs.h>"}, + {"bits/statvfs.h$", "<sys/statvfs.h>"}, + {"bits/timerfd.h$", "<sys/timerfd.h>"}, + {"bits/utsname.h$", "<sys/utsname.h>"}, + {"bits/auxv.h$", "<sys/auxv.h>"}, + {"bits/byteswap-16.h$", "<byteswap.h>"}, + {"bits/byteswap.h$", "<byteswap.h>"}, + {"bits/confname.h$", "<unistd.h>"}, + {"bits/dirent.h$", "<dirent.h>"}, + {"bits/dlfcn.h$", "<dlfcn.h>"}, + {"bits/elfclass.h$", "<link.h>"}, + {"bits/endian.h$", "<endian.h>"}, + {"bits/environments.h$", "<unistd.h>"}, + {"bits/fcntl-linux.h$", "<fcntl.h>"}, + {"bits/fcntl.h$", "<fcntl.h>"}, + {"bits/in.h$", "<netinet/in.h>"}, + {"bits/ioctl-types.h$", "<sys/ioctl.h>"}, + {"bits/ioctls.h$", "<sys/ioctl.h>"}, + {"bits/link.h$", "<link.h>"}, + {"bits/mqueue.h$", "<mqueue.h>"}, + {"bits/netdb.h$", "<netdb.h>"}, + {"bits/param.h$", "<sys/param.h>"}, + {"bits/poll.h$", "<sys/poll.h>"}, + {"bits/posix_opt.h$", "<bits/posix_opt.h>"}, + {"bits/pthreadtypes.h$", "<pthread.h>"}, + {"bits/sched.h$", "<sched.h>"}, + {"bits/select.h$", "<sys/select.h>"}, + {"bits/semaphore.h$", "<semaphore.h>"}, + {"bits/sigthread.h$", "<pthread.h>"}, + {"bits/sockaddr.h$", "<sys/socket.h>"}, + {"bits/socket.h$", "<sys/socket.h>"}, + {"bits/socket_type.h$", "<sys/socket.h>"}, + {"bits/stab.def$", "<stab.h>"}, + {"bits/stat.h$", "<sys/stat.h>"}, + {"bits/stropts.h$", "<stropts.h>"}, + {"bits/syscall.h$", "<sys/syscall.h>"}, + {"bits/syslog-path.h$", "<sys/syslog.h>"}, + {"bits/termios.h$", "<termios.h>"}, + {"bits/types.h$", "<sys/types.h>"}, + {"bits/typesizes.h$", "<sys/types.h>"}, + {"bits/uio.h$", "<sys/uio.h>"}, + {"bits/ustat.h$", "<sys/ustat.h>"}, + {"bits/utmp.h$", "<utmp.h>"}, + {"bits/utmpx.h$", "<utmpx.h>"}, + {"bits/waitflags.h$", "<sys/wait.h>"}, + {"bits/waitstatus.h$", "<sys/wait.h>"}, + {"bits/xtitypes.h$", "<stropts.h>"}, + }; + return &STLPostfixHeaderMap; +} + +} // namespace find_all_symbols +} // namespace clang diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.h b/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.h new file mode 100644 index 00000000000..49bc5f3037d --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.h @@ -0,0 +1,22 @@ +//===-- STLPostfixHeaderMap.h - hardcoded header map for STL ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_TOOL_STL_POSTFIX_HEADER_MAP_H +#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_TOOL_STL_POSTFIX_HEADER_MAP_H + +#include "HeaderMapCollector.h" + +namespace clang { +namespace find_all_symbols { + +const HeaderMapCollector::RegexHeaderMap *getSTLPostfixHeaderMap(); + +} // namespace find_all_symbols +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_TOOL_STL_POSTFIX_HEADER_MAP_H diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/SymbolInfo.cpp b/clang-tools-extra/clang-include-fixer/find-all-symbols/SymbolInfo.cpp new file mode 100644 index 00000000000..e5b4dba4b7a --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/SymbolInfo.cpp @@ -0,0 +1,136 @@ +//===-- SymbolInfo.cpp - Symbol Info ----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "SymbolInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" + +using llvm::yaml::MappingTraits; +using llvm::yaml::IO; +using llvm::yaml::Input; +using ContextType = clang::find_all_symbols::SymbolInfo::ContextType; +using clang::find_all_symbols::SymbolInfo; +using clang::find_all_symbols::SymbolAndSignals; +using SymbolKind = clang::find_all_symbols::SymbolInfo::SymbolKind; + +LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(SymbolAndSignals) +LLVM_YAML_IS_SEQUENCE_VECTOR(SymbolInfo::Context) + +namespace llvm { +namespace yaml { +template <> struct MappingTraits<SymbolAndSignals> { + static void mapping(IO &io, SymbolAndSignals &Symbol) { + io.mapRequired("Name", Symbol.Symbol.Name); + io.mapRequired("Contexts", Symbol.Symbol.Contexts); + io.mapRequired("FilePath", Symbol.Symbol.FilePath); + io.mapRequired("Type", Symbol.Symbol.Type); + io.mapRequired("Seen", Symbol.Signals.Seen); + io.mapRequired("Used", Symbol.Signals.Used); + } +}; + +template <> struct ScalarEnumerationTraits<ContextType> { + static void enumeration(IO &io, ContextType &value) { + io.enumCase(value, "Record", ContextType::Record); + io.enumCase(value, "Namespace", ContextType::Namespace); + io.enumCase(value, "EnumDecl", ContextType::EnumDecl); + } +}; + +template <> struct ScalarEnumerationTraits<SymbolKind> { + static void enumeration(IO &io, SymbolKind &value) { + io.enumCase(value, "Variable", SymbolKind::Variable); + io.enumCase(value, "Function", SymbolKind::Function); + io.enumCase(value, "Class", SymbolKind::Class); + io.enumCase(value, "TypedefName", SymbolKind::TypedefName); + io.enumCase(value, "EnumDecl", SymbolKind::EnumDecl); + io.enumCase(value, "EnumConstantDecl", SymbolKind::EnumConstantDecl); + io.enumCase(value, "Macro", SymbolKind::Macro); + io.enumCase(value, "Unknown", SymbolKind::Unknown); + } +}; + +template <> struct MappingTraits<SymbolInfo::Context> { + static void mapping(IO &io, SymbolInfo::Context &Context) { + io.mapRequired("ContextType", Context.first); + io.mapRequired("ContextName", Context.second); + } +}; + +} // namespace yaml +} // namespace llvm + +namespace clang { +namespace find_all_symbols { + +SymbolInfo::SymbolInfo(llvm::StringRef Name, SymbolKind Type, + llvm::StringRef FilePath, + const std::vector<Context> &Contexts) + : Name(Name), Type(Type), FilePath(FilePath), Contexts(Contexts) {} + +bool SymbolInfo::operator==(const SymbolInfo &Symbol) const { + return std::tie(Name, Type, FilePath, Contexts) == + std::tie(Symbol.Name, Symbol.Type, Symbol.FilePath, Symbol.Contexts); +} + +bool SymbolInfo::operator<(const SymbolInfo &Symbol) const { + return std::tie(Name, Type, FilePath, Contexts) < + std::tie(Symbol.Name, Symbol.Type, Symbol.FilePath, Symbol.Contexts); +} + +std::string SymbolInfo::getQualifiedName() const { + std::string QualifiedName = Name; + for (const auto &Context : Contexts) { + if (Context.first == ContextType::EnumDecl) + continue; + QualifiedName = Context.second + "::" + QualifiedName; + } + return QualifiedName; +} + +SymbolInfo::Signals &SymbolInfo::Signals::operator+=(const Signals &RHS) { + Seen += RHS.Seen; + Used += RHS.Used; + return *this; +} + +SymbolInfo::Signals SymbolInfo::Signals::operator+(const Signals &RHS) const { + Signals Result = *this; + Result += RHS; + return Result; +} + +bool SymbolInfo::Signals::operator==(const Signals &RHS) const { + return std::tie(Seen, Used) == std::tie(RHS.Seen, RHS.Used); +} + +bool SymbolAndSignals::operator==(const SymbolAndSignals& RHS) const { + return std::tie(Symbol, Signals) == std::tie(RHS.Symbol, RHS.Signals); +} + +bool WriteSymbolInfosToStream(llvm::raw_ostream &OS, + const SymbolInfo::SignalMap &Symbols) { + llvm::yaml::Output yout(OS); + for (const auto &Symbol : Symbols) { + SymbolAndSignals S{Symbol.first, Symbol.second}; + yout << S; + } + return true; +} + +std::vector<SymbolAndSignals> ReadSymbolInfosFromYAML(llvm::StringRef Yaml) { + std::vector<SymbolAndSignals> Symbols; + llvm::yaml::Input yin(Yaml); + yin >> Symbols; + return Symbols; +} + +} // namespace find_all_symbols +} // namespace clang diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/SymbolInfo.h b/clang-tools-extra/clang-include-fixer/find-all-symbols/SymbolInfo.h new file mode 100644 index 00000000000..6def1c70218 --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/SymbolInfo.h @@ -0,0 +1,142 @@ +//===-- SymbolInfo.h - Symbol Info ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FIND_ALL_SYMBOLS_SYMBOLINFO_H +#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FIND_ALL_SYMBOLS_SYMBOLINFO_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" +#include <set> +#include <string> +#include <vector> + +namespace clang { +namespace find_all_symbols { +/// \brief Describes a named symbol from a header. +/// Symbols with the same qualified name and type (e.g. function overloads) +/// that appear in the same header are represented by a single SymbolInfo. +/// +/// TODO: keep track of instances, e.g. overload locations and signatures. +class SymbolInfo { +public: + /// \brief The SymbolInfo Type. + enum class SymbolKind { + Function, + Class, + Variable, + TypedefName, + EnumDecl, + EnumConstantDecl, + Macro, + Unknown, + }; + + /// \brief The Context Type. + enum class ContextType { + Namespace, // Symbols declared in a namespace. + Record, // Symbols declared in a class. + EnumDecl, // Enum constants declared in a enum declaration. + }; + + /// \brief A pair of <ContextType, ContextName>. + typedef std::pair<ContextType, std::string> Context; + + // \brief Signals are signals gathered by observing how a symbol is used. + // These are used to rank results. + struct Signals { + Signals() {} + Signals(unsigned Seen, unsigned Used) : Seen(Seen), Used(Used) {} + + // Number of times this symbol was visible to a TU. + unsigned Seen = 0; + + // Number of times this symbol was referenced a TU's main file. + unsigned Used = 0; + + Signals &operator+=(const Signals &RHS); + Signals operator+(const Signals &RHS) const; + bool operator==(const Signals &RHS) const; + }; + + using SignalMap = std::map<SymbolInfo, Signals>; + + // The default constructor is required by YAML traits in + // LLVM_YAML_IS_DOCUMENT_LIST_VECTOR. + SymbolInfo() : Type(SymbolKind::Unknown) {} + + SymbolInfo(llvm::StringRef Name, SymbolKind Type, llvm::StringRef FilePath, + const std::vector<Context> &Contexts); + + void SetFilePath(llvm::StringRef Path) { FilePath = Path; } + + /// \brief Get symbol name. + llvm::StringRef getName() const { return Name; } + + /// \brief Get the fully-qualified symbol name. + std::string getQualifiedName() const; + + /// \brief Get symbol type. + SymbolKind getSymbolKind() const { return Type; } + + /// \brief Get a relative file path where symbol comes from. + llvm::StringRef getFilePath() const { return FilePath; } + + /// \brief Get symbol contexts. + const std::vector<SymbolInfo::Context> &getContexts() const { + return Contexts; + } + + bool operator<(const SymbolInfo &Symbol) const; + + bool operator==(const SymbolInfo &Symbol) const; + +private: + friend struct llvm::yaml::MappingTraits<struct SymbolAndSignals>; + + /// \brief Identifier name. + std::string Name; + + /// \brief Symbol type. + SymbolKind Type; + + /// \brief The file path where the symbol comes from. It's a relative file + /// path based on the build directory. + std::string FilePath; + + /// \brief Contains information about symbol contexts. Context information is + /// stored from the inner-most level to outer-most level. + /// + /// For example, if a symbol 'x' is declared as: + /// namespace na { namespace nb { class A { int x; } } } + /// The contexts would be { {RECORD, "A"}, {NAMESPACE, "nb"}, {NAMESPACE, + /// "na"} }. + /// The name of an anonymous namespace is "". + /// + /// If the symbol is declared in `TranslationUnitDecl`, it has no context. + std::vector<Context> Contexts; +}; + +struct SymbolAndSignals { + SymbolInfo Symbol; + SymbolInfo::Signals Signals; + bool operator==(const SymbolAndSignals& RHS) const; +}; + +/// \brief Write SymbolInfos to a stream (YAML format). +bool WriteSymbolInfosToStream(llvm::raw_ostream &OS, + const SymbolInfo::SignalMap &Symbols); + +/// \brief Read SymbolInfos from a YAML document. +std::vector<SymbolAndSignals> ReadSymbolInfosFromYAML(llvm::StringRef Yaml); + +} // namespace find_all_symbols +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FIND_ALL_SYMBOLS_SYMBOLINFO_H diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/SymbolReporter.h b/clang-tools-extra/clang-include-fixer/find-all-symbols/SymbolReporter.h new file mode 100644 index 00000000000..25e86219150 --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/SymbolReporter.h @@ -0,0 +1,29 @@ +//===--- SymbolReporter.h - Symbol Reporter ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_SYMBOL_REPORTER_H +#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_SYMBOL_REPORTER_H + +#include "SymbolInfo.h" + +namespace clang { +namespace find_all_symbols { + +/// \brief An interface for classes that collect symbols. +class SymbolReporter { +public: + virtual ~SymbolReporter() = default; + + virtual void reportSymbols(llvm::StringRef FileName, + const SymbolInfo::SignalMap &Symbols) = 0; +}; + +} // namespace find_all_symbols +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_SYMBOL_REPORTER_H diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/tool/CMakeLists.txt b/clang-tools-extra/clang-include-fixer/find-all-symbols/tool/CMakeLists.txt new file mode 100644 index 00000000000..64278ad1843 --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/tool/CMakeLists.txt @@ -0,0 +1,24 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) + +add_clang_executable(find-all-symbols + FindAllSymbolsMain.cpp + ) + +target_link_libraries(find-all-symbols + PRIVATE + clangAST + clangASTMatchers + clangBasic + clangFrontend + clangLex + clangSerialization + clangTooling + findAllSymbols + ) + +install(TARGETS find-all-symbols + RUNTIME DESTINATION bin) + +install(PROGRAMS run-find-all-symbols.py + DESTINATION share/clang + COMPONENT find-all-symbols) diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/tool/FindAllSymbolsMain.cpp b/clang-tools-extra/clang-include-fixer/find-all-symbols/tool/FindAllSymbolsMain.cpp new file mode 100644 index 00000000000..dbbe0738d03 --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/tool/FindAllSymbolsMain.cpp @@ -0,0 +1,151 @@ +//===-- FindAllSymbolsMain.cpp - find all symbols tool ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "FindAllSymbolsAction.h" +#include "STLPostfixHeaderMap.h" +#include "SymbolInfo.h" +#include "SymbolReporter.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/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/ThreadPool.h" +#include "llvm/Support/raw_ostream.h" +#include <map> +#include <mutex> +#include <set> +#include <string> +#include <system_error> +#include <vector> + +using namespace clang::tooling; +using namespace llvm; +using SymbolInfo = clang::find_all_symbols::SymbolInfo; + +// Apply a custom category to all command-line options so that they are the +// only ones displayed. +static cl::OptionCategory FindAllSymbolsCategory("find_all_symbols options"); + +// CommonOptionsParser declares HelpMessage with a description of the common +// command-line options related to the compilation database and input files. +// It's nice to have this help message in all tools. +static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); + +// A help message for this specific tool can be added afterwards. +static cl::extrahelp MoreHelp("\nMore help text..."); + +static cl::opt<std::string> OutputDir("output-dir", cl::desc(R"( +The output directory for saving the results.)"), + cl::init("."), + cl::cat(FindAllSymbolsCategory)); + +static cl::opt<std::string> MergeDir("merge-dir", cl::desc(R"( +The directory for merging symbols.)"), + cl::init(""), + cl::cat(FindAllSymbolsCategory)); +namespace clang { +namespace find_all_symbols { + +class YamlReporter : public SymbolReporter { +public: + void reportSymbols(StringRef FileName, + const SymbolInfo::SignalMap &Symbols) override { + int FD; + SmallString<128> ResultPath; + llvm::sys::fs::createUniqueFile( + OutputDir + "/" + llvm::sys::path::filename(FileName) + "-%%%%%%.yaml", + FD, ResultPath); + llvm::raw_fd_ostream OS(FD, /*shouldClose=*/true); + WriteSymbolInfosToStream(OS, Symbols); + } +}; + +bool Merge(llvm::StringRef MergeDir, llvm::StringRef OutputFile) { + std::error_code EC; + SymbolInfo::SignalMap Symbols; + std::mutex SymbolMutex; + auto AddSymbols = [&](ArrayRef<SymbolAndSignals> NewSymbols) { + // Synchronize set accesses. + std::unique_lock<std::mutex> LockGuard(SymbolMutex); + for (const auto &Symbol : NewSymbols) { + Symbols[Symbol.Symbol] += Symbol.Signals; + } + }; + + // Load all symbol files in MergeDir. + { + llvm::ThreadPool Pool; + for (llvm::sys::fs::directory_iterator Dir(MergeDir, EC), DirEnd; + Dir != DirEnd && !EC; Dir.increment(EC)) { + // Parse YAML files in parallel. + Pool.async( + [&AddSymbols](std::string Path) { + auto Buffer = llvm::MemoryBuffer::getFile(Path); + if (!Buffer) { + llvm::errs() << "Can't open " << Path << "\n"; + return; + } + std::vector<SymbolAndSignals> Symbols = + ReadSymbolInfosFromYAML(Buffer.get()->getBuffer()); + for (auto &Symbol : Symbols) { + // Only count one occurrence per file, to avoid spam. + Symbol.Signals.Seen = std::min(Symbol.Signals.Seen, 1u); + Symbol.Signals.Used = std::min(Symbol.Signals.Used, 1u); + } + // FIXME: Merge without creating such a heavy contention point. + AddSymbols(Symbols); + }, + Dir->path()); + } + } + + llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_None); + if (EC) { + llvm::errs() << "Can't open '" << OutputFile << "': " << EC.message() + << '\n'; + return false; + } + WriteSymbolInfosToStream(OS, Symbols); + return true; +} + +} // namespace clang +} // namespace find_all_symbols + +int main(int argc, const char **argv) { + CommonOptionsParser OptionsParser(argc, argv, FindAllSymbolsCategory); + ClangTool Tool(OptionsParser.getCompilations(), + OptionsParser.getSourcePathList()); + + std::vector<std::string> sources = OptionsParser.getSourcePathList(); + if (sources.empty()) { + llvm::errs() << "Must specify at least one one source file.\n"; + return 1; + } + if (!MergeDir.empty()) { + clang::find_all_symbols::Merge(MergeDir, sources[0]); + return 0; + } + + clang::find_all_symbols::YamlReporter Reporter; + + auto Factory = + llvm::make_unique<clang::find_all_symbols::FindAllSymbolsActionFactory>( + &Reporter, clang::find_all_symbols::getSTLPostfixHeaderMap()); + return Tool.run(Factory.get()); +} diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/tool/run-find-all-symbols.py b/clang-tools-extra/clang-include-fixer/find-all-symbols/tool/run-find-all-symbols.py new file mode 100755 index 00000000000..5e9dde72343 --- /dev/null +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/tool/run-find-all-symbols.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python +# +#=- run-find-all-symbols.py - Parallel find-all-symbols runner -*- python -*-=# +# +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +#===------------------------------------------------------------------------===# + +""" +Parallel find-all-symbols runner +================================ + +Runs find-all-symbols over all files in a compilation database. + +Example invocations. +- Run find-all-symbols on all files in the current working directory. + run-find-all-symbols.py <source-file> + +Compilation database setup: +http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html +""" + +import argparse +import json +import multiprocessing +import os +import Queue +import shutil +import subprocess +import sys +import tempfile +import threading + + +def find_compilation_database(path): + """Adjusts the directory until a compilation database is found.""" + result = './' + while not os.path.isfile(os.path.join(result, path)): + if os.path.realpath(result) == '/': + print 'Error: could not find compilation database.' + sys.exit(1) + result += '../' + return os.path.realpath(result) + + +def MergeSymbols(directory, args): + """Merge all symbol files (yaml) in a given directaory into a single file.""" + invocation = [args.binary, '-merge-dir='+directory, args.saving_path] + subprocess.call(invocation) + print 'Merge is finished. Saving results in ' + args.saving_path + + +def run_find_all_symbols(args, tmpdir, build_path, queue): + """Takes filenames out of queue and runs find-all-symbols on them.""" + while True: + name = queue.get() + invocation = [args.binary, name, '-output-dir='+tmpdir, '-p='+build_path] + sys.stdout.write(' '.join(invocation) + '\n') + subprocess.call(invocation) + queue.task_done() + + +def main(): + parser = argparse.ArgumentParser(description='Runs find-all-symbols over all' + 'files in a compilation database.') + parser.add_argument('-binary', metavar='PATH', + default='./bin/find-all-symbols', + help='path to find-all-symbols binary') + parser.add_argument('-j', type=int, default=0, + help='number of instances to be run in parallel.') + parser.add_argument('-p', dest='build_path', + help='path used to read a compilation database.') + parser.add_argument('-saving-path', default='./find_all_symbols_db.yaml', + help='result saving path') + args = parser.parse_args() + + db_path = 'compile_commands.json' + + if args.build_path is not None: + build_path = args.build_path + else: + build_path = find_compilation_database(db_path) + + tmpdir = tempfile.mkdtemp() + + # Load the database and extract all files. + database = json.load(open(os.path.join(build_path, db_path))) + files = [entry['file'] for entry in database] + + max_task = args.j + if max_task == 0: + max_task = multiprocessing.cpu_count() + + try: + # Spin up a bunch of tidy-launching threads. + queue = Queue.Queue(max_task) + for _ in range(max_task): + t = threading.Thread(target=run_find_all_symbols, + args=(args, tmpdir, build_path, queue)) + t.daemon = True + t.start() + + # Fill the queue with files. + for name in files: + queue.put(name) + + # Wait for all threads to be done. + queue.join() + + MergeSymbols(tmpdir, args) + + + except KeyboardInterrupt: + # This is a sad hack. Unfortunately subprocess goes + # bonkers with ctrl-c and we start forking merrily. + print '\nCtrl-C detected, goodbye.' + os.kill(0, 9) + + +if __name__ == '__main__': + main() |

