[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