[clang-tools-extra] r276280 - [include-fixer] Add mising qualifiers to all instances of an unidentified symbol.

Haojian Wu via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 21 06:47:09 PDT 2016


Author: hokein
Date: Thu Jul 21 08:47:09 2016
New Revision: 276280

URL: http://llvm.org/viewvc/llvm-project?rev=276280&view=rev
Log:
[include-fixer] Add mising qualifiers to all instances of an unidentified symbol.

Reviewers: bkramer

Subscribers: ioeric, cfe-commits

Differential Revision: https://reviews.llvm.org/D22567

Modified:
    clang-tools-extra/trunk/include-fixer/IncludeFixer.cpp
    clang-tools-extra/trunk/include-fixer/IncludeFixer.h
    clang-tools-extra/trunk/include-fixer/IncludeFixerContext.cpp
    clang-tools-extra/trunk/include-fixer/IncludeFixerContext.h
    clang-tools-extra/trunk/include-fixer/tool/ClangIncludeFixer.cpp
    clang-tools-extra/trunk/include-fixer/tool/clang-include-fixer.py
    clang-tools-extra/trunk/test/include-fixer/commandline_options.cpp
    clang-tools-extra/trunk/unittests/include-fixer/IncludeFixerTest.cpp

Modified: clang-tools-extra/trunk/include-fixer/IncludeFixer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/include-fixer/IncludeFixer.cpp?rev=276280&r1=276279&r2=276280&view=diff
==============================================================================
--- clang-tools-extra/trunk/include-fixer/IncludeFixer.cpp (original)
+++ clang-tools-extra/trunk/include-fixer/IncludeFixer.cpp Thu Jul 21 08:47:09 2016
@@ -227,17 +227,28 @@ public:
                                     Symbol.getContexts(),
                                     Symbol.getNumOccurrences());
     }
-    return IncludeFixerContext(QuerySymbolInfo, SymbolCandidates);
+    return IncludeFixerContext(QuerySymbolInfos, SymbolCandidates);
   }
 
 private:
   /// Query the database for a given identifier.
