Skip to content

Commit 765b125

Browse files
committed
[clangd] Untangle Hover from XRefs, move into own file.
Summary: This is mostly mechanical, with a few exceptions: - getDeducedType moved into AST.h where it belongs. It now takes ASTContext instead of ParsedAST, and avoids using the preprocessor. - hover now uses SelectionTree directly rather than via getDeclAtPosition helper - hover on 'auto' used to find the decl that contained the 'auto' and use that to set Kind and documentation for the hover result. Now we use targetDecl() to find the decl matching the deduced type instead. This changes tests, e.g. 'variable' -> class for auto on lambdas. I think this is better, but the motivation was to avoid depending on the internals of DeducedTypeVisitor. This functionality is removed from the visitor. Reviewers: kadircet Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D70357
1 parent c54d21c commit 765b125

File tree

13 files changed

+2025
-1961
lines changed

13 files changed

+2025
-1961
lines changed

clang-tools-extra/clangd/AST.cpp

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@
1515
#include "clang/AST/DeclarationName.h"
1616
#include "clang/AST/NestedNameSpecifier.h"
1717
#include "clang/AST/PrettyPrinter.h"
18+
#include "clang/AST/RecursiveASTVisitor.h"
1819
#include "clang/AST/TemplateBase.h"
1920
#include "clang/Basic/SourceLocation.h"
2021
#include "clang/Basic/SourceManager.h"
2122
#include "clang/Basic/Specifiers.h"
2223
#include "clang/Index/USRGeneration.h"
24+
#include "clang/Lex/Lexer.h"
2325
#include "llvm/ADT/Optional.h"
2426
#include "llvm/Support/Casting.h"
2527
#include "llvm/Support/ScopedPrinter.h"
@@ -253,5 +255,114 @@ QualType declaredType(const TypeDecl *D) {
253255
return D->getASTContext().getTypeDeclType(D);
254256
}
255257

