[clangd] Split locateSymbolAt into several component functions, to allow later reuse. NFC

This commit is contained in:
Sam McCall 2020-03-02 18:45:05 +01:00
parent 91cdbd521a
commit e7de00cf97

View File

@ -172,85 +172,53 @@ llvm::Optional<Location> makeLocation(ASTContext &AST, SourceLocation TokLoc,
} // namespace
std::vector<DocumentLink> getDocumentLinks(ParsedAST &AST) {
const auto &SM = AST.getSourceManager();
auto MainFilePath =
getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
if (!MainFilePath) {
elog("Failed to get a path for the main file, so no links");
return {};
}
std::vector<DocumentLink> Result;
for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
if (!Inc.Resolved.empty()) {
Result.push_back(DocumentLink(
{Inc.R, URIForFile::canonicalize(Inc.Resolved, *MainFilePath)}));
}
}
return Result;
}
std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
const SymbolIndex *Index) {
const auto &SM = AST.getSourceManager();
auto MainFilePath =
getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
if (!MainFilePath) {
elog("Failed to get a path for the main file, so no references");
return {};
}
// Treat #included files as symbols, to enable go-to-definition on them.
// Treat #included files as symbols, to enable go-to-definition on them.
static llvm::Optional<LocatedSymbol>
locateFileReferent(const Position &Pos, ParsedAST &AST,
llvm::StringRef MainFilePath) {
for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
if (!Inc.Resolved.empty() && Inc.R.start.line == Pos.line) {
LocatedSymbol File;
File.Name = std::string(llvm::sys::path::filename(Inc.Resolved));
File.PreferredDeclaration = {
URIForFile::canonicalize(Inc.Resolved, *MainFilePath), Range{}};
URIForFile::canonicalize(Inc.Resolved, MainFilePath), Range{}};
File.Definition = File.PreferredDeclaration;
// We're not going to find any further symbols on #include lines.
return {std::move(File)};
return File;
}
}
return llvm::None;
}
auto CurLoc = sourceLocationInMainFile(SM, Pos);
if (!CurLoc) {
elog("locateSymbolAt failed to convert position to source location: {0}",
CurLoc.takeError());
return {};
}
// Macros are simple: there's no declaration/definition distinction.
// As a consequence, there's no need to look them up in the index either.
std::vector<LocatedSymbol> Result;
const auto *TouchedIdentifier =
syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());
if (TouchedIdentifier) {
if (auto M = locateMacroAt(*TouchedIdentifier, AST.getPreprocessor())) {
if (auto Loc = makeLocation(AST.getASTContext(),
M->Info->getDefinitionLoc(), *MainFilePath)) {
LocatedSymbol Macro;
Macro.Name = std::string(M->Name);
Macro.PreferredDeclaration = *Loc;
Macro.Definition = Loc;
Result.push_back(std::move(Macro));
// Don't look at the AST or index if we have a macro result.
// (We'd just return declarations referenced from the macro's
// expansion.)
return Result;
}
// Macros are simple: there's no declaration/definition distinction.
// As a consequence, there's no need to look them up in the index either.
static llvm::Optional<LocatedSymbol>
locateMacroReferent(const syntax::Token &TouchedIdentifier, ParsedAST &AST,
llvm::StringRef MainFilePath) {
if (auto M = locateMacroAt(TouchedIdentifier, AST.getPreprocessor())) {
if (auto Loc = makeLocation(AST.getASTContext(),
M->Info->getDefinitionLoc(), MainFilePath)) {
LocatedSymbol Macro;
Macro.Name = std::string(M->Name);
Macro.PreferredDeclaration = *Loc;
Macro.Definition = Loc;
return Macro;
}
}
return llvm::None;
}
// Decls are more complicated.
// The AST contains at least a declaration, maybe a definition.
// These are up-to-date, and so generally preferred over index results.
// We perform a single batch index lookup to find additional definitions.
// Decls are more complicated.
// The AST contains at least a declaration, maybe a definition.
// These are up-to-date, and so generally preferred over index results.
// We perform a single batch index lookup to find additional definitions.
static std::vector<LocatedSymbol>
locateASTReferent(SourceLocation CurLoc, const syntax::Token *TouchedIdentifier,
ParsedAST &AST, llvm::StringRef MainFilePath,
const SymbolIndex *Index) {
const SourceManager &SM = AST.getSourceManager();
// Results follow the order of Symbols.Decls.
std::vector<LocatedSymbol> Result;
// Keep track of SymbolID -> index mapping, to fill in index data later.
llvm::DenseMap<SymbolID, size_t> ResultIndex;
@ -259,7 +227,7 @@ std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
const NamedDecl *Preferred = Def ? Def : D;
auto Loc = makeLocation(AST.getASTContext(), nameLocation(*Preferred, SM),
*MainFilePath);
MainFilePath);
if (!Loc)
return;
@ -278,7 +246,7 @@ std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
// Emit all symbol locations (declaration or definition) from AST.
DeclRelationSet Relations =
DeclRelation::TemplatePattern | DeclRelation::Alias;
for (const NamedDecl *D : getDeclAtPosition(AST, *CurLoc, Relations)) {
for (const NamedDecl *D : getDeclAtPosition(AST, CurLoc, Relations)) {
// Special case: void foo() ^override: jump to the overridden method.
if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
const InheritableAttr *Attr = D->getAttr<OverrideAttr>();
@ -320,23 +288,23 @@ std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
if (R.Definition) { // from AST
// Special case: if the AST yielded a definition, then it may not be
// the right *declaration*. Prefer the one from the index.
if (auto Loc = toLSPLocation(Sym.CanonicalDeclaration, *MainFilePath))
if (auto Loc = toLSPLocation(Sym.CanonicalDeclaration, MainFilePath))
R.PreferredDeclaration = *Loc;
// We might still prefer the definition from the index, e.g. for
// generated symbols.
if (auto Loc = toLSPLocation(
getPreferredLocation(*R.Definition, Sym.Definition, Scratch),
*MainFilePath))
MainFilePath))
R.Definition = *Loc;
} else {
R.Definition = toLSPLocation(Sym.Definition, *MainFilePath);
R.Definition = toLSPLocation(Sym.Definition, MainFilePath);
// Use merge logic to choose AST or index declaration.
if (auto Loc = toLSPLocation(
getPreferredLocation(R.PreferredDeclaration,
Sym.CanonicalDeclaration, Scratch),
*MainFilePath))
MainFilePath))
R.PreferredDeclaration = *Loc;
}
});
@ -345,6 +313,60 @@ std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
return Result;
}
std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
const SymbolIndex *Index) {
const auto &SM = AST.getSourceManager();
auto MainFilePath =
getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
if (!MainFilePath) {
elog("Failed to get a path for the main file, so no references");
return {};
}
if (auto File = locateFileReferent(Pos, AST, *MainFilePath))
return {std::move(*File)};
auto CurLoc = sourceLocationInMainFile(SM, Pos);
if (!CurLoc) {
elog("locateSymbolAt failed to convert position to source location: {0}",
CurLoc.takeError());
return {};
}
const syntax::Token *TouchedIdentifier =
syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());
if (TouchedIdentifier)
if (auto Macro =
locateMacroReferent(*TouchedIdentifier, AST, *MainFilePath))
// Don't look at the AST or index if we have a macro result.
// (We'd just return declarations referenced from the macro's
// expansion.)
return {*std::move(Macro)};
return locateASTReferent(*CurLoc, TouchedIdentifier, AST, *MainFilePath,
Index);
}
std::vector<DocumentLink> getDocumentLinks(ParsedAST &AST) {
const auto &SM = AST.getSourceManager();
auto MainFilePath =
getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
if (!MainFilePath) {
elog("Failed to get a path for the main file, so no links");
return {};
}
std::vector<DocumentLink> Result;
for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
if (!Inc.Resolved.empty()) {
Result.push_back(DocumentLink(
{Inc.R, URIForFile::canonicalize(Inc.Resolved, *MainFilePath)}));
}
}
return Result;
}
namespace {
/// Collects references to symbols within the main file.