aboutsummaryrefslogtreecommitdiff
path: root/clangd/XRefs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clangd/XRefs.cpp')
-rw-r--r--clangd/XRefs.cpp210
1 files changed, 164 insertions, 46 deletions
diff --git a/clangd/XRefs.cpp b/clangd/XRefs.cpp
index 2995fd92..e95730ba 100644
--- a/clangd/XRefs.cpp
+++ b/clangd/XRefs.cpp
@@ -12,6 +12,7 @@
#include "SourceCode.h"
#include "URI.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Index/IndexDataConsumer.h"
#include "clang/Index/IndexingAction.h"
#include "clang/Index/USRGeneration.h"
@@ -24,7 +25,7 @@ namespace {
// Get the definition from a given declaration `D`.
// Return nullptr if no definition is found, or the declaration type of `D` is
// not supported.
-const Decl *GetDefinition(const Decl *D) {
+const Decl *getDefinition(const Decl *D) {
assert(D);
if (const auto *TD = dyn_cast<TagDecl>(D))
return TD->getDefinition();
@@ -39,18 +40,18 @@ const Decl *GetDefinition(const Decl *D) {
// HintPath is used to resolve the path of URI.
// FIXME: figure out a good home for it, and share the implementation with
// FindSymbols.
-llvm::Optional<Location> ToLSPLocation(const SymbolLocation &Loc,
+llvm::Optional<Location> toLSPLocation(const SymbolLocation &Loc,
llvm::StringRef HintPath) {
if (!Loc)
return llvm::None;
auto Uri = URI::parse(Loc.FileURI);
if (!Uri) {
- log("Could not parse URI: " + Loc.FileURI);
+ log("Could not parse URI: {0}", Loc.FileURI);
return llvm::None;
}
auto Path = URI::resolve(*Uri, HintPath);
if (!Path) {
- log("Could not resolve URI: " + Loc.FileURI);
+ log("Could not resolve URI: {0}", Loc.FileURI);
return llvm::None;
}
Location LSPLoc;
@@ -115,7 +116,7 @@ public:
// We don't use parameter `D`, as Parameter `D` is the canonical
// declaration, which is the first declaration of a redeclarable
// declaration, and it could be a forward declaration.
- if (const auto *Def = GetDefinition(D)) {
+ if (const auto *Def = getDefinition(D)) {
Decls.push_back(Def);
} else {
// Couldn't find a definition, fall back to use `D`.
@@ -174,20 +175,6 @@ IdentifiedSymbol getSymbolAtPosition(ParsedAST &AST, SourceLocation Pos) {
return {DeclMacrosFinder.takeDecls(), DeclMacrosFinder.takeMacroInfos()};
}
-llvm::Optional<std::string>
-getAbsoluteFilePath(const FileEntry *F, const SourceManager &SourceMgr) {
- SmallString<64> FilePath = F->tryGetRealPathName();
- if (FilePath.empty())
- FilePath = F->getName();
- if (!llvm::sys::path::is_absolute(FilePath)) {
- if (!SourceMgr.getFileManager().makeAbsolutePath(FilePath)) {
- log("Could not turn relative path to absolute: " + FilePath);
- return llvm::None;
- }
- }
- return FilePath.str().str();
-}
-
llvm::Optional<Location>
makeLocation(ParsedAST &AST, const SourceRange &ValSourceRange) {
const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
@@ -215,27 +202,15 @@ makeLocation(ParsedAST &AST, const SourceRange &ValSourceRange) {
return L;
}
-// Get the symbol ID for a declaration, if possible.
-llvm::Optional<SymbolID> getSymbolID(const Decl *D) {
- llvm::SmallString<128> USR;
- if (index::generateUSRForDecl(D, USR)) {
- return None;
- }
- return SymbolID(USR);
-}
-
} // namespace
std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos,
const SymbolIndex *Index) {
const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
- SourceLocation SourceLocationBeg =
- getBeginningOfIdentifier(AST, Pos, SourceMgr.getMainFileID());
std::vector<Location> Result;
// Handle goto definition for #include.
- for (auto &Inc : AST.getInclusions()) {
- Position Pos = sourceLocToPosition(SourceMgr, SourceLocationBeg);
+ for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
if (!Inc.Resolved.empty() && Inc.R.contains(Pos))
Result.push_back(Location{URIForFile{Inc.Resolved}, {}});
}
@@ -243,6 +218,8 @@ std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos,
return Result;
// Identified symbols at a specific position.
+ SourceLocation SourceLocationBeg =
+ getBeginningOfIdentifier(AST, Pos, SourceMgr.getMainFileID());
auto Symbols = getSymbolAtPosition(AST, SourceLocationBeg);
for (auto Item : Symbols.Macros) {
@@ -293,7 +270,7 @@ std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos,
auto L = makeLocation(AST, SourceRange(Loc, Loc));
// The declaration in the identified symbols is a definition if possible
// otherwise it is declaration.
- bool IsDef = GetDefinition(D) == D;
+ bool IsDef = getDefinition(D) == D;
// Populate one of the slots with location for the AST.
if (!IsDef)
Candidate.Decl = L;
@@ -319,9 +296,9 @@ std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos,
auto &Value = It->second;
if (!Value.Def)
- Value.Def = ToLSPLocation(Sym.Definition, HintPath);
+ Value.Def = toLSPLocation(Sym.Definition, HintPath);
if (!Value.Decl)
- Value.Decl = ToLSPLocation(Sym.CanonicalDeclaration, HintPath);
+ Value.Decl = toLSPLocation(Sym.CanonicalDeclaration, HintPath);
});
}
@@ -424,7 +401,7 @@ std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST,
return DocHighlightsFinder.takeHighlights();
}
-static PrintingPolicy PrintingPolicyForDecls(PrintingPolicy Base) {
+static PrintingPolicy printingPolicyForDecls(PrintingPolicy Base) {
PrintingPolicy Policy(Base);
Policy.AnonymousTagLocations = false;
@@ -438,11 +415,11 @@ static PrintingPolicy PrintingPolicyForDecls(PrintingPolicy Base) {
/// Return a string representation (e.g. "class MyNamespace::MyClass") of
/// the type declaration \p TD.
-static std::string TypeDeclToString(const TypeDecl *TD) {
+static std::string typeDeclToString(const TypeDecl *TD) {
QualType Type = TD->getASTContext().getTypeDeclType(TD);
PrintingPolicy Policy =
- PrintingPolicyForDecls(TD->getASTContext().getPrintingPolicy());
+ printingPolicyForDecls(TD->getASTContext().getPrintingPolicy());
std::string Name;
llvm::raw_string_ostream Stream(Name);
@@ -453,10 +430,10 @@ static std::string TypeDeclToString(const TypeDecl *TD) {
/// Return a string representation (e.g. "namespace ns1::ns2") of
/// the named declaration \p ND.
-static std::string NamedDeclQualifiedName(const NamedDecl *ND,
+static std::string namedDeclQualifiedName(const NamedDecl *ND,
StringRef Prefix) {
PrintingPolicy Policy =
- PrintingPolicyForDecls(ND->getASTContext().getPrintingPolicy());
+ printingPolicyForDecls(ND->getASTContext().getPrintingPolicy());
std::string Name;
llvm::raw_string_ostream Stream(Name);
@@ -475,11 +452,11 @@ static llvm::Optional<std::string> getScopeName(const Decl *D) {
if (isa<TranslationUnitDecl>(DC))
return std::string("global namespace");
if (const TypeDecl *TD = dyn_cast<TypeDecl>(DC))
- return TypeDeclToString(TD);
+ return typeDeclToString(TD);
else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC))
- return NamedDeclQualifiedName(ND, "namespace");
+ return namedDeclQualifiedName(ND, "namespace");
else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
- return NamedDeclQualifiedName(FD, "function");
+ return namedDeclQualifiedName(FD, "function");
return llvm::None;
}
@@ -506,7 +483,7 @@ static Hover getHoverContents(const Decl *D) {
llvm::raw_string_ostream OS(DeclText);
PrintingPolicy Policy =
- PrintingPolicyForDecls(D->getASTContext().getPrintingPolicy());
+ printingPolicyForDecls(D->getASTContext().getPrintingPolicy());
D->print(OS, Policy);
@@ -516,6 +493,18 @@ static Hover getHoverContents(const Decl *D) {
return H;
}
+/// Generate a \p Hover object given the type \p T.
+static Hover getHoverContents(QualType T, ASTContext &ASTCtx) {
+ Hover H;
+ std::string TypeText;
+ llvm::raw_string_ostream OS(TypeText);
+ PrintingPolicy Policy = printingPolicyForDecls(ASTCtx.getPrintingPolicy());
+ T.print(OS, Policy);
+ OS.flush();
+ H.contents.value += TypeText;
+ return H;
+}
+
/// Generate a \p Hover object given the macro \p MacroInf.
static Hover getHoverContents(StringRef MacroName) {
Hover H;
@@ -526,7 +515,132 @@ static Hover getHoverContents(StringRef MacroName) {
return H;
}
-Hover getHover(ParsedAST &AST, Position Pos) {
+namespace {
+/// Computes the deduced type at a given location by visiting the relevant
+/// nodes. We use this to display the actual type when hovering over an "auto"
+/// keyword or "decltype()" expression.
+/// FIXME: This could have been a lot simpler by visiting AutoTypeLocs but it
+/// seems that the AutoTypeLocs that can be visited along with their AutoType do
+/// not have the deduced type set. Instead, we have to go to the appropriate
+/// DeclaratorDecl/FunctionDecl and work our back to the AutoType that does have
+/// a deduced type set. The AST should be improved to simplify this scenario.
+class DeducedTypeVisitor : public RecursiveASTVisitor<DeducedTypeVisitor> {
+ SourceLocation SearchedLocation;
+ llvm::Optional<QualType> DeducedType;
+
+public:
+ DeducedTypeVisitor(SourceLocation SearchedLocation)
+ : SearchedLocation(SearchedLocation) {}
+
+ llvm::Optional<QualType> getDeducedType() { return DeducedType; }
+
+ // Handle auto initializers:
+ //- auto i = 1;
+ //- decltype(auto) i = 1;
+ //- auto& i = 1;
+ bool VisitDeclaratorDecl(DeclaratorDecl *D) {
+ if (!D->getTypeSourceInfo() ||
+ D->getTypeSourceInfo()->getTypeLoc().getBeginLoc() != SearchedLocation)
+ return true;
+
+ auto DeclT = D->getType();
+ // "auto &" is represented as a ReferenceType containing an AutoType
+ if (const ReferenceType *RT = dyn_cast<ReferenceType>(DeclT.getTypePtr()))
+ DeclT = RT->getPointeeType();
+
+ const AutoType *AT = dyn_cast<AutoType>(DeclT.getTypePtr());
+ if (AT && !AT->getDeducedType().isNull()) {
+ // For auto, use the underlying type because the const& would be
+ // represented twice: written in the code and in the hover.
+ // Example: "const auto I = 1", we only want "int" when hovering on auto,
+ // not "const int".
+ //
+ // For decltype(auto), take the type as is because it cannot be written
+ // with qualifiers or references but its decuded type can be const-ref.
+ DeducedType = AT->isDecltypeAuto() ? DeclT : DeclT.getUnqualifiedType();
+ }
+ return true;
+ }
+
+ // Handle auto return types:
+ //- auto foo() {}
+ //- auto& foo() {}
+ //- auto foo() -> decltype(1+1) {}
+ //- operator auto() const { return 10; }
+ bool VisitFunctionDecl(FunctionDecl *D) {
+ if (!D->getTypeSourceInfo())
+ return true;
+ // Loc of auto in return type (c++14).
+ auto CurLoc = D->getReturnTypeSourceRange().getBegin();
+ // Loc of "auto" in operator auto()
+ if (CurLoc.isInvalid() && dyn_cast<CXXConversionDecl>(D))
+ CurLoc = D->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
+ // Loc of "auto" in function with traling return type (c++11).
+ if (CurLoc.isInvalid())
+ CurLoc = D->getSourceRange().getBegin();
+ if (CurLoc != SearchedLocation)
+ return true;
+
+ auto T = D->getReturnType();
+ // "auto &" is represented as a ReferenceType containing an AutoType.
+ if (const ReferenceType *RT = dyn_cast<ReferenceType>(T.getTypePtr()))
+ T = RT->getPointeeType();
+
+ const AutoType *AT = dyn_cast<AutoType>(T.getTypePtr());
+ if (AT && !AT->getDeducedType().isNull()) {
+ DeducedType = T.getUnqualifiedType();
+ } else { // auto in a trailing return type just points to a DecltypeType.
+ const DecltypeType *DT = dyn_cast<DecltypeType>(T.getTypePtr());
+ if (!DT->getUnderlyingType().isNull())
+ DeducedType = DT->getUnderlyingType();
+ }
+ return true;
+ }
+
+ // Handle non-auto decltype, e.g.:
+ // - auto foo() -> decltype(expr) {}
+ // - decltype(expr);
+ bool VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
+ if (TL.getBeginLoc() != SearchedLocation)
+ return true;
+
+ // A DecltypeType's underlying type can be another DecltypeType! E.g.
+ // int I = 0;
+ // decltype(I) J = I;
+ // decltype(J) K = J;
+ const DecltypeType *DT = dyn_cast<DecltypeType>(TL.getTypePtr());
+ while (DT && !DT->getUnderlyingType().isNull()) {
+ DeducedType = DT->getUnderlyingType();
+ DT = dyn_cast<DecltypeType>(DeducedType->getTypePtr());
+ }
+ return true;
+ }
+};
+} // namespace
+
+/// Retrieves the deduced type at a given location (auto, decltype).
+llvm::Optional<QualType> getDeducedType(ParsedAST &AST,
+ SourceLocation SourceLocationBeg) {
+ Token Tok;
+ auto &ASTCtx = AST.getASTContext();
+ // Only try to find a deduced type if the token is auto or decltype.
+ if (!SourceLocationBeg.isValid() ||
+ Lexer::getRawToken(SourceLocationBeg, Tok, ASTCtx.getSourceManager(),
+ ASTCtx.getLangOpts(), false) ||
+ !Tok.is(tok::raw_identifier)) {
+ return {};
+ }
+ AST.getPreprocessor().LookUpIdentifierInfo(Tok);
+ if (!(Tok.is(tok::kw_auto) || Tok.is(tok::kw_decltype)))
+ return {};
+
+ DeducedTypeVisitor V(SourceLocationBeg);
+ for (Decl *D : AST.getLocalTopLevelDecls())
+ V.TraverseDecl(D);
+ return V.getDeducedType();
+}
+
+Optional<Hover> getHover(ParsedAST &AST, Position Pos) {
const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
SourceLocation SourceLocationBeg =
getBeginningOfIdentifier(AST, Pos, SourceMgr.getMainFileID());
@@ -539,7 +653,11 @@ Hover getHover(ParsedAST &AST, Position Pos) {
if (!Symbols.Decls.empty())
return getHoverContents(Symbols.Decls[0]);
- return Hover();
+ auto DeducedType = getDeducedType(AST, SourceLocationBeg);
+ if (DeducedType && !DeducedType->isNull())
+ return getHoverContents(*DeducedType, AST.getASTContext());
+
+ return None;
}
} // namespace clangd