forked from OSchip/llvm-project
[include-fixer] Use scope contexts information to improve query.
Reviewers: bkramer Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D20205 llvm-svn: 269430
This commit is contained in:
parent
a4bc53afba
commit
57cdcb07d6
|
@ -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.
|
||||
|
|
|
@ -39,10 +39,10 @@ SymbolIndexManager::search(llvm::StringRef Identifier) const {
|
|||
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::StringRef Identifier) const {
|
|||
}
|
||||
}
|
||||
|
||||
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.
|
||||
|
|
|
@ -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, MultipleMissingSymbols) {
|
|||
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
|
||||
|
|
Loading…
Reference in New Issue