14#include "clang/AST/ASTDiagnostic.h"
15#include "clang/AST/Decl.h"
16#include "clang/AST/DeclarationName.h"
17#include "clang/AST/Expr.h"
18#include "clang/AST/ExprCXX.h"
19#include "clang/AST/RecursiveASTVisitor.h"
20#include "clang/AST/Stmt.h"
21#include "clang/AST/StmtVisitor.h"
22#include "clang/AST/Type.h"
23#include "clang/Basic/Builtins.h"
24#include "clang/Basic/OperatorKinds.h"
25#include "clang/Basic/SourceManager.h"
26#include "llvm/ADT/DenseSet.h"
27#include "llvm/ADT/ScopeExit.h"
28#include "llvm/ADT/StringExtras.h"
29#include "llvm/ADT/StringRef.h"
30#include "llvm/ADT/Twine.h"
31#include "llvm/Support/Casting.h"
32#include "llvm/Support/SaveAndRestore.h"
33#include "llvm/Support/ScopedPrinter.h"
34#include "llvm/Support/raw_ostream.h"
49class AggregateDesignatorNames {
51 AggregateDesignatorNames(QualType T) {
53 T = T.getCanonicalType();
54 if (T->isArrayType()) {
59 if (
const RecordDecl *RD = T->getAsRecordDecl()) {
61 FieldsIt = RD->field_begin();
62 FieldsEnd = RD->field_end();
63 if (
const auto *CRD = llvm::dyn_cast<CXXRecordDecl>(RD)) {
64 BasesIt = CRD->bases_begin();
65 BasesEnd = CRD->bases_end();
66 Valid = CRD->isAggregate();
68 OneField = Valid && BasesIt == BasesEnd && FieldsIt != FieldsEnd &&
69 std::next(FieldsIt) == FieldsEnd;
74 operator bool() {
return Valid; }
79 else if (BasesIt != BasesEnd)
81 else if (FieldsIt != FieldsEnd)
86 bool append(std::string &
Out,
bool ForSubobject) {
89 Out.append(std::to_string(Index));
93 if (BasesIt != BasesEnd)
95 if (FieldsIt != FieldsEnd) {
96 llvm::StringRef FieldName;
97 if (
const IdentifierInfo *II = FieldsIt->getIdentifier())
98 FieldName = II->getName();
102 (FieldsIt->isAnonymousStructOrUnion() ||
109 Out.append(FieldName.begin(), FieldName.end());
119 bool IsArray =
false;
120 bool OneField =
false;
122 CXXRecordDecl::base_class_const_iterator BasesIt;
123 CXXRecordDecl::base_class_const_iterator BasesEnd;
124 RecordDecl::field_iterator FieldsIt;
125 RecordDecl::field_iterator FieldsEnd;
143void collectDesignators(
const InitListExpr *Sem,
144 llvm::DenseMap<SourceLocation, std::string> &
Out,
145 const llvm::DenseSet<SourceLocation> &NestedBraces,
146 std::string &Prefix) {
147 if (!Sem || Sem->isTransparent())
149 assert(Sem->isSemanticForm());
153 AggregateDesignatorNames Fields(Sem->getType());
156 for (
const Expr *Init : Sem->inits()) {
157 auto Next = llvm::make_scope_exit([&, Size(Prefix.size())] {
163 if (!Init || llvm::isa<ImplicitValueInitExpr>(Init))
166 const auto *BraceElidedSubobject = llvm::dyn_cast<InitListExpr>(Init);
167 if (BraceElidedSubobject &&
168 NestedBraces.contains(BraceElidedSubobject->getLBraceLoc()))
169 BraceElidedSubobject =
nullptr;
171 if (!Fields.append(Prefix, BraceElidedSubobject !=
nullptr))
173 if (BraceElidedSubobject) {
178 collectDesignators(BraceElidedSubobject,
Out, NestedBraces, Prefix);
181 Out.try_emplace(Init->getBeginLoc(), Prefix);
187llvm::DenseMap<SourceLocation, std::string>
188getDesignators(
const InitListExpr *Syn) {
189 assert(Syn->isSyntacticForm());
194 llvm::DenseSet<SourceLocation> NestedBraces;
195 for (
const Expr *Init : Syn->inits())
196 if (
auto *Nested = llvm::dyn_cast<InitListExpr>(Init))
197 NestedBraces.insert(Nested->getLBraceLoc());
201 llvm::DenseMap<SourceLocation, std::string> Designators;
202 std::string EmptyPrefix;
203 collectDesignators(Syn->isSemanticForm() ? Syn : Syn->getSemanticForm(),
204 Designators, NestedBraces, EmptyPrefix);
208void stripLeadingUnderscores(StringRef &
Name) {
Name =
Name.ltrim(
'_'); }
212template <
typename Ty,
typename =
decltype(((Ty *)
nullptr)->getDecl())>
213const NamedDecl *getDeclForTypeImpl(
const Ty *T) {
216const NamedDecl *getDeclForTypeImpl(
const void *T) {
return nullptr; }
217const NamedDecl *getDeclForType(
const Type *T) {
218 switch (T->getTypeClass()) {
219#define ABSTRACT_TYPE(TY, BASE)
220#define TYPE(TY, BASE) \
222 return getDeclForTypeImpl(llvm::cast<TY##Type>(T));
223#include "clang/AST/TypeNodes.inc"
225 llvm_unreachable(
"Unknown TypeClass enum");
229llvm::StringRef getSimpleName(
const DeclarationName &DN) {
230 if (IdentifierInfo *Ident = DN.getAsIdentifierInfo())
231 return Ident->getName();
234llvm::StringRef getSimpleName(
const NamedDecl &D) {
235 return getSimpleName(
D.getDeclName());
237llvm::StringRef getSimpleName(QualType T) {
238 if (
const auto *ET = llvm::dyn_cast<ElaboratedType>(T))
239 return getSimpleName(ET->getNamedType());
240 if (
const auto *BT = llvm::dyn_cast<BuiltinType>(T)) {
241 PrintingPolicy PP(LangOptions{});
242 PP.adjustForCPlusPlus();
243 return BT->getName(PP);
245 if (
const auto *D = getDeclForType(T.getTypePtr()))
246 return getSimpleName(
D->getDeclName());
253std::string summarizeExpr(
const Expr *
E) {
254 struct Namer : ConstStmtVisitor<Namer, std::string> {
255 std::string Visit(
const Expr *
E) {
258 return ConstStmtVisitor::Visit(
E->IgnoreImplicit());
262 std::string VisitMemberExpr(
const MemberExpr *
E) {
263 return getSimpleName(*
E->getMemberDecl()).str();
265 std::string VisitDeclRefExpr(
const DeclRefExpr *
E) {
266 return getSimpleName(*
E->getFoundDecl()).str();
268 std::string VisitCallExpr(
const CallExpr *
E) {
269 return Visit(
E->getCallee());
272 VisitCXXDependentScopeMemberExpr(
const CXXDependentScopeMemberExpr *
E) {
273 return getSimpleName(
E->getMember()).str();
276 VisitDependentScopeDeclRefExpr(
const DependentScopeDeclRefExpr *
E) {
277 return getSimpleName(
E->getDeclName()).str();
279 std::string VisitCXXFunctionalCastExpr(
const CXXFunctionalCastExpr *
E) {
280 return getSimpleName(
E->getType()).str();
282 std::string VisitCXXTemporaryObjectExpr(
const CXXTemporaryObjectExpr *
E) {
283 return getSimpleName(
E->getType()).str();
287 std::string VisitCXXMemberCallExpr(
const CXXMemberCallExpr *
E) {
289 if (
E->getNumArgs() == 0 &&
290 E->getMethodDecl()->getDeclName().getNameKind() ==
291 DeclarationName::CXXConversionFunctionName &&
292 E->getSourceRange() ==
293 E->getImplicitObjectArgument()->getSourceRange())
294 return Visit(
E->getImplicitObjectArgument());
295 return ConstStmtVisitor::VisitCXXMemberCallExpr(
E);
297 std::string VisitCXXConstructExpr(
const CXXConstructExpr *
E) {
298 if (
E->getNumArgs() == 1)
299 return Visit(
E->getArg(0));
304 std::string VisitCXXBoolLiteralExpr(
const CXXBoolLiteralExpr *
E) {
305 return E->getValue() ?
"true" :
"false";
307 std::string VisitIntegerLiteral(
const IntegerLiteral *
E) {
308 return llvm::to_string(
E->getValue());
310 std::string VisitFloatingLiteral(
const FloatingLiteral *
E) {
312 llvm::raw_string_ostream
OS(Result);
313 E->getValue().print(
OS);
315 Result.resize(llvm::StringRef(Result).rtrim().size());
318 std::string VisitStringLiteral(
const StringLiteral *
E) {
319 std::string Result =
"\"";
320 if (
E->containsNonAscii()) {
322 }
else if (
E->getLength() > 10) {
323 Result +=
E->getString().take_front(7);
326 llvm::raw_string_ostream
OS(Result);
327 llvm::printEscapedString(
E->getString(),
OS);
329 Result.push_back(
'"');
334 std::string printUnary(llvm::StringRef Spelling,
const Expr *Operand,
336 std::string Sub = Visit(Operand);
340 return (Spelling + Sub).str();
344 bool InsideBinary =
false;
345 std::string printBinary(llvm::StringRef Spelling,
const Expr *LHSOp,
349 llvm::SaveAndRestore InBinary(InsideBinary,
true);
351 std::string LHS = Visit(LHSOp);
352 std::string RHS = Visit(RHSOp);
353 if (LHS.empty() && RHS.empty())
367 std::string VisitUnaryOperator(
const UnaryOperator *
E) {
368 return printUnary(
E->getOpcodeStr(
E->getOpcode()),
E->getSubExpr(),
371 std::string VisitBinaryOperator(
const BinaryOperator *
E) {
372 return printBinary(
E->getOpcodeStr(
E->getOpcode()),
E->getLHS(),
375 std::string VisitCXXOperatorCallExpr(
const CXXOperatorCallExpr *
E) {
376 const char *Spelling = getOperatorSpelling(
E->getOperator());
378 if ((
E->getOperator() == OO_PlusPlus ||
379 E->getOperator() == OO_MinusMinus) &&
380 E->getNumArgs() == 2)
381 return printUnary(Spelling,
E->getArg(0),
false);
382 if (
E->isInfixBinaryOp())
383 return printBinary(Spelling,
E->getArg(0),
E->getArg(1));
384 if (
E->getNumArgs() == 1) {
385 switch (
E->getOperator()) {
394 return printUnary(Spelling,
E->getArg(0),
true);
402 return Namer{}.Visit(
E);
407bool isSugaredTemplateParameter(QualType QT) {
408 static auto PeelWrapper = [](QualType QT) {
411 QualType Peeled = QT->getPointeeType();
412 return Peeled.isNull() ? QT : Peeled;
440 if (QT->getAs<SubstTemplateTypeParmType>())
442 QualType Desugared = QT->getLocallyUnqualifiedSingleStepDesugaredType();
445 else if (
auto Peeled = PeelWrapper(Desugared); Peeled != QT)
455std::optional<QualType> desugar(ASTContext &
AST, QualType QT) {
456 bool ShouldAKA =
false;
457 auto Desugared = clang::desugarForDiagnostic(
AST, QT, ShouldAKA);
470QualType maybeDesugar(ASTContext &
AST, QualType QT) {
474 if (isSugaredTemplateParameter(QT))
475 return desugar(
AST, QT).value_or(QT);
478 if (QT->isDecltypeType())
479 return QT.getCanonicalType();
480 if (
const AutoType *AT = QT->getContainedAutoType())
481 if (!AT->getDeducedType().isNull() &&
482 AT->getDeducedType()->isDecltypeType())
483 return QT.getCanonicalType();
492static FunctionProtoTypeLoc getPrototypeLoc(Expr *Fn) {
494 Expr *NakedFn = Fn->IgnoreParenCasts();
495 if (
const auto *T = NakedFn->getType().getTypePtr()->getAs<TypedefType>()) {
496 Target = T->getDecl()->getTypeSourceInfo()->getTypeLoc();
497 }
else if (
const auto *DR = dyn_cast<DeclRefExpr>(NakedFn)) {
498 const auto *
D = DR->getDecl();
499 if (
const auto *
const VD = dyn_cast<VarDecl>(D)) {
500 Target = VD->getTypeSourceInfo()->getTypeLoc();
509 if (
auto P = Target.getAs<PointerTypeLoc>()) {
510 Target = P.getPointeeLoc();
513 if (
auto A = Target.getAs<AttributedTypeLoc>()) {
514 Target =
A.getModifiedLoc();
517 if (
auto P = Target.getAs<ParenTypeLoc>()) {
518 Target = P.getInnerLoc();
524 if (
auto F = Target.getAs<FunctionProtoTypeLoc>()) {
534 const FunctionDecl *
Decl =
nullptr;
540 InlayHintVisitor(std::vector<InlayHint> &
Results, ParsedAST &
AST,
541 const Config &Cfg, std::optional<Range> RestrictRange)
543 Cfg(Cfg), RestrictRange(std::move(RestrictRange)),
544 MainFileID(
AST.getSourceManager().getMainFileID()),
545 Resolver(
AST.getHeuristicResolver()),
546 TypeHintPolicy(this->AST.getPrintingPolicy()) {
548 llvm::StringRef Buf =
549 AST.getSourceManager().getBufferData(MainFileID, &
Invalid);
550 MainFileBuf =
Invalid ? StringRef{} : Buf;
552 TypeHintPolicy.SuppressScope =
true;
553 TypeHintPolicy.AnonymousTagLocations =
560 bool VisitTypeLoc(TypeLoc TL) {
561 if (
const auto *DT = llvm::dyn_cast<DecltypeType>(TL.getType()))
562 if (QualType UT = DT->getUnderlyingType(); !UT->isDependentType())
563 addTypeHint(TL.getSourceRange(), UT,
": ");
567 bool VisitCXXConstructExpr(CXXConstructExpr *
E) {
572 if (!
E->getParenOrBraceRange().isValid() ||
573 E->isStdInitListInitialization()) {
578 Callee.Decl =
E->getConstructor();
581 processCall(Callee, {
E->getArgs(),
E->getNumArgs()});
585 bool VisitCallExpr(CallExpr *
E) {
589 bool IsFunctor = isFunctionObjectCallExpr(
E);
594 if ((isa<CXXOperatorCallExpr>(
E) && !IsFunctor) ||
595 isa<UserDefinedLiteral>(
E))
599 if (CalleeDecls.size() != 1)
603 if (
const auto *FD = dyn_cast<FunctionDecl>(CalleeDecls[0]))
605 else if (
const auto *FTD = dyn_cast<FunctionTemplateDecl>(CalleeDecls[0]))
606 Callee.Decl = FTD->getTemplatedDecl();
607 else if (FunctionProtoTypeLoc
Loc = getPrototypeLoc(
E->getCallee()))
619 llvm::ArrayRef<const Expr *>
Args = {
E->getArgs(),
E->getNumArgs()};
623 if (
const CXXMethodDecl *
Method =
624 dyn_cast_or_null<CXXMethodDecl>(Callee.Decl);
627 processCall(Callee,
Args);
631 bool VisitFunctionDecl(FunctionDecl *D) {
633 llvm::dyn_cast<FunctionProtoType>(
D->getType().getTypePtr())) {
634 if (!FPT->hasTrailingReturn()) {
635 if (
auto FTL =
D->getFunctionTypeLoc())
636 addReturnTypeHint(D, FTL.getRParenLoc());
642 if (
const Stmt *Body =
D->getBody())
643 addBlockEndHint(Body->getSourceRange(),
"",
printName(
AST, *D),
"");
648 bool VisitForStmt(ForStmt *S) {
652 if (
auto *DS = llvm::dyn_cast_or_null<DeclStmt>(S->getInit());
653 DS && DS->isSingleDecl())
654 Name = getSimpleName(llvm::cast<NamedDecl>(*DS->getSingleDecl()));
656 Name = summarizeExpr(S->getCond());
657 markBlockEnd(S->getBody(),
"for",
Name);
662 bool VisitCXXForRangeStmt(CXXForRangeStmt *S) {
664 markBlockEnd(S->getBody(),
"for", getSimpleName(*S->getLoopVariable()));
668 bool VisitWhileStmt(WhileStmt *S) {
670 markBlockEnd(S->getBody(),
"while", summarizeExpr(S->getCond()));
674 bool VisitSwitchStmt(SwitchStmt *S) {
676 markBlockEnd(S->getBody(),
"switch", summarizeExpr(S->getCond()));
687 bool VisitIfStmt(IfStmt *S) {
689 if (
const auto *ElseIf = llvm::dyn_cast_or_null<IfStmt>(S->getElse()))
692 if (
const auto *EndCS = llvm::dyn_cast<CompoundStmt>(
693 S->getElse() ? S->getElse() : S->getThen())) {
695 {S->getThen()->getBeginLoc(), EndCS->getRBracLoc()},
"if",
696 ElseIfs.contains(S) ?
"" : summarizeExpr(S->getCond()),
"");
702 void markBlockEnd(
const Stmt *Body, llvm::StringRef
Label,
703 llvm::StringRef
Name =
"") {
704 if (
const auto *CS = llvm::dyn_cast_or_null<CompoundStmt>(Body))
705 addBlockEndHint(CS->getSourceRange(),
Label,
Name,
"");
708 bool VisitTagDecl(TagDecl *D) {
710 std::string DeclPrefix =
D->getKindName().str();
711 if (
const auto *ED = dyn_cast<EnumDecl>(D)) {
713 DeclPrefix += ED->isScopedUsingClassTag() ?
" class" :
" struct";
715 addBlockEndHint(
D->getBraceRange(), DeclPrefix, getSimpleName(*D),
";");
720 bool VisitNamespaceDecl(NamespaceDecl *D) {
724 addBlockEndHint(
D->getSourceRange(),
"namespace", getSimpleName(*D),
"");
729 bool VisitLambdaExpr(LambdaExpr *
E) {
730 FunctionDecl *
D =
E->getCallOperator();
731 if (!
E->hasExplicitResultType())
732 addReturnTypeHint(D,
E->hasExplicitParameters()
733 ?
D->getFunctionTypeLoc().getRParenLoc()
734 :
E->getIntroducerRange().getEnd());
738 void addReturnTypeHint(FunctionDecl *D, SourceRange Range) {
739 auto *AT =
D->getReturnType()->getContainedAutoType();
740 if (!AT || AT->getDeducedType().isNull())
742 addTypeHint(Range,
D->getReturnType(),
"-> ");
745 bool VisitVarDecl(VarDecl *D) {
748 if (
auto *DD = dyn_cast<DecompositionDecl>(D)) {
749 for (
auto *Binding : DD->bindings()) {
753 if (
auto Type = Binding->getType();
754 !
Type.isNull() && !
Type->isDependentType())
755 addTypeHint(Binding->getLocation(),
Type.getCanonicalType(),
761 if (
auto *AT =
D->getType()->getContainedAutoType()) {
762 if (AT->isDeduced() && !
D->getType()->isDependentType()) {
768 addTypeHint(
D->getLocation(),
D->getType(),
": ");
773 if (
auto *PVD = llvm::dyn_cast<ParmVarDecl>(D)) {
774 if (
D->getIdentifier() && PVD->getType()->isDependentType() &&
777 if (
auto *IPVD = getOnlyParamInstantiation(PVD))
778 addTypeHint(
D->getLocation(), IPVD->getType(),
": ");
785 ParmVarDecl *getOnlyParamInstantiation(ParmVarDecl *D) {
786 auto *TemplateFunction = llvm::dyn_cast<FunctionDecl>(
D->getDeclContext());
787 if (!TemplateFunction)
789 auto *InstantiatedFunction = llvm::dyn_cast_or_null<FunctionDecl>(
791 if (!InstantiatedFunction)
794 unsigned ParamIdx = 0;
795 for (
auto *Param : TemplateFunction->parameters()) {
798 if (Param->isParameterPack())
804 assert(ParamIdx < TemplateFunction->getNumParams() &&
805 "Couldn't find param in list?");
806 assert(ParamIdx < InstantiatedFunction->getNumParams() &&
807 "Instantiated function has fewer (non-pack) parameters?");
808 return InstantiatedFunction->getParamDecl(ParamIdx);
811 bool VisitInitListExpr(InitListExpr *Syn) {
817 assert(Syn->isSyntacticForm() &&
"RAV should not visit implicit code!");
820 if (Syn->isIdiomaticZeroInitializer(
AST.getLangOpts()))
822 llvm::DenseMap<SourceLocation, std::string> Designators =
824 for (
const Expr *Init : Syn->inits()) {
825 if (llvm::isa<DesignatedInitExpr>(Init))
827 auto It = Designators.find(Init->getBeginLoc());
828 if (It != Designators.end() &&
829 !isPrecededByParamNameComment(Init, It->second))
830 addDesignatorHint(Init->getSourceRange(), It->second);
838 using NameVec = SmallVector<StringRef, 8>;
840 void processCall(Callee Callee, llvm::ArrayRef<const Expr *>
Args) {
841 assert(Callee.Decl || Callee.Loc);
848 if (
auto *Ctor = dyn_cast<CXXConstructorDecl>(Callee.Decl))
849 if (Ctor->isCopyOrMoveConstructor())
853 Callee.Decl ? Callee.Decl->parameters() : Callee.Loc.getParams();
856 SmallVector<const ParmVarDecl *> ForwardedParams;
860 ForwardedParams = {Params.begin(), Params.end()};
862 NameVec ParameterNames = chooseParameterNames(ForwardedParams);
868 (isSetter(Callee.Decl, ParameterNames) || isSimpleBuiltin(Callee.Decl)))
871 for (
size_t I = 0; I < ParameterNames.size() && I <
Args.size(); ++I) {
875 if (isa<PackExpansionExpr>(
Args[I])) {
879 StringRef
Name = ParameterNames[I];
880 bool NameHint = shouldHintName(
Args[I],
Name);
881 bool ReferenceHint = shouldHintReference(Params[I], ForwardedParams[I]);
883 if (NameHint || ReferenceHint) {
884 addInlayHint(
Args[I]->getSourceRange(), HintSide::Left,
886 NameHint ?
Name :
"",
": ");
891 static bool isSetter(
const FunctionDecl *Callee,
const NameVec &ParamNames) {
892 if (ParamNames.size() != 1)
895 StringRef
Name = getSimpleName(*Callee);
896 if (!
Name.starts_with_insensitive(
"set"))
910 StringRef WhatItIsSetting =
Name.substr(3).ltrim(
"_");
911 return WhatItIsSetting.equals_insensitive(ParamNames[0]);
916 static bool isSimpleBuiltin(
const FunctionDecl *Callee) {
917 switch (Callee->getBuiltinID()) {
918 case Builtin::BIaddressof:
919 case Builtin::BIas_const:
920 case Builtin::BIforward:
921 case Builtin::BImove:
922 case Builtin::BImove_if_noexcept:
929 bool shouldHintName(
const Expr *Arg, StringRef ParamName) {
930 if (ParamName.empty())
935 if (ParamName == getSpelledIdentifier(Arg))
939 if (isPrecededByParamNameComment(Arg, ParamName))
945 bool shouldHintReference(
const ParmVarDecl *Param,
946 const ParmVarDecl *ForwardedParam) {
969 auto Type = Param->getType();
970 auto ForwardedType = ForwardedParam->getType();
971 return Type->isLValueReferenceType() &&
972 ForwardedType->isLValueReferenceType() &&
973 !ForwardedType.getNonReferenceType().isConstQualified() &&
980 bool isPrecededByParamNameComment(
const Expr *
E, StringRef ParamName) {
981 auto &SM =
AST.getSourceManager();
982 auto FileLoc = SM.getFileLoc(
E->getBeginLoc());
983 auto Decomposed = SM.getDecomposedLoc(FileLoc);
984 if (Decomposed.first != MainFileID)
987 StringRef SourcePrefix = MainFileBuf.substr(0, Decomposed.second);
989 SourcePrefix = SourcePrefix.rtrim();
991 if (!SourcePrefix.consume_back(
"*/"))
995 llvm::StringLiteral IgnoreChars =
" =.";
996 SourcePrefix = SourcePrefix.rtrim(IgnoreChars);
997 ParamName = ParamName.trim(IgnoreChars);
999 if (!SourcePrefix.consume_back(ParamName))
1001 SourcePrefix = SourcePrefix.rtrim(IgnoreChars);
1002 return SourcePrefix.endswith(
"/*");
1007 static StringRef getSpelledIdentifier(
const Expr *
E) {
1008 E =
E->IgnoreUnlessSpelledInSource();
1010 if (
auto *DRE = dyn_cast<DeclRefExpr>(
E))
1011 if (!DRE->getQualifier())
1012 return getSimpleName(*DRE->getDecl());
1014 if (
auto *ME = dyn_cast<MemberExpr>(
E))
1015 if (!ME->getQualifier() && ME->isImplicitAccess())
1016 return getSimpleName(*ME->getMemberDecl());
1021 NameVec chooseParameterNames(SmallVector<const ParmVarDecl *>
Parameters) {
1022 NameVec ParameterNames;
1028 ParameterNames.emplace_back();
1030 auto SimpleName = getSimpleName(*P);
1033 if (SimpleName.empty()) {
1034 if (
const auto *PD = getParamDefinition(P)) {
1035 SimpleName = getSimpleName(*PD);
1038 ParameterNames.emplace_back(SimpleName);
1044 for (
auto &
Name : ParameterNames)
1045 stripLeadingUnderscores(
Name);
1047 return ParameterNames;
1052 static const ParmVarDecl *getParamDefinition(
const ParmVarDecl *P) {
1053 if (
auto *Callee = dyn_cast<FunctionDecl>(P->getDeclContext())) {
1054 if (
auto *Def = Callee->getDefinition()) {
1055 auto I = std::distance(Callee->param_begin(),
1056 llvm::find(Callee->parameters(), P));
1057 if (I < Callee->getNumParams()) {
1058 return Def->getParamDecl(I);
1068 llvm::StringRef Prefix, llvm::StringRef
Label,
1069 llvm::StringRef
Suffix) {
1070 auto LSPRange = getHintRange(R);
1078 llvm::StringRef Prefix, llvm::StringRef
Label,
1079 llvm::StringRef
Suffix) {
1085#define CHECK_KIND(Enumerator, ConfigProperty) \
1086 case InlayHintKind::Enumerator: \
1087 assert(Cfg.InlayHints.ConfigProperty && \
1088 "Shouldn't get here if kind is disabled!"); \
1089 if (!Cfg.InlayHints.ConfigProperty) \
1099 Position LSPPos =
Side == HintSide::Left ? LSPRange.start : LSPRange.end;
1100 if (RestrictRange &&
1101 (LSPPos < RestrictRange->start || !(LSPPos < RestrictRange->end)))
1103 bool PadLeft = Prefix.consume_front(
" ");
1104 bool PadRight =
Suffix.consume_back(
" ");
1106 PadLeft, PadRight, LSPRange});
1110 std::optional<Range> getHintRange(SourceRange R) {
1111 const auto &SM =
AST.getSourceManager();
1112 auto Spelled = Tokens.spelledForExpanded(Tokens.expandedTokens(R));
1116 return std::nullopt;
1118 if (SM.getFileID(
Spelled->front().location()) != SM.getMainFileID() ||
1119 SM.getFileID(
Spelled->back().location()) != SM.getMainFileID())
1120 return std::nullopt;
1125 void addTypeHint(SourceRange R, QualType T, llvm::StringRef Prefix) {
1131 auto Desugared = maybeDesugar(
AST, T);
1132 std::string TypeName = Desugared.getAsString(TypeHintPolicy);
1133 if (T != Desugared && !shouldPrintTypeHint(TypeName)) {
1136 TypeName = T.getAsString(TypeHintPolicy);
1138 if (shouldPrintTypeHint(TypeName))
1143 void addDesignatorHint(SourceRange R, llvm::StringRef
Text) {
1148 bool shouldPrintTypeHint(llvm::StringRef TypeName)
const noexcept {
1153 void addBlockEndHint(SourceRange BraceRange, StringRef DeclPrefix,
1154 StringRef
Name, StringRef OptionalPunctuation) {
1155 auto HintRange = computeBlockEndHintRange(BraceRange, OptionalPunctuation);
1159 std::string
Label = DeclPrefix.str();
1164 constexpr unsigned HintMaxLengthLimit = 60;
1165 if (
Label.length() > HintMaxLengthLimit)
1178 std::optional<Range> computeBlockEndHintRange(SourceRange BraceRange,
1179 StringRef OptionalPunctuation) {
1180 constexpr unsigned HintMinLineLimit = 2;
1182 auto &SM =
AST.getSourceManager();
1183 auto [BlockBeginFileId, BlockBeginOffset] =
1184 SM.getDecomposedLoc(SM.getFileLoc(BraceRange.getBegin()));
1185 auto RBraceLoc = SM.getFileLoc(BraceRange.getEnd());
1186 auto [RBraceFileId, RBraceOffset] = SM.getDecomposedLoc(RBraceLoc);
1192 if (BlockBeginFileId != MainFileID || RBraceFileId != MainFileID)
1193 return std::nullopt;
1195 StringRef RestOfLine = MainFileBuf.substr(RBraceOffset).split(
'\n').first;
1196 if (!RestOfLine.starts_with(
"}"))
1197 return std::nullopt;
1199 StringRef TrimmedTrailingText = RestOfLine.drop_front().trim();
1200 if (!TrimmedTrailingText.empty() &&
1201 TrimmedTrailingText != OptionalPunctuation)
1202 return std::nullopt;
1204 auto BlockBeginLine = SM.getLineNumber(BlockBeginFileId, BlockBeginOffset);
1205 auto RBraceLine = SM.getLineNumber(RBraceFileId, RBraceOffset);
1208 if (BlockBeginLine + HintMinLineLimit - 1 > RBraceLine)
1209 return std::nullopt;
1212 StringRef HintRangeText = RestOfLine.take_front(
1213 TrimmedTrailingText.empty()
1215 : TrimmedTrailingText.bytes_end() - RestOfLine.bytes_begin());
1219 SM, RBraceLoc.getLocWithOffset(HintRangeText.size()));
1220 return Range{HintStart, HintEnd};
1223 static bool isFunctionObjectCallExpr(CallExpr *
E)
noexcept {
1224 if (
auto *CallExpr = dyn_cast<CXXOperatorCallExpr>(
E))
1225 return CallExpr->getOperator() == OverloadedOperatorKind::OO_Call;
1229 std::vector<InlayHint> &
Results;
1231 const syntax::TokenBuffer &Tokens;
1233 std::optional<Range> RestrictRange;
1235 StringRef MainFileBuf;
1236 const HeuristicResolver *Resolver;
1237 PrintingPolicy TypeHintPolicy;
1243 std::optional<Range> RestrictRange) {
1244 std::vector<InlayHint>
Results;
1248 InlayHintVisitor Visitor(
Results,
AST, Cfg, std::move(RestrictRange));
1249 Visitor.TraverseAST(
AST.getASTContext());
ArrayRef< const ParmVarDecl * > Parameters
const FunctionDecl * Decl
std::vector< CodeCompletionResult > Results
CompiledFragmentImpl & Out
CharSourceRange Range
SourceRange for the file name.
llvm::DenseSet< const IfStmt * > ElseIfs
#define CHECK_KIND(Enumerator, ConfigProperty)
llvm::raw_string_ostream OS
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.
bool isReservedName(llvm::StringRef Name)
Returns true if Name is reserved, like _Foo or __Vector_base.
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...
@ 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!
===– 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