[clang-tools-extra] r356897 - Rename directory housing clang-include-fixer to be eponymous
Nico Weber via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 25 07:09:11 PDT 2019
Author: nico
Date: Mon Mar 25 07:09:10 2019
New Revision: 356897
URL: http://llvm.org/viewvc/llvm-project?rev=356897&view=rev
Log:
Rename directory housing clang-include-fixer to be eponymous
Makes the name of this directory consistent with the names of the other
directories in clang-tools-extra.
Similar to r356254. No intended behavior change.
Differential Revision: https://reviews.llvm.org/D59750
Added:
clang-tools-extra/trunk/clang-include-fixer/
clang-tools-extra/trunk/clang-include-fixer/CMakeLists.txt
clang-tools-extra/trunk/clang-include-fixer/FuzzySymbolIndex.cpp
clang-tools-extra/trunk/clang-include-fixer/FuzzySymbolIndex.h
clang-tools-extra/trunk/clang-include-fixer/InMemorySymbolIndex.cpp
clang-tools-extra/trunk/clang-include-fixer/InMemorySymbolIndex.h
clang-tools-extra/trunk/clang-include-fixer/IncludeFixer.cpp
clang-tools-extra/trunk/clang-include-fixer/IncludeFixer.h
clang-tools-extra/trunk/clang-include-fixer/IncludeFixerContext.cpp
clang-tools-extra/trunk/clang-include-fixer/IncludeFixerContext.h
clang-tools-extra/trunk/clang-include-fixer/SymbolIndex.h
clang-tools-extra/trunk/clang-include-fixer/SymbolIndexManager.cpp
clang-tools-extra/trunk/clang-include-fixer/SymbolIndexManager.h
clang-tools-extra/trunk/clang-include-fixer/YamlSymbolIndex.cpp
clang-tools-extra/trunk/clang-include-fixer/YamlSymbolIndex.h
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/CMakeLists.txt
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllMacros.cpp
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllMacros.h
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbols.h
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbolsAction.cpp
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbolsAction.h
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/HeaderMapCollector.cpp
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/HeaderMapCollector.h
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PathConfig.cpp
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PathConfig.h
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PragmaCommentHandler.cpp
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PragmaCommentHandler.h
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.h
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/SymbolInfo.cpp
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/SymbolInfo.h
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/SymbolReporter.h
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/tool/
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/tool/CMakeLists.txt
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/tool/FindAllSymbolsMain.cpp
clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/tool/run-find-all-symbols.py (with props)
clang-tools-extra/trunk/clang-include-fixer/plugin/
clang-tools-extra/trunk/clang-include-fixer/plugin/CMakeLists.txt
clang-tools-extra/trunk/clang-include-fixer/plugin/IncludeFixerPlugin.cpp
clang-tools-extra/trunk/clang-include-fixer/tool/
clang-tools-extra/trunk/clang-include-fixer/tool/CMakeLists.txt
clang-tools-extra/trunk/clang-include-fixer/tool/ClangIncludeFixer.cpp
clang-tools-extra/trunk/clang-include-fixer/tool/clang-include-fixer-test.el
clang-tools-extra/trunk/clang-include-fixer/tool/clang-include-fixer.el
clang-tools-extra/trunk/clang-include-fixer/tool/clang-include-fixer.py
clang-tools-extra/trunk/docs/clang-include-fixer.rst
clang-tools-extra/trunk/test/clang-include-fixer/
clang-tools-extra/trunk/test/clang-include-fixer/Inputs/
clang-tools-extra/trunk/test/clang-include-fixer/Inputs/database_template.json
clang-tools-extra/trunk/test/clang-include-fixer/Inputs/fake_yaml_db.yaml
clang-tools-extra/trunk/test/clang-include-fixer/Inputs/merge/
clang-tools-extra/trunk/test/clang-include-fixer/Inputs/merge/a.yaml
clang-tools-extra/trunk/test/clang-include-fixer/Inputs/merge/b.yaml
clang-tools-extra/trunk/test/clang-include-fixer/commandline_options.cpp
clang-tools-extra/trunk/test/clang-include-fixer/exit_on_fatal.cpp
clang-tools-extra/trunk/test/clang-include-fixer/fixeddb.cpp
clang-tools-extra/trunk/test/clang-include-fixer/include_path.cpp
clang-tools-extra/trunk/test/clang-include-fixer/merge.test
clang-tools-extra/trunk/test/clang-include-fixer/multiple_fixes.cpp
clang-tools-extra/trunk/test/clang-include-fixer/prefix_variable.cpp
clang-tools-extra/trunk/test/clang-include-fixer/query_symbol.cpp
clang-tools-extra/trunk/test/clang-include-fixer/ranking.cpp
clang-tools-extra/trunk/test/clang-include-fixer/yaml_fuzzy.cpp
clang-tools-extra/trunk/test/clang-include-fixer/yamldb.cpp
clang-tools-extra/trunk/test/clang-include-fixer/yamldb_autodetect.cpp
clang-tools-extra/trunk/unittests/clang-include-fixer/
clang-tools-extra/trunk/unittests/clang-include-fixer/CMakeLists.txt
clang-tools-extra/trunk/unittests/clang-include-fixer/FuzzySymbolIndexTests.cpp
clang-tools-extra/trunk/unittests/clang-include-fixer/IncludeFixerTest.cpp
clang-tools-extra/trunk/unittests/clang-include-fixer/find-all-symbols/
clang-tools-extra/trunk/unittests/clang-include-fixer/find-all-symbols/CMakeLists.txt
clang-tools-extra/trunk/unittests/clang-include-fixer/find-all-symbols/FindAllSymbolsTests.cpp
Removed:
clang-tools-extra/trunk/docs/include-fixer.rst
clang-tools-extra/trunk/include-fixer/
clang-tools-extra/trunk/test/include-fixer/
clang-tools-extra/trunk/unittests/include-fixer/
Modified:
clang-tools-extra/trunk/CMakeLists.txt
clang-tools-extra/trunk/clang-move/Move.cpp
clang-tools-extra/trunk/clang-tidy/add_new_check.py
clang-tools-extra/trunk/docs/ReleaseNotes.rst
clang-tools-extra/trunk/docs/doxygen.cfg.in
clang-tools-extra/trunk/docs/index.rst
clang-tools-extra/trunk/unittests/CMakeLists.txt
Modified: clang-tools-extra/trunk/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/CMakeLists.txt?rev=356897&r1=356896&r2=356897&view=diff
==============================================================================
--- clang-tools-extra/trunk/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/CMakeLists.txt Mon Mar 25 07:09:10 2019
@@ -11,10 +11,10 @@ add_subdirectory(clang-tidy-vs)
add_subdirectory(clang-change-namespace)
add_subdirectory(clang-doc)
-add_subdirectory(clang-query)
+add_subdirectory(clang-include-fixer)
add_subdirectory(clang-move)
+add_subdirectory(clang-query)
add_subdirectory(clangd)
-add_subdirectory(include-fixer)
add_subdirectory(pp-trace)
add_subdirectory(tool-template)
Added: clang-tools-extra/trunk/clang-include-fixer/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/CMakeLists.txt?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/CMakeLists.txt (added)
+++ clang-tools-extra/trunk/clang-include-fixer/CMakeLists.txt Mon Mar 25 07:09:10 2019
@@ -0,0 +1,29 @@
+set(LLVM_LINK_COMPONENTS
+ support
+ )
+
+add_clang_library(clangIncludeFixer
+ IncludeFixer.cpp
+ IncludeFixerContext.cpp
+ InMemorySymbolIndex.cpp
+ FuzzySymbolIndex.cpp
+ SymbolIndexManager.cpp
+ YamlSymbolIndex.cpp
+
+ LINK_LIBS
+ clangAST
+ clangBasic
+ clangFormat
+ clangFrontend
+ clangLex
+ clangParse
+ clangSema
+ clangSerialization
+ clangTooling
+ clangToolingCore
+ findAllSymbols
+ )
+
+add_subdirectory(plugin)
+add_subdirectory(tool)
+add_subdirectory(find-all-symbols)
Added: clang-tools-extra/trunk/clang-include-fixer/FuzzySymbolIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/FuzzySymbolIndex.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/FuzzySymbolIndex.cpp (added)
+++ clang-tools-extra/trunk/clang-include-fixer/FuzzySymbolIndex.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,142 @@
+//===--- FuzzySymbolIndex.cpp - Lookup symbols for autocomplete -*- 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 "FuzzySymbolIndex.h"
+#include "llvm/Support/Regex.h"
+
+using clang::find_all_symbols::SymbolAndSignals;
+using llvm::StringRef;
+
+namespace clang {
+namespace include_fixer {
+namespace {
+
+class MemSymbolIndex : public FuzzySymbolIndex {
+public:
+ MemSymbolIndex(std::vector<SymbolAndSignals> Symbols) {
+ for (auto &Symbol : Symbols) {
+ auto Tokens = tokenize(Symbol.Symbol.getName());
+ this->Symbols.emplace_back(
+ StringRef(llvm::join(Tokens.begin(), Tokens.end(), " ")),
+ std::move(Symbol));
+ }
+ }
+
+ std::vector<SymbolAndSignals> search(StringRef Query) override {
+ auto Tokens = tokenize(Query);
+ llvm::Regex Pattern("^" + queryRegexp(Tokens));
+ std::vector<SymbolAndSignals> Results;
+ for (const Entry &E : Symbols)
+ if (Pattern.match(E.first))
+ Results.push_back(E.second);
+ return Results;
+ }
+
+private:
+ using Entry = std::pair<llvm::SmallString<32>, SymbolAndSignals>;
+ std::vector<Entry> Symbols;
+};
+
+// Helpers for tokenize state machine.
+enum TokenizeState {
+ EMPTY, // No pending characters.
+ ONE_BIG, // Read one uppercase letter, could be WORD or Word.
+ BIG_WORD, // Reading an uppercase WORD.
+ SMALL_WORD, // Reading a lowercase word.
+ NUMBER // Reading a number.
+};
+
+enum CharType { UPPER, LOWER, DIGIT, MISC };
+CharType classify(char c) {
+ if (isupper(c))
+ return UPPER;
+ if (islower(c))
+ return LOWER;
+ if (isdigit(c))
+ return DIGIT;
+ return MISC;
+}
+
+} // namespace
+
+std::vector<std::string> FuzzySymbolIndex::tokenize(StringRef Text) {
+ std::vector<std::string> Result;
+ // State describes the treatment of text from Start to I.
+ // Once text is Flush()ed into Result, we're done with it and advance Start.
+ TokenizeState State = EMPTY;
+ size_t Start = 0;
+ auto Flush = [&](size_t End) {
+ if (State != EMPTY) {
+ Result.push_back(Text.substr(Start, End - Start).lower());
+ State = EMPTY;
+ }
+ Start = End;
+ };
+ for (size_t I = 0; I < Text.size(); ++I) {
+ CharType Type = classify(Text[I]);
+ if (Type == MISC)
+ Flush(I);
+ else if (Type == LOWER)
+ switch (State) {
+ case BIG_WORD:
+ Flush(I - 1); // FOOBar: first token is FOO, not FOOB.
+ LLVM_FALLTHROUGH;
+ case ONE_BIG:
+ State = SMALL_WORD;
+ LLVM_FALLTHROUGH;
+ case SMALL_WORD:
+ break;
+ default:
+ Flush(I);
+ State = SMALL_WORD;
+ }
+ else if (Type == UPPER)
+ switch (State) {
+ case ONE_BIG:
+ State = BIG_WORD;
+ LLVM_FALLTHROUGH;
+ case BIG_WORD:
+ break;
+ default:
+ Flush(I);
+ State = ONE_BIG;
+ }
+ else if (Type == DIGIT && State != NUMBER) {
+ Flush(I);
+ State = NUMBER;
+ }
+ }
+ Flush(Text.size());
+ return Result;
+}
+
+std::string
+FuzzySymbolIndex::queryRegexp(const std::vector<std::string> &Tokens) {
+ std::string Result;
+ for (size_t I = 0; I < Tokens.size(); ++I) {
+ if (I)
+ Result.append("[[:alnum:]]* ");
+ for (size_t J = 0; J < Tokens[I].size(); ++J) {
+ if (J)
+ Result.append("([[:alnum:]]* )?");
+ Result.push_back(Tokens[I][J]);
+ }
+ }
+ return Result;
+}
+
+llvm::Expected<std::unique_ptr<FuzzySymbolIndex>>
+FuzzySymbolIndex::createFromYAML(StringRef FilePath) {
+ auto Buffer = llvm::MemoryBuffer::getFile(FilePath);
+ if (!Buffer)
+ return llvm::errorCodeToError(Buffer.getError());
+ return llvm::make_unique<MemSymbolIndex>(
+ find_all_symbols::ReadSymbolInfosFromYAML(Buffer.get()->getBuffer()));
+}
+
+} // namespace include_fixer
+} // namespace clang
Added: clang-tools-extra/trunk/clang-include-fixer/FuzzySymbolIndex.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/FuzzySymbolIndex.h?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/FuzzySymbolIndex.h (added)
+++ clang-tools-extra/trunk/clang-include-fixer/FuzzySymbolIndex.h Mon Mar 25 07:09:10 2019
@@ -0,0 +1,54 @@
+//===--- FuzzySymbolIndex.h - Lookup symbols for autocomplete ---*- 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_FUZZY_SYMBOL_INDEX_H
+#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FUZZY_SYMBOL_INDEX_H
+
+#include "SymbolIndex.h"
+#include "find-all-symbols/SymbolInfo.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace include_fixer {
+
+// A FuzzySymbolIndex retrieves top-level symbols matching a query string.
+//
+// It refines the contract of SymbolIndex::search to do fuzzy matching:
+// - symbol names are tokenized: "unique ptr", "string ref".
+// - query must match prefixes of symbol tokens: [upt]
+// - if the query has multiple tokens, splits must match: [StR], not [STr].
+// Helpers for tokenization and regex matching are provided.
+//
+// Implementations may choose to truncate results, refuse short queries, etc.
+class FuzzySymbolIndex : public SymbolIndex {
+public:
+ // Loads the specified clang-include-fixer database and returns an index serving it.
+ static llvm::Expected<std::unique_ptr<FuzzySymbolIndex>>
+ createFromYAML(llvm::StringRef File);
+
+ // Helpers for implementing indexes:
+
+ // Transforms a symbol name or query into a sequence of tokens.
+ // - URLHandlerCallback --> [url, handler, callback]
+ // - snake_case11 --> [snake, case, 11]
+ // - _WTF$ --> [wtf]
+ static std::vector<std::string> tokenize(llvm::StringRef Text);
+
+ // Transforms query tokens into an unanchored regexp to match symbol tokens.
+ // - [fe f] --> /f(\w* )?e\w* f/, matches [fee fie foe].
+ static std::string queryRegexp(const std::vector<std::string> &Tokens);
+};
+
+} // namespace include_fixer
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FUZZY_SYMBOL_INDEX_H
Added: clang-tools-extra/trunk/clang-include-fixer/InMemorySymbolIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/InMemorySymbolIndex.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/InMemorySymbolIndex.cpp (added)
+++ clang-tools-extra/trunk/clang-include-fixer/InMemorySymbolIndex.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,31 @@
+//===-- InMemorySymbolIndex.cpp--------------------------------------------===//
+//
+// 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 "InMemorySymbolIndex.h"
+
+using clang::find_all_symbols::SymbolAndSignals;
+
+namespace clang {
+namespace include_fixer {
+
+InMemorySymbolIndex::InMemorySymbolIndex(
+ const std::vector<SymbolAndSignals> &Symbols) {
+ for (const auto &Symbol : Symbols)
+ LookupTable[Symbol.Symbol.getName()].push_back(Symbol);
+}
+
+std::vector<SymbolAndSignals>
+InMemorySymbolIndex::search(llvm::StringRef Identifier) {
+ auto I = LookupTable.find(Identifier);
+ if (I != LookupTable.end())
+ return I->second;
+ return {};
+}
+
+} // namespace include_fixer
+} // namespace clang
Added: clang-tools-extra/trunk/clang-include-fixer/InMemorySymbolIndex.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/InMemorySymbolIndex.h?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/InMemorySymbolIndex.h (added)
+++ clang-tools-extra/trunk/clang-include-fixer/InMemorySymbolIndex.h Mon Mar 25 07:09:10 2019
@@ -0,0 +1,37 @@
+//===-- InMemorySymbolIndex.h -----------------------------------*- 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_INMEMORYSYMBOLINDEX_H
+#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INMEMORYSYMBOLINDEX_H
+
+#include "SymbolIndex.h"
+#include <map>
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace include_fixer {
+
+/// Xref database with fixed content.
+class InMemorySymbolIndex : public SymbolIndex {
+public:
+ InMemorySymbolIndex(
+ const std::vector<find_all_symbols::SymbolAndSignals> &Symbols);
+
+ std::vector<find_all_symbols::SymbolAndSignals>
+ search(llvm::StringRef Identifier) override;
+
+private:
+ std::map<std::string, std::vector<find_all_symbols::SymbolAndSignals>>
+ LookupTable;
+};
+
+} // namespace include_fixer
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INMEMORYSYMBOLINDEX_H
Added: clang-tools-extra/trunk/clang-include-fixer/IncludeFixer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/IncludeFixer.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/IncludeFixer.cpp (added)
+++ clang-tools-extra/trunk/clang-include-fixer/IncludeFixer.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,444 @@
+//===-- IncludeFixer.cpp - Include inserter based on sema callbacks -------===//
+//
+// 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 "IncludeFixer.h"
+#include "clang/Format/Format.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/ParseAST.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+#define DEBUG_TYPE "clang-include-fixer"
+
+using namespace clang;
+
+namespace clang {
+namespace include_fixer {
+namespace {
+/// Manages the parse, gathers include suggestions.
+class Action : public clang::ASTFrontendAction {
+public:
+ explicit Action(SymbolIndexManager &SymbolIndexMgr, bool MinimizeIncludePaths)
+ : SemaSource(SymbolIndexMgr, MinimizeIncludePaths,
+ /*GenerateDiagnostics=*/false) {}
+
+ std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(clang::CompilerInstance &Compiler,
+ StringRef InFile) override {
+ SemaSource.setFilePath(InFile);
+ return llvm::make_unique<clang::ASTConsumer>();
+ }
+
+ void ExecuteAction() override {
+ clang::CompilerInstance *Compiler = &getCompilerInstance();
+ assert(!Compiler->hasSema() && "CI already has Sema");
+
+ // Set up our hooks into sema and parse the AST.
+ if (hasCodeCompletionSupport() &&
+ !Compiler->getFrontendOpts().CodeCompletionAt.FileName.empty())
+ Compiler->createCodeCompletionConsumer();
+
+ clang::CodeCompleteConsumer *CompletionConsumer = nullptr;
+ if (Compiler->hasCodeCompletionConsumer())
+ CompletionConsumer = &Compiler->getCodeCompletionConsumer();
+
+ Compiler->createSema(getTranslationUnitKind(), CompletionConsumer);
+ SemaSource.setCompilerInstance(Compiler);
+ Compiler->getSema().addExternalSource(&SemaSource);
+
+ clang::ParseAST(Compiler->getSema(), Compiler->getFrontendOpts().ShowStats,
+ Compiler->getFrontendOpts().SkipFunctionBodies);
+ }
+
+ IncludeFixerContext
+ getIncludeFixerContext(const clang::SourceManager &SourceManager,
+ clang::HeaderSearch &HeaderSearch) const {
+ return SemaSource.getIncludeFixerContext(SourceManager, HeaderSearch,
+ SemaSource.getMatchedSymbols());
+ }
+
+private:
+ IncludeFixerSemaSource SemaSource;
+};
+
+} // namespace
+
+IncludeFixerActionFactory::IncludeFixerActionFactory(
+ SymbolIndexManager &SymbolIndexMgr,
+ std::vector<IncludeFixerContext> &Contexts, StringRef StyleName,
+ bool MinimizeIncludePaths)
+ : SymbolIndexMgr(SymbolIndexMgr), Contexts(Contexts),
+ MinimizeIncludePaths(MinimizeIncludePaths) {}
+
+IncludeFixerActionFactory::~IncludeFixerActionFactory() = default;
+
+bool IncludeFixerActionFactory::runInvocation(
+ std::shared_ptr<clang::CompilerInvocation> Invocation,
+ clang::FileManager *Files,
+ std::shared_ptr<clang::PCHContainerOperations> PCHContainerOps,
+ clang::DiagnosticConsumer *Diagnostics) {
+ assert(Invocation->getFrontendOpts().Inputs.size() == 1);
+
+ // Set up Clang.
+ clang::CompilerInstance Compiler(PCHContainerOps);
+ Compiler.setInvocation(std::move(Invocation));
+ Compiler.setFileManager(Files);
+
+ // Create the compiler's actual diagnostics engine. We want to drop all
+ // diagnostics here.
+ Compiler.createDiagnostics(new clang::IgnoringDiagConsumer,
+ /*ShouldOwnClient=*/true);
+ Compiler.createSourceManager(*Files);
+
+ // We abort on fatal errors so don't let a large number of errors become
+ // fatal. A missing #include can cause thousands of errors.
+ Compiler.getDiagnostics().setErrorLimit(0);
+
+ // Run the parser, gather missing includes.
+ auto ScopedToolAction =
+ llvm::make_unique<Action>(SymbolIndexMgr, MinimizeIncludePaths);
+ Compiler.ExecuteAction(*ScopedToolAction);
+
+ Contexts.push_back(ScopedToolAction->getIncludeFixerContext(
+ Compiler.getSourceManager(),
+ Compiler.getPreprocessor().getHeaderSearchInfo()));
+
+ // Technically this should only return true if we're sure that we have a
+ // parseable file. We don't know that though. Only inform users of fatal
+ // errors.
+ return !Compiler.getDiagnostics().hasFatalErrorOccurred();
+}
+
+static bool addDiagnosticsForContext(TypoCorrection &Correction,
+ const IncludeFixerContext &Context,
+ StringRef Code, SourceLocation StartOfFile,
+ ASTContext &Ctx) {
+ auto Reps = createIncludeFixerReplacements(
+ Code, Context, format::getLLVMStyle(), /*AddQualifiers=*/false);
+ if (!Reps || Reps->size() != 1)
+ return false;
+
+ unsigned DiagID = Ctx.getDiagnostics().getCustomDiagID(
+ DiagnosticsEngine::Note, "Add '#include %0' to provide the missing "
+ "declaration [clang-include-fixer]");
+
+ // FIXME: Currently we only generate a diagnostic for the first header. Give
+ // the user choices.
+ const tooling::Replacement &Placed = *Reps->begin();
+
+ auto Begin = StartOfFile.getLocWithOffset(Placed.getOffset());
+ auto End = Begin.getLocWithOffset(std::max(0, (int)Placed.getLength() - 1));
+ PartialDiagnostic PD(DiagID, Ctx.getDiagAllocator());
+ PD << Context.getHeaderInfos().front().Header
+ << FixItHint::CreateReplacement(CharSourceRange::getCharRange(Begin, End),
+ Placed.getReplacementText());
+ Correction.addExtraDiagnostic(std::move(PD));
+ return true;
+}
+
+/// Callback for incomplete types. If we encounter a forward declaration we
+/// have the fully qualified name ready. Just query that.
+bool IncludeFixerSemaSource::MaybeDiagnoseMissingCompleteType(
+ clang::SourceLocation Loc, clang::QualType T) {
+ // Ignore spurious callbacks from SFINAE contexts.
+ if (CI->getSema().isSFINAEContext())
+ return false;
+
+ clang::ASTContext &context = CI->getASTContext();
+ std::string QueryString = QualType(T->getUnqualifiedDesugaredType(), 0)
+ .getAsString(context.getPrintingPolicy());
+ LLVM_DEBUG(llvm::dbgs() << "Query missing complete type '" << QueryString
+ << "'");
+ // Pass an empty range here since we don't add qualifier in this case.
+ std::vector<find_all_symbols::SymbolInfo> MatchedSymbols =
+ query(QueryString, "", tooling::Range());
+
+ if (!MatchedSymbols.empty() && GenerateDiagnostics) {
+ TypoCorrection Correction;
+ FileID FID = CI->getSourceManager().getFileID(Loc);
+ StringRef Code = CI->getSourceManager().getBufferData(FID);
+ SourceLocation StartOfFile =
+ CI->getSourceManager().getLocForStartOfFile(FID);
+ addDiagnosticsForContext(
+ Correction,
+ getIncludeFixerContext(CI->getSourceManager(),
+ CI->getPreprocessor().getHeaderSearchInfo(),
+ MatchedSymbols),
+ Code, StartOfFile, CI->getASTContext());
+ for (const PartialDiagnostic &PD : Correction.getExtraDiagnostics())
+ CI->getSema().Diag(Loc, PD);
+ }
+ return true;
+}
+
+/// Callback for unknown identifiers. Try to piece together as much
+/// qualification as we can get and do a query.
+clang::TypoCorrection IncludeFixerSemaSource::CorrectTypo(
+ const DeclarationNameInfo &Typo, int LookupKind, Scope *S, CXXScopeSpec *SS,
+ CorrectionCandidateCallback &CCC, DeclContext *MemberContext,
+ bool EnteringContext, const ObjCObjectPointerType *OPT) {
+ // Ignore spurious callbacks from SFINAE contexts.
+ if (CI->getSema().isSFINAEContext())
+ return clang::TypoCorrection();
+
+ // We currently ignore the unidentified symbol which is not from the
+ // main file.
+ //
+ // However, this is not always true due to templates in a non-self contained
+ // header, consider the case:
+ //
+ // // header.h
+ // template <typename T>
+ // class Foo {
+ // T t;
+ // };
+ //
+ // // test.cc
+ // // We need to add <bar.h> in test.cc instead of header.h.
+ // class Bar;
+ // Foo<Bar> foo;
+ //
+ // FIXME: Add the missing header to the header file where the symbol comes
+ // from.
+ if (!CI->getSourceManager().isWrittenInMainFile(Typo.getLoc()))
+ return clang::TypoCorrection();
+
+ std::string TypoScopeString;
+ if (S) {
+ // FIXME: Currently we only use namespace contexts. Use other context
+ // types for query.
+ for (const auto *Context = S->getEntity(); Context;
+ Context = Context->getParent()) {
+ if (const auto *ND = dyn_cast<NamespaceDecl>(Context)) {
+ if (!ND->getName().empty())
+ TypoScopeString = ND->getNameAsString() + "::" + TypoScopeString;
+ }
+ }
+ }
+
+ auto ExtendNestedNameSpecifier = [this](CharSourceRange Range) {
+ StringRef Source =
+ Lexer::getSourceText(Range, CI->getSourceManager(), CI->getLangOpts());
+
+ // Skip forward until we find a character that's neither identifier nor
+ // colon. This is a bit of a hack around the fact that we will only get a
+ // single callback for a long nested name if a part of the beginning is
+ // unknown. For example:
+ //
+ // llvm::sys::path::parent_path(...)
+ // ^~~~ ^~~
+ // known
+ // ^~~~
+ // unknown, last callback
+ // ^~~~~~~~~~~
+ // no callback
+ //
+ // With the extension we get the full nested name specifier including
+ // parent_path.
+ // FIXME: Don't rely on source text.
+ const char *End = Source.end();
+ while (isIdentifierBody(*End) || *End == ':')
+ ++End;
+
+ return std::string(Source.begin(), End);
+ };
+
+ /// If we have a scope specification, use that to get more precise results.
+ std::string QueryString;
+ tooling::Range SymbolRange;
+ const auto &SM = CI->getSourceManager();
+ auto CreateToolingRange = [&QueryString, &SM](SourceLocation BeginLoc) {
+ return tooling::Range(SM.getDecomposedLoc(BeginLoc).second,
+ QueryString.size());
+ };
+ if (SS && SS->getRange().isValid()) {
+ auto Range = CharSourceRange::getTokenRange(SS->getRange().getBegin(),
+ Typo.getLoc());
+
+ QueryString = ExtendNestedNameSpecifier(Range);
+ SymbolRange = CreateToolingRange(Range.getBegin());
+ } else if (Typo.getName().isIdentifier() && !Typo.getLoc().isMacroID()) {
+ auto Range =
+ CharSourceRange::getTokenRange(Typo.getBeginLoc(), Typo.getEndLoc());
+
+ QueryString = ExtendNestedNameSpecifier(Range);
+ SymbolRange = CreateToolingRange(Range.getBegin());
+ } else {
+ QueryString = Typo.getAsString();
+ SymbolRange = CreateToolingRange(Typo.getLoc());
+ }
+
+ LLVM_DEBUG(llvm::dbgs() << "TypoScopeQualifiers: " << TypoScopeString
+ << "\n");
+ std::vector<find_all_symbols::SymbolInfo> MatchedSymbols =
+ query(QueryString, TypoScopeString, SymbolRange);
+
+ if (!MatchedSymbols.empty() && GenerateDiagnostics) {
+ TypoCorrection Correction(Typo.getName());
+ Correction.setCorrectionRange(SS, Typo);
+ FileID FID = SM.getFileID(Typo.getLoc());
+ StringRef Code = SM.getBufferData(FID);
+ SourceLocation StartOfFile = SM.getLocForStartOfFile(FID);
+ if (addDiagnosticsForContext(
+ Correction, getIncludeFixerContext(
+ SM, CI->getPreprocessor().getHeaderSearchInfo(),
+ MatchedSymbols),
+ Code, StartOfFile, CI->getASTContext()))
+ return Correction;
+ }
+ return TypoCorrection();
+}
+
+/// Get the minimal include for a given path.
+std::string IncludeFixerSemaSource::minimizeInclude(
+ StringRef Include, const clang::SourceManager &SourceManager,
+ clang::HeaderSearch &HeaderSearch) const {
+ if (!MinimizeIncludePaths)
+ return Include;
+
+ // Get the FileEntry for the include.
+ StringRef StrippedInclude = Include.trim("\"<>");
+ const FileEntry *Entry =
+ SourceManager.getFileManager().getFile(StrippedInclude);
+
+ // If the file doesn't exist return the path from the database.
+ // FIXME: This should never happen.
+ if (!Entry)
+ return Include;
+
+ bool IsSystem;
+ std::string Suggestion =
+ HeaderSearch.suggestPathToFileForDiagnostics(Entry, &IsSystem);
+
+ return IsSystem ? '<' + Suggestion + '>' : '"' + Suggestion + '"';
+}
+
+/// Get the include fixer context for the queried symbol.
+IncludeFixerContext IncludeFixerSemaSource::getIncludeFixerContext(
+ const clang::SourceManager &SourceManager,
+ clang::HeaderSearch &HeaderSearch,
+ ArrayRef<find_all_symbols::SymbolInfo> MatchedSymbols) const {
+ std::vector<find_all_symbols::SymbolInfo> SymbolCandidates;
+ for (const auto &Symbol : MatchedSymbols) {
+ std::string FilePath = Symbol.getFilePath().str();
+ std::string MinimizedFilePath = minimizeInclude(
+ ((FilePath[0] == '"' || FilePath[0] == '<') ? FilePath
+ : "\"" + FilePath + "\""),
+ SourceManager, HeaderSearch);
+ SymbolCandidates.emplace_back(Symbol.getName(), Symbol.getSymbolKind(),
+ MinimizedFilePath, Symbol.getContexts());
+ }
+ return IncludeFixerContext(FilePath, QuerySymbolInfos, SymbolCandidates);
+}
+
+std::vector<find_all_symbols::SymbolInfo>
+IncludeFixerSemaSource::query(StringRef Query, StringRef ScopedQualifiers,
+ tooling::Range Range) {
+ assert(!Query.empty() && "Empty query!");
+
+ // Save all instances of an unidentified symbol.
+ //
+ // We use conservative behavior for detecting the same unidentified symbol
+ // here. The symbols which have the same ScopedQualifier and RawIdentifier
+ // are considered equal. So that clang-include-fixer avoids false positives,
+ // and always adds missing qualifiers to correct symbols.
+ if (!GenerateDiagnostics && !QuerySymbolInfos.empty()) {
+ if (ScopedQualifiers == QuerySymbolInfos.front().ScopedQualifiers &&
+ Query == QuerySymbolInfos.front().RawIdentifier) {
+ QuerySymbolInfos.push_back({Query.str(), ScopedQualifiers, Range});
+ }
+ return {};
+ }
+
+ LLVM_DEBUG(llvm::dbgs() << "Looking up '" << Query << "' at ");
+ LLVM_DEBUG(CI->getSourceManager()
+ .getLocForStartOfFile(CI->getSourceManager().getMainFileID())
+ .getLocWithOffset(Range.getOffset())
+ .print(llvm::dbgs(), CI->getSourceManager()));
+ LLVM_DEBUG(llvm::dbgs() << " ...");
+ llvm::StringRef FileName = CI->getSourceManager().getFilename(
+ CI->getSourceManager().getLocForStartOfFile(
+ CI->getSourceManager().getMainFileID()));
+
+ QuerySymbolInfos.push_back({Query.str(), ScopedQualifiers, Range});
+
+ // Query the symbol based on C++ name Lookup rules.
+ // Firstly, lookup the identifier with scoped namespace contexts;
+ // If that fails, falls back to look up the identifier directly.
+ //
+ // For example:
+ //
+ // namespace a {
+ // b::foo f;
+ // }
+ //
+ // 1. lookup a::b::foo.
+ // 2. lookup b::foo.
+ std::string QueryString = ScopedQualifiers.str() + Query.str();
+ // It's unsafe to do nested search for the identifier with scoped namespace
+ // context, it might treat the identifier as a nested class of the scoped
+ // namespace.
+ std::vector<find_all_symbols::SymbolInfo> MatchedSymbols =
+ SymbolIndexMgr.search(QueryString, /*IsNestedSearch=*/false, FileName);
+ if (MatchedSymbols.empty())
+ MatchedSymbols =
+ SymbolIndexMgr.search(Query, /*IsNestedSearch=*/true, FileName);
+ LLVM_DEBUG(llvm::dbgs() << "Having found " << MatchedSymbols.size()
+ << " symbols\n");
+ // We store a copy of MatchedSymbols in a place where it's globally reachable.
+ // This is used by the standalone version of the tool.
+ this->MatchedSymbols = MatchedSymbols;
+ return MatchedSymbols;
+}
+
+llvm::Expected<tooling::Replacements> createIncludeFixerReplacements(
+ StringRef Code, const IncludeFixerContext &Context,
+ const clang::format::FormatStyle &Style, bool AddQualifiers) {
+ if (Context.getHeaderInfos().empty())
+ return tooling::Replacements();
+ StringRef FilePath = Context.getFilePath();
+ std::string IncludeName =
+ "#include " + Context.getHeaderInfos().front().Header + "\n";
+ // Create replacements for the new header.
+ clang::tooling::Replacements Insertions;
+ auto Err =
+ Insertions.add(tooling::Replacement(FilePath, UINT_MAX, 0, IncludeName));
+ if (Err)
+ return std::move(Err);
+
+ auto CleanReplaces = cleanupAroundReplacements(Code, Insertions, Style);
+ if (!CleanReplaces)
+ return CleanReplaces;
+
+ auto Replaces = std::move(*CleanReplaces);
+ if (AddQualifiers) {
+ for (const auto &Info : Context.getQuerySymbolInfos()) {
+ // Ignore the empty range.
+ if (Info.Range.getLength() > 0) {
+ auto R = tooling::Replacement(
+ {FilePath, Info.Range.getOffset(), Info.Range.getLength(),
+ Context.getHeaderInfos().front().QualifiedName});
+ auto Err = Replaces.add(R);
+ if (Err) {
+ llvm::consumeError(std::move(Err));
+ R = tooling::Replacement(
+ R.getFilePath(), Replaces.getShiftedCodePosition(R.getOffset()),
+ R.getLength(), R.getReplacementText());
+ Replaces = Replaces.merge(tooling::Replacements(R));
+ }
+ }
+ }
+ }
+ return formatReplacements(Code, Replaces, Style);
+}
+
+} // namespace include_fixer
+} // namespace clang
Added: clang-tools-extra/trunk/clang-include-fixer/IncludeFixer.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/IncludeFixer.h?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/IncludeFixer.h (added)
+++ clang-tools-extra/trunk/clang-include-fixer/IncludeFixer.h Mon Mar 25 07:09:10 2019
@@ -0,0 +1,157 @@
+//===-- IncludeFixer.h - Include inserter -----------------------*- 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_INCLUDEFIXER_H
+#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INCLUDEFIXER_H
+
+#include "IncludeFixerContext.h"
+#include "SymbolIndexManager.h"
+#include "clang/Format/Format.h"
+#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "clang/Tooling/Tooling.h"
+#include <memory>
+#include <vector>
+
+namespace clang {
+
+class CompilerInvocation;
+class DiagnosticConsumer;
+class FileManager;
+class PCHContainerOperations;
+
+namespace include_fixer {
+
+class IncludeFixerActionFactory : public clang::tooling::ToolAction {
+public:
+ /// \param SymbolIndexMgr A source for matching symbols to header files.
+ /// \param Contexts The contexts for the symbols being queried.
+ /// \param StyleName Fallback style for reformatting.
+ /// \param MinimizeIncludePaths whether inserted include paths are optimized.
+ IncludeFixerActionFactory(SymbolIndexManager &SymbolIndexMgr,
+ std::vector<IncludeFixerContext> &Contexts,
+ StringRef StyleName,
+ bool MinimizeIncludePaths = true);
+
+ ~IncludeFixerActionFactory() override;
+
+ bool
+ runInvocation(std::shared_ptr<clang::CompilerInvocation> Invocation,
+ clang::FileManager *Files,
+ std::shared_ptr<clang::PCHContainerOperations> PCHContainerOps,
+ clang::DiagnosticConsumer *Diagnostics) override;
+
+private:
+ /// The client to use to find cross-references.
+ SymbolIndexManager &SymbolIndexMgr;
+
+ /// Multiple contexts for files being processed.
+ std::vector<IncludeFixerContext> &Contexts;
+
+ /// Whether inserted include paths should be optimized.
+ bool MinimizeIncludePaths;
+
+ /// The fallback format style for formatting after insertion if no
+ /// clang-format config file was found.
+ std::string FallbackStyle;
+};
+
+/// Create replacements, which are generated by clang-format, for the
+/// missing header and mising qualifiers insertions. The function uses the
+/// first header for insertion.
+///
+/// \param Code The source code.
+/// \param Context The context which contains all information for creating
+/// clang-include-fixer replacements.
+/// \param Style clang-format style being used.
+/// \param AddQualifiers Whether we should add qualifiers to all instances of
+/// an unidentified symbol.
+///
+/// \return Formatted replacements for inserting, sorting headers and adding
+/// qualifiers on success; otherwise, an llvm::Error carrying llvm::StringError
+/// is returned.
+llvm::Expected<tooling::Replacements> createIncludeFixerReplacements(
+ StringRef Code, const IncludeFixerContext &Context,
+ const format::FormatStyle &Style = format::getLLVMStyle(),
+ bool AddQualifiers = true);
+
+/// Handles callbacks from sema, does the include lookup and turns it into an
+/// IncludeFixerContext.
+class IncludeFixerSemaSource : public clang::ExternalSemaSource {
+public:
+ explicit IncludeFixerSemaSource(SymbolIndexManager &SymbolIndexMgr,
+ bool MinimizeIncludePaths,
+ bool GenerateDiagnostics)
+ : SymbolIndexMgr(SymbolIndexMgr),
+ MinimizeIncludePaths(MinimizeIncludePaths),
+ GenerateDiagnostics(GenerateDiagnostics) {}
+
+ void setCompilerInstance(CompilerInstance *CI) { this->CI = CI; }
+ void setFilePath(StringRef FilePath) { this->FilePath = FilePath; }
+
+ /// Callback for incomplete types. If we encounter a forward declaration we
+ /// have the fully qualified name ready. Just query that.
+ bool MaybeDiagnoseMissingCompleteType(clang::SourceLocation Loc,
+ clang::QualType T) override;
+
+ /// Callback for unknown identifiers. Try to piece together as much
+ /// qualification as we can get and do a query.
+ clang::TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo,
+ int LookupKind, Scope *S, CXXScopeSpec *SS,
+ CorrectionCandidateCallback &CCC,
+ DeclContext *MemberContext,
+ bool EnteringContext,
+ const ObjCObjectPointerType *OPT) override;
+
+ /// Get the minimal include for a given path.
+ std::string minimizeInclude(StringRef Include,
+ const clang::SourceManager &SourceManager,
+ clang::HeaderSearch &HeaderSearch) const;
+
+ /// Get the include fixer context for the queried symbol.
+ IncludeFixerContext getIncludeFixerContext(
+ const clang::SourceManager &SourceManager,
+ clang::HeaderSearch &HeaderSearch,
+ ArrayRef<find_all_symbols::SymbolInfo> MatchedSymbols) const;
+
+ /// Get the global matched symbols.
+ ArrayRef<find_all_symbols::SymbolInfo> getMatchedSymbols() const {
+ return MatchedSymbols;
+ }
+
+private:
+ /// Query the database for a given identifier.
+ std::vector<find_all_symbols::SymbolInfo>
+ query(StringRef Query, StringRef ScopedQualifiers, tooling::Range Range);
+
+ CompilerInstance *CI;
+
+ /// The client to use to find cross-references.
+ SymbolIndexManager &SymbolIndexMgr;
+
+ /// The information of the symbols being queried.
+ std::vector<IncludeFixerContext::QuerySymbolInfo> QuerySymbolInfos;
+
+ /// All symbol candidates which match QuerySymbol. We only include the first
+ /// discovered identifier to avoid getting caught in results from error
+ /// recovery.
+ std::vector<find_all_symbols::SymbolInfo> MatchedSymbols;
+
+ /// The file path to the file being processed.
+ std::string FilePath;
+
+ /// Whether we should use the smallest possible include path.
+ bool MinimizeIncludePaths = true;
+
+ /// Whether we should generate diagnostics with fixits for missing symbols.
+ bool GenerateDiagnostics = false;
+};
+} // namespace include_fixer
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INCLUDEFIXER_H
Added: clang-tools-extra/trunk/clang-include-fixer/IncludeFixerContext.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/IncludeFixerContext.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/IncludeFixerContext.cpp (added)
+++ clang-tools-extra/trunk/clang-include-fixer/IncludeFixerContext.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,115 @@
+//===-- IncludeFixerContext.cpp - Include fixer context ---------*- 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 "IncludeFixerContext.h"
+#include <algorithm>
+
+namespace clang {
+namespace include_fixer {
+
+namespace {
+
+// Splits a multiply qualified names (e.g. a::b::c).
+llvm::SmallVector<llvm::StringRef, 8>
+SplitQualifiers(llvm::StringRef StringQualifiers) {
+ llvm::SmallVector<llvm::StringRef, 8> Qualifiers;
+ StringQualifiers.split(Qualifiers, "::");
+ return Qualifiers;
+}
+
+std::string createQualifiedNameForReplacement(
+ llvm::StringRef RawSymbolName,
+ llvm::StringRef SymbolScopedQualifiersName,
+ const find_all_symbols::SymbolInfo &MatchedSymbol) {
+ // No need to add missing qualifiers if SymbolIndentifer has a global scope
+ // operator "::".
+ if (RawSymbolName.startswith("::"))
+ return RawSymbolName;
+
+ std::string QualifiedName = MatchedSymbol.getQualifiedName();
+
+ // For nested classes, the qualified name constructed from database misses
+ // some stripped qualifiers, because when we search a symbol in database,
+ // we strip qualifiers from the end until we find a result. So append the
+ // missing stripped qualifiers here.
+ //
+ // Get stripped qualifiers.
+ auto SymbolQualifiers = SplitQualifiers(RawSymbolName);
+ std::string StrippedQualifiers;
+ while (!SymbolQualifiers.empty() &&
+ !llvm::StringRef(QualifiedName).endswith(SymbolQualifiers.back())) {
+ StrippedQualifiers =
+ "::" + SymbolQualifiers.back().str() + StrippedQualifiers;
+ SymbolQualifiers.pop_back();
+ }
+ // Append the missing stripped qualifiers.
+ std::string FullyQualifiedName = QualifiedName + StrippedQualifiers;
+
+ // Try to find and skip the common prefix qualifiers.
+ auto FullySymbolQualifiers = SplitQualifiers(FullyQualifiedName);
+ auto ScopedQualifiers = SplitQualifiers(SymbolScopedQualifiersName);
+ auto FullySymbolQualifiersIter = FullySymbolQualifiers.begin();
+ auto SymbolScopedQualifiersIter = ScopedQualifiers.begin();
+ while (FullySymbolQualifiersIter != FullySymbolQualifiers.end() &&
+ SymbolScopedQualifiersIter != ScopedQualifiers.end()) {
+ if (*FullySymbolQualifiersIter != *SymbolScopedQualifiersIter)
+ break;
+ ++FullySymbolQualifiersIter;
+ ++SymbolScopedQualifiersIter;
+ }
+ std::string Result;
+ for (; FullySymbolQualifiersIter != FullySymbolQualifiers.end();
+ ++FullySymbolQualifiersIter) {
+ if (!Result.empty())
+ Result += "::";
+ Result += *FullySymbolQualifiersIter;
+ }
+ return Result;
+}
+
+} // anonymous namespace
+
+IncludeFixerContext::IncludeFixerContext(
+ StringRef FilePath, std::vector<QuerySymbolInfo> QuerySymbols,
+ std::vector<find_all_symbols::SymbolInfo> Symbols)
+ : FilePath(FilePath), QuerySymbolInfos(std::move(QuerySymbols)),
+ MatchedSymbols(std::move(Symbols)) {
+ // Remove replicated QuerySymbolInfos with the same range.
+ //
+ // QuerySymbolInfos may contain replicated elements. Because CorrectTypo
+ // callback doesn't always work as we expected. In somecases, it will be
+ // triggered at the same position or unidentified symbol multiple times.
+ std::sort(QuerySymbolInfos.begin(), QuerySymbolInfos.end(),
+ [&](const QuerySymbolInfo &A, const QuerySymbolInfo &B) {
+ return std::make_pair(A.Range.getOffset(), A.Range.getLength()) <
+ std::make_pair(B.Range.getOffset(), B.Range.getLength());
+ });
+ QuerySymbolInfos.erase(
+ std::unique(QuerySymbolInfos.begin(), QuerySymbolInfos.end(),
+ [](const QuerySymbolInfo &A, const QuerySymbolInfo &B) {
+ return A.Range == B.Range;
+ }),
+ QuerySymbolInfos.end());
+ for (const auto &Symbol : MatchedSymbols) {
+ HeaderInfos.push_back(
+ {Symbol.getFilePath().str(),
+ createQualifiedNameForReplacement(
+ QuerySymbolInfos.front().RawIdentifier,
+ QuerySymbolInfos.front().ScopedQualifiers, Symbol)});
+ }
+ // Deduplicate header infos.
+ HeaderInfos.erase(std::unique(HeaderInfos.begin(), HeaderInfos.end(),
+ [](const HeaderInfo &A, const HeaderInfo &B) {
+ return A.Header == B.Header &&
+ A.QualifiedName == B.QualifiedName;
+ }),
+ HeaderInfos.end());
+}
+
+} // include_fixer
+} // clang
Added: clang-tools-extra/trunk/clang-include-fixer/IncludeFixerContext.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/IncludeFixerContext.h?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/IncludeFixerContext.h (added)
+++ clang-tools-extra/trunk/clang-include-fixer/IncludeFixerContext.h Mon Mar 25 07:09:10 2019
@@ -0,0 +1,94 @@
+//===-- IncludeFixerContext.h - Include fixer context -----------*- 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_INCLUDEFIXERCONTEXT_H
+#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INCLUDEFIXERCONTEXT_H
+
+#include "find-all-symbols/SymbolInfo.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace include_fixer {
+
+/// \brief A context for a file being processed. It includes all query
+/// information, e.g. symbols being queried in database, all header candidates.
+class IncludeFixerContext {
+public:
+ struct HeaderInfo {
+ /// \brief The header where QualifiedName comes from.
+ std::string Header;
+ /// \brief A symbol name with completed namespace qualifiers which will
+ /// replace the original symbol.
+ std::string QualifiedName;
+ };
+
+ struct QuerySymbolInfo {
+ /// \brief The raw symbol name being queried in database. This name might
+ /// miss some namespace qualifiers, and will be replaced by a fully
+ /// qualified one.
+ std::string RawIdentifier;
+
+ /// \brief The qualifiers of the scope in which SymbolIdentifier lookup
+ /// occurs. It is represented as a sequence of names and scope resolution
+ /// operatiors ::, ending with a scope resolution operator (e.g. a::b::).
+ /// Empty if SymbolIdentifier is not in a specific scope.
+ std::string ScopedQualifiers;
+
+ /// \brief The replacement range of RawIdentifier.
+ tooling::Range Range;
+ };
+
+ IncludeFixerContext() = default;
+ IncludeFixerContext(StringRef FilePath,
+ std::vector<QuerySymbolInfo> QuerySymbols,
+ std::vector<find_all_symbols::SymbolInfo> Symbols);
+
+ /// \brief Get symbol name.
+ llvm::StringRef getSymbolIdentifier() const {
+ return QuerySymbolInfos.front().RawIdentifier;
+ }
+
+ /// \brief Get replacement range of the symbol.
+ tooling::Range getSymbolRange() const {
+ return QuerySymbolInfos.front().Range;
+ }
+
+ /// \brief Get the file path to the file being processed.
+ StringRef getFilePath() const { return FilePath; }
+
+ /// \brief Get header information.
+ const std::vector<HeaderInfo> &getHeaderInfos() const { return HeaderInfos; }
+
+ /// \brief Get information of symbols being querid.
+ const std::vector<QuerySymbolInfo> &getQuerySymbolInfos() const {
+ return QuerySymbolInfos;
+ }
+
+private:
+ friend struct llvm::yaml::MappingTraits<IncludeFixerContext>;
+
+ /// \brief The file path to the file being processed.
+ std::string FilePath;
+
+ /// \brief All instances of an unidentified symbol being queried.
+ std::vector<QuerySymbolInfo> QuerySymbolInfos;
+
+ /// \brief The symbol candidates which match SymbolIdentifier. The symbols are
+ /// sorted in a descending order based on the popularity info in SymbolInfo.
+ std::vector<find_all_symbols::SymbolInfo> MatchedSymbols;
+
+ /// \brief The header information.
+ std::vector<HeaderInfo> HeaderInfos;
+};
+
+} // namespace include_fixer
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INCLUDEFIXERCONTEXT_H
Added: clang-tools-extra/trunk/clang-include-fixer/SymbolIndex.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/SymbolIndex.h?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/SymbolIndex.h (added)
+++ clang-tools-extra/trunk/clang-include-fixer/SymbolIndex.h Mon Mar 25 07:09:10 2019
@@ -0,0 +1,37 @@
+//===-- SymbolIndex.h - Interface for symbol-header matching ----*- 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_SYMBOLINDEX_H
+#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_SYMBOLINDEX_H
+
+#include "find-all-symbols/SymbolInfo.h"
+#include "llvm/ADT/StringRef.h"
+#include <vector>
+
+namespace clang {
+namespace include_fixer {
+
+/// This class provides an interface for finding all `SymbolInfo`s corresponding
+/// to a symbol name from a symbol database.
+class SymbolIndex {
+public:
+ virtual ~SymbolIndex() = default;
+
+ /// Search for all `SymbolInfo`s corresponding to an identifier.
+ /// \param Identifier The unqualified identifier being searched for.
+ /// \returns A list of `SymbolInfo` candidates.
+ // FIXME: Expose the type name so we can also insert using declarations (or
+ // fix the usage)
+ virtual std::vector<find_all_symbols::SymbolAndSignals>
+ search(llvm::StringRef Identifier) = 0;
+};
+
+} // namespace include_fixer
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_SYMBOLINDEX_H
Added: clang-tools-extra/trunk/clang-include-fixer/SymbolIndexManager.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/SymbolIndexManager.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/SymbolIndexManager.cpp (added)
+++ clang-tools-extra/trunk/clang-include-fixer/SymbolIndexManager.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,158 @@
+//===-- SymbolIndexManager.cpp - Managing multiple SymbolIndices-*- 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 "SymbolIndexManager.h"
+#include "find-all-symbols/SymbolInfo.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Path.h"
+
+#define DEBUG_TYPE "clang-include-fixer"
+
+namespace clang {
+namespace include_fixer {
+
+using find_all_symbols::SymbolInfo;
+using find_all_symbols::SymbolAndSignals;
+
+// Calculate a score based on whether we think the given header is closely
+// related to the given source file.
+static double similarityScore(llvm::StringRef FileName,
+ llvm::StringRef Header) {
+ // Compute the maximum number of common path segements between Header and
+ // a suffix of FileName.
+ // We do not do a full longest common substring computation, as Header
+ // specifies the path we would directly #include, so we assume it is rooted
+ // relatively to a subproject of the repository.
+ int MaxSegments = 1;
+ for (auto FileI = llvm::sys::path::begin(FileName),
+ FileE = llvm::sys::path::end(FileName);
+ FileI != FileE; ++FileI) {
+ int Segments = 0;
+ for (auto HeaderI = llvm::sys::path::begin(Header),
+ HeaderE = llvm::sys::path::end(Header), I = FileI;
+ HeaderI != HeaderE && *I == *HeaderI && I != FileE; ++I, ++HeaderI) {
+ ++Segments;
+ }
+ MaxSegments = std::max(Segments, MaxSegments);
+ }
+ return MaxSegments;
+}
+
+static void rank(std::vector<SymbolAndSignals> &Symbols,
+ llvm::StringRef FileName) {
+ llvm::DenseMap<llvm::StringRef, double> Score;
+ for (const auto &Symbol : Symbols) {
+ // Calculate a score from the similarity of the header the symbol is in
+ // with the current file and the popularity of the symbol.
+ double NewScore = similarityScore(FileName, Symbol.Symbol.getFilePath()) *
+ (1.0 + std::log2(1 + Symbol.Signals.Seen));
+ double &S = Score[Symbol.Symbol.getFilePath()];
+ S = std::max(S, NewScore);
+ }
+ // Sort by the gathered scores. Use file name as a tie breaker so we can
+ // deduplicate.
+ std::sort(Symbols.begin(), Symbols.end(),
+ [&](const SymbolAndSignals &A, const SymbolAndSignals &B) {
+ auto AS = Score[A.Symbol.getFilePath()];
+ auto BS = Score[B.Symbol.getFilePath()];
+ if (AS != BS)
+ return AS > BS;
+ return A.Symbol.getFilePath() < B.Symbol.getFilePath();
+ });
+}
+
+std::vector<find_all_symbols::SymbolInfo>
+SymbolIndexManager::search(llvm::StringRef Identifier,
+ bool IsNestedSearch,
+ llvm::StringRef FileName) const {
+ // The identifier may be fully qualified, so split it and get all the context
+ // names.
+ llvm::SmallVector<llvm::StringRef, 8> Names;
+ Identifier.split(Names, "::");
+
+ bool IsFullyQualified = false;
+ if (Identifier.startswith("::")) {
+ Names.erase(Names.begin()); // Drop first (empty) element.
+ IsFullyQualified = true;
+ }
+
+ // As long as we don't find a result keep stripping name parts from the end.
+ // This is to support nested classes which aren't recorded in the database.
+ // Eventually we will either hit a class (namespaces aren't in the database
+ // either) and can report that result.
+ bool TookPrefix = false;
+ std::vector<SymbolAndSignals> MatchedSymbols;
+ do {
+ std::vector<SymbolAndSignals> Symbols;
+ for (const auto &DB : SymbolIndices) {
+ auto Res = DB.get()->search(Names.back());
+ Symbols.insert(Symbols.end(), Res.begin(), Res.end());
+ }
+
+ LLVM_DEBUG(llvm::dbgs() << "Searching " << Names.back() << "... got "
+ << Symbols.size() << " results...\n");
+
+ for (auto &SymAndSig : Symbols) {
+ const SymbolInfo &Symbol = SymAndSig.Symbol;
+ // Match the identifier name without qualifier.
+ bool IsMatched = true;
+ auto SymbolContext = Symbol.getContexts().begin();
+ auto IdentiferContext = Names.rbegin() + 1; // Skip identifier name.
+ // Match the remaining context names.
+ while (IdentiferContext != Names.rend() &&
+ SymbolContext != Symbol.getContexts().end()) {
+ if (SymbolContext->second == *IdentiferContext) {
+ ++IdentiferContext;
+ ++SymbolContext;
+ } else if (SymbolContext->first ==
+ find_all_symbols::SymbolInfo::ContextType::EnumDecl) {
+ // Skip non-scoped enum context.
+ ++SymbolContext;
+ } else {
+ IsMatched = false;
+ break;
+ }
+ }
+
+ // If the name was qualified we only want to add results if we evaluated
+ // all contexts.
+ if (IsFullyQualified)
+ IsMatched &= (SymbolContext == Symbol.getContexts().end());
+
+ // FIXME: Support full match. At this point, we only find symbols in
+ // database which end with the same contexts with the identifier.
+ if (IsMatched && IdentiferContext == Names.rend()) {
+ // If we're in a situation where we took a prefix but the thing we
+ // found couldn't possibly have a nested member ignore it.
+ if (TookPrefix &&
+ (Symbol.getSymbolKind() == SymbolInfo::SymbolKind::Function ||
+ Symbol.getSymbolKind() == SymbolInfo::SymbolKind::Variable ||
+ Symbol.getSymbolKind() ==
+ SymbolInfo::SymbolKind::EnumConstantDecl ||
+ Symbol.getSymbolKind() == SymbolInfo::SymbolKind::Macro))
+ continue;
+
+ MatchedSymbols.push_back(std::move(SymAndSig));
+ }
+ }
+ Names.pop_back();
+ TookPrefix = true;
+ } while (MatchedSymbols.empty() && !Names.empty() && IsNestedSearch);
+
+ rank(MatchedSymbols, FileName);
+ // Strip signals, they are no longer needed.
+ std::vector<SymbolInfo> Res;
+ for (auto &SymAndSig : MatchedSymbols)
+ Res.push_back(std::move(SymAndSig.Symbol));
+ return Res;
+}
+
+} // namespace include_fixer
+} // namespace clang
Added: clang-tools-extra/trunk/clang-include-fixer/SymbolIndexManager.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/SymbolIndexManager.h?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/SymbolIndexManager.h (added)
+++ clang-tools-extra/trunk/clang-include-fixer/SymbolIndexManager.h Mon Mar 25 07:09:10 2019
@@ -0,0 +1,65 @@
+//===-- SymbolIndexManager.h - Managing multiple SymbolIndices --*- 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_SYMBOLINDEXMANAGER_H
+#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_SYMBOLINDEXMANAGER_H
+
+#include "SymbolIndex.h"
+#include "find-all-symbols/SymbolInfo.h"
+#include "llvm/ADT/StringRef.h"
+
+#ifdef _MSC_VER
+// Disable warnings from ppltasks.h transitively included by <future>.
+#pragma warning(push)
+#pragma warning(disable:4530)
+#endif
+
+#include <future>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+namespace clang {
+namespace include_fixer {
+
+/// This class provides an interface for finding the header files corresponding
+/// to an identifier in the source code from multiple symbol databases.
+class SymbolIndexManager {
+public:
+ void addSymbolIndex(std::function<std::unique_ptr<SymbolIndex>()> F) {
+#if LLVM_ENABLE_THREADS
+ auto Strategy = std::launch::async;
+#else
+ auto Strategy = std::launch::deferred;
+#endif
+ SymbolIndices.push_back(std::async(Strategy, F));
+ }
+
+ /// Search for header files to be included for an identifier.
+ /// \param Identifier The identifier being searched for. May or may not be
+ /// fully qualified.
+ /// \param IsNestedSearch Whether searching nested classes. If true, the
+ /// method tries to strip identifier name parts from the end until it
+ /// finds the corresponding candidates in database (e.g for identifier
+ /// "b::foo", the method will try to find "b" if it fails to find
+ /// "b::foo").
+ ///
+ /// \returns A list of symbol candidates.
+ std::vector<find_all_symbols::SymbolInfo>
+ search(llvm::StringRef Identifier, bool IsNestedSearch = true,
+ llvm::StringRef FileName = "") const;
+
+private:
+ std::vector<std::shared_future<std::unique_ptr<SymbolIndex>>> SymbolIndices;
+};
+
+} // namespace include_fixer
+} // namespace clang
+
+#endif
Added: clang-tools-extra/trunk/clang-include-fixer/YamlSymbolIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/YamlSymbolIndex.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/YamlSymbolIndex.cpp (added)
+++ clang-tools-extra/trunk/clang-include-fixer/YamlSymbolIndex.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,60 @@
+//===-- YamlSymbolIndex.cpp -----------------------------------------------===//
+//
+// 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 "YamlSymbolIndex.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include <string>
+#include <vector>
+
+using clang::find_all_symbols::SymbolInfo;
+using clang::find_all_symbols::SymbolAndSignals;
+
+namespace clang {
+namespace include_fixer {
+
+llvm::ErrorOr<std::unique_ptr<YamlSymbolIndex>>
+YamlSymbolIndex::createFromFile(llvm::StringRef FilePath) {
+ auto Buffer = llvm::MemoryBuffer::getFile(FilePath);
+ if (!Buffer)
+ return Buffer.getError();
+
+ return std::unique_ptr<YamlSymbolIndex>(new YamlSymbolIndex(
+ find_all_symbols::ReadSymbolInfosFromYAML(Buffer.get()->getBuffer())));
+}
+
+llvm::ErrorOr<std::unique_ptr<YamlSymbolIndex>>
+YamlSymbolIndex::createFromDirectory(llvm::StringRef Directory,
+ llvm::StringRef Name) {
+ // Walk upwards from Directory, looking for files.
+ for (llvm::SmallString<128> PathStorage = Directory; !Directory.empty();
+ Directory = llvm::sys::path::parent_path(Directory)) {
+ assert(Directory.size() <= PathStorage.size());
+ PathStorage.resize(Directory.size()); // Shrink to parent.
+ llvm::sys::path::append(PathStorage, Name);
+ if (auto DB = createFromFile(PathStorage))
+ return DB;
+ }
+ return llvm::make_error_code(llvm::errc::no_such_file_or_directory);
+}
+
+std::vector<SymbolAndSignals>
+YamlSymbolIndex::search(llvm::StringRef Identifier) {
+ std::vector<SymbolAndSignals> Results;
+ for (const auto &Symbol : Symbols) {
+ if (Symbol.Symbol.getName() == Identifier)
+ Results.push_back(Symbol);
+ }
+ return Results;
+}
+
+} // namespace include_fixer
+} // namespace clang
Added: clang-tools-extra/trunk/clang-include-fixer/YamlSymbolIndex.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/YamlSymbolIndex.h?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/YamlSymbolIndex.h (added)
+++ clang-tools-extra/trunk/clang-include-fixer/YamlSymbolIndex.h Mon Mar 25 07:09:10 2019
@@ -0,0 +1,45 @@
+//===-- YamlSymbolIndex.h ---------------------------------------*- 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_YAMLSYMBOLINDEX_H
+#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_YAMLSYMBOLINDEX_H
+
+#include "SymbolIndex.h"
+#include "find-all-symbols/SymbolInfo.h"
+#include "llvm/Support/ErrorOr.h"
+#include <map>
+#include <vector>
+
+namespace clang {
+namespace include_fixer {
+
+/// Yaml format database.
+class YamlSymbolIndex : public SymbolIndex {
+public:
+ /// Create a new Yaml db from a file.
+ static llvm::ErrorOr<std::unique_ptr<YamlSymbolIndex>>
+ createFromFile(llvm::StringRef FilePath);
+ /// Look for a file called \c Name in \c Directory and all parent directories.
+ static llvm::ErrorOr<std::unique_ptr<YamlSymbolIndex>>
+ createFromDirectory(llvm::StringRef Directory, llvm::StringRef Name);
+
+ std::vector<find_all_symbols::SymbolAndSignals>
+ search(llvm::StringRef Identifier) override;
+
+private:
+ explicit YamlSymbolIndex(
+ std::vector<find_all_symbols::SymbolAndSignals> Symbols)
+ : Symbols(std::move(Symbols)) {}
+
+ std::vector<find_all_symbols::SymbolAndSignals> Symbols;
+};
+
+} // namespace include_fixer
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_YAMLSYMBOLINDEX_H
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/CMakeLists.txt?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/CMakeLists.txt (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/CMakeLists.txt Mon Mar 25 07:09:10 2019
@@ -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)
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllMacros.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllMacros.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllMacros.cpp (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllMacros.cpp Mon Mar 25 07:09:10 2019
@@ -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
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllMacros.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllMacros.h?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllMacros.h (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllMacros.h Mon Mar 25 07:09:10 2019
@@ -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
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp Mon Mar 25 07:09:10 2019
@@ -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
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbols.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbols.h?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbols.h (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbols.h Mon Mar 25 07:09:10 2019
@@ -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
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbolsAction.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbolsAction.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbolsAction.cpp (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbolsAction.cpp Mon Mar 25 07:09:10 2019
@@ -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
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbolsAction.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbolsAction.h?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbolsAction.h (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/FindAllSymbolsAction.h Mon Mar 25 07:09:10 2019
@@ -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
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/HeaderMapCollector.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/HeaderMapCollector.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/HeaderMapCollector.cpp (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/HeaderMapCollector.cpp Mon Mar 25 07:09:10 2019
@@ -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
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/HeaderMapCollector.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/HeaderMapCollector.h?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/HeaderMapCollector.h (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/HeaderMapCollector.h Mon Mar 25 07:09:10 2019
@@ -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
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PathConfig.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PathConfig.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PathConfig.cpp (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PathConfig.cpp Mon Mar 25 07:09:10 2019
@@ -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
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PathConfig.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PathConfig.h?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PathConfig.h (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PathConfig.h Mon Mar 25 07:09:10 2019
@@ -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
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PragmaCommentHandler.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PragmaCommentHandler.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PragmaCommentHandler.cpp (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PragmaCommentHandler.cpp Mon Mar 25 07:09:10 2019
@@ -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
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PragmaCommentHandler.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PragmaCommentHandler.h?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PragmaCommentHandler.h (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/PragmaCommentHandler.h Mon Mar 25 07:09:10 2019
@@ -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
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp Mon Mar 25 07:09:10 2019
@@ -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
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.h?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.h (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.h Mon Mar 25 07:09:10 2019
@@ -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
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/SymbolInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/SymbolInfo.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/SymbolInfo.cpp (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/SymbolInfo.cpp Mon Mar 25 07:09:10 2019
@@ -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
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/SymbolInfo.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/SymbolInfo.h?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/SymbolInfo.h (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/SymbolInfo.h Mon Mar 25 07:09:10 2019
@@ -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
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/SymbolReporter.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/SymbolReporter.h?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/SymbolReporter.h (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/SymbolReporter.h Mon Mar 25 07:09:10 2019
@@ -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
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/tool/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/tool/CMakeLists.txt?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/tool/CMakeLists.txt (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/tool/CMakeLists.txt Mon Mar 25 07:09:10 2019
@@ -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)
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/tool/FindAllSymbolsMain.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/tool/FindAllSymbolsMain.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/tool/FindAllSymbolsMain.cpp (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/tool/FindAllSymbolsMain.cpp Mon Mar 25 07:09:10 2019
@@ -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());
+}
Added: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/tool/run-find-all-symbols.py
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/tool/run-find-all-symbols.py?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/tool/run-find-all-symbols.py (added)
+++ clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/tool/run-find-all-symbols.py Mon Mar 25 07:09:10 2019
@@ -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()
Propchange: clang-tools-extra/trunk/clang-include-fixer/find-all-symbols/tool/run-find-all-symbols.py
------------------------------------------------------------------------------
svn:executable = *
Added: clang-tools-extra/trunk/clang-include-fixer/plugin/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/plugin/CMakeLists.txt?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/plugin/CMakeLists.txt (added)
+++ clang-tools-extra/trunk/clang-include-fixer/plugin/CMakeLists.txt Mon Mar 25 07:09:10 2019
@@ -0,0 +1,13 @@
+add_clang_library(clangIncludeFixerPlugin
+ IncludeFixerPlugin.cpp
+
+ LINK_LIBS
+ clangAST
+ clangBasic
+ clangFrontend
+ clangIncludeFixer
+ clangParse
+ clangSema
+ clangTooling
+ ${LLVM_PTHREAD_LIB}
+ )
Added: clang-tools-extra/trunk/clang-include-fixer/plugin/IncludeFixerPlugin.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/plugin/IncludeFixerPlugin.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/plugin/IncludeFixerPlugin.cpp (added)
+++ clang-tools-extra/trunk/clang-include-fixer/plugin/IncludeFixerPlugin.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,99 @@
+//===- IncludeFixerPlugin.cpp - clang-include-fixer as a clang plugin -----===//
+//
+// 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 "../IncludeFixer.h"
+#include "../YamlSymbolIndex.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/Parse/ParseAST.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/Support/Path.h"
+
+namespace clang {
+namespace include_fixer {
+
+/// The core include fixer plugin action. This just provides the AST consumer
+/// and command line flag parsing for using include fixer as a clang plugin.
+class ClangIncludeFixerPluginAction : public PluginASTAction {
+ /// ASTConsumer to keep the symbol index alive. We don't really need an
+ /// ASTConsumer for this plugin (everything is funneled on the side through
+ /// Sema) but we have to keep the symbol index alive until sema is done.
+ struct ASTConsumerManagerWrapper : public ASTConsumer {
+ ASTConsumerManagerWrapper(std::shared_ptr<SymbolIndexManager> SIM)
+ : SymbolIndexMgr(std::move(SIM)) {}
+ std::shared_ptr<SymbolIndexManager> SymbolIndexMgr;
+ };
+
+public:
+ explicit ClangIncludeFixerPluginAction()
+ : SymbolIndexMgr(std::make_shared<SymbolIndexManager>()),
+ SemaSource(new IncludeFixerSemaSource(*SymbolIndexMgr,
+ /*MinimizeIncludePaths=*/true,
+ /*GenerateDiagnostics=*/true)) {}
+
+ std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(clang::CompilerInstance &CI, StringRef InFile) override {
+ CI.setExternalSemaSource(SemaSource);
+ SemaSource->setFilePath(InFile);
+ SemaSource->setCompilerInstance(&CI);
+ return llvm::make_unique<ASTConsumerManagerWrapper>(SymbolIndexMgr);
+ }
+
+ void ExecuteAction() override {} // Do nothing.
+
+ bool ParseArgs(const CompilerInstance &CI,
+ const std::vector<std::string> &Args) override {
+ StringRef DB = "yaml";
+ StringRef Input;
+
+ // Parse the extra command line args.
+ // FIXME: This is very limited at the moment.
+ for (StringRef Arg : Args) {
+ if (Arg.startswith("-db="))
+ DB = Arg.substr(strlen("-db="));
+ else if (Arg.startswith("-input="))
+ Input = Arg.substr(strlen("-input="));
+ }
+
+ std::string InputFile = CI.getFrontendOpts().Inputs[0].getFile();
+ auto CreateYamlIdx = [=]() -> std::unique_ptr<include_fixer::SymbolIndex> {
+ llvm::ErrorOr<std::unique_ptr<include_fixer::YamlSymbolIndex>> SymbolIdx(
+ nullptr);
+ if (DB == "yaml") {
+ if (!Input.empty()) {
+ SymbolIdx = include_fixer::YamlSymbolIndex::createFromFile(Input);
+ } else {
+ // If we don't have any input file, look in the directory of the first
+ // file and its parents.
+ SmallString<128> AbsolutePath(tooling::getAbsolutePath(InputFile));
+ StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
+ SymbolIdx = include_fixer::YamlSymbolIndex::createFromDirectory(
+ Directory, "find_all_symbols_db.yaml");
+ }
+ }
+ return std::move(*SymbolIdx);
+ };
+
+ SymbolIndexMgr->addSymbolIndex(std::move(CreateYamlIdx));
+ return true;
+ }
+
+private:
+ std::shared_ptr<SymbolIndexManager> SymbolIndexMgr;
+ IntrusiveRefCntPtr<IncludeFixerSemaSource> SemaSource;
+};
+} // namespace include_fixer
+} // namespace clang
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the include fixer plugin.
+volatile int ClangIncludeFixerPluginAnchorSource = 0;
+
+static clang::FrontendPluginRegistry::Add<
+ clang::include_fixer::ClangIncludeFixerPluginAction>
+ X("clang-include-fixer", "clang-include-fixer");
Added: clang-tools-extra/trunk/clang-include-fixer/tool/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/tool/CMakeLists.txt?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/tool/CMakeLists.txt (added)
+++ clang-tools-extra/trunk/clang-include-fixer/tool/CMakeLists.txt Mon Mar 25 07:09:10 2019
@@ -0,0 +1,28 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+
+add_clang_tool(clang-include-fixer
+ ClangIncludeFixer.cpp
+ )
+
+target_link_libraries(clang-include-fixer
+ PRIVATE
+ clangBasic
+ clangFormat
+ clangFrontend
+ clangIncludeFixer
+ clangRewrite
+ clangSerialization
+ clangTooling
+ clangToolingCore
+ findAllSymbols
+ )
+
+install(TARGETS clang-include-fixer
+ RUNTIME DESTINATION bin)
+
+install(PROGRAMS clang-include-fixer.el
+ DESTINATION share/clang
+ COMPONENT clang-include-fixer)
+install(PROGRAMS clang-include-fixer.py
+ DESTINATION share/clang
+ COMPONENT clang-include-fixer)
Added: clang-tools-extra/trunk/clang-include-fixer/tool/ClangIncludeFixer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/tool/ClangIncludeFixer.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/tool/ClangIncludeFixer.cpp (added)
+++ clang-tools-extra/trunk/clang-include-fixer/tool/ClangIncludeFixer.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,473 @@
+//===-- ClangIncludeFixer.cpp - Standalone include fixer ------------------===//
+//
+// 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 "FuzzySymbolIndex.h"
+#include "InMemorySymbolIndex.h"
+#include "IncludeFixer.h"
+#include "IncludeFixerContext.h"
+#include "SymbolIndexManager.h"
+#include "YamlSymbolIndex.h"
+#include "clang/Format/Format.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using namespace clang;
+using namespace llvm;
+using clang::include_fixer::IncludeFixerContext;
+
+LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(IncludeFixerContext)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(IncludeFixerContext::HeaderInfo)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(IncludeFixerContext::QuerySymbolInfo)
+
+namespace llvm {
+namespace yaml {
+
+template <> struct MappingTraits<tooling::Range> {
+ struct NormalizedRange {
+ NormalizedRange(const IO &) : Offset(0), Length(0) {}
+
+ NormalizedRange(const IO &, const tooling::Range &R)
+ : Offset(R.getOffset()), Length(R.getLength()) {}
+
+ tooling::Range denormalize(const IO &) {
+ return tooling::Range(Offset, Length);
+ }
+
+ unsigned Offset;
+ unsigned Length;
+ };
+ static void mapping(IO &IO, tooling::Range &Info) {
+ MappingNormalization<NormalizedRange, tooling::Range> Keys(IO, Info);
+ IO.mapRequired("Offset", Keys->Offset);
+ IO.mapRequired("Length", Keys->Length);
+ }
+};
+
+template <> struct MappingTraits<IncludeFixerContext::HeaderInfo> {
+ static void mapping(IO &io, IncludeFixerContext::HeaderInfo &Info) {
+ io.mapRequired("Header", Info.Header);
+ io.mapRequired("QualifiedName", Info.QualifiedName);
+ }
+};
+
+template <> struct MappingTraits<IncludeFixerContext::QuerySymbolInfo> {
+ static void mapping(IO &io, IncludeFixerContext::QuerySymbolInfo &Info) {
+ io.mapRequired("RawIdentifier", Info.RawIdentifier);
+ io.mapRequired("Range", Info.Range);
+ }
+};
+
+template <> struct MappingTraits<IncludeFixerContext> {
+ static void mapping(IO &IO, IncludeFixerContext &Context) {
+ IO.mapRequired("QuerySymbolInfos", Context.QuerySymbolInfos);
+ IO.mapRequired("HeaderInfos", Context.HeaderInfos);
+ IO.mapRequired("FilePath", Context.FilePath);
+ }
+};
+} // namespace yaml
+} // namespace llvm
+
+namespace {
+cl::OptionCategory IncludeFixerCategory("Tool options");
+
+enum DatabaseFormatTy {
+ fixed, ///< Hard-coded mapping.
+ yaml, ///< Yaml database created by find-all-symbols.
+ fuzzyYaml, ///< Yaml database with fuzzy-matched identifiers.
+};
+
+cl::opt<DatabaseFormatTy> DatabaseFormat(
+ "db", cl::desc("Specify input format"),
+ cl::values(clEnumVal(fixed, "Hard-coded mapping"),
+ clEnumVal(yaml, "Yaml database created by find-all-symbols"),
+ clEnumVal(fuzzyYaml, "Yaml database, with fuzzy-matched names")),
+ cl::init(yaml), cl::cat(IncludeFixerCategory));
+
+cl::opt<std::string> Input("input",
+ cl::desc("String to initialize the database"),
+ cl::cat(IncludeFixerCategory));
+
+cl::opt<std::string>
+ QuerySymbol("query-symbol",
+ cl::desc("Query a given symbol (e.g. \"a::b::foo\") in\n"
+ "database directly without parsing the file."),
+ cl::cat(IncludeFixerCategory));
+
+cl::opt<bool>
+ MinimizeIncludePaths("minimize-paths",
+ cl::desc("Whether to minimize added include paths"),
+ cl::init(true), cl::cat(IncludeFixerCategory));
+
+cl::opt<bool> Quiet("q", cl::desc("Reduce terminal output"), cl::init(false),
+ cl::cat(IncludeFixerCategory));
+
+cl::opt<bool>
+ STDINMode("stdin",
+ cl::desc("Override source file's content (in the overlaying\n"
+ "virtual file system) with input from <stdin> and run\n"
+ "the tool on the new content with the compilation\n"
+ "options of the source file. This mode is currently\n"
+ "used for editor integration."),
+ cl::init(false), cl::cat(IncludeFixerCategory));
+
+cl::opt<bool> OutputHeaders(
+ "output-headers",
+ cl::desc("Print the symbol being queried and all its relevant headers in\n"
+ "JSON format to stdout:\n"
+ " {\n"
+ " \"FilePath\": \"/path/to/foo.cc\",\n"
+ " \"QuerySymbolInfos\": [\n"
+ " {\"RawIdentifier\": \"foo\",\n"
+ " \"Range\": {\"Offset\": 0, \"Length\": 3}}\n"
+ " ],\n"
+ " \"HeaderInfos\": [ {\"Header\": \"\\\"foo_a.h\\\"\",\n"
+ " \"QualifiedName\": \"a::foo\"} ]\n"
+ " }"),
+ cl::init(false), cl::cat(IncludeFixerCategory));
+
+cl::opt<std::string> InsertHeader(
+ "insert-header",
+ cl::desc("Insert a specific header. This should run with STDIN mode.\n"
+ "The result is written to stdout. It is currently used for\n"
+ "editor integration. Support YAML/JSON format:\n"
+ " -insert-header=\"{\n"
+ " FilePath: \"/path/to/foo.cc\",\n"
+ " QuerySymbolInfos: [\n"
+ " {RawIdentifier: foo,\n"
+ " Range: {Offset: 0, Length: 3}}\n"
+ " ],\n"
+ " HeaderInfos: [ {Headers: \"\\\"foo_a.h\\\"\",\n"
+ " QualifiedName: \"a::foo\"} ]}\""),
+ cl::init(""), cl::cat(IncludeFixerCategory));
+
+cl::opt<std::string>
+ Style("style",
+ cl::desc("Fallback style for reformatting after inserting new\n"
+ "headers if there is no clang-format config file found."),
+ cl::init("llvm"), cl::cat(IncludeFixerCategory));
+
+std::unique_ptr<include_fixer::SymbolIndexManager>
+createSymbolIndexManager(StringRef FilePath) {
+ using find_all_symbols::SymbolInfo;
+
+ auto SymbolIndexMgr = llvm::make_unique<include_fixer::SymbolIndexManager>();
+ switch (DatabaseFormat) {
+ case fixed: {
+ // Parse input and fill the database with it.
+ // <symbol>=<header><, header...>
+ // Multiple symbols can be given, separated by semicolons.
+ std::map<std::string, std::vector<std::string>> SymbolsMap;
+ SmallVector<StringRef, 4> SemicolonSplits;
+ StringRef(Input).split(SemicolonSplits, ";");
+ std::vector<find_all_symbols::SymbolAndSignals> Symbols;
+ for (StringRef Pair : SemicolonSplits) {
+ auto Split = Pair.split('=');
+ std::vector<std::string> Headers;
+ SmallVector<StringRef, 4> CommaSplits;
+ Split.second.split(CommaSplits, ",");
+ for (size_t I = 0, E = CommaSplits.size(); I != E; ++I)
+ Symbols.push_back(
+ {SymbolInfo(Split.first.trim(), SymbolInfo::SymbolKind::Unknown,
+ CommaSplits[I].trim(), {}),
+ // Use fake "seen" signal for tests, so first header wins.
+ SymbolInfo::Signals(/*Seen=*/static_cast<unsigned>(E - I),
+ /*Used=*/0)});
+ }
+ SymbolIndexMgr->addSymbolIndex([=]() {
+ return llvm::make_unique<include_fixer::InMemorySymbolIndex>(Symbols);
+ });
+ break;
+ }
+ case yaml: {
+ auto CreateYamlIdx = [=]() -> std::unique_ptr<include_fixer::SymbolIndex> {
+ llvm::ErrorOr<std::unique_ptr<include_fixer::YamlSymbolIndex>> DB(
+ nullptr);
+ if (!Input.empty()) {
+ DB = include_fixer::YamlSymbolIndex::createFromFile(Input);
+ } else {
+ // If we don't have any input file, look in the directory of the
+ // first
+ // file and its parents.
+ SmallString<128> AbsolutePath(tooling::getAbsolutePath(FilePath));
+ StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
+ DB = include_fixer::YamlSymbolIndex::createFromDirectory(
+ Directory, "find_all_symbols_db.yaml");
+ }
+
+ if (!DB) {
+ llvm::errs() << "Couldn't find YAML db: " << DB.getError().message()
+ << '\n';
+ return nullptr;
+ }
+ return std::move(*DB);
+ };
+
+ SymbolIndexMgr->addSymbolIndex(std::move(CreateYamlIdx));
+ break;
+ }
+ case fuzzyYaml: {
+ // This mode is not very useful, because we don't correct the identifier.
+ // It's main purpose is to expose FuzzySymbolIndex to tests.
+ SymbolIndexMgr->addSymbolIndex(
+ []() -> std::unique_ptr<include_fixer::SymbolIndex> {
+ auto DB = include_fixer::FuzzySymbolIndex::createFromYAML(Input);
+ if (!DB) {
+ llvm::errs() << "Couldn't load fuzzy YAML db: "
+ << llvm::toString(DB.takeError()) << '\n';
+ return nullptr;
+ }
+ return std::move(*DB);
+ });
+ break;
+ }
+ }
+ return SymbolIndexMgr;
+}
+
+void writeToJson(llvm::raw_ostream &OS, const IncludeFixerContext& Context) {
+ OS << "{\n"
+ << " \"FilePath\": \""
+ << llvm::yaml::escape(Context.getFilePath()) << "\",\n"
+ << " \"QuerySymbolInfos\": [\n";
+ for (const auto &Info : Context.getQuerySymbolInfos()) {
+ OS << " {\"RawIdentifier\": \"" << Info.RawIdentifier << "\",\n";
+ OS << " \"Range\":{";
+ OS << "\"Offset\":" << Info.Range.getOffset() << ",";
+ OS << "\"Length\":" << Info.Range.getLength() << "}}";
+ if (&Info != &Context.getQuerySymbolInfos().back())
+ OS << ",\n";
+ }
+ OS << "\n ],\n";
+ OS << " \"HeaderInfos\": [\n";
+ const auto &HeaderInfos = Context.getHeaderInfos();
+ for (const auto &Info : HeaderInfos) {
+ OS << " {\"Header\": \"" << llvm::yaml::escape(Info.Header) << "\",\n"
+ << " \"QualifiedName\": \"" << Info.QualifiedName << "\"}";
+ if (&Info != &HeaderInfos.back())
+ OS << ",\n";
+ }
+ OS << "\n";
+ OS << " ]\n";
+ OS << "}\n";
+}
+
+int includeFixerMain(int argc, const char **argv) {
+ tooling::CommonOptionsParser options(argc, argv, IncludeFixerCategory);
+ tooling::ClangTool tool(options.getCompilations(),
+ options.getSourcePathList());
+
+ llvm::StringRef SourceFilePath = options.getSourcePathList().front();
+ // In STDINMode, we override the file content with the <stdin> input.
+ // Since `tool.mapVirtualFile` takes `StringRef`, we define `Code` outside of
+ // the if-block so that `Code` is not released after the if-block.
+ std::unique_ptr<llvm::MemoryBuffer> Code;
+ if (STDINMode) {
+ assert(options.getSourcePathList().size() == 1 &&
+ "Expect exactly one file path in STDINMode.");
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> CodeOrErr =
+ MemoryBuffer::getSTDIN();
+ if (std::error_code EC = CodeOrErr.getError()) {
+ errs() << EC.message() << "\n";
+ return 1;
+ }
+ Code = std::move(CodeOrErr.get());
+ if (Code->getBufferSize() == 0)
+ return 0; // Skip empty files.
+
+ tool.mapVirtualFile(SourceFilePath, Code->getBuffer());
+ }
+
+ if (!InsertHeader.empty()) {
+ if (!STDINMode) {
+ errs() << "Should be running in STDIN mode\n";
+ return 1;
+ }
+
+ llvm::yaml::Input yin(InsertHeader);
+ IncludeFixerContext Context;
+ yin >> Context;
+
+ const auto &HeaderInfos = Context.getHeaderInfos();
+ assert(!HeaderInfos.empty());
+ // We only accept one unique header.
+ // Check all elements in HeaderInfos have the same header.
+ bool IsUniqueHeader = std::equal(
+ HeaderInfos.begin()+1, HeaderInfos.end(), HeaderInfos.begin(),
+ [](const IncludeFixerContext::HeaderInfo &LHS,
+ const IncludeFixerContext::HeaderInfo &RHS) {
+ return LHS.Header == RHS.Header;
+ });
+ if (!IsUniqueHeader) {
+ errs() << "Expect exactly one unique header.\n";
+ return 1;
+ }
+
+ // If a header has multiple symbols, we won't add the missing namespace
+ // qualifiers because we don't know which one is exactly used.
+ //
+ // Check whether all elements in HeaderInfos have the same qualified name.
+ bool IsUniqueQualifiedName = std::equal(
+ HeaderInfos.begin() + 1, HeaderInfos.end(), HeaderInfos.begin(),
+ [](const IncludeFixerContext::HeaderInfo &LHS,
+ const IncludeFixerContext::HeaderInfo &RHS) {
+ return LHS.QualifiedName == RHS.QualifiedName;
+ });
+ auto InsertStyle = format::getStyle(format::DefaultFormatStyle,
+ Context.getFilePath(), Style);
+ if (!InsertStyle) {
+ llvm::errs() << llvm::toString(InsertStyle.takeError()) << "\n";
+ return 1;
+ }
+ auto Replacements = clang::include_fixer::createIncludeFixerReplacements(
+ Code->getBuffer(), Context, *InsertStyle,
+ /*AddQualifiers=*/IsUniqueQualifiedName);
+ if (!Replacements) {
+ errs() << "Failed to create replacements: "
+ << llvm::toString(Replacements.takeError()) << "\n";
+ return 1;
+ }
+
+ auto ChangedCode =
+ tooling::applyAllReplacements(Code->getBuffer(), *Replacements);
+ if (!ChangedCode) {
+ llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n";
+ return 1;
+ }
+ llvm::outs() << *ChangedCode;
+ return 0;
+ }
+
+ // Set up data source.
+ std::unique_ptr<include_fixer::SymbolIndexManager> SymbolIndexMgr =
+ createSymbolIndexManager(SourceFilePath);
+ if (!SymbolIndexMgr)
+ return 1;
+
+ // Query symbol mode.
+ if (!QuerySymbol.empty()) {
+ auto MatchedSymbols = SymbolIndexMgr->search(
+ QuerySymbol, /*IsNestedSearch=*/true, SourceFilePath);
+ for (auto &Symbol : MatchedSymbols) {
+ std::string HeaderPath = Symbol.getFilePath().str();
+ Symbol.SetFilePath(((HeaderPath[0] == '"' || HeaderPath[0] == '<')
+ ? HeaderPath
+ : "\"" + HeaderPath + "\""));
+ }
+
+ // We leave an empty symbol range as we don't know the range of the symbol
+ // being queried in this mode. clang-include-fixer won't add namespace
+ // qualifiers if the symbol range is empty, which also fits this case.
+ IncludeFixerContext::QuerySymbolInfo Symbol;
+ Symbol.RawIdentifier = QuerySymbol;
+ auto Context =
+ IncludeFixerContext(SourceFilePath, {Symbol}, MatchedSymbols);
+ writeToJson(llvm::outs(), Context);
+ return 0;
+ }
+
+ // Now run our tool.
+ std::vector<include_fixer::IncludeFixerContext> Contexts;
+ include_fixer::IncludeFixerActionFactory Factory(*SymbolIndexMgr, Contexts,
+ Style, MinimizeIncludePaths);
+
+ if (tool.run(&Factory) != 0) {
+ // We suppress all Clang diagnostics (because they would be wrong,
+ // clang-include-fixer does custom recovery) but still want to give some
+ // feedback in case there was a compiler error we couldn't recover from.
+ // The most common case for this is a #include in the file that couldn't be
+ // found.
+ llvm::errs() << "Fatal compiler error occurred while parsing file!"
+ " (incorrect include paths?)\n";
+ return 1;
+ }
+
+ assert(!Contexts.empty());
+
+ if (OutputHeaders) {
+ // FIXME: Print contexts of all processing files instead of the first one.
+ writeToJson(llvm::outs(), Contexts.front());
+ return 0;
+ }
+
+ std::vector<tooling::Replacements> FixerReplacements;
+ for (const auto &Context : Contexts) {
+ StringRef FilePath = Context.getFilePath();
+ auto InsertStyle =
+ format::getStyle(format::DefaultFormatStyle, FilePath, Style);
+ if (!InsertStyle) {
+ llvm::errs() << llvm::toString(InsertStyle.takeError()) << "\n";
+ return 1;
+ }
+ auto Buffer = llvm::MemoryBuffer::getFile(FilePath);
+ if (!Buffer) {
+ errs() << "Couldn't open file: " + FilePath.str() + ": "
+ << Buffer.getError().message() + "\n";
+ return 1;
+ }
+
+ auto Replacements = clang::include_fixer::createIncludeFixerReplacements(
+ Buffer.get()->getBuffer(), Context, *InsertStyle);
+ if (!Replacements) {
+ errs() << "Failed to create replacement: "
+ << llvm::toString(Replacements.takeError()) << "\n";
+ return 1;
+ }
+ FixerReplacements.push_back(*Replacements);
+ }
+
+ if (!Quiet) {
+ for (const auto &Context : Contexts) {
+ if (!Context.getHeaderInfos().empty()) {
+ llvm::errs() << "Added #include "
+ << Context.getHeaderInfos().front().Header << " for "
+ << Context.getFilePath() << "\n";
+ }
+ }
+ }
+
+ if (STDINMode) {
+ assert(FixerReplacements.size() == 1);
+ auto ChangedCode = tooling::applyAllReplacements(Code->getBuffer(),
+ FixerReplacements.front());
+ if (!ChangedCode) {
+ llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n";
+ return 1;
+ }
+ llvm::outs() << *ChangedCode;
+ return 0;
+ }
+
+ // Set up a new source manager for applying the resulting replacements.
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions);
+ DiagnosticsEngine Diagnostics(new DiagnosticIDs, &*DiagOpts);
+ TextDiagnosticPrinter DiagnosticPrinter(outs(), &*DiagOpts);
+ SourceManager SM(Diagnostics, tool.getFiles());
+ Diagnostics.setClient(&DiagnosticPrinter, false);
+
+ // Write replacements to disk.
+ Rewriter Rewrites(SM, LangOptions());
+ for (const auto &Replacement : FixerReplacements) {
+ if (!tooling::applyAllReplacements(Replacement, Rewrites)) {
+ llvm::errs() << "Failed to apply replacements.\n";
+ return 1;
+ }
+ }
+ return Rewrites.overwriteChangedFiles();
+}
+
+} // namespace
+
+int main(int argc, const char **argv) {
+ return includeFixerMain(argc, argv);
+}
Added: clang-tools-extra/trunk/clang-include-fixer/tool/clang-include-fixer-test.el
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/tool/clang-include-fixer-test.el?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/tool/clang-include-fixer-test.el (added)
+++ clang-tools-extra/trunk/clang-include-fixer/tool/clang-include-fixer-test.el Mon Mar 25 07:09:10 2019
@@ -0,0 +1,65 @@
+;;; clang-include-fixer-test.el --- unit tests for clang-include-fixer.el -*- lexical-binding: t; -*-
+
+;;; Commentary:
+
+;; Unit tests for clang-include-fixer.el.
+
+;;; Code:
+
+(require 'clang-include-fixer)
+
+(require 'cc-mode)
+(require 'ert)
+
+(ert-deftest clang-include-fixer--insert-line ()
+ "Unit test for `clang-include-fixer--insert-line'."
+ (with-temp-buffer
+ (insert "aa\nab\nac\nad\n")
+ (let ((from (current-buffer)))
+ (with-temp-buffer
+ (insert "aa\nac\nad\n")
+ (let ((to (current-buffer)))
+ (should (clang-include-fixer--insert-line from to))
+ (should (equal (buffer-string) "aa\nab\nac\nad\n")))))
+ (should (equal (buffer-string) "aa\nab\nac\nad\n"))))
+
+(ert-deftest clang-include-fixer--insert-line-diff-on-empty-line ()
+ "Unit test for `clang-include-fixer--insert-line'."
+ (with-temp-buffer
+ (insert "aa\nab\n\nac\nad\n")
+ (let ((from (current-buffer)))
+ (with-temp-buffer
+ (insert "aa\n\nac\nad\n")
+ (let ((to (current-buffer)))
+ (should (clang-include-fixer--insert-line from to))
+ (should (equal (buffer-string) "aa\nab\n\nac\nad\n")))))
+ (should (equal (buffer-string) "aa\nab\n\nac\nad\n"))))
+
+(ert-deftest clang-include-fixer--symbol-at-point ()
+ "Unit test for `clang-include-fixer--symbol-at-point'."
+ (with-temp-buffer
+ (insert "a+bbb::cc")
+ (c++-mode)
+ (goto-char (point-min))
+ (should (equal (clang-include-fixer--symbol-at-point) "a"))
+ (forward-char)
+ ;; Emacs treats the character immediately following a symbol as part of the
+ ;; symbol.
+ (should (equal (clang-include-fixer--symbol-at-point) "a"))
+ (forward-char)
+ (should (equal (clang-include-fixer--symbol-at-point) "bbb::cc"))
+ (goto-char (point-max))
+ (should (equal (clang-include-fixer--symbol-at-point) "bbb::cc"))))
+
+(ert-deftest clang-include-fixer--highlight ()
+ (with-temp-buffer
+ (insert "util::Status foo;\n")
+ (setq buffer-file-coding-system 'utf-8-unix)
+ (should (equal nil (clang-include-fixer--highlight
+ '((Range . ((Offset . 0) (Length . 0)))))))
+ (let ((overlay (clang-include-fixer--highlight
+ '((Range . ((Offset . 1) (Length . 12)))))))
+ (should (equal 2 (overlay-start overlay)))
+ (should (equal 14 (overlay-end overlay))))))
+
+;;; clang-include-fixer-test.el ends here
Added: clang-tools-extra/trunk/clang-include-fixer/tool/clang-include-fixer.el
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/tool/clang-include-fixer.el?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/tool/clang-include-fixer.el (added)
+++ clang-tools-extra/trunk/clang-include-fixer/tool/clang-include-fixer.el Mon Mar 25 07:09:10 2019
@@ -0,0 +1,460 @@
+;;; clang-include-fixer.el --- Emacs integration of the clang include fixer -*- lexical-binding: t; -*-
+
+;; Keywords: tools, c
+;; Package-Requires: ((cl-lib "0.5") (json "1.2") (let-alist "1.0.4"))
+
+;;; Commentary:
+
+;; This package allows Emacs users to invoke the 'clang-include-fixer' within
+;; Emacs. 'clang-include-fixer' provides an automated way of adding #include
+;; directives for missing symbols in one translation unit, see
+;; <http://clang.llvm.org/extra/clang-include-fixer.html>.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'json)
+(require 'let-alist)
+
+(defgroup clang-include-fixer nil
+ "Clang-based include fixer."
+ :group 'tools)
+
+(defvar clang-include-fixer-add-include-hook nil
+ "A hook that will be called for every added include.
+The first argument is the filename of the include, the second argument is
+non-nil if the include is a system-header.")
+
+(defcustom clang-include-fixer-executable
+ "clang-include-fixer"
+ "Location of the clang-include-fixer executable.
+
+A string containing the name or the full path of the executable."
+ :group 'clang-include-fixer
+ :type '(file :must-match t)
+ :risky t)
+
+(defcustom clang-include-fixer-input-format
+ 'yaml
+ "Input format for clang-include-fixer.
+This string is passed as -db argument to
+`clang-include-fixer-executable'."
+ :group 'clang-include-fixer
+ :type '(radio
+ (const :tag "Hard-coded mapping" :fixed)
+ (const :tag "YAML" yaml)
+ (symbol :tag "Other"))
+ :risky t)
+
+(defcustom clang-include-fixer-init-string
+ ""
+ "Database initialization string for clang-include-fixer.
+This string is passed as -input argument to
+`clang-include-fixer-executable'."
+ :group 'clang-include-fixer
+ :type 'string
+ :risky t)
+
+(defface clang-include-fixer-highlight '((t :background "green"))
+ "Used for highlighting the symbol for which a header file is being added.")
+
+;;;###autoload
+(defun clang-include-fixer ()
+ "Invoke the Include Fixer to insert missing C++ headers."
+ (interactive)
+ (message (concat "Calling the include fixer. "
+ "This might take some seconds. Please wait."))
+ (clang-include-fixer--start #'clang-include-fixer--add-header
+ "-output-headers"))
+
+;;;###autoload
+(defun clang-include-fixer-at-point ()
+ "Invoke the Clang include fixer for the symbol at point."
+ (interactive)
+ (let ((symbol (clang-include-fixer--symbol-at-point)))
+ (unless symbol
+ (user-error "No symbol at current location"))
+ (clang-include-fixer-from-symbol symbol)))
+
+;;;###autoload
+(defun clang-include-fixer-from-symbol (symbol)
+ "Invoke the Clang include fixer for the SYMBOL.
+When called interactively, prompts the user for a symbol."
+ (interactive
+ (list (read-string "Symbol: " (clang-include-fixer--symbol-at-point))))
+ (clang-include-fixer--start #'clang-include-fixer--add-header
+ (format "-query-symbol=%s" symbol)))
+
+(defun clang-include-fixer--start (callback &rest args)
+ "Asynchronously start clang-include-fixer with parameters ARGS.
+The current file name is passed after ARGS as last argument. If
+the call was successful the returned result is stored in a
+temporary buffer, and CALLBACK is called with the temporary
+buffer as only argument."
+ (unless buffer-file-name
+ (user-error "clang-include-fixer works only in buffers that visit a file"))
+ (let ((process (if (and (fboundp 'make-process)
+ ;; ‘make-process’ doesn’t support remote files
+ ;; (https://debbugs.gnu.org/cgi/bugreport.cgi?bug=28691).
+ (not (find-file-name-handler default-directory
+ 'start-file-process)))
+ ;; Prefer using ‘make-process’ if possible, because
+ ;; ‘start-process’ doesn’t allow us to separate the
+ ;; standard error from the output.
+ (clang-include-fixer--make-process callback args)
+ (clang-include-fixer--start-process callback args))))
+ (save-restriction
+ (widen)
+ (process-send-region process (point-min) (point-max)))
+ (process-send-eof process))
+ nil)
+
+(defun clang-include-fixer--make-process (callback args)
+ "Start a new clang-incude-fixer process using `make-process'.
+CALLBACK is called after the process finishes successfully; it is
+called with a single argument, the buffer where standard output
+has been inserted. ARGS is a list of additional command line
+arguments. Return the new process object."
+ (let ((stdin (current-buffer))
+ (stdout (generate-new-buffer "*clang-include-fixer output*"))
+ (stderr (generate-new-buffer "*clang-include-fixer errors*")))
+ (make-process :name "clang-include-fixer"
+ :buffer stdout
+ :command (clang-include-fixer--command args)
+ :coding 'utf-8-unix
+ :noquery t
+ :connection-type 'pipe
+ :sentinel (clang-include-fixer--sentinel stdin stdout stderr
+ callback)
+ :stderr stderr)))
+
+(defun clang-include-fixer--start-process (callback args)
+ "Start a new clang-incude-fixer process using `start-file-process'.
+CALLBACK is called after the process finishes successfully; it is
+called with a single argument, the buffer where standard output
+has been inserted. ARGS is a list of additional command line
+arguments. Return the new process object."
+ (let* ((stdin (current-buffer))
+ (stdout (generate-new-buffer "*clang-include-fixer output*"))
+ (process-connection-type nil)
+ (process (apply #'start-file-process "clang-include-fixer" stdout
+ (clang-include-fixer--command args))))
+ (set-process-coding-system process 'utf-8-unix 'utf-8-unix)
+ (set-process-query-on-exit-flag process nil)
+ (set-process-sentinel process
+ (clang-include-fixer--sentinel stdin stdout nil
+ callback))
+ process))
+
+(defun clang-include-fixer--command (args)
+ "Return the clang-include-fixer command line.
+Returns a list; the first element is the binary to
+execute (`clang-include-fixer-executable'), and the remaining
+elements are the command line arguments. Adds proper arguments
+for `clang-include-fixer-input-format' and
+`clang-include-fixer-init-string'. Appends the current buffer's
+file name; prepends ARGS directly in front of it."
+ (cl-check-type args list)
+ `(,clang-include-fixer-executable
+ ,(format "-db=%s" clang-include-fixer-input-format)
+ ,(format "-input=%s" clang-include-fixer-init-string)
+ "-stdin"
+ , at args
+ ,(clang-include-fixer--file-local-name buffer-file-name)))
+
+(defun clang-include-fixer--sentinel (stdin stdout stderr callback)
+ "Return a process sentinel for clang-include-fixer processes.
+STDIN, STDOUT, and STDERR are buffers for the standard streams;
+only STDERR may be nil. CALLBACK is called in the case of
+success; it is called with a single argument, STDOUT. On
+failure, a buffer containing the error output is displayed."
+ (cl-check-type stdin buffer-live)
+ (cl-check-type stdout buffer-live)
+ (cl-check-type stderr (or null buffer-live))
+ (cl-check-type callback function)
+ (lambda (process event)
+ (cl-check-type process process)
+ (cl-check-type event string)
+ (unwind-protect
+ (if (string-equal event "finished\n")
+ (progn
+ (when stderr (kill-buffer stderr))
+ (with-current-buffer stdin
+ (funcall callback stdout))
+ (kill-buffer stdout))
+ (when stderr (kill-buffer stdout))
+ (message "clang-include-fixer failed")
+ (with-current-buffer (or stderr stdout)
+ (insert "\nProcess " (process-name process)
+ ?\s event))
+ (display-buffer (or stderr stdout))))
+ nil))
+
+(defun clang-include-fixer--replace-buffer (stdout)
+ "Replace current buffer by content of STDOUT."
+ (cl-check-type stdout buffer-live)
+ (barf-if-buffer-read-only)
+ (cond ((fboundp 'replace-buffer-contents) (replace-buffer-contents stdout))
+ ((clang-include-fixer--insert-line stdout (current-buffer)))
+ (t (erase-buffer) (insert-buffer-substring stdout)))
+ (message "Fix applied")
+ nil)
+
+(defun clang-include-fixer--insert-line (from to)
+ "Insert a single missing line from the buffer FROM into TO.
+FROM and TO must be buffers. If the contents of FROM and TO are
+equal, do nothing and return non-nil. If FROM contains a single
+line missing from TO, insert that line into TO so that the buffer
+contents are equal and return non-nil. Otherwise, do nothing and
+return nil. Buffer restrictions are ignored."
+ (cl-check-type from buffer-live)
+ (cl-check-type to buffer-live)
+ (with-current-buffer from
+ (save-excursion
+ (save-restriction
+ (widen)
+ (with-current-buffer to
+ (save-excursion
+ (save-restriction
+ (widen)
+ ;; Search for the first buffer difference.
+ (let ((chars (abs (compare-buffer-substrings to nil nil from nil nil))))
+ (if (zerop chars)
+ ;; Buffer contents are equal, nothing to do.
+ t
+ (goto-char chars)
+ ;; We might have ended up in the middle of a line if the
+ ;; current line partially matches. In this case we would
+ ;; have to insert more than a line. Move to the beginning of
+ ;; the line to avoid this situation.
+ (beginning-of-line)
+ (with-current-buffer from
+ (goto-char chars)
+ (beginning-of-line)
+ (let ((from-begin (point))
+ (from-end (progn (forward-line) (point)))
+ (to-point (with-current-buffer to (point))))
+ ;; Search for another buffer difference after the line in
+ ;; question. If there is none, we can proceed.
+ (when (zerop (compare-buffer-substrings from from-end nil
+ to to-point nil))
+ (with-current-buffer to
+ (insert-buffer-substring from from-begin from-end))
+ t))))))))))))
+
+(defun clang-include-fixer--add-header (stdout)
+ "Analyse the result of clang-include-fixer stored in STDOUT.
+Add a missing header if there is any. If there are multiple
+possible headers the user can select one of them to be included.
+Temporarily highlight the affected symbols. Asynchronously call
+clang-include-fixer to insert the selected header."
+ (cl-check-type stdout buffer-live)
+ (let ((context (clang-include-fixer--parse-json stdout)))
+ (let-alist context
+ (cond
+ ((null .QuerySymbolInfos)
+ (message "The file is fine, no need to add a header."))
+ ((null .HeaderInfos)
+ (message "Couldn't find header for '%s'"
+ (let-alist (car .QuerySymbolInfos) .RawIdentifier)))
+ (t
+ ;; Users may C-g in prompts, make sure the process sentinel
+ ;; behaves correctly.
+ (with-local-quit
+ ;; Replace the HeaderInfos list by a single header selected by
+ ;; the user.
+ (clang-include-fixer--select-header context)
+ ;; Call clang-include-fixer again to insert the selected header.
+ (clang-include-fixer--start
+ (let ((old-tick (buffer-chars-modified-tick)))
+ (lambda (stdout)
+ (when (/= old-tick (buffer-chars-modified-tick))
+ ;; Replacing the buffer now would undo the user’s changes.
+ (user-error (concat "The buffer has been changed "
+ "before the header could be inserted")))
+ (clang-include-fixer--replace-buffer stdout)
+ (let-alist context
+ (let-alist (car .HeaderInfos)
+ (with-local-quit
+ (run-hook-with-args 'clang-include-fixer-add-include-hook
+ (substring .Header 1 -1)
+ (string= (substring .Header 0 1) "<")))))))
+ (format "-insert-header=%s"
+ (clang-include-fixer--encode-json context))))))))
+ nil)
+
+(defun clang-include-fixer--select-header (context)
+ "Prompt the user for a header if necessary.
+CONTEXT must be a clang-include-fixer context object in
+association list format. If it contains more than one HeaderInfo
+element, prompt the user to select one of the headers. CONTEXT
+is modified to include only the selected element."
+ (cl-check-type context cons)
+ (let-alist context
+ (if (cdr .HeaderInfos)
+ (clang-include-fixer--prompt-for-header context)
+ (message "Only one include is missing: %s"
+ (let-alist (car .HeaderInfos) .Header))))
+ nil)
+
+(defvar clang-include-fixer--history nil
+ "History for `clang-include-fixer--prompt-for-header'.")
+
+(defun clang-include-fixer--prompt-for-header (context)
+ "Prompt the user for a single header.
+The choices are taken from the HeaderInfo elements in CONTEXT.
+They are replaced by the single element selected by the user."
+ (let-alist context
+ (let ((symbol (clang-include-fixer--symbol-name .QuerySymbolInfos))
+ ;; Add temporary highlighting so that the user knows which
+ ;; symbols the current session is about.
+ (overlays (remove nil
+ (mapcar #'clang-include-fixer--highlight .QuerySymbolInfos))))
+ (unwind-protect
+ (save-excursion
+ ;; While prompting, go to the closest overlay so that the user sees
+ ;; some context.
+ (when overlays
+ (goto-char (clang-include-fixer--closest-overlay overlays)))
+ (cl-flet ((header (info) (let-alist info .Header)))
+ ;; The header-infos is already sorted by clang-include-fixer.
+ (let* ((headers (mapcar #'header .HeaderInfos))
+ (header (completing-read
+ (clang-include-fixer--format-message
+ "Select include for '%s': " symbol)
+ headers nil :require-match nil
+ 'clang-include-fixer--history
+ ;; Specify a default to prevent the behavior
+ ;; described in
+ ;; https://github.com/DarwinAwardWinner/ido-completing-read-plus#why-does-ret-sometimes-not-select-the-first-completion-on-the-list--why-is-there-an-empty-entry-at-the-beginning-of-the-completion-list--what-happened-to-old-style-default-selection.
+ (car headers)))
+ (info (cl-find header .HeaderInfos :key #'header :test #'string=)))
+ (unless info (user-error "No header selected"))
+ (setcar .HeaderInfos info)
+ (setcdr .HeaderInfos nil))))
+ (mapc #'delete-overlay overlays)))))
+
+(defun clang-include-fixer--symbol-name (symbol-infos)
+ "Return the unique symbol name in SYMBOL-INFOS.
+Raise a signal if the symbol name is not unique."
+ (let ((symbols (delete-dups (mapcar (lambda (info)
+ (let-alist info .RawIdentifier))
+ symbol-infos))))
+ (when (cdr symbols)
+ (error "Multiple symbols %s returned" symbols))
+ (car symbols)))
+
+(defun clang-include-fixer--highlight (symbol-info)
+ "Add an overlay to highlight SYMBOL-INFO, if it points to a non-empty range.
+Return the overlay object, or nil."
+ (let-alist symbol-info
+ (unless (zerop .Range.Length)
+ (let ((overlay (make-overlay
+ (clang-include-fixer--filepos-to-bufferpos
+ .Range.Offset 'approximate)
+ (clang-include-fixer--filepos-to-bufferpos
+ (+ .Range.Offset .Range.Length) 'approximate))))
+ (overlay-put overlay 'face 'clang-include-fixer-highlight)
+ overlay))))
+
+(defun clang-include-fixer--closest-overlay (overlays)
+ "Return the start of the overlay in OVERLAYS that is closest to point."
+ (cl-check-type overlays cons)
+ (let ((point (point))
+ acc)
+ (dolist (overlay overlays acc)
+ (let ((start (overlay-start overlay)))
+ (when (or (null acc) (< (abs (- point start)) (abs (- point acc))))
+ (setq acc start))))))
+
+(defun clang-include-fixer--parse-json (buffer)
+ "Parse a JSON response from clang-include-fixer in BUFFER.
+Return the JSON object as an association list."
+ (with-current-buffer buffer
+ (save-excursion
+ (goto-char (point-min))
+ (let ((json-object-type 'alist)
+ (json-array-type 'list)
+ (json-key-type 'symbol)
+ (json-false :json-false)
+ (json-null nil)
+ (json-pre-element-read-function nil)
+ (json-post-element-read-function nil))
+ (json-read)))))
+
+(defun clang-include-fixer--encode-json (object)
+ "Return the JSON representation of OBJECT as a string."
+ (let ((json-encoding-separator ",")
+ (json-encoding-default-indentation " ")
+ (json-encoding-pretty-print nil)
+ (json-encoding-lisp-style-closings nil)
+ (json-encoding-object-sort-predicate nil))
+ (json-encode object)))
+
+(defun clang-include-fixer--symbol-at-point ()
+ "Return the qualified symbol at point.
+If there is no symbol at point, return nil."
+ ;; Let ‘bounds-of-thing-at-point’ to do the hard work and deal with edge
+ ;; cases.
+ (let ((bounds (bounds-of-thing-at-point 'symbol)))
+ (when bounds
+ (let ((beg (car bounds))
+ (end (cdr bounds)))
+ (save-excursion
+ ;; Extend the symbol range to the left. Skip over namespace
+ ;; delimiters and parent namespace names.
+ (goto-char beg)
+ (while (and (clang-include-fixer--skip-double-colon-backward)
+ (skip-syntax-backward "w_")))
+ ;; Skip over one more namespace delimiter, for absolute names.
+ (clang-include-fixer--skip-double-colon-backward)
+ (setq beg (point))
+ ;; Extend the symbol range to the right. Skip over namespace
+ ;; delimiters and child namespace names.
+ (goto-char end)
+ (while (and (clang-include-fixer--skip-double-colon-forward)
+ (skip-syntax-forward "w_")))
+ (setq end (point)))
+ (buffer-substring-no-properties beg end)))))
+
+(defun clang-include-fixer--skip-double-colon-forward ()
+ "Skip a double colon.
+When the next two characters are '::', skip them and return
+non-nil. Otherwise return nil."
+ (let ((end (+ (point) 2)))
+ (when (and (<= end (point-max))
+ (string-equal (buffer-substring-no-properties (point) end) "::"))
+ (goto-char end)
+ t)))
+
+(defun clang-include-fixer--skip-double-colon-backward ()
+ "Skip a double colon.
+When the previous two characters are '::', skip them and return
+non-nil. Otherwise return nil."
+ (let ((beg (- (point) 2)))
+ (when (and (>= beg (point-min))
+ (string-equal (buffer-substring-no-properties beg (point)) "::"))
+ (goto-char beg)
+ t)))
+
+;; ‘filepos-to-bufferpos’ is new in Emacs 25.1. Provide a fallback for older
+;; versions.
+(defalias 'clang-include-fixer--filepos-to-bufferpos
+ (if (fboundp 'filepos-to-bufferpos)
+ 'filepos-to-bufferpos
+ (lambda (byte &optional _quality _coding-system)
+ (byte-to-position (1+ byte)))))
+
+;; ‘format-message’ is new in Emacs 25.1. Provide a fallback for older
+;; versions.
+(defalias 'clang-include-fixer--format-message
+ (if (fboundp 'format-message) 'format-message 'format))
+
+;; ‘file-local-name’ is new in Emacs 26.1. Provide a fallback for older
+;; versions.
+(defalias 'clang-include-fixer--file-local-name
+ (if (fboundp 'file-local-name) #'file-local-name
+ (lambda (file) (or (file-remote-p file 'localname) file))))
+
+(provide 'clang-include-fixer)
+;;; clang-include-fixer.el ends here
Added: clang-tools-extra/trunk/clang-include-fixer/tool/clang-include-fixer.py
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-include-fixer/tool/clang-include-fixer.py?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-include-fixer/tool/clang-include-fixer.py (added)
+++ clang-tools-extra/trunk/clang-include-fixer/tool/clang-include-fixer.py Mon Mar 25 07:09:10 2019
@@ -0,0 +1,210 @@
+# This file is a minimal clang-include-fixer vim-integration. To install:
+# - Change 'binary' if clang-include-fixer is not on the path (see below).
+# - Add to your .vimrc:
+#
+# noremap <leader>cf :pyf path/to/llvm/source/tools/clang/tools/extra/clang-include-fixer/tool/clang-include-fixer.py<cr>
+#
+# This enables clang-include-fixer for NORMAL and VISUAL mode. Change
+# "<leader>cf" to another binding if you need clang-include-fixer on a
+# different key.
+#
+# To set up clang-include-fixer, see
+# http://clang.llvm.org/extra/clang-include-fixer.html
+#
+# With this integration you can press the bound key and clang-include-fixer will
+# be run on the current buffer.
+#
+# It operates on the current, potentially unsaved buffer and does not create
+# or save any files. To revert a fix, just undo.
+
+import argparse
+import difflib
+import json
+import re
+import subprocess
+import vim
+
+# set g:clang_include_fixer_path to the path to clang-include-fixer if it is not
+# on the path.
+# Change this to the full path if clang-include-fixer is not on the path.
+binary = 'clang-include-fixer'
+if vim.eval('exists("g:clang_include_fixer_path")') == "1":
+ binary = vim.eval('g:clang_include_fixer_path')
+
+maximum_suggested_headers = 3
+if vim.eval('exists("g:clang_include_fixer_maximum_suggested_headers")') == "1":
+ maximum_suggested_headers = max(
+ 1,
+ vim.eval('g:clang_include_fixer_maximum_suggested_headers'))
+
+increment_num = 5
+if vim.eval('exists("g:clang_include_fixer_increment_num")') == "1":
+ increment_num = max(
+ 1,
+ vim.eval('g:clang_include_fixer_increment_num'))
+
+jump_to_include = False
+if vim.eval('exists("g:clang_include_fixer_jump_to_include")') == "1":
+ jump_to_include = vim.eval('g:clang_include_fixer_jump_to_include') != "0"
+
+query_mode = False
+if vim.eval('exists("g:clang_include_fixer_query_mode")') == "1":
+ query_mode = vim.eval('g:clang_include_fixer_query_mode') != "0"
+
+
+def GetUserSelection(message, headers, maximum_suggested_headers):
+ eval_message = message + '\n'
+ for idx, header in enumerate(headers[0:maximum_suggested_headers]):
+ eval_message += "({0}). {1}\n".format(idx + 1, header)
+ eval_message += "Enter (q) to quit;"
+ if maximum_suggested_headers < len(headers):
+ eval_message += " (m) to show {0} more candidates.".format(
+ min(increment_num, len(headers) - maximum_suggested_headers))
+
+ eval_message += "\nSelect (default 1): "
+ res = vim.eval("input('{0}')".format(eval_message))
+ if res == '':
+ # choose the top ranked header by default
+ idx = 1
+ elif res == 'q':
+ raise Exception(' Insertion cancelled...')
+ elif res == 'm':
+ return GetUserSelection(message,
+ headers, maximum_suggested_headers + increment_num)
+ else:
+ try:
+ idx = int(res)
+ if idx <= 0 or idx > len(headers):
+ raise Exception()
+ except Exception:
+ # Show a new prompt on invalid option instead of aborting so that users
+ # don't need to wait for another clang-include-fixer run.
+ print >> sys.stderr, "Invalid option:", res
+ return GetUserSelection(message, headers, maximum_suggested_headers)
+ return headers[idx - 1]
+
+
+def execute(command, text):
+ p = subprocess.Popen(command,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ stdin=subprocess.PIPE)
+ return p.communicate(input=text)
+
+
+def InsertHeaderToVimBuffer(header, text):
+ command = [binary, "-stdin", "-insert-header=" + json.dumps(header),
+ vim.current.buffer.name]
+ stdout, stderr = execute(command, text)
+ if stderr:
+ raise Exception(stderr)
+ if stdout:
+ lines = stdout.splitlines()
+ sequence = difflib.SequenceMatcher(None, vim.current.buffer, lines)
+ line_num = None
+ for op in reversed(sequence.get_opcodes()):
+ if op[0] != 'equal':
+ vim.current.buffer[op[1]:op[2]] = lines[op[3]:op[4]]
+ if op[0] == 'insert':
+ # line_num in vim is 1-based.
+ line_num = op[1] + 1
+
+ if jump_to_include and line_num:
+ vim.current.window.cursor = (line_num, 0)
+
+
+# The vim internal implementation (expand("cword"/"cWORD")) doesn't support
+# our use case very well, we re-implement our own one.
+def get_symbol_under_cursor():
+ line = vim.eval("line(\".\")")
+ # column number in vim is 1-based.
+ col = int(vim.eval("col(\".\")")) - 1
+ line_text = vim.eval("getline({0})".format(line))
+ if len(line_text) == 0: return ""
+ symbol_pos_begin = col
+ p = re.compile('[a-zA-Z0-9:_]')
+ while symbol_pos_begin >= 0 and p.match(line_text[symbol_pos_begin]):
+ symbol_pos_begin -= 1
+
+ symbol_pos_end = col
+ while symbol_pos_end < len(line_text) and p.match(line_text[symbol_pos_end]):
+ symbol_pos_end += 1
+ return line_text[symbol_pos_begin+1:symbol_pos_end]
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description='Vim integration for clang-include-fixer')
+ parser.add_argument('-db', default='yaml',
+ help='clang-include-fixer input format.')
+ parser.add_argument('-input', default='',
+ help='String to initialize the database.')
+ # Don't throw exception when parsing unknown arguements to make the script
+ # work in neovim.
+ # Neovim (at least v0.2.1) somehow mangles the sys.argv in a weird way: it
+ # will pass additional arguments (e.g. "-c script_host.py") to sys.argv,
+ # which makes the script fail.
+ args, _ = parser.parse_known_args()
+
+ # Get the current text.
+ buf = vim.current.buffer
+ text = '\n'.join(buf)
+
+ if query_mode:
+ symbol = get_symbol_under_cursor()
+ if len(symbol) == 0:
+ print "Skip querying empty symbol."
+ return
+ command = [binary, "-stdin", "-query-symbol="+get_symbol_under_cursor(),
+ "-db=" + args.db, "-input=" + args.input,
+ vim.current.buffer.name]
+ else:
+ # Run command to get all headers.
+ command = [binary, "-stdin", "-output-headers", "-db=" + args.db,
+ "-input=" + args.input, vim.current.buffer.name]
+ stdout, stderr = execute(command, text)
+ if stderr:
+ print >> sys.stderr, "Error while running clang-include-fixer: " + stderr
+ return
+
+ include_fixer_context = json.loads(stdout)
+ query_symbol_infos = include_fixer_context["QuerySymbolInfos"]
+ if not query_symbol_infos:
+ print "The file is fine, no need to add a header."
+ return
+ symbol = query_symbol_infos[0]["RawIdentifier"]
+ # The header_infos is already sorted by clang-include-fixer.
+ header_infos = include_fixer_context["HeaderInfos"]
+ # Deduplicate headers while keeping the order, so that the same header would
+ # not be suggested twice.
+ unique_headers = []
+ seen = set()
+ for header_info in header_infos:
+ header = header_info["Header"]
+ if header not in seen:
+ seen.add(header)
+ unique_headers.append(header)
+
+ if not unique_headers:
+ print "Couldn't find a header for {0}.".format(symbol)
+ return
+
+ try:
+ selected = unique_headers[0]
+ inserted_header_infos = header_infos
+ if len(unique_headers) > 1:
+ selected = GetUserSelection(
+ "choose a header file for {0}.".format(symbol),
+ unique_headers, maximum_suggested_headers)
+ inserted_header_infos = [
+ header for header in header_infos if header["Header"] == selected]
+ include_fixer_context["HeaderInfos"] = inserted_header_infos
+
+ InsertHeaderToVimBuffer(include_fixer_context, text)
+ print "Added #include {0} for {1}.".format(selected, symbol)
+ except Exception as error:
+ print >> sys.stderr, error.message
+ return
+
+
+if __name__ == '__main__':
+ main()
Modified: clang-tools-extra/trunk/clang-move/Move.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/Move.cpp?rev=356897&r1=356896&r2=356897&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-move/Move.cpp (original)
+++ clang-tools-extra/trunk/clang-move/Move.cpp Mon Mar 25 07:09:10 2019
@@ -765,7 +765,7 @@ void ClangMoveTool::removeDeclsInOldFile
if (Context->Spec.OldDependOnNew &&
MakeAbsolutePath(SM, FilePath) ==
makeAbsolutePath(Context->Spec.OldHeader)) {
- // FIXME: Minimize the include path like include-fixer.
+ // FIXME: Minimize the include path like clang-include-fixer.
std::string IncludeNewH =
"#include \"" + Context->Spec.NewHeader + "\"\n";
// This replacment for inserting header will be cleaned up at the end.
Modified: clang-tools-extra/trunk/clang-tidy/add_new_check.py
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/add_new_check.py?rev=356897&r1=356896&r2=356897&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/add_new_check.py (original)
+++ clang-tools-extra/trunk/clang-tidy/add_new_check.py Mon Mar 25 07:09:10 2019
@@ -198,7 +198,7 @@ def add_release_notes(module_path, modul
lines = f.readlines()
lineMatcher = re.compile('Improvements to clang-tidy')
- nextSectionMatcher = re.compile('Improvements to include-fixer')
+ nextSectionMatcher = re.compile('Improvements to clang-include-fixer')
checkerMatcher = re.compile('- New :doc:`(.*)')
print('Updating %s...' % filename)
Modified: clang-tools-extra/trunk/docs/ReleaseNotes.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/ReleaseNotes.rst?rev=356897&r1=356896&r2=356897&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/ReleaseNotes.rst (original)
+++ clang-tools-extra/trunk/docs/ReleaseNotes.rst Mon Mar 25 07:09:10 2019
@@ -143,7 +143,7 @@ Improvements to clang-tidy
but either don't specify it or the clause is specified but with the kind
other than ``none``, and suggests to use the ``default(none)`` clause.
-Improvements to include-fixer
+Improvements to clang-include-fixer
-----------------------------
The improvements are...
Added: clang-tools-extra/trunk/docs/clang-include-fixer.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-include-fixer.rst?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/docs/clang-include-fixer.rst (added)
+++ clang-tools-extra/trunk/docs/clang-include-fixer.rst Mon Mar 25 07:09:10 2019
@@ -0,0 +1,155 @@
+===================
+Clang-Include-Fixer
+===================
+
+.. contents::
+
+One of the major nuisances of C++ compared to other languages is the manual
+management of ``#include`` directives in any file.
+:program:`clang-include-fixer` addresses one aspect of this problem by providing
+an automated way of adding ``#include`` directives for missing symbols in one
+translation unit.
+
+While inserting missing ``#include``, :program:`clang-include-fixer` adds
+missing namespace qualifiers to all instances of an unidentified symbol if
+the symbol is missing some prefix namespace qualifiers.
+
+Setup
+=====
+
+To use :program:`clang-include-fixer` two databases are required. Both can be
+generated with existing tools.
+
+- Compilation database. Contains the compiler commands for any given file in a
+ project and can be generated by CMake, see `How To Setup Tooling For LLVM`_.
+- Symbol index. Contains all symbol information in a project to match a given
+ identifier to a header file.
+
+Ideally both databases (``compile_commands.json`` and
+``find_all_symbols_db.yaml``) are linked into the root of the source tree they
+correspond to. Then the :program:`clang-include-fixer` can automatically pick
+them up if called with a source file from that tree. Note that by default
+``compile_commands.json`` as generated by CMake does not include header files,
+so only implementation files can be handled by tools.
+
+.. _How To Setup Tooling For LLVM: https://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
+
+Creating a Symbol Index From a Compilation Database
+---------------------------------------------------
+
+The include fixer contains :program:`find-all-symbols`, a tool to create a
+symbol database in YAML format from a compilation database by parsing all
+source files listed in it. The following list of commands shows how to set up a
+database for LLVM, any project built by CMake should follow similar steps.
+
+.. code-block:: console
+
+ $ cd path/to/llvm-build
+ $ ninja find-all-symbols // build find-all-symbols tool.
+ $ ninja clang-include-fixer // build clang-include-fixer tool.
+ $ ls compile_commands.json # Make sure compile_commands.json exists.
+ compile_commands.json
+ $ path/to/llvm/source/tools/clang/tools/extra/clang-include-fixer/find-all-symbols/tool/run-find-all-symbols.py
+ ... wait as clang indexes the code base ...
+ $ ln -s $PWD/find_all_symbols_db.yaml path/to/llvm/source/ # Link database into the source tree.
+ $ ln -s $PWD/compile_commands.json path/to/llvm/source/ # Also link compilation database if it's not there already.
+ $ cd path/to/llvm/source
+ $ /path/to/clang-include-fixer -db=yaml path/to/file/with/missing/include.cpp
+ Added #include "foo.h"
+
+Integrate with Vim
+------------------
+To run `clang-include-fixer` on a potentially unsaved buffer in Vim. Add the
+following key binding to your ``.vimrc``:
+
+.. code-block:: console
+
+ noremap <leader>cf :pyf path/to/llvm/source/tools/clang/tools/extra/clang-include-fixer/tool/clang-include-fixer.py<cr>
+
+This enables `clang-include-fixer` for NORMAL and VISUAL mode. Change
+`<leader>cf` to another binding if you need clang-include-fixer on a different
+key. The `<leader> key
+<http://vim.wikia.com/wiki/Mapping_keys_in_Vim_-_Tutorial_(Part_3)#Map_leader>`_
+is a reference to a specific key defined by the mapleader variable and is bound
+to backslash by default.
+
+Make sure vim can find :program:`clang-include-fixer`:
+
+- Add the path to :program:`clang-include-fixer` to the PATH environment variable.
+- Or set ``g:clang_include_fixer_path`` in vimrc: ``let g:clang_include_fixer_path=path/to/clang-include-fixer``
+
+You can customize the number of headers being shown by setting
+``let g:clang_include_fixer_maximum_suggested_headers=5``
+
+Customized settings in `.vimrc`:
+
+- ``let g:clang_include_fixer_path = "clang-include-fixer"``
+
+ Set clang-include-fixer binary file path.
+
+- ``let g:clang_include_fixer_maximum_suggested_headers = 3``
+
+ Set the maximum number of ``#includes`` to show. Default is 3.
+
+- ``let g:clang_include_fixer_increment_num = 5``
+
+ Set the increment number of #includes to show every time when pressing ``m``.
+ Default is 5.
+
+- ``let g:clang_include_fixer_jump_to_include = 0``
+
+ Set to 1 if you want to jump to the new inserted ``#include`` line. Default is
+ 0.
+
+- ``let g:clang_include_fixer_query_mode = 0``
+
+ Set to 1 if you want to insert ``#include`` for the symbol under the cursor.
+ Default is 0. Compared to normal mode, this mode won't parse the source file
+ and only search the sysmbol from database, which is faster than normal mode.
+
+See ``clang-include-fixer.py`` for more details.
+
+Integrate with Emacs
+--------------------
+To run `clang-include-fixer` on a potentially unsaved buffer in Emacs.
+Ensure that Emacs finds ``clang-include-fixer.el`` by adding the directory
+containing the file to the ``load-path`` and requiring the `clang-include-fixer`
+in your ``.emacs``:
+
+.. code-block:: console
+
+ (add-to-list 'load-path "path/to/llvm/source/tools/clang/tools/extra/clang-include-fixer/tool/"
+ (require 'clang-include-fixer)
+
+Within Emacs the tool can be invoked with the command
+``M-x clang-include-fixer``. This will insert the header that defines the
+first undefined symbol; if there is more than one header that would define the
+symbol, the user is prompted to select one.
+
+To include the header that defines the symbol at point, run
+``M-x clang-include-fixer-at-point``.
+
+Make sure Emacs can find :program:`clang-include-fixer`:
+
+- Either add the parent directory of :program:`clang-include-fixer` to the PATH
+ environment variable, or customize the Emacs user option
+ ``clang-include-fixer-executable`` to point to the file name of the program.
+
+How it Works
+============
+
+To get the most information out of Clang at parse time,
+:program:`clang-include-fixer` runs in tandem with the parse and receives
+callbacks from Clang's semantic analysis. In particular it reuses the existing
+support for typo corrections. Whenever Clang tries to correct a potential typo
+it emits a callback to the include fixer which then looks for a corresponding
+file. At this point rich lookup information is still available, which is not
+available in the AST at a later stage.
+
+The identifier that should be typo corrected is then sent to the database, if a
+header file is returned it is added as an include directive at the top of the
+file.
+
+Currently :program:`clang-include-fixer` only inserts a single include at a
+time to avoid getting caught in follow-up errors. If multiple `#include`
+additions are desired the program can be rerun until a fix-point is reached.
Modified: clang-tools-extra/trunk/docs/doxygen.cfg.in
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/doxygen.cfg.in?rev=356897&r1=356896&r2=356897&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/doxygen.cfg.in (original)
+++ clang-tools-extra/trunk/docs/doxygen.cfg.in Mon Mar 25 07:09:10 2019
@@ -752,7 +752,7 @@ INPUT = \
@abs_srcdir@/../clang-reorder-fields \
@abs_srcdir@/../clang-tidy \
@abs_srcdir@/../clangd \
- @abs_srcdir@/../include-fixer \
+ @abs_srcdir@/../clang-include-fixer \
@abs_srcdir@/../modularize \
@abs_srcdir@/../pp-trace \
@abs_srcdir@/../tool-template \
Removed: clang-tools-extra/trunk/docs/include-fixer.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/include-fixer.rst?rev=356896&view=auto
==============================================================================
--- clang-tools-extra/trunk/docs/include-fixer.rst (original)
+++ clang-tools-extra/trunk/docs/include-fixer.rst (removed)
@@ -1,155 +0,0 @@
-===================
-Clang-Include-Fixer
-===================
-
-.. contents::
-
-One of the major nuisances of C++ compared to other languages is the manual
-management of ``#include`` directives in any file.
-:program:`clang-include-fixer` addresses one aspect of this problem by providing
-an automated way of adding ``#include`` directives for missing symbols in one
-translation unit.
-
-While inserting missing ``#include``, :program:`clang-include-fixer` adds
-missing namespace qualifiers to all instances of an unidentified symbol if
-the symbol is missing some prefix namespace qualifiers.
-
-Setup
-=====
-
-To use :program:`clang-include-fixer` two databases are required. Both can be
-generated with existing tools.
-
-- Compilation database. Contains the compiler commands for any given file in a
- project and can be generated by CMake, see `How To Setup Tooling For LLVM`_.
-- Symbol index. Contains all symbol information in a project to match a given
- identifier to a header file.
-
-Ideally both databases (``compile_commands.json`` and
-``find_all_symbols_db.yaml``) are linked into the root of the source tree they
-correspond to. Then the :program:`clang-include-fixer` can automatically pick
-them up if called with a source file from that tree. Note that by default
-``compile_commands.json`` as generated by CMake does not include header files,
-so only implementation files can be handled by tools.
-
-.. _How To Setup Tooling For LLVM: https://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
-
-Creating a Symbol Index From a Compilation Database
----------------------------------------------------
-
-The include fixer contains :program:`find-all-symbols`, a tool to create a
-symbol database in YAML format from a compilation database by parsing all
-source files listed in it. The following list of commands shows how to set up a
-database for LLVM, any project built by CMake should follow similar steps.
-
-.. code-block:: console
-
- $ cd path/to/llvm-build
- $ ninja find-all-symbols // build find-all-symbols tool.
- $ ninja clang-include-fixer // build clang-include-fixer tool.
- $ ls compile_commands.json # Make sure compile_commands.json exists.
- compile_commands.json
- $ path/to/llvm/source/tools/clang/tools/extra/include-fixer/find-all-symbols/tool/run-find-all-symbols.py
- ... wait as clang indexes the code base ...
- $ ln -s $PWD/find_all_symbols_db.yaml path/to/llvm/source/ # Link database into the source tree.
- $ ln -s $PWD/compile_commands.json path/to/llvm/source/ # Also link compilation database if it's not there already.
- $ cd path/to/llvm/source
- $ /path/to/clang-include-fixer -db=yaml path/to/file/with/missing/include.cpp
- Added #include "foo.h"
-
-Integrate with Vim
-------------------
-To run `clang-include-fixer` on a potentially unsaved buffer in Vim. Add the
-following key binding to your ``.vimrc``:
-
-.. code-block:: console
-
- noremap <leader>cf :pyf path/to/llvm/source/tools/clang/tools/extra/include-fixer/tool/clang-include-fixer.py<cr>
-
-This enables `clang-include-fixer` for NORMAL and VISUAL mode. Change
-`<leader>cf` to another binding if you need clang-include-fixer on a different
-key. The `<leader> key
-<http://vim.wikia.com/wiki/Mapping_keys_in_Vim_-_Tutorial_(Part_3)#Map_leader>`_
-is a reference to a specific key defined by the mapleader variable and is bound
-to backslash by default.
-
-Make sure vim can find :program:`clang-include-fixer`:
-
-- Add the path to :program:`clang-include-fixer` to the PATH environment variable.
-- Or set ``g:clang_include_fixer_path`` in vimrc: ``let g:clang_include_fixer_path=path/to/clang-include-fixer``
-
-You can customize the number of headers being shown by setting
-``let g:clang_include_fixer_maximum_suggested_headers=5``
-
-Customized settings in `.vimrc`:
-
-- ``let g:clang_include_fixer_path = "clang-include-fixer"``
-
- Set clang-include-fixer binary file path.
-
-- ``let g:clang_include_fixer_maximum_suggested_headers = 3``
-
- Set the maximum number of ``#includes`` to show. Default is 3.
-
-- ``let g:clang_include_fixer_increment_num = 5``
-
- Set the increment number of #includes to show every time when pressing ``m``.
- Default is 5.
-
-- ``let g:clang_include_fixer_jump_to_include = 0``
-
- Set to 1 if you want to jump to the new inserted ``#include`` line. Default is
- 0.
-
-- ``let g:clang_include_fixer_query_mode = 0``
-
- Set to 1 if you want to insert ``#include`` for the symbol under the cursor.
- Default is 0. Compared to normal mode, this mode won't parse the source file
- and only search the sysmbol from database, which is faster than normal mode.
-
-See ``clang-include-fixer.py`` for more details.
-
-Integrate with Emacs
---------------------
-To run `clang-include-fixer` on a potentially unsaved buffer in Emacs.
-Ensure that Emacs finds ``clang-include-fixer.el`` by adding the directory
-containing the file to the ``load-path`` and requiring the `clang-include-fixer`
-in your ``.emacs``:
-
-.. code-block:: console
-
- (add-to-list 'load-path "path/to/llvm/source/tools/clang/tools/extra/include-fixer/tool/"
- (require 'clang-include-fixer)
-
-Within Emacs the tool can be invoked with the command
-``M-x clang-include-fixer``. This will insert the header that defines the
-first undefined symbol; if there is more than one header that would define the
-symbol, the user is prompted to select one.
-
-To include the header that defines the symbol at point, run
-``M-x clang-include-fixer-at-point``.
-
-Make sure Emacs can find :program:`clang-include-fixer`:
-
-- Either add the parent directory of :program:`clang-include-fixer` to the PATH
- environment variable, or customize the Emacs user option
- ``clang-include-fixer-executable`` to point to the file name of the program.
-
-How it Works
-============
-
-To get the most information out of Clang at parse time,
-:program:`clang-include-fixer` runs in tandem with the parse and receives
-callbacks from Clang's semantic analysis. In particular it reuses the existing
-support for typo corrections. Whenever Clang tries to correct a potential typo
-it emits a callback to the include fixer which then looks for a corresponding
-file. At this point rich lookup information is still available, which is not
-available in the AST at a later stage.
-
-The identifier that should be typo corrected is then sent to the database, if a
-header file is returned it is added as an include directive at the top of the
-file.
-
-Currently :program:`clang-include-fixer` only inserts a single include at a
-time to avoid getting caught in follow-up errors. If multiple `#include`
-additions are desired the program can be rerun until a fix-point is reached.
Modified: clang-tools-extra/trunk/docs/index.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/index.rst?rev=356897&r1=356896&r2=356897&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/index.rst (original)
+++ clang-tools-extra/trunk/docs/index.rst Mon Mar 25 07:09:10 2019
@@ -16,7 +16,7 @@ Contents
:maxdepth: 2
clang-tidy/index
- include-fixer
+ clang-include-fixer
modularize
pp-trace
clang-rename
Added: clang-tools-extra/trunk/test/clang-include-fixer/Inputs/database_template.json
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-include-fixer/Inputs/database_template.json?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-include-fixer/Inputs/database_template.json (added)
+++ clang-tools-extra/trunk/test/clang-include-fixer/Inputs/database_template.json Mon Mar 25 07:09:10 2019
@@ -0,0 +1,7 @@
+[
+{
+ "directory": "test_dir/build",
+ "command": "clang++ -I../include -o bar.o test_dir/src/bar.cpp",
+ "file": "test_dir/src/bar.cpp"
+}
+]
Added: clang-tools-extra/trunk/test/clang-include-fixer/Inputs/fake_yaml_db.yaml
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-include-fixer/Inputs/fake_yaml_db.yaml?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-include-fixer/Inputs/fake_yaml_db.yaml (added)
+++ clang-tools-extra/trunk/test/clang-include-fixer/Inputs/fake_yaml_db.yaml Mon Mar 25 07:09:10 2019
@@ -0,0 +1,71 @@
+---
+Name: foo
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+ - ContextType: Namespace
+ ContextName: b
+FilePath: foo.h
+Type: Class
+Seen: 1
+Used: 0
+---
+Name: foo_bar
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+ - ContextType: Namespace
+ ContextName: b
+FilePath: foobar.h
+Type: Class
+Seen: 0
+Used: 0
+---
+Name: bar
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+ - ContextType: Namespace
+ ContextName: b
+FilePath: ../include/bar.h
+Type: Class
+Seen: 1
+Used: 0
+---
+Name: bar
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+ - ContextType: Namespace
+ ContextName: b
+FilePath: ../include/bar.h
+Type: Class
+Seen: 3
+Used: 0
+---
+Name: bar
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+ - ContextType: Namespace
+ ContextName: b
+FilePath: ../include/zbar.h
+Type: Class
+Seen: 3
+Used: 0
+---
+Name: b
+Contexts:
+FilePath: var.h
+Type: Variable
+Seen: 1
+Used: 0
+---
+Name: bar
+Contexts:
+ - ContextType: Namespace
+ ContextName: c
+FilePath: test/clang-include-fixer/baz.h
+Type: Class
+Seen: 1
+Used: 0
Added: clang-tools-extra/trunk/test/clang-include-fixer/Inputs/merge/a.yaml
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-include-fixer/Inputs/merge/a.yaml?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-include-fixer/Inputs/merge/a.yaml (added)
+++ clang-tools-extra/trunk/test/clang-include-fixer/Inputs/merge/a.yaml Mon Mar 25 07:09:10 2019
@@ -0,0 +1,20 @@
+---
+Name: foo
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+FilePath: foo.h
+Type: Class
+Seen: 1
+Used: 1
+...
+---
+Name: bar
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+FilePath: ../include/bar.h
+Type: Class
+Seen: 1
+Used: 2
+...
Added: clang-tools-extra/trunk/test/clang-include-fixer/Inputs/merge/b.yaml
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-include-fixer/Inputs/merge/b.yaml?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-include-fixer/Inputs/merge/b.yaml (added)
+++ clang-tools-extra/trunk/test/clang-include-fixer/Inputs/merge/b.yaml Mon Mar 25 07:09:10 2019
@@ -0,0 +1,20 @@
+---
+Name: foo
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+FilePath: foo.h
+Type: Class
+Seen: 1
+Used: 2
+...
+---
+Name: bar
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+FilePath: ../include/barbar.h
+Type: Class
+Seen: 1
+Used: 0
+...
Added: clang-tools-extra/trunk/test/clang-include-fixer/commandline_options.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-include-fixer/commandline_options.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-include-fixer/commandline_options.cpp (added)
+++ clang-tools-extra/trunk/test/clang-include-fixer/commandline_options.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,15 @@
+// RUN: echo "foo f;" > %t.cpp
+// RUN: clang-include-fixer -db=fixed -input='foo= "foo.h","bar.h"' -output-headers %t.cpp -- | FileCheck %s
+// RUN: cat %t.cpp | clang-include-fixer -stdin -insert-header='{FilePath: "%/t.cpp", QuerySymbolInfos: [{RawIdentifier: foo, Range: {Offset: 0, Length: 3}}], HeaderInfos: [{Header: "\"foo.h\"", QualifiedName: "foo"}]}' %t.cpp | FileCheck %s -check-prefix=CHECK-CODE
+// RUN: cat %t.cpp | not clang-include-fixer -stdin -insert-header='{FilePath: "%/t.cpp", QuerySymbolInfos: [{RawIdentifier: foo, Range: {Offset: 0, Length: 3}}], HeaderInfos: [{Header: "\"foo.h\"", QualifiedName: "foo"},{Header: "\"foo2.h\"", QualifiedName: "foo"}]}' %t.cpp
+// RUN: cat %t.cpp | clang-include-fixer -stdin -insert-header='{FilePath: "%/t.cpp", QuerySymbolInfos: [{RawIdentifier: foo, Range: {Offset: 0, Length: 3}}], HeaderInfos: [{Header: "\"foo.h\"", QualifiedName: "a:foo"},{Header: "\"foo.h\"", QualifiedName: "b:foo"}]}' %t.cpp
+//
+// CHECK: "HeaderInfos": [
+// CHECK-NEXT: {"Header": "\"foo.h\"",
+// CHECK-NEXT: "QualifiedName": "foo"},
+// CHECK-NEXT: {"Header": "\"bar.h\"",
+// CHECK-NEXT: "QualifiedName": "foo"}
+// CHECK-NEXT:]
+//
+// CHECK-CODE: #include "foo.h"
+// CHECK-CODE: foo f;
Added: clang-tools-extra/trunk/test/clang-include-fixer/exit_on_fatal.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-include-fixer/exit_on_fatal.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-include-fixer/exit_on_fatal.cpp (added)
+++ clang-tools-extra/trunk/test/clang-include-fixer/exit_on_fatal.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,10 @@
+// RUN: sed -e 's#//.*$##' %s > %t.cpp
+// RUN: not clang-include-fixer -db=fixed -input='foo= "foo.h"' %t.cpp --
+// RUN: FileCheck %s -input-file=%t.cpp
+
+// CHECK-NOT: #include
+// CHECK: #include "doesnotexist.h"
+// CHECK-NEXT: foo f;
+
+#include "doesnotexist.h"
+foo f;
Added: clang-tools-extra/trunk/test/clang-include-fixer/fixeddb.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-include-fixer/fixeddb.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-include-fixer/fixeddb.cpp (added)
+++ clang-tools-extra/trunk/test/clang-include-fixer/fixeddb.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,8 @@
+// RUN: sed -e 's#//.*$##' %s > %t.cpp
+// RUN: clang-include-fixer -db=fixed -input='foo= "foo.h","bar.h"' %t.cpp --
+// RUN: FileCheck %s -input-file=%t.cpp
+
+// CHECK: #include "foo.h"
+// CHECK: foo f;
+
+foo f;
Added: clang-tools-extra/trunk/test/clang-include-fixer/include_path.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-include-fixer/include_path.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-include-fixer/include_path.cpp (added)
+++ clang-tools-extra/trunk/test/clang-include-fixer/include_path.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,19 @@
+// RUN: mkdir -p %T/clang-include-fixer/include
+// RUN: mkdir -p %T/clang-include-fixer/symbols
+// RUN: mkdir -p %T/clang-include-fixer/build
+// RUN: mkdir -p %T/clang-include-fixer/src
+// RUN: sed 's|test_dir|%/T/clang-include-fixer|g' %S/Inputs/database_template.json > %T/clang-include-fixer/build/compile_commands.json
+// RUN: echo -e '#include "bar.h"\nb::a::bar f;' > %T/clang-include-fixer/src/bar.cpp
+// RUN: echo 'namespace b { namespace a { class bar {}; } }' > %T/clang-include-fixer/include/bar.h
+// RUN: cd %T/clang-include-fixer/build
+// RUN: find-all-symbols -output-dir=%T/clang-include-fixer/symbols -p=. %T/clang-include-fixer/src/bar.cpp
+// RUN: find-all-symbols -merge-dir=%T/clang-include-fixer/symbols %T/clang-include-fixer/build/find_all_symbols.yaml
+// RUN: FileCheck -input-file=%T/clang-include-fixer/build/find_all_symbols.yaml -check-prefix=CHECK-YAML %s
+//
+// RUN: echo 'b::a::bar f;' > %T/clang-include-fixer/src/bar.cpp
+// RUN: clang-include-fixer -db=yaml -input=%T/clang-include-fixer/build/find_all_symbols.yaml -minimize-paths=true -p=. %T/clang-include-fixer/src/bar.cpp
+// RUN: FileCheck -input-file=%T/clang-include-fixer/src/bar.cpp %s
+
+// CHECK-YAML: ..{{[/\\]}}include{{[/\\]}}bar.h
+// CHECK: #include "bar.h"
+// CHECK: b::a::bar f;
Added: clang-tools-extra/trunk/test/clang-include-fixer/merge.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-include-fixer/merge.test?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-include-fixer/merge.test (added)
+++ clang-tools-extra/trunk/test/clang-include-fixer/merge.test Mon Mar 25 07:09:10 2019
@@ -0,0 +1,33 @@
+# RUN: find-all-symbols -merge-dir=%S/Inputs/merge %t.merged
+# RUN: sed '/^#/d' %s > %t.golden
+# RUN: diff -u %t.golden %t.merged
+---
+Name: bar
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+FilePath: '../include/bar.h'
+Type: Class
+Seen: 1
+Used: 1
+...
+---
+Name: bar
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+FilePath: '../include/barbar.h'
+Type: Class
+Seen: 1
+Used: 0
+...
+---
+Name: foo
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+FilePath: foo.h
+Type: Class
+Seen: 2
+Used: 2
+...
Added: clang-tools-extra/trunk/test/clang-include-fixer/multiple_fixes.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-include-fixer/multiple_fixes.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-include-fixer/multiple_fixes.cpp (added)
+++ clang-tools-extra/trunk/test/clang-include-fixer/multiple_fixes.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,13 @@
+// REQUIRES: shell
+// RUN: sed -e 's#//.*$##' %s > %t.cpp
+// RUN: mkdir -p %T/clang-include-fixer/multiple-fixes
+// RUN: echo 'foo f;' > %T/clang-include-fixer/multiple-fixes/foo.cpp
+// RUN: echo 'bar b;' > %T/clang-include-fixer/multiple-fixes/bar.cpp
+// RUN: clang-include-fixer -db=fixed -input='foo= "foo.h";bar= "bar.h"' %T/clang-include-fixer/multiple-fixes/*.cpp --
+// RUN: FileCheck -input-file=%T/clang-include-fixer/multiple-fixes/bar.cpp %s -check-prefix=CHECK-BAR
+// RUN: FileCheck -input-file=%T/clang-include-fixer/multiple-fixes/foo.cpp %s -check-prefix=CHECK-FOO
+//
+// CHECK-FOO: #include "foo.h"
+// CHECK-FOO: foo f;
+// CHECK-BAR: #include "bar.h"
+// CHECK-BAR: bar b;
Added: clang-tools-extra/trunk/test/clang-include-fixer/prefix_variable.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-include-fixer/prefix_variable.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-include-fixer/prefix_variable.cpp (added)
+++ clang-tools-extra/trunk/test/clang-include-fixer/prefix_variable.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,10 @@
+// RUN: sed -e 's#//.*$##' %s > %t.cpp
+// RUN: clang-include-fixer -db=yaml -input=%p/Inputs/fake_yaml_db.yaml %t.cpp --
+// RUN: FileCheck %s -input-file=%t.cpp
+
+// CHECK-NOT: #include
+// CHECK: doesnotexist f;
+
+namespace b {
+doesnotexist f;
+}
Added: clang-tools-extra/trunk/test/clang-include-fixer/query_symbol.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-include-fixer/query_symbol.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-include-fixer/query_symbol.cpp (added)
+++ clang-tools-extra/trunk/test/clang-include-fixer/query_symbol.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,13 @@
+// RUN: clang-include-fixer -db=fixed -input='foo= "foo.h","bar.h"' -query-symbol="foo" test.cpp -- | FileCheck %s
+
+// CHECK: "FilePath": "test.cpp",
+// CHECK-NEXT:"QuerySymbolInfos": [
+// CHECK-NEXT: {"RawIdentifier": "foo",
+// CHECK-NEXT: "Range":{"Offset":0,"Length":0}}
+// CHECK-NEXT:],
+// CHECK-NEXT:"HeaderInfos": [
+// CHECK-NEXT: {"Header": "\"foo.h\"",
+// CHECK-NEXT: "QualifiedName": "foo"},
+// CHECK-NEXT: {"Header": "\"bar.h\"",
+// CHECK-NEXT: "QualifiedName": "foo"}
+// CHECK-NEXT:]
Added: clang-tools-extra/trunk/test/clang-include-fixer/ranking.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-include-fixer/ranking.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-include-fixer/ranking.cpp (added)
+++ clang-tools-extra/trunk/test/clang-include-fixer/ranking.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,13 @@
+// RUN: clang-include-fixer -db=yaml -input=%S/Inputs/fake_yaml_db.yaml -output-headers %s -- | FileCheck %s
+// RUN: clang-include-fixer -query-symbol bar -db=yaml -input=%S/Inputs/fake_yaml_db.yaml -output-headers %s -- | FileCheck %s
+
+// CHECK: "HeaderInfos": [
+// CHECK-NEXT: {"Header": "\"test/clang-include-fixer/baz.h\"",
+// CHECK-NEXT: "QualifiedName": "c::bar"},
+// CHECK-NEXT: {"Header": "\"../include/bar.h\"",
+// CHECK-NEXT: "QualifiedName": "b::a::bar"},
+// CHECK-NEXT: {"Header": "\"../include/zbar.h\"",
+// CHECK-NEXT: "QualifiedName": "b::a::bar"}
+// CHECK-NEXT:]
+
+bar b;
Added: clang-tools-extra/trunk/test/clang-include-fixer/yaml_fuzzy.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-include-fixer/yaml_fuzzy.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-include-fixer/yaml_fuzzy.cpp (added)
+++ clang-tools-extra/trunk/test/clang-include-fixer/yaml_fuzzy.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,9 @@
+// RUN: sed -e 's#//.*$##' %s > %t.cpp
+// RUN: clang-include-fixer -db=fuzzyYaml -input=%p/Inputs/fake_yaml_db.yaml %t.cpp --
+// RUN: FileCheck %s -input-file=%t.cpp
+
+// clang-include-fixer will add the include, but doesn't complete the symbol.
+// CHECK: #include "foobar.h"
+// CHECK: fba f;
+
+b::a::fba f;
Added: clang-tools-extra/trunk/test/clang-include-fixer/yamldb.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-include-fixer/yamldb.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-include-fixer/yamldb.cpp (added)
+++ clang-tools-extra/trunk/test/clang-include-fixer/yamldb.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,8 @@
+// RUN: sed -e 's#//.*$##' %s > %t.cpp
+// RUN: clang-include-fixer -db=yaml -input=%p/Inputs/fake_yaml_db.yaml %t.cpp --
+// RUN: FileCheck %s -input-file=%t.cpp
+
+// CHECK: #include "foo.h"
+// CHECK: b::a::foo f;
+
+b::a::foo f;
Added: clang-tools-extra/trunk/test/clang-include-fixer/yamldb_autodetect.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-include-fixer/yamldb_autodetect.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-include-fixer/yamldb_autodetect.cpp (added)
+++ clang-tools-extra/trunk/test/clang-include-fixer/yamldb_autodetect.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,11 @@
+// RUN: mkdir -p %T/foo/bar
+// RUN: cp %p/Inputs/fake_yaml_db.yaml %T/find_all_symbols_db.yaml
+// RUN: cd %T/foo
+// RUN: sed -e 's#//.*$##' %s > bar/test.cpp
+// RUN: clang-include-fixer -db=yaml bar/test.cpp --
+// RUN: FileCheck %s -input-file=bar/test.cpp
+
+// CHECK: #include "foo.h"
+// CHECK: b::a::foo f;
+
+b::a::foo f;
Modified: clang-tools-extra/trunk/unittests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/CMakeLists.txt?rev=356897&r1=356896&r2=356897&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/unittests/CMakeLists.txt Mon Mar 25 07:09:10 2019
@@ -17,8 +17,8 @@ endif()
add_subdirectory(clang-apply-replacements)
add_subdirectory(clang-change-namespace)
add_subdirectory(clang-doc)
+add_subdirectory(clang-include-fixer)
add_subdirectory(clang-move)
add_subdirectory(clang-query)
add_subdirectory(clang-tidy)
add_subdirectory(clangd)
-add_subdirectory(include-fixer)
Added: clang-tools-extra/trunk/unittests/clang-include-fixer/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-include-fixer/CMakeLists.txt?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-include-fixer/CMakeLists.txt (added)
+++ clang-tools-extra/trunk/unittests/clang-include-fixer/CMakeLists.txt Mon Mar 25 07:09:10 2019
@@ -0,0 +1,32 @@
+set(LLVM_LINK_COMPONENTS
+ support
+ )
+
+get_filename_component(INCLUDE_FIXER_SOURCE_DIR
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../clang-include-fixer REALPATH)
+include_directories(
+ ${INCLUDE_FIXER_SOURCE_DIR}
+ )
+
+# We'd like to clang/unittests/Tooling/RewriterTestContext.h in the test.
+include_directories(${CLANG_SOURCE_DIR})
+
+add_extra_unittest(IncludeFixerTests
+ IncludeFixerTest.cpp
+ FuzzySymbolIndexTests.cpp
+ )
+
+target_link_libraries(IncludeFixerTests
+ PRIVATE
+ clangBasic
+ clangFormat
+ clangFrontend
+ clangIncludeFixer
+ clangRewrite
+ clangSerialization
+ clangTooling
+ clangToolingCore
+ findAllSymbols
+ )
+
+add_subdirectory(find-all-symbols)
Added: clang-tools-extra/trunk/unittests/clang-include-fixer/FuzzySymbolIndexTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-include-fixer/FuzzySymbolIndexTests.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-include-fixer/FuzzySymbolIndexTests.cpp (added)
+++ clang-tools-extra/trunk/unittests/clang-include-fixer/FuzzySymbolIndexTests.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,60 @@
+//===-- FuzzySymbolIndexTests.cpp - Fuzzy symbol index unit tests ---------===//
+//
+// 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 "FuzzySymbolIndex.h"
+#include "gmock/gmock.h"
+#include "llvm/Support/Regex.h"
+#include "gtest/gtest.h"
+
+using testing::ElementsAre;
+using testing::Not;
+
+namespace clang {
+namespace include_fixer {
+namespace {
+
+TEST(FuzzySymbolIndexTest, Tokenize) {
+ EXPECT_THAT(FuzzySymbolIndex::tokenize("URLHandlerCallback"),
+ ElementsAre("url", "handler", "callback"));
+ EXPECT_THAT(FuzzySymbolIndex::tokenize("snake_case11"),
+ ElementsAre("snake", "case", "11"));
+ EXPECT_THAT(FuzzySymbolIndex::tokenize("__$42!!BOB\nbob"),
+ ElementsAre("42", "bob", "bob"));
+}
+
+MATCHER_P(MatchesSymbol, Identifier, "") {
+ llvm::Regex Pattern("^" + arg);
+ std::string err;
+ if (!Pattern.isValid(err)) {
+ *result_listener << "invalid regex: " << err;
+ return false;
+ }
+ auto Tokens = FuzzySymbolIndex::tokenize(Identifier);
+ std::string Target = llvm::join(Tokens.begin(), Tokens.end(), " ");
+ *result_listener << "matching against '" << Target << "'";
+ return llvm::Regex("^" + arg).match(Target);
+}
+
+TEST(FuzzySymbolIndexTest, QueryRegexp) {
+ auto QueryRegexp = [](const std::string &query) {
+ return FuzzySymbolIndex::queryRegexp(FuzzySymbolIndex::tokenize(query));
+ };
+ EXPECT_THAT(QueryRegexp("uhc"), MatchesSymbol("URLHandlerCallback"));
+ EXPECT_THAT(QueryRegexp("urhaca"), MatchesSymbol("URLHandlerCallback"));
+ EXPECT_THAT(QueryRegexp("uhcb"), Not(MatchesSymbol("URLHandlerCallback")))
+ << "Non-prefix";
+ EXPECT_THAT(QueryRegexp("uc"), Not(MatchesSymbol("URLHandlerCallback")))
+ << "Skip token";
+
+ EXPECT_THAT(QueryRegexp("uptr"), MatchesSymbol("unique_ptr"));
+ EXPECT_THAT(QueryRegexp("UniP"), MatchesSymbol("unique_ptr"));
+}
+
+} // namespace
+} // namespace include_fixer
+} // namespace clang
Added: clang-tools-extra/trunk/unittests/clang-include-fixer/IncludeFixerTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-include-fixer/IncludeFixerTest.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-include-fixer/IncludeFixerTest.cpp (added)
+++ clang-tools-extra/trunk/unittests/clang-include-fixer/IncludeFixerTest.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,371 @@
+//===-- IncludeFixerTest.cpp - Include fixer unit tests -------------------===//
+//
+// 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 "InMemorySymbolIndex.h"
+#include "IncludeFixer.h"
+#include "SymbolIndexManager.h"
+#include "unittests/Tooling/RewriterTestContext.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace include_fixer {
+namespace {
+
+using find_all_symbols::SymbolInfo;
+using find_all_symbols::SymbolAndSignals;
+
+static bool runOnCode(tooling::ToolAction *ToolAction, StringRef Code,
+ StringRef FileName,
+ const std::vector<std::string> &ExtraArgs) {
+ llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
+ new llvm::vfs::InMemoryFileSystem);
+ llvm::IntrusiveRefCntPtr<FileManager> Files(
+ new FileManager(FileSystemOptions(), InMemoryFileSystem));
+ // FIXME: Investigate why -fms-compatibility breaks tests.
+ std::vector<std::string> Args = {"include_fixer", "-fsyntax-only",
+ "-fno-ms-compatibility", FileName};
+ Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
+ tooling::ToolInvocation Invocation(
+ Args, ToolAction, Files.get(),
+ std::make_shared<PCHContainerOperations>());
+
+ InMemoryFileSystem->addFile(FileName, 0,
+ llvm::MemoryBuffer::getMemBuffer(Code));
+
+ InMemoryFileSystem->addFile("foo.h", 0,
+ llvm::MemoryBuffer::getMemBuffer("\n"));
+ InMemoryFileSystem->addFile("dir/bar.h", 0,
+ llvm::MemoryBuffer::getMemBuffer("\n"));
+ InMemoryFileSystem->addFile("dir/otherdir/qux.h", 0,
+ llvm::MemoryBuffer::getMemBuffer("\n"));
+ InMemoryFileSystem->addFile("header.h", 0,
+ llvm::MemoryBuffer::getMemBuffer("bar b;"));
+ return Invocation.run();
+}
+
+static std::string runIncludeFixer(
+ StringRef Code,
+ const std::vector<std::string> &ExtraArgs = std::vector<std::string>()) {
+ std::vector<SymbolAndSignals> Symbols = {
+ {SymbolInfo("string", SymbolInfo::SymbolKind::Class, "<string>",
+ {{SymbolInfo::ContextType::Namespace, "std"}}),
+ SymbolInfo::Signals{}},
+ {SymbolInfo("sting", SymbolInfo::SymbolKind::Class, "\"sting\"",
+ {{SymbolInfo::ContextType::Namespace, "std"}}),
+ SymbolInfo::Signals{}},
+ {SymbolInfo("foo", SymbolInfo::SymbolKind::Class,
+ "\"dir/otherdir/qux.h\"",
+ {{SymbolInfo::ContextType::Namespace, "b"},
+ {SymbolInfo::ContextType::Namespace, "a"}}),
+ SymbolInfo::Signals{}},
+ {SymbolInfo("bar", SymbolInfo::SymbolKind::Class, "\"bar.h\"",
+ {{SymbolInfo::ContextType::Namespace, "b"},
+ {SymbolInfo::ContextType::Namespace, "a"}}),
+ SymbolInfo::Signals{}},
+ {SymbolInfo("bar", SymbolInfo::SymbolKind::Class, "\"bar2.h\"",
+ {{SymbolInfo::ContextType::Namespace, "c"},
+ {SymbolInfo::ContextType::Namespace, "a"}}),
+ SymbolInfo::Signals{}},
+ {SymbolInfo("Green", SymbolInfo::SymbolKind::Class, "\"color.h\"",
+ {{SymbolInfo::ContextType::EnumDecl, "Color"},
+ {SymbolInfo::ContextType::Namespace, "b"},
+ {SymbolInfo::ContextType::Namespace, "a"}}),
+ SymbolInfo::Signals{}},
+ {SymbolInfo("Vector", SymbolInfo::SymbolKind::Class, "\"Vector.h\"",
+ {{SymbolInfo::ContextType::Namespace, "__a"},
+ {SymbolInfo::ContextType::Namespace, "a"}}),
+ SymbolInfo::Signals{/*Seen=*/2, 0}},
+ {SymbolInfo("Vector", SymbolInfo::SymbolKind::Class, "\"Vector.h\"",
+ {{SymbolInfo::ContextType::Namespace, "a"}}),
+ SymbolInfo::Signals{/*Seen=*/2, 0}},
+ {SymbolInfo("StrCat", SymbolInfo::SymbolKind::Class, "\"strcat.h\"",
+ {{SymbolInfo::ContextType::Namespace, "str"}}),
+ SymbolInfo::Signals{}},
+ {SymbolInfo("str", SymbolInfo::SymbolKind::Class, "\"str.h\"", {}),
+ SymbolInfo::Signals{}},
+ {SymbolInfo("foo2", SymbolInfo::SymbolKind::Class, "\"foo2.h\"", {}),
+ SymbolInfo::Signals{}},
+ };
+ auto SymbolIndexMgr = llvm::make_unique<SymbolIndexManager>();
+ SymbolIndexMgr->addSymbolIndex(
+ [=]() { return llvm::make_unique<InMemorySymbolIndex>(Symbols); });
+
+ std::vector<IncludeFixerContext> FixerContexts;
+ IncludeFixerActionFactory Factory(*SymbolIndexMgr, FixerContexts, "llvm");
+ std::string FakeFileName = "input.cc";
+ runOnCode(&Factory, Code, FakeFileName, ExtraArgs);
+ assert(FixerContexts.size() == 1);
+ if (FixerContexts.front().getHeaderInfos().empty())
+ return Code;
+ auto Replaces = createIncludeFixerReplacements(Code, FixerContexts.front());
+ EXPECT_TRUE(static_cast<bool>(Replaces))
+ << llvm::toString(Replaces.takeError()) << "\n";
+ if (!Replaces)
+ return "";
+ RewriterTestContext Context;
+ FileID ID = Context.createInMemoryFile(FakeFileName, Code);
+ tooling::applyAllReplacements(*Replaces, Context.Rewrite);
+ return Context.getRewrittenText(ID);
+}
+
+TEST(IncludeFixer, Typo) {
+ EXPECT_EQ("#include <string>\nstd::string foo;\n",
+ runIncludeFixer("std::string foo;\n"));
+
+ EXPECT_EQ("// comment\n#include \"foo.h\"\n#include <string>\n"
+ "std::string foo;\n#include \"dir/bar.h\"\n",
+ runIncludeFixer("// comment\n#include \"foo.h\"\nstd::string foo;\n"
+ "#include \"dir/bar.h\"\n"));
+
+ EXPECT_EQ("#include \"foo.h\"\n#include <string>\nstd::string foo;\n",
+ runIncludeFixer("#include \"foo.h\"\nstd::string foo;\n"));
+
+ EXPECT_EQ(
+ "#include \"foo.h\"\n#include <string>\nstd::string::size_type foo;\n",
+ runIncludeFixer("#include \"foo.h\"\nstd::string::size_type foo;\n"));
+
+ EXPECT_EQ("#include <string>\nstd::string foo;\n",
+ runIncludeFixer("string foo;\n"));
+
+ // Should not match std::string.
+ EXPECT_EQ("::string foo;\n", runIncludeFixer("::string foo;\n"));
+}
+
+TEST(IncludeFixer, IncompleteType) {
+ EXPECT_EQ(
+ "#include \"foo.h\"\n#include <string>\n"
+ "namespace std {\nclass string;\n}\nstd::string foo;\n",
+ runIncludeFixer("#include \"foo.h\"\n"
+ "namespace std {\nclass string;\n}\nstring foo;\n"));
+
+ EXPECT_EQ("#include <string>\n"
+ "class string;\ntypedef string foo;\nfoo f;\n",
+ runIncludeFixer("class string;\ntypedef string foo;\nfoo f;\n"));
+}
+
+TEST(IncludeFixer, MinimizeInclude) {
+ std::vector<std::string> IncludePath = {"-Idir/"};
+ EXPECT_EQ("#include \"otherdir/qux.h\"\na::b::foo bar;\n",
+ runIncludeFixer("a::b::foo bar;\n", IncludePath));
+
+ IncludePath = {"-isystemdir"};
+ EXPECT_EQ("#include <otherdir/qux.h>\na::b::foo bar;\n",
+ runIncludeFixer("a::b::foo bar;\n", IncludePath));
+
+ IncludePath = {"-iquotedir"};
+ EXPECT_EQ("#include \"otherdir/qux.h\"\na::b::foo bar;\n",
+ runIncludeFixer("a::b::foo bar;\n", IncludePath));
+
+ IncludePath = {"-Idir", "-Idir/otherdir"};
+ EXPECT_EQ("#include \"qux.h\"\na::b::foo bar;\n",
+ runIncludeFixer("a::b::foo bar;\n", IncludePath));
+}
+
+TEST(IncludeFixer, NestedName) {
+ EXPECT_EQ("#include \"dir/otherdir/qux.h\"\n"
+ "int x = a::b::foo(0);\n",
+ runIncludeFixer("int x = a::b::foo(0);\n"));
+
+ // FIXME: Handle simple macros.
+ EXPECT_EQ("#define FOO a::b::foo\nint x = FOO;\n",
+ runIncludeFixer("#define FOO a::b::foo\nint x = FOO;\n"));
+ EXPECT_EQ("#define FOO(x) a::##x\nint x = FOO(b::foo);\n",
+ runIncludeFixer("#define FOO(x) a::##x\nint x = FOO(b::foo);\n"));
+
+ // The empty namespace is cleaned up by clang-format after clang-include-fixer
+ // finishes.
+ EXPECT_EQ("#include \"dir/otherdir/qux.h\"\n"
+ "\nint a = a::b::foo(0);\n",
+ runIncludeFixer("namespace a {}\nint a = a::b::foo(0);\n"));
+}
+
+TEST(IncludeFixer, MultipleMissingSymbols) {
+ EXPECT_EQ("#include <string>\nstd::string bar;\nstd::sting foo;\n",
+ runIncludeFixer("std::string bar;\nstd::sting foo;\n"));
+}
+
+TEST(IncludeFixer, ScopedNamespaceSymbols) {
+ EXPECT_EQ("#include \"bar.h\"\nnamespace a {\nb::bar b;\n}",
+ runIncludeFixer("namespace a {\nb::bar b;\n}"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace A {\na::b::bar b;\n}",
+ runIncludeFixer("namespace A {\na::b::bar b;\n}"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace a {\nvoid func() { b::bar b; }\n} "
+ "// namespace a",
+ runIncludeFixer("namespace a {\nvoid func() { b::bar b; }\n}"));
+ EXPECT_EQ("namespace A { c::b::bar b; }\n",
+ runIncludeFixer("namespace A { c::b::bar b; }\n"));
+ // FIXME: The header should not be added here. Remove this after we support
+ // full match.
+ EXPECT_EQ("#include \"bar.h\"\nnamespace A {\na::b::bar b;\n}",
+ runIncludeFixer("namespace A {\nb::bar b;\n}"));
+
+ // Finds candidates for "str::StrCat".
+ EXPECT_EQ("#include \"strcat.h\"\nnamespace foo2 {\nstr::StrCat b;\n}",
+ runIncludeFixer("namespace foo2 {\nstr::StrCat b;\n}"));
+ // str::StrCat2 doesn't exist.
+ // In these two cases, StrCat2 is a nested class of class str.
+ EXPECT_EQ("#include \"str.h\"\nnamespace foo2 {\nstr::StrCat2 b;\n}",
+ runIncludeFixer("namespace foo2 {\nstr::StrCat2 b;\n}"));
+ EXPECT_EQ("#include \"str.h\"\nnamespace ns {\nstr::StrCat2 b;\n}",
+ runIncludeFixer("namespace ns {\nstr::StrCat2 b;\n}"));
+}
+
+TEST(IncludeFixer, EnumConstantSymbols) {
+ EXPECT_EQ("#include \"color.h\"\nint test = a::b::Green;\n",
+ runIncludeFixer("int test = a::b::Green;\n"));
+}
+
+TEST(IncludeFixer, IgnoreSymbolFromHeader) {
+ std::string Code = "#include \"header.h\"";
+ EXPECT_EQ(Code, runIncludeFixer(Code));
+}
+
+// FIXME: add test cases for inserting and sorting multiple headers when
+// clang-include-fixer supports multiple headers insertion.
+TEST(IncludeFixer, InsertAndSortSingleHeader) {
+ // Insert one header.
+ std::string Code = "#include \"a.h\"\n"
+ "#include \"foo.h\"\n"
+ "\n"
+ "namespace a {\nb::bar b;\n}\n";
+ std::string Expected = "#include \"a.h\"\n"
+ "#include \"bar.h\"\n"
+ "#include \"foo.h\"\n"
+ "\n"
+ "namespace a {\nb::bar b;\n}\n";
+ EXPECT_EQ(Expected, runIncludeFixer(Code));
+}
+
+TEST(IncludeFixer, DoNotDeleteMatchedSymbol) {
+ EXPECT_EQ("#include \"Vector.h\"\na::Vector v;",
+ runIncludeFixer("a::Vector v;"));
+}
+
+TEST(IncludeFixer, FixNamespaceQualifiers) {
+ EXPECT_EQ("#include \"bar.h\"\na::b::bar b;\n",
+ runIncludeFixer("b::bar b;\n"));
+ EXPECT_EQ("#include \"bar.h\"\na::b::bar b;\n",
+ runIncludeFixer("a::b::bar b;\n"));
+ EXPECT_EQ("#include \"bar.h\"\na::b::bar b;\n",
+ runIncludeFixer("bar b;\n"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace a {\nb::bar b;\n}\n",
+ runIncludeFixer("namespace a {\nb::bar b;\n}\n"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace a {\nb::bar b;\n}\n",
+ runIncludeFixer("namespace a {\nbar b;\n}\n"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace a {\nnamespace b{\nbar b;\n}\n} "
+ "// namespace a\n",
+ runIncludeFixer("namespace a {\nnamespace b{\nbar b;\n}\n}\n"));
+ EXPECT_EQ("c::b::bar b;\n",
+ runIncludeFixer("c::b::bar b;\n"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace d {\na::b::bar b;\n}\n",
+ runIncludeFixer("namespace d {\nbar b;\n}\n"));
+ EXPECT_EQ("#include \"bar2.h\"\nnamespace c {\na::c::bar b;\n}\n",
+ runIncludeFixer("namespace c {\nbar b;\n}\n"));
+
+ // Test common qualifers reduction.
+ EXPECT_EQ("#include \"bar.h\"\nnamespace a {\nnamespace d {\nb::bar b;\n}\n} "
+ "// namespace a\n",
+ runIncludeFixer("namespace a {\nnamespace d {\nbar b;\n}\n}\n"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace d {\nnamespace a {\na::b::bar "
+ "b;\n}\n} // namespace d\n",
+ runIncludeFixer("namespace d {\nnamespace a {\nbar b;\n}\n}\n"));
+
+ // Test nested classes.
+ EXPECT_EQ("#include \"bar.h\"\nnamespace d {\na::b::bar::t b;\n}\n",
+ runIncludeFixer("namespace d {\nbar::t b;\n}\n"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace c {\na::b::bar::t b;\n}\n",
+ runIncludeFixer("namespace c {\nbar::t b;\n}\n"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace a {\nb::bar::t b;\n}\n",
+ runIncludeFixer("namespace a {\nbar::t b;\n}\n"));
+
+ EXPECT_EQ("#include \"color.h\"\nint test = a::b::Green;\n",
+ runIncludeFixer("int test = Green;\n"));
+ EXPECT_EQ("#include \"color.h\"\nnamespace d {\nint test = a::b::Green;\n}\n",
+ runIncludeFixer("namespace d {\nint test = Green;\n}\n"));
+ EXPECT_EQ("#include \"color.h\"\nnamespace a {\nint test = b::Green;\n}\n",
+ runIncludeFixer("namespace a {\nint test = Green;\n}\n"));
+
+ // Test global scope operator.
+ EXPECT_EQ("#include \"bar.h\"\n::a::b::bar b;\n",
+ runIncludeFixer("::a::b::bar b;\n"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace a {\n::a::b::bar b;\n}\n",
+ runIncludeFixer("namespace a {\n::a::b::bar b;\n}\n"));
+}
+
+TEST(IncludeFixer, FixNamespaceQualifiersForAllInstances) {
+ const char TestCode[] = R"(
+namespace a {
+bar b;
+int func1() {
+ bar a;
+ bar *p = new bar();
+ return 0;
+}
+} // namespace a
+
+namespace a {
+bar func2() {
+ bar f;
+ return f;
+}
+} // namespace a
+
+// Non-fixed cases:
+void f() {
+ bar b;
+}
+
+namespace a {
+namespace c {
+ bar b;
+} // namespace c
+} // namespace a
+)";
+
+ const char ExpectedCode[] = R"(
+#include "bar.h"
+namespace a {
+b::bar b;
+int func1() {
+ b::bar a;
+ b::bar *p = new b::bar();
+ return 0;
+}
+} // namespace a
+
+namespace a {
+b::bar func2() {
+ b::bar f;
+ return f;
+}
+} // namespace a
+
+// Non-fixed cases:
+void f() {
+ bar b;
+}
+
+namespace a {
+namespace c {
+ bar b;
+} // namespace c
+} // namespace a
+)";
+
+ EXPECT_EQ(ExpectedCode, runIncludeFixer(TestCode));
+}
+
+TEST(IncludeFixer, DontAddQualifiersForMissingCompleteType) {
+ EXPECT_EQ("#include \"bar.h\"\nclass bar;\nvoid f() {\nbar* b;\nb->f();\n}",
+ runIncludeFixer("class bar;\nvoid f() {\nbar* b;\nb->f();\n}"));
+}
+
+} // namespace
+} // namespace include_fixer
+} // namespace clang
Added: clang-tools-extra/trunk/unittests/clang-include-fixer/find-all-symbols/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-include-fixer/find-all-symbols/CMakeLists.txt?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-include-fixer/find-all-symbols/CMakeLists.txt (added)
+++ clang-tools-extra/trunk/unittests/clang-include-fixer/find-all-symbols/CMakeLists.txt Mon Mar 25 07:09:10 2019
@@ -0,0 +1,25 @@
+set(LLVM_LINK_COMPONENTS
+ support
+ )
+
+get_filename_component(INCLUDE_FIXER_SOURCE_DIR
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../clang-include-fixer/find-all-symbols REALPATH)
+include_directories(
+ ${INCLUDE_FIXER_SOURCE_DIR}
+ )
+
+add_extra_unittest(FindAllSymbolsTests
+ FindAllSymbolsTests.cpp
+ )
+
+target_link_libraries(FindAllSymbolsTests
+ PRIVATE
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangFrontend
+ clangLex
+ clangSerialization
+ clangTooling
+ findAllSymbols
+ )
Added: clang-tools-extra/trunk/unittests/clang-include-fixer/find-all-symbols/FindAllSymbolsTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-include-fixer/find-all-symbols/FindAllSymbolsTests.cpp?rev=356897&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-include-fixer/find-all-symbols/FindAllSymbolsTests.cpp (added)
+++ clang-tools-extra/trunk/unittests/clang-include-fixer/find-all-symbols/FindAllSymbolsTests.cpp Mon Mar 25 07:09:10 2019
@@ -0,0 +1,577 @@
+//===-- FindAllSymbolsTests.cpp - find all symbols unit tests ---*- 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 "HeaderMapCollector.h"
+#include "SymbolInfo.h"
+#include "SymbolReporter.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/PCHContainerOperations.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include "gtest/gtest.h"
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace find_all_symbols {
+
+static const char HeaderName[] = "symbols.h";
+
+class TestSymbolReporter : public SymbolReporter {
+public:
+ ~TestSymbolReporter() override {}
+
+ void reportSymbols(llvm::StringRef FileName,
+ const SymbolInfo::SignalMap &NewSymbols) override {
+ for (const auto &Entry : NewSymbols)
+ Symbols[Entry.first] += Entry.second;
+ }
+
+ int seen(const SymbolInfo &Symbol) const {
+ auto it = Symbols.find(Symbol);
+ return it == Symbols.end() ? 0 : it->second.Seen;
+ }
+
+ int used(const SymbolInfo &Symbol) const {
+ auto it = Symbols.find(Symbol);
+ return it == Symbols.end() ? 0 : it->second.Used;
+ }
+
+private:
+ SymbolInfo::SignalMap Symbols;
+};
+
+class FindAllSymbolsTest : public ::testing::Test {
+public:
+ int seen(const SymbolInfo &Symbol) { return Reporter.seen(Symbol); }
+
+ int used(const SymbolInfo &Symbol) { return Reporter.used(Symbol); }
+
+ bool runFindAllSymbols(StringRef HeaderCode, StringRef MainCode) {
+ llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
+ new llvm::vfs::InMemoryFileSystem);
+ llvm::IntrusiveRefCntPtr<FileManager> Files(
+ new FileManager(FileSystemOptions(), InMemoryFileSystem));
+
+ std::string FileName = "symbol.cc";
+
+ const std::string InternalHeader = "internal/internal_header.h";
+ const std::string TopHeader = "<top>";
+ // Test .inc header path. The header for `IncHeaderClass` should be
+ // internal.h, which will eventually be mapped to <top>.
+ std::string IncHeader = "internal/private.inc";
+ std::string IncHeaderCode = "class IncHeaderClass {};";
+
+ HeaderMapCollector::RegexHeaderMap RegexMap = {
+ {R"(internal_.*\.h$)", TopHeader.c_str()},
+ };
+
+ std::string InternalCode =
+ "#include \"private.inc\"\nclass Internal {};";
+ SymbolInfo InternalSymbol("Internal", SymbolInfo::SymbolKind::Class,
+ TopHeader, {});
+ SymbolInfo IncSymbol("IncHeaderClass", SymbolInfo::SymbolKind::Class,
+ TopHeader, {});
+ InMemoryFileSystem->addFile(
+ IncHeader, 0, llvm::MemoryBuffer::getMemBuffer(IncHeaderCode));
+ InMemoryFileSystem->addFile(InternalHeader, 0,
+ llvm::MemoryBuffer::getMemBuffer(InternalCode));
+
+ std::unique_ptr<tooling::FrontendActionFactory> Factory(
+ new FindAllSymbolsActionFactory(&Reporter, &RegexMap));
+
+ tooling::ToolInvocation Invocation(
+ {std::string("find_all_symbols"), std::string("-fsyntax-only"),
+ std::string("-std=c++11"), FileName},
+ Factory->create(), Files.get(),
+ std::make_shared<PCHContainerOperations>());
+
+ InMemoryFileSystem->addFile(HeaderName, 0,
+ llvm::MemoryBuffer::getMemBuffer(HeaderCode));
+
+ std::string Content = "#include\"" + std::string(HeaderName) +
+ "\"\n"
+ "#include \"" +
+ InternalHeader + "\"";
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+ // Test path cleaning for both decls and macros.
+ const std::string DirtyHeader = "./internal/./a/b.h";
+ Content += "\n#include \"" + DirtyHeader + "\"";
+ const std::string CleanHeader = "internal/a/b.h";
+ const std::string DirtyHeaderContent =
+ "#define INTERNAL 1\nclass ExtraInternal {};";
+ InMemoryFileSystem->addFile(
+ DirtyHeader, 0, llvm::MemoryBuffer::getMemBuffer(DirtyHeaderContent));
+ SymbolInfo DirtyMacro("INTERNAL", SymbolInfo::SymbolKind::Macro,
+ CleanHeader, {});
+ SymbolInfo DirtySymbol("ExtraInternal", SymbolInfo::SymbolKind::Class,
+ CleanHeader, {});
+#endif // _MSC_VER && __MINGW32__
+ Content += "\n" + MainCode.str();
+ InMemoryFileSystem->addFile(FileName, 0,
+ llvm::MemoryBuffer::getMemBuffer(Content));
+ Invocation.run();
+ EXPECT_EQ(1, seen(InternalSymbol));
+ EXPECT_EQ(1, seen(IncSymbol));
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+ EXPECT_EQ(1, seen(DirtySymbol));
+ EXPECT_EQ(1, seen(DirtyMacro));
+#endif // _MSC_VER && __MINGW32__
+ return true;
+ }
+
+protected:
+ TestSymbolReporter Reporter;
+};
+
+TEST_F(FindAllSymbolsTest, VariableSymbols) {
+ static const char Header[] = R"(
+ extern int xargc;
+ namespace na {
+ static bool SSSS = false;
+ namespace nb { const long long *XXXX; }
+ })";
+ static const char Main[] = R"(
+ auto y = &na::nb::XXXX;
+ int main() { if (na::SSSS) return xargc; }
+ )";
+ runFindAllSymbols(Header, Main);
+
+ SymbolInfo Symbol =
+ SymbolInfo("xargc", SymbolInfo::SymbolKind::Variable, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("SSSS", SymbolInfo::SymbolKind::Variable, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, "na"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("XXXX", SymbolInfo::SymbolKind::Variable, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, "nb"},
+ {SymbolInfo::ContextType::Namespace, "na"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, ExternCSymbols) {
+ static const char Header[] = R"(
+ extern "C" {
+ int C_Func() { return 0; }
+ struct C_struct {
+ int Member;
+ };
+ })";
+ static const char Main[] = R"(
+ C_struct q() {
+ int(*ptr)() = C_Func;
+ return {0};
+ }
+ )";
+ runFindAllSymbols(Header, Main);
+
+ SymbolInfo Symbol =
+ SymbolInfo("C_Func", SymbolInfo::SymbolKind::Function, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol =
+ SymbolInfo("C_struct", SymbolInfo::SymbolKind::Class, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, CXXRecordSymbols) {
+ static const char Header[] = R"(
+ struct Glob {};
+ struct A; // Not a defintion, ignored.
+ class NOP; // Not a defintion, ignored
+ namespace na {
+ struct A {
+ struct AAAA {};
+ int x;
+ int y;
+ void f() {}
+ };
+ }; //
+ )";
+ static const char Main[] = R"(
+ static Glob glob;
+ static na::A::AAAA* a;
+ )";
+ runFindAllSymbols(Header, Main);
+
+ SymbolInfo Symbol =
+ SymbolInfo("Glob", SymbolInfo::SymbolKind::Class, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("A", SymbolInfo::SymbolKind::Class, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, "na"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("AAA", SymbolInfo::SymbolKind::Class, HeaderName,
+ {{SymbolInfo::ContextType::Record, "A"},
+ {SymbolInfo::ContextType::Namespace, "na"}});
+ EXPECT_EQ(0, seen(Symbol));
+ EXPECT_EQ(0, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, CXXRecordSymbolsTemplate) {
+ static const char Header[] = R"(
+ template <typename T>
+ struct T_TEMP {
+ template <typename _Tp1>
+ struct rebind { typedef T_TEMP<_Tp1> other; };
+ };
+ // Ignore specialization.
+ template class T_TEMP<char>;
+
+ template <typename T>
+ class Observer {
+ };
+ // Ignore specialization.
+ template <> class Observer<int> {};
+ )";
+ static const char Main[] = R"(
+ extern T_TEMP<int>::rebind<char> weirdo;
+ )";
+ runFindAllSymbols(Header, Main);
+
+ SymbolInfo Symbol =
+ SymbolInfo("T_TEMP", SymbolInfo::SymbolKind::Class, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, DontIgnoreTemplatePartialSpecialization) {
+ static const char Code[] = R"(
+ template<class> class Class; // undefined
+ template<class R, class... ArgTypes>
+ class Class<R(ArgTypes...)> {
+ };
+
+ template<class T> void f() {};
+ template<> void f<int>() {};
+ )";
+ runFindAllSymbols(Code, "");
+ SymbolInfo Symbol =
+ SymbolInfo("Class", SymbolInfo::SymbolKind::Class, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ Symbol = SymbolInfo("f", SymbolInfo::SymbolKind::Function, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, FunctionSymbols) {
+ static const char Header[] = R"(
+ namespace na {
+ int gg(int);
+ int f(const int &a) { int Local; static int StaticLocal; return 0; }
+ static void SSSFFF() {}
+ } // namespace na
+ namespace na {
+ namespace nb {
+ template<typename T>
+ void fun(T t) {};
+ } // namespace nb
+ } // namespace na";
+ )";
+ static const char Main[] = R"(
+ int(*gg)(int) = &na::gg;
+ int main() {
+ (void)na::SSSFFF;
+ na::nb::fun(0);
+ return na::f(gg(0));
+ }
+ )";
+ runFindAllSymbols(Header, Main);
+
+ SymbolInfo Symbol =
+ SymbolInfo("gg", SymbolInfo::SymbolKind::Function, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, "na"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("f", SymbolInfo::SymbolKind::Function, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, "na"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("SSSFFF", SymbolInfo::SymbolKind::Function, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, "na"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("fun", SymbolInfo::SymbolKind::Function, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, "nb"},
+ {SymbolInfo::ContextType::Namespace, "na"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, NamespaceTest) {
+ static const char Header[] = R"(
+ int X1;
+ namespace { int X2; }
+ namespace { namespace { int X3; } }
+ namespace { namespace nb { int X4; } }
+ namespace na { inline namespace __1 { int X5; } }
+ )";
+ static const char Main[] = R"(
+ using namespace nb;
+ int main() {
+ X1 = X2;
+ X3 = X4;
+ (void)na::X5;
+ }
+ )";
+ runFindAllSymbols(Header, Main);
+
+ SymbolInfo Symbol =
+ SymbolInfo("X1", SymbolInfo::SymbolKind::Variable, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("X2", SymbolInfo::SymbolKind::Variable, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, ""}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("X3", SymbolInfo::SymbolKind::Variable, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, ""},
+ {SymbolInfo::ContextType::Namespace, ""}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("X4", SymbolInfo::SymbolKind::Variable, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, "nb"},
+ {SymbolInfo::ContextType::Namespace, ""}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("X5", SymbolInfo::SymbolKind::Variable, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, "na"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, DecayedTypeTest) {
+ static const char Header[] = "void DecayedFunc(int x[], int y[10]) {}";
+ static const char Main[] = R"(int main() { DecayedFunc(nullptr, nullptr); })";
+ runFindAllSymbols(Header, Main);
+ SymbolInfo Symbol = SymbolInfo(
+ "DecayedFunc", SymbolInfo::SymbolKind::Function, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, CTypedefTest) {
+ static const char Header[] = R"(
+ typedef unsigned size_t_;
+ typedef struct { int x; } X;
+ using XX = X;
+ )";
+ static const char Main[] = R"(
+ size_t_ f;
+ template<typename T> struct vector{};
+ vector<X> list;
+ void foo(const XX&){}
+ )";
+ runFindAllSymbols(Header, Main);
+
+ SymbolInfo Symbol = SymbolInfo("size_t_", SymbolInfo::SymbolKind::TypedefName,
+ HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("X", SymbolInfo::SymbolKind::TypedefName, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol =
+ SymbolInfo("XX", SymbolInfo::SymbolKind::TypedefName, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, EnumTest) {
+ static const char Header[] = R"(
+ enum Glob_E { G1, G2 };
+ enum class Altitude { high='h', low='l'};
+ enum { A1, A2 };
+ class A {
+ public:
+ enum A_ENUM { X1, X2 };
+ };
+ enum DECL : int;
+ )";
+ static const char Main[] = R"(
+ static auto flags = G1 | G2;
+ static auto alt = Altitude::high;
+ static auto nested = A::X1;
+ extern DECL whatever;
+ static auto flags2 = A1 | A2;
+ )";
+ runFindAllSymbols(Header, Main);
+
+ SymbolInfo Symbol =
+ SymbolInfo("Glob_E", SymbolInfo::SymbolKind::EnumDecl, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(0, used(Symbol));
+
+ Symbol =
+ SymbolInfo("G1", SymbolInfo::SymbolKind::EnumConstantDecl, HeaderName,
+ {{SymbolInfo::ContextType::EnumDecl, "Glob_E"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol =
+ SymbolInfo("G2", SymbolInfo::SymbolKind::EnumConstantDecl, HeaderName,
+ {{SymbolInfo::ContextType::EnumDecl, "Glob_E"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol =
+ SymbolInfo("Altitude", SymbolInfo::SymbolKind::EnumDecl, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+ Symbol =
+ SymbolInfo("high", SymbolInfo::SymbolKind::EnumConstantDecl, HeaderName,
+ {{SymbolInfo::ContextType::EnumDecl, "Altitude"}});
+ EXPECT_EQ(0, seen(Symbol));
+ EXPECT_EQ(0, used(Symbol));
+
+ Symbol = SymbolInfo("A1", SymbolInfo::SymbolKind::EnumConstantDecl,
+ HeaderName, {{SymbolInfo::ContextType::EnumDecl, ""}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+ Symbol = SymbolInfo("A2", SymbolInfo::SymbolKind::EnumConstantDecl,
+ HeaderName, {{SymbolInfo::ContextType::EnumDecl, ""}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+ Symbol = SymbolInfo("", SymbolInfo::SymbolKind::EnumDecl, HeaderName, {});
+ EXPECT_EQ(0, seen(Symbol));
+ EXPECT_EQ(0, used(Symbol));
+
+ Symbol = SymbolInfo("A_ENUM", SymbolInfo::SymbolKind::EnumDecl, HeaderName,
+ {{SymbolInfo::ContextType::Record, "A"}});
+ EXPECT_EQ(0, seen(Symbol));
+ EXPECT_EQ(0, used(Symbol));
+
+ Symbol = SymbolInfo("X1", SymbolInfo::SymbolKind::EnumDecl, HeaderName,
+ {{SymbolInfo::ContextType::EnumDecl, "A_ENUM"},
+ {SymbolInfo::ContextType::Record, "A"}});
+ EXPECT_EQ(0, seen(Symbol));
+
+ Symbol = SymbolInfo("DECL", SymbolInfo::SymbolKind::EnumDecl, HeaderName, {});
+ EXPECT_EQ(0, seen(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, IWYUPrivatePragmaTest) {
+ static const char Header[] = R"(
+ // IWYU pragma: private, include "bar.h"
+ struct Bar {
+ };
+ )";
+ static const char Main[] = R"(
+ Bar bar;
+ )";
+ runFindAllSymbols(Header, Main);
+
+ SymbolInfo Symbol =
+ SymbolInfo("Bar", SymbolInfo::SymbolKind::Class, "bar.h", {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, MacroTest) {
+ static const char Header[] = R"(
+ #define X
+ #define Y 1
+ #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
+ )";
+ static const char Main[] = R"(
+ #ifdef X
+ int main() { return MAX(0,Y); }
+ #endif
+ )";
+ runFindAllSymbols(Header, Main);
+ SymbolInfo Symbol =
+ SymbolInfo("X", SymbolInfo::SymbolKind::Macro, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("Y", SymbolInfo::SymbolKind::Macro, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("MAX", SymbolInfo::SymbolKind::Macro, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, MacroTestWithIWYU) {
+ static const char Header[] = R"(
+ // IWYU pragma: private, include "bar.h"
+ #define X 1
+ #define Y 1
+ #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
+ )";
+ static const char Main[] = R"(
+ #ifdef X
+ int main() { return MAX(0,Y); }
+ #endif
+ )";
+ runFindAllSymbols(Header, Main);
+ SymbolInfo Symbol =
+ SymbolInfo("X", SymbolInfo::SymbolKind::Macro, "bar.h", {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("Y", SymbolInfo::SymbolKind::Macro, "bar.h", {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("MAX", SymbolInfo::SymbolKind::Macro, "bar.h", {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, NoFriendTest) {
+ static const char Header[] = R"(
+ class WorstFriend {
+ friend void Friend();
+ friend class BestFriend;
+ };
+ )";
+ runFindAllSymbols(Header, "");
+ SymbolInfo Symbol =
+ SymbolInfo("WorstFriend", SymbolInfo::SymbolKind::Class, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+
+ Symbol =
+ SymbolInfo("Friend", SymbolInfo::SymbolKind::Function, HeaderName, {});
+ EXPECT_EQ(0, seen(Symbol));
+
+ Symbol =
+ SymbolInfo("BestFriend", SymbolInfo::SymbolKind::Class, HeaderName, {});
+ EXPECT_EQ(0, seen(Symbol));
+}
+
+} // namespace find_all_symbols
+} // namespace clang
More information about the cfe-commits
mailing list