-  bool query(StringRef Query, StringRef ScopedQualifiers, tooling::Range Range) {
+  bool query(StringRef Query, StringRef ScopedQualifiers,
+             tooling::Range Range) {
     assert(!Query.empty() && "Empty query!");
 
-    // Skip other identifiers once we have discovered an identfier successfully.
-    if (!MatchedSymbols.empty())
+    // 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 include-fixer avoids false positives, and
+    // always adds missing qualifiers to correct symbols.
+    if (!QuerySymbolInfos.empty()) {
+      if (ScopedQualifiers == QuerySymbolInfos.front().ScopedQualifiers &&
+          Query == QuerySymbolInfos.front().RawIdentifier) {
+        QuerySymbolInfos.push_back({Query.str(), ScopedQualifiers, Range});
+      }
       return false;
+    }
 
     DEBUG(llvm::dbgs() << "Looking up '" << Query << "' at ");
     DEBUG(getCompilerInstance()
@@ -248,7 +259,7 @@ private:
               .print(llvm::dbgs(), getCompilerInstance().getSourceManager()));
     DEBUG(llvm::dbgs() << " ...");
 
-    QuerySymbolInfo = {Query.str(), ScopedQualifiers, Range};
+    QuerySymbolInfos.push_back({Query.str(), ScopedQualifiers, Range});
 
     // Query the symbol based on C++ name Lookup rules.
     // Firstly, lookup the identifier with scoped namespace contexts;
@@ -274,8 +285,8 @@ private:
   /// The client to use to find cross-references.
   SymbolIndexManager &SymbolIndexMgr;
 
-  /// The symbol information.
-  IncludeFixerContext::QuerySymbolInfo QuerySymbolInfo;
+  /// 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
@@ -332,13 +343,13 @@ bool IncludeFixerActionFactory::runInvoc
   return !Compiler.getDiagnostics().hasFatalErrorOccurred();
 }
 
-llvm::Expected<tooling::Replacements>
-createInsertHeaderReplacements(StringRef Code, StringRef FilePath,
-                               StringRef Header,
-                               const clang::format::FormatStyle &Style) {
-  if (Header.empty())
+llvm::Expected<tooling::Replacements> createIncludeFixerReplacements(
+    StringRef Code, StringRef FilePath, const IncludeFixerContext &Context,
+    const clang::format::FormatStyle &Style, bool AddQualifiers) {
+  if (Context.getHeaderInfos().empty())
     return tooling::Replacements();
-  std::string IncludeName = "#include " + Header.str() + "\n";
+  std::string IncludeName =
+      "#include " + Context.getHeaderInfos().front().Header + "\n";
   // Create replacements for the new header.
   clang::tooling::Replacements Insertions = {
       tooling::Replacement(FilePath, UINT_MAX, 0, IncludeName)};
@@ -346,6 +357,14 @@ createInsertHeaderReplacements(StringRef
   auto CleanReplaces = cleanupAroundReplacements(Code, Insertions, Style);
   if (!CleanReplaces)
     return CleanReplaces;
+
+  if (AddQualifiers) {
+    for (const auto &Info : Context.getQuerySymbolInfos()) {
+      CleanReplaces->insert({FilePath, Info.Range.getOffset(),
+                             Info.Range.getLength(),
+                             Context.getHeaderInfos().front().QualifiedName});
+    }
+  }
   return formatReplacements(Code, *CleanReplaces, Style);
 }
 

Modified: clang-tools-extra/trunk/include-fixer/IncludeFixer.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/include-fixer/IncludeFixer.h?rev=276280&r1=276279&r2=276280&view=diff
==============================================================================
--- clang-tools-extra/trunk/include-fixer/IncludeFixer.h (original)
+++ clang-tools-extra/trunk/include-fixer/IncludeFixer.h Thu Jul 21 08:47:09 2016
@@ -60,19 +60,25 @@ private:
   std::string FallbackStyle;
 };
 
-/// Create replacements, which are generated by clang-format, for the header
-/// insertion.
+/// 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 FilePath The source file path.
-/// \param Header The header being inserted.
+/// \param Context The context which contains all information for creating
+/// 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 Replacements for inserting and sorting headers on success;
-/// otherwise, an llvm::Error carrying llvm::StringError is returned.
-llvm::Expected<tooling::Replacements> createInsertHeaderReplacements(
-    StringRef Code, StringRef FilePath, StringRef Header,
-    const clang::format::FormatStyle &Style = clang::format::getLLVMStyle());
+/// \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, StringRef FilePath, const IncludeFixerContext &Context,
+    const format::FormatStyle &Style = format::getLLVMStyle(),
+    bool AddQualifiers = true);
 
 } // namespace include_fixer
 } // namespace clang

Modified: clang-tools-extra/trunk/include-fixer/IncludeFixerContext.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/include-fixer/IncludeFixerContext.cpp?rev=276280&r1=276279&r2=276280&view=diff
==============================================================================
--- clang-tools-extra/trunk/include-fixer/IncludeFixerContext.cpp (original)
+++ clang-tools-extra/trunk/include-fixer/IncludeFixerContext.cpp Thu Jul 21 08:47:09 2016
@@ -75,14 +75,33 @@ std::string createQualifiedNameForReplac
 } // anonymous namespace
 
 IncludeFixerContext::IncludeFixerContext(
-    const QuerySymbolInfo &QuerySymbol,
+    std::vector<QuerySymbolInfo> QuerySymbols,
     std::vector<find_all_symbols::SymbolInfo> Symbols)
