|
15 | 15 | #include "clang/AST/DeclarationName.h"
|
16 | 16 | #include "clang/AST/NestedNameSpecifier.h"
|
17 | 17 | #include "clang/AST/PrettyPrinter.h"
|
| 18 | +#include "clang/AST/RecursiveASTVisitor.h" |
18 | 19 | #include "clang/AST/TemplateBase.h"
|
19 | 20 | #include "clang/Basic/SourceLocation.h"
|
20 | 21 | #include "clang/Basic/SourceManager.h"
|
21 | 22 | #include "clang/Basic/Specifiers.h"
|
22 | 23 | #include "clang/Index/USRGeneration.h"
|
| 24 | +#include "clang/Lex/Lexer.h" |
23 | 25 | #include "llvm/ADT/Optional.h"
|
24 | 26 | #include "llvm/Support/Casting.h"
|
25 | 27 | #include "llvm/Support/ScopedPrinter.h"
|
@@ -253,5 +255,114 @@ QualType declaredType(const TypeDecl *D) {
|
253 | 255 | return D->getASTContext().getTypeDeclType(D);
|
254 | 256 | }
|
255 | 257 |
|
| 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 | + |
256 | 367 | } // namespace clangd
|
257 | 368 | } // namespace clang
|
0 commit comments