258+
namespace {
259+
/// Computes the deduced type at a given location by visiting the relevant
260+
/// nodes. We use this to display the actual type when hovering over an "auto"
261+
/// keyword or "decltype()" expression.
262+
/// FIXME: This could have been a lot simpler by visiting AutoTypeLocs but it
263+
/// seems that the AutoTypeLocs that can be visited along with their AutoType do
264+
/// not have the deduced type set. Instead, we have to go to the appropriate
265+
/// DeclaratorDecl/FunctionDecl and work our back to the AutoType that does have
266+
/// a deduced type set. The AST should be improved to simplify this scenario.
267+
class DeducedTypeVisitor : public RecursiveASTVisitor<DeducedTypeVisitor> {
268+
SourceLocation SearchedLocation;
269+
270+
public:
271+
DeducedTypeVisitor(SourceLocation SearchedLocation)
272+
: SearchedLocation(SearchedLocation) {}
273+
274+
// Handle auto initializers:
275+
//- auto i = 1;
276+
//- decltype(auto) i = 1;
277+
//- auto& i = 1;
278+
//- auto* i = &a;
279+
bool VisitDeclaratorDecl(DeclaratorDecl *D) {
280+
if (!D->getTypeSourceInfo() ||
281+
D->getTypeSourceInfo()->getTypeLoc().getBeginLoc() != SearchedLocation)
282+
return true;
283+
284+
if (auto *AT = D->getType()->getContainedAutoType()) {
285+
if (!AT->getDeducedType().isNull())
286+
DeducedType = AT->getDeducedType();
287+
}
288+
return true;
289+
}
290+
291+
// Handle auto return types:
292+
//- auto foo() {}
293+
//- auto& foo() {}
294+
//- auto foo() -> int {}
295+
//- auto foo() -> decltype(1+1) {}
296+
//- operator auto() const { return 10; }
297+
bool VisitFunctionDecl(FunctionDecl *D) {
298+
if (!D->getTypeSourceInfo())
299+
return true;
300+
// Loc of auto in return type (c++14).
301+
auto CurLoc = D->getReturnTypeSourceRange().getBegin();
302+
// Loc of "auto" in operator auto()
303+
if (CurLoc.isInvalid() && dyn_cast<CXXConversionDecl>(D))
304+
CurLoc = D->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
305+
// Loc of "auto" in function with traling return type (c++11).
306+
if (CurLoc.isInvalid())
307+
CurLoc = D->getSourceRange().getBegin();
308+
if (CurLoc != SearchedLocation)
309+
return true;
310+
311+
const AutoType *AT = D->getReturnType()->getContainedAutoType();
312+
if (AT && !AT->getDeducedType().isNull()) {
313+
DeducedType = AT->getDeducedType();
314+
} else if (auto DT = dyn_cast<DecltypeType>(D->getReturnType())) {
315+
// auto in a trailing return type just points to a DecltypeType and
316+
// getContainedAutoType does not unwrap it.
317+
if (!DT->getUnderlyingType().isNull())
318+
DeducedType = DT->getUnderlyingType();
319+
} else if (!D->getReturnType().isNull()) {
320+
DeducedType = D->getReturnType();
321+
}
322+
return true;
323+
}
324+
325+
// Handle non-auto decltype, e.g.:
326+
// - auto foo() -> decltype(expr) {}
327+
// - decltype(expr);
328+
bool VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
329+
if (TL.getBeginLoc() != SearchedLocation)
330+
return true;
331+
332+
// A DecltypeType's underlying type can be another DecltypeType! E.g.
333+
// int I = 0;
334+
// decltype(I) J = I;
335+
// decltype(J) K = J;
336+
const DecltypeType *DT = dyn_cast<DecltypeType>(TL.getTypePtr());
337+
while (DT && !DT->getUnderlyingType().isNull()) {
338+
DeducedType = DT->getUnderlyingType();
339+
DT = dyn_cast<DecltypeType>(DeducedType.getTypePtr());
340+
}
341+
return true;
342+
}
343+
344+
QualType DeducedType;
345+
};
346+
} // namespace
347+
348+
llvm::Optional<QualType> getDeducedType(ASTContext &ASTCtx,
349+
SourceLocation Loc) {
350+
Token Tok;
351+
// Only try to find a deduced type if the token is auto or decltype.
352+
if (!Loc.isValid() ||
353+
Lexer::getRawToken(Loc, Tok, ASTCtx.getSourceManager(),
354+
ASTCtx.getLangOpts(), false) ||
355+
!Tok.is(tok::raw_identifier) ||
356+
!(Tok.getRawIdentifier() == "auto" ||
357+
Tok.getRawIdentifier() == "decltype")) {
358+
return {};
359+
}
360+
DeducedTypeVisitor V(Loc);
361+
V.TraverseAST(ASTCtx);
362+
if (V.DeducedType.isNull())
363+
return llvm::None;
364+
return V.DeducedType;
365+
}
366+
256367
} // namespace clangd
257368
} // namespace clang

clang-tools-extra/clangd/AST.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ NestedNameSpecifierLoc getQualifierLoc(const NamedDecl &ND);
116116
// (i.e. vector<T*> rather than vector<type-parameter-0-0 *>.
117117
QualType declaredType(const TypeDecl *D);
118118

119+
/// Retrieves the deduced type at a given location (auto, decltype).
120+
/// Retuns None unless Loc starts an auto/decltype token.
121+
/// It will return the underlying type.
122+
llvm::Optional<QualType> getDeducedType(ASTContext &, SourceLocation Loc);
123+
119124
} // namespace clangd
120125
} // namespace clang
121126

clang-tools-extra/clangd/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ add_clang_library(clangDaemon
5757
GlobalCompilationDatabase.cpp
5858
Headers.cpp
5959
HeaderSourceSwitch.cpp
60+
Hover.cpp
6061
IncludeFixer.cpp
6162
JSONTransport.cpp
6263
Logger.cpp

clang-tools-extra/clangd/ClangdServer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "FormattedString.h"
1717
#include "Function.h"
1818
#include "GlobalCompilationDatabase.h"
19+
#include "Hover.h"
1920
#include "Protocol.h"
2021
#include "SemanticHighlighting.h"
2122
#include "TUScheduler.h"

0 commit comments

Comments
 (0)