-    : MatchedSymbols(std::move(Symbols)), QuerySymbol(QuerySymbol) {
+    : 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) {
+              if (A.Range.getOffset() != B.Range.getOffset())
+                return A.Range.getOffset() < B.Range.getOffset();
+              return A.Range.getLength() == 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(
-             QuerySymbol.RawIdentifier, QuerySymbol.ScopedQualifiers, Symbol)});
+             QuerySymbolInfos.front().RawIdentifier,
+             QuerySymbolInfos.front().ScopedQualifiers, Symbol)});
   }
   // Deduplicate header infos.
   HeaderInfos.erase(std::unique(HeaderInfos.begin(), HeaderInfos.end(),

Modified: clang-tools-extra/trunk/include-fixer/IncludeFixerContext.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/include-fixer/IncludeFixerContext.h?rev=276280&r1=276279&r2=276280&view=diff
==============================================================================
--- clang-tools-extra/trunk/include-fixer/IncludeFixerContext.h (original)
+++ clang-tools-extra/trunk/include-fixer/IncludeFixerContext.h Thu Jul 21 08:47:09 2016
@@ -46,31 +46,39 @@ public:
   };
 
   IncludeFixerContext() = default;
-  IncludeFixerContext(const QuerySymbolInfo &QuerySymbol,
+  IncludeFixerContext(std::vector<QuerySymbolInfo> QuerySymbols,
                       std::vector<find_all_symbols::SymbolInfo> Symbols);
 
   /// \brief Get symbol name.
   llvm::StringRef getSymbolIdentifier() const {
-    return QuerySymbol.RawIdentifier;
+    return QuerySymbolInfos.front().RawIdentifier;
   }
 
   /// \brief Get replacement range of the symbol.
-  tooling::Range getSymbolRange() const { return QuerySymbol.Range; }
+  tooling::Range getSymbolRange() const {
+    return QuerySymbolInfos.front().Range;
+  }
 
+  /// \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 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;
-
-  /// \brief The information of the symbol being queried.
-  QuerySymbolInfo QuerySymbol;
 };
 
 } // namespace include_fixer

