9#include "../clang-tidy/utils/DesignatedInitializers.h"
16#include "clang/AST/ASTDiagnostic.h"
17#include "clang/AST/Decl.h"
18#include "clang/AST/DeclBase.h"
19#include "clang/AST/DeclarationName.h"
20#include "clang/AST/Expr.h"
21#include "clang/AST/ExprCXX.h"
22#include "clang/AST/RecursiveASTVisitor.h"
23#include "clang/AST/Stmt.h"
24#include "clang/AST/StmtVisitor.h"
25#include "clang/AST/Type.h"
26#include "clang/Basic/Builtins.h"
27#include "clang/Basic/OperatorKinds.h"
28#include "clang/Basic/SourceLocation.h"
29#include "clang/Basic/SourceManager.h"
30#include "llvm/ADT/DenseSet.h"
31#include "llvm/ADT/STLExtras.h"
32#include "llvm/ADT/SmallVector.h"
33#include "llvm/ADT/StringExtras.h"
34#include "llvm/ADT/StringRef.h"
35#include "llvm/ADT/Twine.h"
36#include "llvm/Support/Casting.h"
37#include "llvm/Support/ErrorHandling.h"
38#include "llvm/Support/FormatVariadic.h"
39#include "llvm/Support/SaveAndRestore.h"
40#include "llvm/Support/ScopedPrinter.h"
41#include "llvm/Support/raw_ostream.h"
54void stripLeadingUnderscores(StringRef &
Name) {
Name =
Name.ltrim(
'_'); }
58template <
typename Ty,
typename =
decltype(((Ty *)
nullptr)->getDecl())>
59const NamedDecl *getDeclForTypeImpl(
const Ty *T) {
62const NamedDecl *getDeclForTypeImpl(
const void *T) {
return nullptr; }
63const NamedDecl *getDeclForType(
const Type *T) {
64 switch (
T->getTypeClass()) {
65#define ABSTRACT_TYPE(TY, BASE)
66#define TYPE(TY, BASE) \
68 return getDeclForTypeImpl(llvm::cast<TY##Type>(T));
69#include "clang/AST/TypeNodes.inc"
71 llvm_unreachable(
"Unknown TypeClass enum");
75llvm::StringRef getSimpleName(
const DeclarationName &DN) {
76 if (IdentifierInfo *Ident = DN.getAsIdentifierInfo())
77 return Ident->getName();
80llvm::StringRef getSimpleName(
const NamedDecl &D) {
81 return getSimpleName(D.getDeclName());
83llvm::StringRef getSimpleName(QualType T) {
84 if (
const auto *ET = llvm::dyn_cast<ElaboratedType>(T))
85 return getSimpleName(ET->getNamedType());
86 if (
const auto *BT = llvm::dyn_cast<BuiltinType>(T)) {
87 PrintingPolicy PP(LangOptions{});
88 PP.adjustForCPlusPlus();
89 return BT->getName(PP);
91 if (
const auto *D = getDeclForType(
T.getTypePtr()))
92 return getSimpleName(D->getDeclName());
99std::string summarizeExpr(
const Expr *
E) {
100 struct Namer : ConstStmtVisitor<Namer, std::string> {
101 std::string Visit(
const Expr *
E) {
104 return ConstStmtVisitor::Visit(
E->IgnoreImplicit());
108 std::string VisitMemberExpr(
const MemberExpr *
E) {
109 return getSimpleName(*
E->getMemberDecl()).str();
111 std::string VisitDeclRefExpr(
const DeclRefExpr *
E) {
112 return getSimpleName(*
E->getFoundDecl()).str();
114 std::string VisitCallExpr(
const CallExpr *
E) {
115 return Visit(
E->getCallee());
118 VisitCXXDependentScopeMemberExpr(
const CXXDependentScopeMemberExpr *
E) {
119 return getSimpleName(
E->getMember()).str();
122 VisitDependentScopeDeclRefExpr(
const DependentScopeDeclRefExpr *
E) {
123 return getSimpleName(
E->getDeclName()).str();
125 std::string VisitCXXFunctionalCastExpr(
const CXXFunctionalCastExpr *
E) {
126 return getSimpleName(
E->getType()).str();
128 std::string VisitCXXTemporaryObjectExpr(
const CXXTemporaryObjectExpr *
E) {
129 return getSimpleName(
E->getType()).str();
133 std::string VisitCXXMemberCallExpr(
const CXXMemberCallExpr *
E) {
135 if (
E->getNumArgs() == 0 &&
E->getMethodDecl() &&
136 E->getMethodDecl()->getDeclName().getNameKind() ==
137 DeclarationName::CXXConversionFunctionName &&
138 E->getSourceRange() ==
139 E->getImplicitObjectArgument()->getSourceRange())
140 return Visit(
E->getImplicitObjectArgument());
141 return ConstStmtVisitor::VisitCXXMemberCallExpr(
E);
143 std::string VisitCXXConstructExpr(
const CXXConstructExpr *
E) {
144 if (
E->getNumArgs() == 1)
145 return Visit(
E->getArg(0));
150 std::string VisitCXXBoolLiteralExpr(
const CXXBoolLiteralExpr *
E) {
151 return E->getValue() ?
"true" :
"false";
153 std::string VisitIntegerLiteral(
const IntegerLiteral *
E) {
154 return llvm::to_string(
E->getValue());
156 std::string VisitFloatingLiteral(
const FloatingLiteral *
E) {
158 llvm::raw_string_ostream
OS(Result);
159 E->getValue().print(
OS);
161 Result.resize(llvm::StringRef(Result).rtrim().size());
164 std::string VisitStringLiteral(
const StringLiteral *
E) {
165 std::string Result =
"\"";
166 if (
E->containsNonAscii()) {
168 }
else if (
E->getLength() > 10) {
169 Result +=
E->getString().take_front(7);
172 llvm::raw_string_ostream
OS(Result);
173 llvm::printEscapedString(
E->getString(),
OS);
175 Result.push_back(
'"');
180 std::string printUnary(llvm::StringRef Spelling,
const Expr *Operand,
182 std::string Sub = Visit(Operand);
186 return (Spelling + Sub).str();
190 bool InsideBinary =
false;
191 std::string printBinary(llvm::StringRef Spelling,
const Expr *LHSOp,
195 llvm::SaveAndRestore InBinary(InsideBinary,
true);
197 std::string LHS = Visit(LHSOp);
198 std::string RHS = Visit(RHSOp);
199 if (LHS.empty() && RHS.empty())
213 std::string VisitUnaryOperator(
const UnaryOperator *
E) {
214 return printUnary(
E->getOpcodeStr(
E->getOpcode()),
E->getSubExpr(),
217 std::string VisitBinaryOperator(
const BinaryOperator *
E) {
218 return printBinary(
E->getOpcodeStr(
E->getOpcode()),
E->getLHS(),
221 std::string VisitCXXOperatorCallExpr(
const CXXOperatorCallExpr *
E) {
222 const char *Spelling = getOperatorSpelling(
E->getOperator());
224 if ((
E->getOperator() == OO_PlusPlus ||
225 E->getOperator() == OO_MinusMinus) &&
226 E->getNumArgs() == 2)
227 return printUnary(Spelling,
E->getArg(0),
false);
228 if (
E->isInfixBinaryOp())
229 return printBinary(Spelling,
E->getArg(0),
E->getArg(1));
230 if (
E->getNumArgs() == 1) {
231 switch (
E->getOperator()) {
240 return printUnary(Spelling,
E->getArg(0),
true);
248 return Namer{}.Visit(
E);
253bool isSugaredTemplateParameter(QualType QT) {
254 static auto PeelWrapper = [](QualType QT) {
257 QualType Peeled = QT->getPointeeType();
258 return Peeled.isNull() ? QT : Peeled;
286 if (QT->getAs<SubstTemplateTypeParmType>())
288 QualType Desugared = QT->getLocallyUnqualifiedSingleStepDesugaredType();
291 else if (
auto Peeled = PeelWrapper(Desugared); Peeled != QT)
301std::optional<QualType> desugar(ASTContext &
AST, QualType QT) {
302 bool ShouldAKA =
false;
303 auto Desugared = clang::desugarForDiagnostic(
AST, QT, ShouldAKA);
316QualType maybeDesugar(ASTContext &
AST, QualType QT) {
320 if (isSugaredTemplateParameter(QT))
321 return desugar(
AST, QT).value_or(QT);
324 if (QT->isDecltypeType())
325 return QT.getCanonicalType();
326 if (
const AutoType *AT = QT->getContainedAutoType())
327 if (!AT->getDeducedType().isNull() &&
328 AT->getDeducedType()->isDecltypeType())
329 return QT.getCanonicalType();
338static FunctionProtoTypeLoc getPrototypeLoc(Expr *Fn) {
340 Expr *NakedFn = Fn->IgnoreParenCasts();
341 if (
const auto *T = NakedFn->getType().getTypePtr()->getAs<TypedefType>()) {
342 Target =
T->getDecl()->getTypeSourceInfo()->getTypeLoc();
343 }
else if (
const auto *DR = dyn_cast<DeclRefExpr>(NakedFn)) {
344 const auto *D = DR->getDecl();
345 if (
const auto *
const VD = dyn_cast<VarDecl>(D)) {
346 Target = VD->getTypeSourceInfo()->getTypeLoc();
355 if (
auto P = Target.getAs<PointerTypeLoc>()) {
356 Target = P.getPointeeLoc();
359 if (
auto A = Target.getAs<AttributedTypeLoc>()) {
360 Target =
A.getModifiedLoc();
363 if (
auto P = Target.getAs<ParenTypeLoc>()) {
364 Target = P.getInnerLoc();
370 if (
auto F = Target.getAs<FunctionProtoTypeLoc>()) {
377ArrayRef<const ParmVarDecl *>
378maybeDropCxxExplicitObjectParameters(ArrayRef<const ParmVarDecl *> Params) {
379 if (!Params.empty() && Params.front()->isExplicitObjectParameter())
380 Params = Params.drop_front(1);
385std::string joinAndTruncate(
const R &Range,
size_t MaxLength) {
387 llvm::raw_string_ostream
OS(
Out);
388 llvm::ListSeparator Sep(
", ");
389 for (
auto &&Element : Range) {
391 if (
Out.size() + Element.size() >= MaxLength) {
404 const FunctionDecl *
Decl =
nullptr;
410 InlayHintVisitor(std::vector<InlayHint> &
Results, ParsedAST &
AST,
411 const Config &Cfg, std::optional<Range> RestrictRange)
413 Cfg(Cfg), RestrictRange(std::move(RestrictRange)),
414 MainFileID(
AST.getSourceManager().getMainFileID()),
415 Resolver(
AST.getHeuristicResolver()),
416 TypeHintPolicy(this->AST.getPrintingPolicy()) {
418 llvm::StringRef Buf =
419 AST.getSourceManager().getBufferData(MainFileID, &
Invalid);
420 MainFileBuf =
Invalid ? StringRef{} : Buf;
422 TypeHintPolicy.SuppressScope =
true;
423 TypeHintPolicy.AnonymousTagLocations =
430 bool VisitTypeLoc(TypeLoc TL) {
431 if (
const auto *DT = llvm::dyn_cast<DecltypeType>(TL.getType()))
432 if (QualType UT = DT->getUnderlyingType(); !UT->isDependentType())
433 addTypeHint(TL.getSourceRange(), UT,
": ");
437 bool VisitCXXConstructExpr(CXXConstructExpr *
E) {
442 if (!
E->getParenOrBraceRange().isValid() ||
443 E->isStdInitListInitialization()) {
448 Callee.Decl =
E->getConstructor();
451 processCall(Callee,
E->getParenOrBraceRange().getEnd(),
452 {E->getArgs(), E->getNumArgs()});
458 bool TraversePseudoObjectExpr(PseudoObjectExpr *
E) {
459 Expr *SyntacticExpr =
E->getSyntacticForm();
460 if (isa<CallExpr>(SyntacticExpr))
475 if (isa<BinaryOperator>(SyntacticExpr))
481 bool VisitCallExpr(CallExpr *
E) {
485 bool IsFunctor = isFunctionObjectCallExpr(
E);
490 if ((isa<CXXOperatorCallExpr>(
E) && !IsFunctor) ||
491 isa<UserDefinedLiteral>(
E))
495 if (CalleeDecls.size() != 1)
499 if (
const auto *FD = dyn_cast<FunctionDecl>(CalleeDecls[0]))
501 else if (
const auto *FTD = dyn_cast<FunctionTemplateDecl>(CalleeDecls[0]))
502 Callee.Decl = FTD->getTemplatedDecl();
503 else if (FunctionProtoTypeLoc
Loc = getPrototypeLoc(
E->getCallee()))
518 llvm::ArrayRef<const Expr *>
Args = {
E->getArgs(),
E->getNumArgs()};
521 if (
const CXXMethodDecl *
Method =
522 dyn_cast_or_null<CXXMethodDecl>(Callee.Decl))
523 if (IsFunctor ||
Method->hasCXXExplicitFunctionObjectParameter())
525 processCall(Callee,
E->getRParenLoc(),
Args);
529 bool VisitFunctionDecl(FunctionDecl *D) {
531 llvm::dyn_cast<FunctionProtoType>(D->getType().getTypePtr())) {
532 if (!FPT->hasTrailingReturn()) {
533 if (
auto FTL = D->getFunctionTypeLoc())
534 addReturnTypeHint(D, FTL.getRParenLoc());
540 if (
const Stmt *Body = D->getBody())
541 addBlockEndHint(Body->getSourceRange(),
"",
printName(
AST, *D),
"");
546 bool VisitForStmt(ForStmt *S) {
550 if (
auto *DS = llvm::dyn_cast_or_null<DeclStmt>(S->getInit());
551 DS && DS->isSingleDecl())
552 Name = getSimpleName(llvm::cast<NamedDecl>(*DS->getSingleDecl()));
554 Name = summarizeExpr(S->getCond());
555 markBlockEnd(S->getBody(),
"for",
Name);
560 bool VisitCXXForRangeStmt(CXXForRangeStmt *S) {
562 markBlockEnd(S->getBody(),
"for", getSimpleName(*S->getLoopVariable()));
566 bool VisitWhileStmt(WhileStmt *S) {
568 markBlockEnd(S->getBody(),
"while", summarizeExpr(S->getCond()));
572 bool VisitSwitchStmt(SwitchStmt *S) {
574 markBlockEnd(S->getBody(),
"switch", summarizeExpr(S->getCond()));
585 bool VisitIfStmt(IfStmt *S) {
587 if (
const auto *ElseIf = llvm::dyn_cast_or_null<IfStmt>(S->getElse()))
590 if (
const auto *EndCS = llvm::dyn_cast<CompoundStmt>(
591 S->getElse() ? S->getElse() : S->getThen())) {
593 {S->getThen()->getBeginLoc(), EndCS->getRBracLoc()},
"if",
594 ElseIfs.contains(S) ?
"" : summarizeExpr(S->getCond()),
"");
600 void markBlockEnd(
const Stmt *Body, llvm::StringRef
Label,
601 llvm::StringRef
Name =
"") {
602 if (
const auto *CS = llvm::dyn_cast_or_null<CompoundStmt>(Body))
603 addBlockEndHint(CS->getSourceRange(),
Label,
Name,
"");
606 bool VisitTagDecl(TagDecl *D) {
608 std::string DeclPrefix = D->getKindName().str();
609 if (
const auto *ED = dyn_cast<EnumDecl>(D)) {
611 DeclPrefix += ED->isScopedUsingClassTag() ?
" class" :
" struct";
613 addBlockEndHint(D->getBraceRange(), DeclPrefix, getSimpleName(*D),
";");
618 bool VisitNamespaceDecl(NamespaceDecl *D) {
622 addBlockEndHint(D->getSourceRange(),
"namespace", getSimpleName(*D),
"");
627 bool VisitLambdaExpr(LambdaExpr *
E) {
628 FunctionDecl *D =
E->getCallOperator();
629 if (!
E->hasExplicitResultType()) {
630 SourceLocation TypeHintLoc;
631 if (!
E->hasExplicitParameters())
632 TypeHintLoc =
E->getIntroducerRange().getEnd();
633 else if (
auto FTL = D->getFunctionTypeLoc())
634 TypeHintLoc = FTL.getRParenLoc();
635 if (TypeHintLoc.isValid())
636 addReturnTypeHint(D, TypeHintLoc);
641 void addReturnTypeHint(FunctionDecl *D, SourceRange Range) {
642 auto *AT = D->getReturnType()->getContainedAutoType();
643 if (!AT || AT->getDeducedType().isNull())
645 addTypeHint(Range, D->getReturnType(),
"-> ");
648 bool VisitVarDecl(VarDecl *D) {
651 if (
auto *DD = dyn_cast<DecompositionDecl>(D)) {
652 for (
auto *Binding : DD->bindings()) {
656 if (
auto Type = Binding->getType();
657 !
Type.isNull() && !
Type->isDependentType())
658 addTypeHint(Binding->getLocation(),
Type.getCanonicalType(),
664 if (
auto *AT = D->getType()->getContainedAutoType()) {
665 if (AT->isDeduced() && !D->getType()->isDependentType()) {
671 addTypeHint(D->getLocation(), D->getType(),
": ");
676 if (
auto *PVD = llvm::dyn_cast<ParmVarDecl>(D)) {
677 if (D->getIdentifier() && PVD->getType()->isDependentType() &&
680 if (
auto *IPVD = getOnlyParamInstantiation(PVD))
681 addTypeHint(D->getLocation(), IPVD->getType(),
": ");
688 ParmVarDecl *getOnlyParamInstantiation(ParmVarDecl *D) {
689 auto *TemplateFunction = llvm::dyn_cast<FunctionDecl>(D->getDeclContext());
690 if (!TemplateFunction)
692 auto *InstantiatedFunction = llvm::dyn_cast_or_null<FunctionDecl>(
694 if (!InstantiatedFunction)
697 unsigned ParamIdx = 0;
698 for (
auto *Param : TemplateFunction->parameters()) {
701 if (Param->isParameterPack())
707 assert(ParamIdx < TemplateFunction->getNumParams() &&
708 "Couldn't find param in list?");
709 assert(ParamIdx < InstantiatedFunction->getNumParams() &&
710 "Instantiated function has fewer (non-pack) parameters?");
711 return InstantiatedFunction->getParamDecl(ParamIdx);
714 bool VisitInitListExpr(InitListExpr *Syn) {
721 assert(Syn->isSyntacticForm() &&
"RAV should not visit implicit code!");
724 if (Syn->isIdiomaticZeroInitializer(
AST.getLangOpts()))
726 llvm::DenseMap<SourceLocation, std::string> Designators =
728 for (
const Expr *Init : Syn->inits()) {
729 if (llvm::isa<DesignatedInitExpr>(Init))
731 auto It = Designators.find(Init->getBeginLoc());
732 if (It != Designators.end() &&
733 !isPrecededByParamNameComment(Init, It->second))
734 addDesignatorHint(Init->getSourceRange(), It->second);
742 using NameVec = SmallVector<StringRef, 8>;
744 void processCall(Callee Callee, SourceLocation RParenOrBraceLoc,
745 llvm::ArrayRef<const Expr *>
Args) {
746 assert(Callee.Decl || Callee.Loc);
754 if (
auto *Ctor = dyn_cast<CXXConstructorDecl>(Callee.Decl))
755 if (Ctor->isCopyOrMoveConstructor())
758 SmallVector<std::string> FormattedDefaultArgs;
759 bool HasNonDefaultArgs =
false;
761 ArrayRef<const ParmVarDecl *> Params, ForwardedParams;
763 SmallVector<const ParmVarDecl *> ForwardedParamsStorage;
765 Params = maybeDropCxxExplicitObjectParameters(Callee.Decl->parameters());
768 maybeDropCxxExplicitObjectParameters(ForwardedParamsStorage);
770 Params = maybeDropCxxExplicitObjectParameters(Callee.Loc.getParams());
771 ForwardedParams = {Params.begin(), Params.end()};
774 NameVec ParameterNames = chooseParameterNames(ForwardedParams);
780 (isSetter(Callee.Decl, ParameterNames) || isSimpleBuiltin(Callee.Decl)))
783 for (
size_t I = 0; I < ParameterNames.size() && I <
Args.size(); ++I) {
787 if (isa<PackExpansionExpr>(
Args[I])) {
791 StringRef
Name = ParameterNames[I];
792 const bool NameHint =
794 const bool ReferenceHint =
795 shouldHintReference(Params[I], ForwardedParams[I]) &&
798 const bool IsDefault = isa<CXXDefaultArgExpr>(
Args[I]);
799 HasNonDefaultArgs |= !IsDefault;
802 const auto SourceText = Lexer::getSourceText(
803 CharSourceRange::getTokenRange(Params[I]->getDefaultArgRange()),
804 AST.getSourceManager(),
AST.getLangOpts());
807 SourceText.contains(
"\n"))
811 FormattedDefaultArgs.emplace_back(
812 llvm::formatv(
"{0}: {1}",
Name, Abbrev));
814 FormattedDefaultArgs.emplace_back(llvm::formatv(
"{0}", Abbrev));
816 }
else if (NameHint || ReferenceHint) {
817 addInlayHint(
Args[I]->getSourceRange(), HintSide::Left,
819 NameHint ?
Name :
"",
": ");
823 if (!FormattedDefaultArgs.empty()) {
826 addInlayHint(SourceRange{RParenOrBraceLoc}, HintSide::Left,
828 HasNonDefaultArgs ?
", " :
"", Hint,
"");
832 static bool isSetter(
const FunctionDecl *Callee,
const NameVec &ParamNames) {
833 if (ParamNames.size() != 1)
836 StringRef
Name = getSimpleName(*Callee);
837 if (!
Name.starts_with_insensitive(
"set"))
851 StringRef WhatItIsSetting =
Name.substr(3).ltrim(
"_");
852 return WhatItIsSetting.equals_insensitive(ParamNames[0]);
857 static bool isSimpleBuiltin(
const FunctionDecl *Callee) {
858 switch (Callee->getBuiltinID()) {
859 case Builtin::BIaddressof:
860 case Builtin::BIas_const:
861 case Builtin::BIforward:
862 case Builtin::BImove:
863 case Builtin::BImove_if_noexcept:
870 bool shouldHintName(
const Expr *Arg, StringRef ParamName) {
871 if (ParamName.empty())
876 if (ParamName == getSpelledIdentifier(Arg))
880 if (isPrecededByParamNameComment(Arg, ParamName))
886 bool shouldHintReference(
const ParmVarDecl *Param,
887 const ParmVarDecl *ForwardedParam) {
910 auto Type = Param->getType();
911 auto ForwardedType = ForwardedParam->getType();
912 return Type->isLValueReferenceType() &&
913 ForwardedType->isLValueReferenceType() &&
914 !ForwardedType.getNonReferenceType().isConstQualified() &&
921 bool isPrecededByParamNameComment(
const Expr *
E, StringRef ParamName) {
922 auto &SM =
AST.getSourceManager();
923 auto FileLoc = SM.getFileLoc(
E->getBeginLoc());
924 auto Decomposed = SM.getDecomposedLoc(FileLoc);
925 if (Decomposed.first != MainFileID)
928 StringRef SourcePrefix = MainFileBuf.substr(0, Decomposed.second);
930 SourcePrefix = SourcePrefix.rtrim();
932 if (!SourcePrefix.consume_back(
"*/"))
936 llvm::StringLiteral IgnoreChars =
" =.";
937 SourcePrefix = SourcePrefix.rtrim(IgnoreChars);
938 ParamName = ParamName.trim(IgnoreChars);
940 if (!SourcePrefix.consume_back(ParamName))
942 SourcePrefix = SourcePrefix.rtrim(IgnoreChars);
943 return SourcePrefix.ends_with(
"/*");
948 static StringRef getSpelledIdentifier(
const Expr *
E) {
949 E =
E->IgnoreUnlessSpelledInSource();
951 if (
auto *DRE = dyn_cast<DeclRefExpr>(
E))
952 if (!DRE->getQualifier())
953 return getSimpleName(*DRE->getDecl());
955 if (
auto *ME = dyn_cast<MemberExpr>(
E))
956 if (!ME->getQualifier() && ME->isImplicitAccess())
957 return getSimpleName(*ME->getMemberDecl());
962 NameVec chooseParameterNames(ArrayRef<const ParmVarDecl *>
Parameters) {
963 NameVec ParameterNames;
969 ParameterNames.emplace_back();
971 auto SimpleName = getSimpleName(*P);
974 if (SimpleName.empty()) {
975 if (
const auto *PD = getParamDefinition(P)) {
976 SimpleName = getSimpleName(*PD);
979 ParameterNames.emplace_back(SimpleName);
985 for (
auto &
Name : ParameterNames)
986 stripLeadingUnderscores(
Name);
988 return ParameterNames;
993 static const ParmVarDecl *getParamDefinition(
const ParmVarDecl *P) {
994 if (
auto *Callee = dyn_cast<FunctionDecl>(P->getDeclContext())) {
995 if (
auto *Def = Callee->getDefinition()) {
996 auto I = std::distance(Callee->param_begin(),
997 llvm::find(Callee->parameters(), P));
998 if (I < (
int)Callee->getNumParams()) {
999 return Def->getParamDecl(I);
1009 llvm::StringRef Prefix, llvm::StringRef
Label,
1010 llvm::StringRef
Suffix) {
1011 auto LSPRange = getHintRange(R);
1019 llvm::StringRef Prefix, llvm::StringRef
Label,
1020 llvm::StringRef
Suffix) {
1026#define CHECK_KIND(Enumerator, ConfigProperty) \
1027 case InlayHintKind::Enumerator: \
1028 assert(Cfg.InlayHints.ConfigProperty && \
1029 "Shouldn't get here if kind is disabled!"); \
1030 if (!Cfg.InlayHints.ConfigProperty) \
1041 Position LSPPos =
Side == HintSide::Left ? LSPRange.start : LSPRange.end;
1042 if (RestrictRange &&
1043 (LSPPos < RestrictRange->start || !(LSPPos < RestrictRange->end)))
1045 bool PadLeft = Prefix.consume_front(
" ");
1046 bool PadRight =
Suffix.consume_back(
" ");
1047 Results.push_back(InlayHint{LSPPos,
1049 Kind, PadLeft, PadRight, LSPRange});
1053 std::optional<Range> getHintRange(SourceRange R) {
1054 const auto &SM =
AST.getSourceManager();
1055 auto Spelled = Tokens.spelledForExpanded(Tokens.expandedTokens(R));
1059 return std::nullopt;
1061 if (SM.getFileID(
Spelled->front().location()) != SM.getMainFileID() ||
1062 SM.getFileID(
Spelled->back().location()) != SM.getMainFileID())
1063 return std::nullopt;
1068 void addTypeHint(SourceRange R, QualType T, llvm::StringRef Prefix) {
1074 auto Desugared = maybeDesugar(
AST, T);
1075 std::string TypeName = Desugared.getAsString(TypeHintPolicy);
1076 if (T != Desugared && !shouldPrintTypeHint(TypeName)) {
1079 TypeName =
T.getAsString(TypeHintPolicy);
1081 if (shouldPrintTypeHint(TypeName))
1086 void addDesignatorHint(SourceRange R, llvm::StringRef
Text) {
1091 bool shouldPrintTypeHint(llvm::StringRef TypeName)
const noexcept {
1096 void addBlockEndHint(SourceRange BraceRange, StringRef DeclPrefix,
1097 StringRef
Name, StringRef OptionalPunctuation) {
1098 auto HintRange = computeBlockEndHintRange(BraceRange, OptionalPunctuation);
1102 std::string
Label = DeclPrefix.str();
1107 constexpr unsigned HintMaxLengthLimit = 60;
1108 if (
Label.length() > HintMaxLengthLimit)
1121 std::optional<Range> computeBlockEndHintRange(SourceRange BraceRange,
1122 StringRef OptionalPunctuation) {
1123 constexpr unsigned HintMinLineLimit = 2;
1125 auto &SM =
AST.getSourceManager();
1126 auto [BlockBeginFileId, BlockBeginOffset] =
1127 SM.getDecomposedLoc(SM.getFileLoc(BraceRange.getBegin()));
1128 auto RBraceLoc = SM.getFileLoc(BraceRange.getEnd());
1129 auto [RBraceFileId, RBraceOffset] = SM.getDecomposedLoc(RBraceLoc);
1135 if (BlockBeginFileId != MainFileID || RBraceFileId != MainFileID)
1136 return std::nullopt;
1138 StringRef RestOfLine = MainFileBuf.substr(RBraceOffset).split(
'\n').first;
1139 if (!RestOfLine.starts_with(
"}"))
1140 return std::nullopt;
1142 StringRef TrimmedTrailingText = RestOfLine.drop_front().trim();
1143 if (!TrimmedTrailingText.empty() &&
1144 TrimmedTrailingText != OptionalPunctuation)
1145 return std::nullopt;
1147 auto BlockBeginLine = SM.getLineNumber(BlockBeginFileId, BlockBeginOffset);
1148 auto RBraceLine = SM.getLineNumber(RBraceFileId, RBraceOffset);
1151 if (BlockBeginLine + HintMinLineLimit - 1 > RBraceLine)
1152 return std::nullopt;
1155 StringRef HintRangeText = RestOfLine.take_front(
1156 TrimmedTrailingText.empty()
1158 : TrimmedTrailingText.bytes_end() - RestOfLine.bytes_begin());
1162 SM, RBraceLoc.getLocWithOffset(HintRangeText.size()));
1163 return Range{HintStart, HintEnd};
1166 static bool isFunctionObjectCallExpr(CallExpr *
E)
noexcept {
1167 if (
auto *CallExpr = dyn_cast<CXXOperatorCallExpr>(
E))
1168 return CallExpr->getOperator() == OverloadedOperatorKind::OO_Call;
1172 std::vector<InlayHint> &
Results;
1174 const syntax::TokenBuffer &Tokens;
1176 std::optional<Range> RestrictRange;
1178 StringRef MainFileBuf;
1179 const HeuristicResolver *Resolver;
1180 PrintingPolicy TypeHintPolicy;
1186 std::optional<Range> RestrictRange) {
1187 std::vector<InlayHint>
Results;
1191 InlayHintVisitor Visitor(
Results,
AST, Cfg, std::move(RestrictRange));
1192 Visitor.TraverseAST(
AST.getASTContext());
ArrayRef< const ParmVarDecl * > Parameters
const FunctionDecl * Decl
llvm::SmallString< 256U > Name
std::vector< CodeCompletionResult > Results
CompiledFragmentImpl & Out
CharSourceRange Range
SourceRange for the file name.
llvm::DenseSet< const IfStmt * > ElseIfs
#define CHECK_KIND(Enumerator, ConfigProperty)
std::vector< const NamedDecl * > resolveCalleeOfCallExpr(const CallExpr *CE) const
Stores and provides access to parsed AST.
SmallVector< const ParmVarDecl * > resolveForwardingParameters(const FunctionDecl *D, unsigned MaxDepth)
Recursively resolves the parameters of a FunctionDecl that forwards its parameters to another functio...
std::string printName(const ASTContext &Ctx, const NamedDecl &ND)
Prints unqualified name of the decl for the purpose of displaying it to the user.
NamedDecl * getOnlyInstantiation(NamedDecl *TemplatedDecl)
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
bool isExpandedFromParameterPack(const ParmVarDecl *D)
Checks whether D is instantiated from a function parameter pack whose type is a bare type parameter p...
InlayHintKind
Inlay hint kinds.
@ BlockEnd
A hint after function, type or namespace definition, indicating the defined symbol name of the defini...
@ DefaultArgument
An inlay hint that is for a default argument.
@ Parameter
An inlay hint that is for a parameter.
@ Type
An inlay hint that for a type annotation.
@ Designator
A hint before an element of an aggregate braced initializer list, indicating what it is initializing.
std::vector< InlayHint > inlayHints(ParsedAST &AST, std::optional< Range > RestrictRange)
Compute and return inlay hints for a file.
TemplateTypeParmTypeLoc getContainedAutoParamType(TypeLoc TL)
@ Invalid
Sentinel bit pattern. DO NOT USE!
llvm::DenseMap< SourceLocation, std::string > getUnwrittenDesignators(const InitListExpr *Syn)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static const Config & current()
Returns the Config of the current Context, or an empty configuration.
bool Enabled
If false, inlay hints are completely disabled.
struct clang::clangd::Config::@8 InlayHints