[clang-tools-extra] r269430 - [include-fixer] Use scope contexts information to improve query.

Haojian Wu via cfe-commits cfe-commits at lists.llvm.org
Fri May 13 08:44:17 PDT 2016


Author: hokein
Date: Fri May 13 10:44:16 2016
New Revision: 269430

URL: http://llvm.org/viewvc/llvm-project?rev=269430&view=rev
Log:
[include-fixer] Use scope contexts information to improve query.

Reviewers: bkramer

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D20205

Modified:
    clang-tools-extra/trunk/include-fixer/IncludeFixer.cpp
    clang-tools-extra/trunk/include-fixer/SymbolIndexManager.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=269430&r1=269429&r2=269430&view=diff
==============================================================================
--- clang-tools-extra/trunk/include-fixer/IncludeFixer.cpp (original)
+++ clang-tools-extra/trunk/include-fixer/IncludeFixer.cpp Fri May 13 10:44:16 2016
@@ -116,6 +116,19 @@ public:
     if (getCompilerInstance().getSema().isSFINAEContext())
       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;
+        }
+      }
+    }
+
     /// If we have a scope specification, use that to get more precise results.
     std::string QueryString;
     if (SS && SS->getRange().isValid()) {
@@ -150,7 +163,23 @@ public:
       QueryString = Typo.getAsString();
     }
 
-    return query(QueryString, Typo.getLoc());
+    // Follow C++ Lookup rules. Firstly, lookup the identifier with scoped
+    // namespace contexts. If fails, falls back to identifier.
+    // For example:
+    //
+    // namespace a {
+    // b::foo f;
+    // }
+    //
+    // 1. lookup a::b::foo.
+    // 2. lookup b::foo.
+    if (!query(TypoScopeString + QueryString, Typo.getLoc()))
+      query(QueryString, Typo.getLoc());
+
+    // FIXME: We should just return the name we got as input here and prevent
+    // clang from trying to correct the typo by itself. That may change the
+    // identifier to something that's not wanted by the user.
+    return clang::TypoCorrection();
   }
 
   StringRef filename() const { return Filename; }
@@ -235,12 +264,12 @@ public:
 
 private:
   /// Query the database for a given identifier.
-  clang::TypoCorrection query(StringRef Query, SourceLocation Loc) {
+  bool query(StringRef Query, SourceLocation Loc) {
     assert(!Query.empty() && "Empty query!");
 
     // Save database lookups by not looking up identifiers multiple times.
     if (!SeenQueries.insert(Query).second)
-      return clang::TypoCorrection();
+      return true;
 
     DEBUG(llvm::dbgs() << "Looking up '" << Query << "' at ");
     DEBUG(Loc.print(llvm::dbgs(), getCompilerInstance().getSourceManager()));
@@ -250,16 +279,13 @@ private:
     auto SearchReply = SymbolIndexMgr.search(Query);
     DEBUG(llvm::dbgs() << SearchReply.size() << " replies\n");
     if (SearchReply.empty())
-      return clang::TypoCorrection();
+      return false;
 
     // Add those files to the set of includes to try out.
     // FIXME: Rank the results and pick the best one instead of the first one.
     TryInclude(Query, SearchReply[0]);
 
-    // FIXME: We should just return the name we got as input here and prevent
-    // clang from trying to correct the typo by itself. That may change the
-    // identifier to something that's not wanted by the user.
-    return clang::TypoCorrection();
+    return true;
   }
 
   /// The client to use to find cross-references.

Modified: clang-tools-extra/trunk/include-fixer/SymbolIndexManager.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/include-fixer/SymbolIndexManager.cpp?rev=269430&r1=269429&r2=269430&view=diff
==============================================================================
--- clang-tools-extra/trunk/include-fixer/SymbolIndexManager.cpp (original)
+++ clang-tools-extra/trunk/include-fixer/SymbolIndexManager.cpp Fri May 13 10:44:16 2016
@@ -39,10 +39,10 @@ SymbolIndexManager::search(llvm::StringR
     if (Symbol.getName() == Names.back()) {
       bool IsMatched = true;
       auto SymbolContext = Symbol.getContexts().begin();
+      auto IdentiferContext = Names.rbegin() + 1; // Skip identifier name;
       // Match the remaining context names.
-      for (auto IdentiferContext = Names.rbegin() + 1;
-           IdentiferContext != Names.rend() &&
-           SymbolContext != Symbol.getContexts().end();
+      for (; IdentiferContext != Names.rend() &&
+             SymbolContext != Symbol.getContexts().end();
            ++IdentiferContext, ++SymbolContext) {
         if (SymbolContext->second != *IdentiferContext) {
           IsMatched = false;
@@ -50,7 +50,9 @@ SymbolIndexManager::search(llvm::StringR
         }
       }
 
-      if (IsMatched) {
+      // 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()) {
         // FIXME: file path should never be in the form of <...> or "...", but
         // the unit test with fixed database use <...> file path, which might
         // need to be changed.

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=269430&r1=269429&r2=269430&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/include-fixer/IncludeFixerTest.cpp (original)
+++ clang-tools-extra/trunk/unittests/include-fixer/IncludeFixerTest.cpp Fri May 13 10:44:16 2016
@@ -59,6 +59,9 @@ static std::string runIncludeFixer(
       SymbolInfo("foo", SymbolInfo::SymbolKind::Class, "\"dir/otherdir/qux.h\"",
                  1, {{SymbolInfo::ContextType::Namespace, "b"},
                      {SymbolInfo::ContextType::Namespace, "a"}}),
+      SymbolInfo("bar", SymbolInfo::SymbolKind::Class, "\"bar.h\"",
+                 1, {{SymbolInfo::ContextType::Namespace, "b"},
+                     {SymbolInfo::ContextType::Namespace, "a"}}),
   };
   auto SymbolIndexMgr = llvm::make_unique<include_fixer::SymbolIndexManager>();
   SymbolIndexMgr->addSymbolIndex(
@@ -137,6 +140,20 @@ TEST(IncludeFixer, MultipleMissingSymbol
             runIncludeFixer("std::string bar;\nstd::sting foo;\n"));
 }
 
+TEST(IncludeFixer, ScopedNamespaceSymbols) {
+  EXPECT_EQ("#include \"bar.h\"\nnamespace a { b::bar b; }\n",
+            runIncludeFixer("namespace a { b::bar b; }\n"));
+  EXPECT_EQ("#include \"bar.h\"\nnamespace A { a::b::bar b; }\n",
+            runIncludeFixer("namespace A { a::b::bar b; }\n"));
+  EXPECT_EQ("#include \"bar.h\"\nnamespace a { void func() { b::bar b; } }\n",
+            runIncludeFixer("namespace a { void 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 { b::bar b; }\n",
+            runIncludeFixer("namespace A { b::bar b; }\n"));
+}
 } // namespace
 } // namespace include_fixer
 } // namespace clang




More information about the cfe-commits mailing list