Modified: clang-tools-extra/trunk/include-fixer/tool/ClangIncludeFixer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/include-fixer/tool/ClangIncludeFixer.cpp?rev=276280&r1=276279&r2=276280&view=diff
==============================================================================
--- clang-tools-extra/trunk/include-fixer/tool/ClangIncludeFixer.cpp (original)
+++ clang-tools-extra/trunk/include-fixer/tool/ClangIncludeFixer.cpp Thu Jul 21 08:47:09 2016
@@ -29,6 +29,7 @@ using clang::include_fixer::IncludeFixer
 LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(IncludeFixerContext)
 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string)
 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(IncludeFixerContext::HeaderInfo)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(IncludeFixerContext::QuerySymbolInfo)
 
 namespace llvm {
 namespace yaml {
@@ -70,7 +71,7 @@ template <> struct MappingTraits<Include
 
 template <> struct MappingTraits<IncludeFixerContext> {
   static void mapping(IO &IO, IncludeFixerContext &Context) {
-    IO.mapRequired("QuerySymbolInfo", Context.QuerySymbol);
+    IO.mapRequired("QuerySymbolInfos", Context.QuerySymbolInfos);
     IO.mapRequired("HeaderInfos", Context.HeaderInfos);
   }
 };
@@ -118,10 +119,10 @@ cl::opt<bool> OutputHeaders(
     cl::desc("Print the symbol being queried and all its relevant headers in\n"
              "JSON format to stdout:\n"
              "  {\n"
-             "    \"QuerySymbolInfo\": {\n"
-             "       \"RawIdentifier\": \"foo\",\n"
-             "       \"Range\": {\"Offset\": 0, \"Length\": 3}\n"
-             "    },\n"
+             "    \"QuerySymbolInfos\": [\n"
+             "       {\"RawIdentifier\": \"foo\",\n"
+             "        \"Range\": {\"Offset\": 0, \"Length\": 3}}\n"
+             "    ],\n"
              "    \"HeaderInfos\": [ {\"Header\": \"\\\"foo_a.h\\\"\",\n"
              "                      \"QualifiedName\": \"a::foo\"} ]\n"
              "  }"),
@@ -133,10 +134,10 @@ cl::opt<std::string> InsertHeader(
              "The result is written to stdout. It is currently used for\n"
              "editor integration. Support YAML/JSON format:\n"
              "  -insert-header=\"{\n"
-             "     QuerySymbolInfo: {\n"
-             "       RawIdentifier: foo,\n"
-             "       Range: {Offset: 0, Length: 3}\n"
-             "     },\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));
@@ -202,13 +203,16 @@ createSymbolIndexManager(StringRef FileP
 
 void writeToJson(llvm::raw_ostream &OS, const IncludeFixerContext& Context) {
   OS << "{\n"
-        "  \"QuerySymbolInfo\": {\n"
-        "     \"RawIdentifier\": \""
-     << Context.getSymbolIdentifier() << "\",\n";
-  OS << "     \"Range\": {";
-  OS << " \"Offset\":" << Context.getSymbolRange().getOffset() << ",";
-  OS << " \"Length\":" << Context.getSymbolRange().getLength() << " }\n";
-  OS << "  },\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) {
@@ -275,16 +279,7 @@ int includeFixerMain(int argc, const cha
       return 1;
     }
 
-    auto Replacements = clang::include_fixer::createInsertHeaderReplacements(
-        Code->getBuffer(), FilePath, Context.getHeaderInfos().front().Header,
-        InsertStyle);
-    if (!Replacements) {
-      errs() << "Failed to create header insertion replacement: "
-             << llvm::toString(Replacements.takeError()) << "\n";
-      return 1;
-    }
-
-    // If a header have multiple symbols, we won't add the missing namespace
+    // 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.
@@ -294,10 +289,16 @@ int includeFixerMain(int argc, const cha
            const IncludeFixerContext::HeaderInfo &RHS) {
           return LHS.QualifiedName == RHS.QualifiedName;
         });
-    if (IsUniqueQualifiedName)
-      Replacements->insert({FilePath, Context.getSymbolRange().getOffset(),
-                            Context.getSymbolRange().getLength(),
-                            Context.getHeaderInfos().front().QualifiedName});
+
+    auto Replacements = clang::include_fixer::createIncludeFixerReplacements(
+        Code->getBuffer(), FilePath, 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) {
@@ -340,9 +341,8 @@ int includeFixerMain(int argc, const cha
     return 1;
   }
 
-  auto Replacements = clang::include_fixer::createInsertHeaderReplacements(
-      /*Code=*/Buffer.get()->getBuffer(), FilePath,
-      Context.getHeaderInfos().front().Header, InsertStyle);
+  auto Replacements = clang::include_fixer::createIncludeFixerReplacements(
+      /*Code=*/Buffer.get()->getBuffer(), FilePath, Context, InsertStyle);
   if (!Replacements) {
     errs() << "Failed to create header insertion replacement: "
            << llvm::toString(Replacements.takeError()) << "\n";
@@ -353,11 +353,6 @@ int includeFixerMain(int argc, const cha
     errs() << "Added #include " << Context.getHeaderInfos().front().Header
            << '\n';
 
-  // Add missing namespace qualifiers to the unidentified symbol.
-  Replacements->insert({FilePath, Context.getSymbolRange().getOffset(),
-                        Context.getSymbolRange().getLength(),
-                        Context.getHeaderInfos().front().QualifiedName});
-
   // Set up a new source manager for applying the resulting replacements.
   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions);
   DiagnosticsEngine Diagnostics(new DiagnosticIDs, &*DiagOpts);

Modified: clang-tools-extra/trunk/include-fixer/tool/clang-include-fixer.py
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/include-fixer/tool/clang-include-fixer.py?rev=276280&r1=276279&r2=276280&view=diff
==============================================================================
--- clang-tools-extra/trunk/include-fixer/tool/clang-include-fixer.py (original)
+++ clang-tools-extra/trunk/include-fixer/tool/clang-include-fixer.py Thu Jul 21 08:47:09 2016
@@ -127,8 +127,11 @@ def main():
     return
 
   include_fixer_context = json.loads(stdout)
-  query_symbol_info = include_fixer_context["QuerySymbolInfo"]
-  symbol = query_symbol_info["RawIdentifier"]
+  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 include-fixer.
   header_infos = include_fixer_context["HeaderInfos"]
   # Deduplicate headers while keeping the order, so that the same header would
@@ -141,10 +144,6 @@ def main():
       seen.add(header)
       unique_headers.append(header)
 
-  if not symbol:
-    print "The file is fine, no need to add a header."
-    return
-
   if not unique_headers:
     print "Couldn't find a header for {0}.".format(symbol)
     return
@@ -152,7 +151,7 @@ def main():
   try:
     # If there is only one suggested header, insert it directly.
     if len(unique_headers) == 1 or maximum_suggested_headers == 1:
-      InsertHeaderToVimBuffer({"QuerySymbolInfo": query_symbol_info,
+      InsertHeaderToVimBuffer({"QuerySymbolInfos": query_symbol_infos,
                                "HeaderInfos": header_infos}, text)
       print "Added #include {0} for {1}.".format(unique_headers[0], symbol)
       return
@@ -163,7 +162,7 @@ def main():
       header for header in header_infos if header["Header"] == selected]
 
     # Insert a selected header.
-    InsertHeaderToVimBuffer({"QuerySymbolInfo": query_symbol_info,
+    InsertHeaderToVimBuffer({"QuerySymbolInfos": query_symbol_infos,
                              "HeaderInfos": selected_header_infos}, text)
     print "Added #include {0} for {1}.".format(selected, symbol)
   except Exception as error:

Modified: clang-tools-extra/trunk/test/include-fixer/commandline_options.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/include-fixer/commandline_options.cpp?rev=276280&r1=276279&r2=276280&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/include-fixer/commandline_options.cpp (original)
+++ clang-tools-extra/trunk/test/include-fixer/commandline_options.cpp Thu Jul 21 08:47:09 2016
@@ -1,9 +1,9 @@
 // REQUIRES: shell
 // 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='{QuerySymbolInfo: {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='{QuerySymbolInfo: {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='{QuerySymbolInfo: {RawIdentifier: foo, Range: {Offset: 0, Length: 3}}, HeaderInfos: [{Header: "\"foo.h\"", QualifiedName: "a:foo"},{Header: "\"foo.h\"", QualifiedName: "b:foo"}]}' %t.cpp
+// RUN: cat %t.cpp | clang-include-fixer -stdin -insert-header='{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='{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='{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\"",

Modified: clang-tools-extra/trunk/unittests/include-fixer/IncludeFixerTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/include-fixer/IncludeFixerTest.cpp?rev=276280&r1=276279&r2=276280&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/include-fixer/IncludeFixerTest.cpp (original)
+++ clang-tools-extra/trunk/unittests/include-fixer/IncludeFixerTest.cpp Thu Jul 21 08:47:09 2016
@@ -89,17 +89,14 @@ static std::string runIncludeFixer(
   runOnCode(&Factory, Code, FakeFileName, ExtraArgs);
   if (FixerContext.getHeaderInfos().empty())
     return Code;
-  auto Replaces = clang::include_fixer::createInsertHeaderReplacements(
-      Code, FakeFileName, FixerContext.getHeaderInfos().front().Header);
+  auto Replaces = clang::include_fixer::createIncludeFixerReplacements(
+      Code, FakeFileName, FixerContext);
   EXPECT_TRUE(static_cast<bool>(Replaces))
       << llvm::toString(Replaces.takeError()) << "\n";
   if (!Replaces)
     return "";
   clang::RewriterTestContext Context;
   clang::FileID ID = Context.createInMemoryFile(FakeFileName, Code);
-  Replaces->insert({FakeFileName, FixerContext.getSymbolRange().getOffset(),
-                    FixerContext.getSymbolRange().getLength(),
-                    FixerContext.getHeaderInfos().front().QualifiedName});
   clang::tooling::applyAllReplacements(*Replaces, Context.Rewrite);
   return Context.getRewrittenText(ID);
 }
@@ -211,12 +208,12 @@ TEST(IncludeFixer, InsertAndSortSingleHe
   std::string Code = "#include \"a.h\"\n"
                      "#include \"foo.h\"\n"
                      "\n"
-                     "namespace a { b::bar b; }";
+                     "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 { b::bar b; }";
+                         "namespace a {\nb::bar b;\n}\n";
   EXPECT_EQ(Expected, runIncludeFixer(Code));
 }
 
@@ -275,6 +272,69 @@ TEST(IncludeFixer, FixNamespaceQualifier
             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));
+}
+
 } // namespace
 } // namespace include_fixer
 } // namespace clang




More information about the cfe-commits mailing list