diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp --- a/clang-tools-extra/clangd/InlayHints.cpp +++ b/clang-tools-extra/clangd/InlayHints.cpp @@ -218,6 +218,13 @@ StructuredBindingPolicy.PrintCanonicalTypes = true; } + bool VisitTypeLoc(TypeLoc TL) { + if (const auto *DT = llvm::dyn_cast(TL.getType())) + if (QualType UT = DT->getUnderlyingType(); !UT->isDependentType()) + addTypeHint(TL.getSourceRange(), UT, ": "); + return true; + } + bool VisitCXXConstructExpr(CXXConstructExpr *E) { // Weed out constructor calls that don't look like a function call with // an argument list, by checking the validity of getParenOrBraceRange(). diff --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp --- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp +++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp @@ -1361,6 +1361,29 @@ EXPECT_THAT(hintsOfKind(AST, InlayHintKind::Type), IsEmpty()); } +TEST(TypeHints, Decltype) { + assertTypeHints(R"cpp( + $a[[decltype(0)]] a; + // FIXME: will be nice to show `: int` instead + $b[[decltype(a)]] b; + const $c[[decltype(0)]] &c = b; + + // Don't show for dependent type + template + constexpr decltype(T{}) d; + + $e[[decltype(0)]] e(); + auto f() -> $f[[decltype(0)]]; + + template struct Foo; + using G = Foo<$g[[decltype(0)]], float>; + )cpp", + ExpectedHint{": int", "a"}, + ExpectedHint{": decltype(0)", "b"}, + ExpectedHint{": int", "c"}, ExpectedHint{": int", "e"}, + ExpectedHint{": int", "f"}, ExpectedHint{": int", "g"}); +} + TEST(DesignatorHints, Basic) { assertDesignatorHints(R"cpp( struct S { int x, y, z; };