summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra
diff options
context:
space:
mode:
authorHaojian Wu <hokein@google.com>2016-08-02 10:43:10 +0000
committerHaojian Wu <hokein@google.com>2016-08-02 10:43:10 +0000
commitadedac68dc300cb87eccfb9735d00325727ac58a (patch)
treee4bcbdaeabec2647d1b60ae3c27d997e2dec51e1 /clang-tools-extra
parent6c3591d33e8b7f4675e6ccdfadc647d0c2357564 (diff)
downloadbcm5719-llvm-adedac68dc300cb87eccfb9735d00325727ac58a.tar.gz
bcm5719-llvm-adedac68dc300cb87eccfb9735d00325727ac58a.zip
[include-fixer] Correct nested class search for identifiers with scoped information
Summary: include-fixer will firstly try to use scoped namespace context information to search identifier. However, in some cases, it's unsafe to do nested class search, because it might treat the identifier as a nested class of scoped namespace. Given the following code, and the symbol database only has two classes: "foo" and "b::Bar". namespace foo { Bar t; } Before getting fixing, include-fixer will never search "Bar" symbol. Because it firstly tries to search "foo::Bar", there is no "Bar" in foo namespace, then it finds "foo" in database finally. So it treats "Bar" is a nested class of "foo". Reviewers: bkramer Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D23023 llvm-svn: 277442
Diffstat (limited to 'clang-tools-extra')
-rw-r--r--clang-tools-extra/include-fixer/IncludeFixer.cpp7
-rw-r--r--clang-tools-extra/include-fixer/IncludeFixerContext.cpp3
-rw-r--r--clang-tools-extra/include-fixer/SymbolIndexManager.cpp7
-rw-r--r--clang-tools-extra/include-fixer/SymbolIndexManager.h13
-rw-r--r--clang-tools-extra/unittests/include-fixer/IncludeFixerTest.cpp18
5 files changed, 36 insertions, 12 deletions
diff --git a/clang-tools-extra/include-fixer/IncludeFixer.cpp b/clang-tools-extra/include-fixer/IncludeFixer.cpp
index 8a1a6e2b17e..f6004c72abb 100644
--- a/clang-tools-extra/include-fixer/IncludeFixer.cpp
+++ b/clang-tools-extra/include-fixer/IncludeFixer.cpp
@@ -275,8 +275,11 @@ private:
// 1. lookup a::b::foo.
// 2. lookup b::foo.
std::string QueryString = ScopedQualifiers.str() + Query.str();
- MatchedSymbols = SymbolIndexMgr.search(QueryString);
- if (MatchedSymbols.empty() && !ScopedQualifiers.empty())
+ // 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.
+ MatchedSymbols = SymbolIndexMgr.search(QueryString, /*IsNestedSearch=*/false);
+ if (MatchedSymbols.empty())
MatchedSymbols = SymbolIndexMgr.search(Query);
DEBUG(llvm::dbgs() << "Having found " << MatchedSymbols.size()
<< " symbols\n");
diff --git a/clang-tools-extra/include-fixer/IncludeFixerContext.cpp b/clang-tools-extra/include-fixer/IncludeFixerContext.cpp
index defbada9559..d1727ae7ab7 100644
--- a/clang-tools-extra/include-fixer/IncludeFixerContext.cpp
+++ b/clang-tools-extra/include-fixer/IncludeFixerContext.cpp
@@ -44,7 +44,8 @@ std::string createQualifiedNameForReplacement(
std::string StrippedQualifiers;
while (!SymbolQualifiers.empty() &&
!llvm::StringRef(QualifiedName).endswith(SymbolQualifiers.back())) {
- StrippedQualifiers = "::" + SymbolQualifiers.back().str();
+ StrippedQualifiers =
+ "::" + SymbolQualifiers.back().str() + StrippedQualifiers;
SymbolQualifiers.pop_back();
}
// Append the missing stripped qualifiers.
diff --git a/clang-tools-extra/include-fixer/SymbolIndexManager.cpp b/clang-tools-extra/include-fixer/SymbolIndexManager.cpp
index 970a6125569..e3426ee3448 100644
--- a/clang-tools-extra/include-fixer/SymbolIndexManager.cpp
+++ b/clang-tools-extra/include-fixer/SymbolIndexManager.cpp
@@ -42,7 +42,8 @@ static void rankByPopularity(std::vector<SymbolInfo> &Symbols) {
}
std::vector<find_all_symbols::SymbolInfo>
-SymbolIndexManager::search(llvm::StringRef Identifier) const {
+SymbolIndexManager::search(llvm::StringRef Identifier,
+ bool IsNestedSearch) const {
// The identifier may be fully qualified, so split it and get all the context
// names.
llvm::SmallVector<llvm::StringRef, 8> Names;
@@ -60,7 +61,7 @@ SymbolIndexManager::search(llvm::StringRef Identifier) const {
// either) and can report that result.
bool TookPrefix = false;
std::vector<clang::find_all_symbols::SymbolInfo> MatchedSymbols;
- while (MatchedSymbols.empty() && !Names.empty()) {
+ do {
std::vector<clang::find_all_symbols::SymbolInfo> Symbols;
for (const auto &DB : SymbolIndices) {
auto Res = DB->search(Names.back().str());
@@ -116,7 +117,7 @@ SymbolIndexManager::search(llvm::StringRef Identifier) const {
}
Names.pop_back();
TookPrefix = true;
- }
+ } while (MatchedSymbols.empty() && !Names.empty() && IsNestedSearch);
rankByPopularity(MatchedSymbols);
return MatchedSymbols;
diff --git a/clang-tools-extra/include-fixer/SymbolIndexManager.h b/clang-tools-extra/include-fixer/SymbolIndexManager.h
index f886404964d..4c43a0c7902 100644
--- a/clang-tools-extra/include-fixer/SymbolIndexManager.h
+++ b/clang-tools-extra/include-fixer/SymbolIndexManager.h
@@ -28,12 +28,15 @@ public:
/// Search for header files to be included for an identifier.
/// \param Identifier The identifier being searched for. May or may not be
/// fully qualified.
- /// \returns A list of inclusion candidates, in a format ready for being
- /// pasted after an #include token.
- // FIXME: Move mapping from SymbolInfo to headers out of
- // SymbolIndexManager::search and return SymbolInfos instead of header paths.
+ /// \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) const;
+ search(llvm::StringRef Identifier, bool IsNestedSearch = true) const;
private:
std::vector<std::unique_ptr<SymbolIndex>> SymbolIndices;
diff --git a/clang-tools-extra/unittests/include-fixer/IncludeFixerTest.cpp b/clang-tools-extra/unittests/include-fixer/IncludeFixerTest.cpp
index 11d5d0de3b9..d6f8081d840 100644
--- a/clang-tools-extra/unittests/include-fixer/IncludeFixerTest.cpp
+++ b/clang-tools-extra/unittests/include-fixer/IncludeFixerTest.cpp
@@ -77,6 +77,12 @@ static std::string runIncludeFixer(
SymbolInfo("Vector", SymbolInfo::SymbolKind::Class, "\"Vector.h\"", 2,
{{SymbolInfo::ContextType::Namespace, "a"}},
/*num_occurrences=*/1),
+ SymbolInfo("StrCat", SymbolInfo::SymbolKind::Class, "\"strcat.h\"",
+ 1, {{SymbolInfo::ContextType::Namespace, "str"}}),
+ SymbolInfo("str", SymbolInfo::SymbolKind::Class, "\"str.h\"",
+ 1, {}),
+ SymbolInfo("foo2", SymbolInfo::SymbolKind::Class, "\"foo2.h\"",
+ 1, {}),
};
auto SymbolIndexMgr = llvm::make_unique<include_fixer::SymbolIndexManager>();
SymbolIndexMgr->addSymbolIndex(
@@ -189,6 +195,16 @@ TEST(IncludeFixer, ScopedNamespaceSymbols) {
// 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) {
@@ -253,7 +269,7 @@ TEST(IncludeFixer, FixNamespaceQualifiers) {
// 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 \"bar2.h\"\nnamespace c {\na::c::bar::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"));
OpenPOWER on IntegriCloud