1 //===--- InlayHints.cpp ------------------------------------------*- C++-*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 #include "InlayHints.h" 9 #include "Config.h" 10 #include "HeuristicResolver.h" 11 #include "ParsedAST.h" 12 #include "clang/AST/DeclarationName.h" 13 #include "clang/AST/ExprCXX.h" 14 #include "clang/AST/RecursiveASTVisitor.h" 15 #include "clang/Basic/SourceManager.h" 16 #include "llvm/ADT/ScopeExit.h" 17 18 namespace clang { 19 namespace clangd { 20 namespace { 21 22 // For now, inlay hints are always anchored at the left or right of their range. 23 enum class HintSide { Left, Right }; 24 25 // Helper class to iterate over the designator names of an aggregate type. 26 // 27 // For an array type, yields [0], [1], [2]... 28 // For aggregate classes, yields null for each base, then .field1, .field2, ... 29 class AggregateDesignatorNames { 30 public: 31 AggregateDesignatorNames(QualType T) { 32 if (!T.isNull()) { 33 T = T.getCanonicalType(); 34 if (T->isArrayType()) { 35 IsArray = true; 36 Valid = true; 37 return; 38 } 39 if (const RecordDecl *RD = T->getAsRecordDecl()) { 40 Valid = true; 41 FieldsIt = RD->field_begin(); 42 FieldsEnd = RD->field_end(); 43 if (const auto *CRD = llvm::dyn_cast<CXXRecordDecl>(RD)) { 44 BasesIt = CRD->bases_begin(); 45 BasesEnd = CRD->bases_end(); 46 Valid = CRD->isAggregate(); 47 } 48 OneField = Valid && BasesIt == BasesEnd && FieldsIt != FieldsEnd && 49 std::next(FieldsIt) == FieldsEnd; 50 } 51 } 52 } 53 // Returns false if the type was not an aggregate. 54 operator bool() { return Valid; } 55 // Advance to the next element in the aggregate. 56 void next() { 57 if (IsArray) 58 ++Index; 59 else if (BasesIt != BasesEnd) 60 ++BasesIt; 61 else if (FieldsIt != FieldsEnd) 62 ++FieldsIt; 63 } 64 // Print the designator to Out. 65 // Returns false if we could not produce a designator for this element. 66 bool append(std::string &Out, bool ForSubobject) { 67 if (IsArray) { 68 Out.push_back('['); 69 Out.append(std::to_string(Index)); 70 Out.push_back(']'); 71 return true; 72 } 73 if (BasesIt != BasesEnd) 74 return false; // Bases can't be designated. Should we make one up? 75 if (FieldsIt != FieldsEnd) { 76 llvm::StringRef FieldName; 77 if (const IdentifierInfo *II = FieldsIt->getIdentifier()) 78 FieldName = II->getName(); 79 80 // For certain objects, their subobjects may be named directly. 81 if (ForSubobject && 82 (FieldsIt->isAnonymousStructOrUnion() || 83 // std::array<int,3> x = {1,2,3}. Designators not strictly valid! 84 (OneField && isReservedName(FieldName)))) 85 return true; 86 87 if (!FieldName.empty() && !isReservedName(FieldName)) { 88 Out.push_back('.'); 89 Out.append(FieldName.begin(), FieldName.end()); 90 return true; 91 } 92 return false; 93 } 94 return false; 95 } 96 97 private: 98 bool Valid = false; 99 bool IsArray = false; 100 bool OneField = false; // e.g. std::array { T __elements[N]; } 101 unsigned Index = 0; 102 CXXRecordDecl::base_class_const_iterator BasesIt; 103 CXXRecordDecl::base_class_const_iterator BasesEnd; 104 RecordDecl::field_iterator FieldsIt; 105 RecordDecl::field_iterator FieldsEnd; 106 }; 107 108 // Collect designator labels describing the elements of an init list. 109 // 110 // This function contributes the designators of some (sub)object, which is 111 // represented by the semantic InitListExpr Sem. 112 // This includes any nested subobjects, but *only* if they are part of the same 113 // original syntactic init list (due to brace elision). 114 // In other words, it may descend into subobjects but not written init-lists. 115 // 116 // For example: struct Outer { Inner a,b; }; struct Inner { int x, y; } 117 // Outer o{{1, 2}, 3}; 118 // This function will be called with Sem = { {1, 2}, {3, ImplicitValue} } 119 // It should generate designators '.a:' and '.b.x:'. 120 // '.a:' is produced directly without recursing into the written sublist. 121 // (The written sublist will have a separate collectDesignators() call later). 122 // Recursion with Prefix='.b' and Sem = {3, ImplicitValue} produces '.b.x:'. 123 void collectDesignators(const InitListExpr *Sem, 124 llvm::DenseMap<SourceLocation, std::string> &Out, 125 const llvm::DenseSet<SourceLocation> &NestedBraces, 126 std::string &Prefix) { 127 if (!Sem || Sem->isTransparent()) 128 return; 129 assert(Sem->isSemanticForm()); 130 131 // The elements of the semantic form all correspond to direct subobjects of 132 // the aggregate type. `Fields` iterates over these subobject names. 133 AggregateDesignatorNames Fields(Sem->getType()); 134 if (!Fields) 135 return; 136 for (const Expr *Init : Sem->inits()) { 137 auto Next = llvm::make_scope_exit([&, Size(Prefix.size())] { 138 Fields.next(); // Always advance to the next subobject name. 139 Prefix.resize(Size); // Erase any designator we appended. 140 }); 141 if (llvm::isa<ImplicitValueInitExpr>(Init)) 142 continue; // a "hole" for a subobject that was not explicitly initialized 143 144 const auto *BraceElidedSubobject = llvm::dyn_cast<InitListExpr>(Init); 145 if (BraceElidedSubobject && 146 NestedBraces.contains(BraceElidedSubobject->getLBraceLoc())) 147 BraceElidedSubobject = nullptr; // there were braces! 148 149 if (!Fields.append(Prefix, BraceElidedSubobject != nullptr)) 150 continue; // no designator available for this subobject 151 if (BraceElidedSubobject) { 152 // If the braces were elided, this aggregate subobject is initialized 153 // inline in the same syntactic list. 154 // Descend into the semantic list describing the subobject. 155 // (NestedBraces are still correct, they're from the same syntactic list). 156 collectDesignators(BraceElidedSubobject, Out, NestedBraces, Prefix); 157 continue; 158 } 159 Out.try_emplace(Init->getBeginLoc(), Prefix); 160 } 161 } 162 163 // Get designators describing the elements of a (syntactic) init list. 164 // This does not produce designators for any explicitly-written nested lists. 165 llvm::DenseMap<SourceLocation, std::string> 166 getDesignators(const InitListExpr *Syn) { 167 assert(Syn->isSyntacticForm()); 168 169 // collectDesignators needs to know which InitListExprs in the semantic tree 170 // were actually written, but InitListExpr::isExplicit() lies. 171 // Instead, record where braces of sub-init-lists occur in the syntactic form. 172 llvm::DenseSet<SourceLocation> NestedBraces; 173 for (const Expr *Init : Syn->inits()) 174 if (auto *Nested = llvm::dyn_cast<InitListExpr>(Init)) 175 NestedBraces.insert(Nested->getLBraceLoc()); 176 177 // Traverse the semantic form to find the designators. 178 // We use their SourceLocation to correlate with the syntactic form later. 179 llvm::DenseMap<SourceLocation, std::string> Designators; 180 std::string EmptyPrefix; 181 collectDesignators(Syn->isSemanticForm() ? Syn : Syn->getSemanticForm(), 182 Designators, NestedBraces, EmptyPrefix); 183 return Designators; 184 } 185 186 class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> { 187 public: 188 InlayHintVisitor(std::vector<InlayHint> &Results, ParsedAST &AST, 189 const Config &Cfg, llvm::Optional<Range> RestrictRange) 190 : Results(Results), AST(AST.getASTContext()), Cfg(Cfg), 191 RestrictRange(std::move(RestrictRange)), 192 MainFileID(AST.getSourceManager().getMainFileID()), 193 Resolver(AST.getHeuristicResolver()), 194 TypeHintPolicy(this->AST.getPrintingPolicy()), 195 StructuredBindingPolicy(this->AST.getPrintingPolicy()) { 196 bool Invalid = false; 197 llvm::StringRef Buf = 198 AST.getSourceManager().getBufferData(MainFileID, &Invalid); 199 MainFileBuf = Invalid ? StringRef{} : Buf; 200 201 TypeHintPolicy.SuppressScope = true; // keep type names short 202 TypeHintPolicy.AnonymousTagLocations = 203 false; // do not print lambda locations 204 205 // For structured bindings, print canonical types. This is important because 206 // for bindings that use the tuple_element protocol, the non-canonical types 207 // would be "tuple_element<I, A>::type". 208 // For "auto", we often prefer sugared types. 209 // Not setting PrintCanonicalTypes for "auto" allows 210 // SuppressDefaultTemplateArgs (set by default) to have an effect. 211 StructuredBindingPolicy = TypeHintPolicy; 212 StructuredBindingPolicy.PrintCanonicalTypes = true; 213 } 214 215 bool VisitCXXConstructExpr(CXXConstructExpr *E) { 216 // Weed out constructor calls that don't look like a function call with 217 // an argument list, by checking the validity of getParenOrBraceRange(). 218 // Also weed out std::initializer_list constructors as there are no names 219 // for the individual arguments. 220 if (!E->getParenOrBraceRange().isValid() || 221 E->isStdInitListInitialization()) { 222 return true; 223 } 224 225 processCall(E->getParenOrBraceRange().getBegin(), E->getConstructor(), 226 {E->getArgs(), E->getNumArgs()}); 227 return true; 228 } 229 230 bool VisitCallExpr(CallExpr *E) { 231 if (!Cfg.InlayHints.Parameters) 232 return true; 233 234 // Do not show parameter hints for operator calls written using operator 235 // syntax or user-defined literals. (Among other reasons, the resulting 236 // hints can look awkard, e.g. the expression can itself be a function 237 // argument and then we'd get two hints side by side). 238 if (isa<CXXOperatorCallExpr>(E) || isa<UserDefinedLiteral>(E)) 239 return true; 240 241 auto CalleeDecls = Resolver->resolveCalleeOfCallExpr(E); 242 if (CalleeDecls.size() != 1) 243 return true; 244 const FunctionDecl *Callee = nullptr; 245 if (const auto *FD = dyn_cast<FunctionDecl>(CalleeDecls[0])) 246 Callee = FD; 247 else if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(CalleeDecls[0])) 248 Callee = FTD->getTemplatedDecl(); 249 if (!Callee) 250 return true; 251 252 processCall(E->getRParenLoc(), Callee, {E->getArgs(), E->getNumArgs()}); 253 return true; 254 } 255 256 bool VisitFunctionDecl(FunctionDecl *D) { 257 if (auto *FPT = 258 llvm::dyn_cast<FunctionProtoType>(D->getType().getTypePtr())) { 259 if (!FPT->hasTrailingReturn()) 260 addReturnTypeHint(D, D->getFunctionTypeLoc().getRParenLoc()); 261 } 262 return true; 263 } 264 265 bool VisitLambdaExpr(LambdaExpr *E) { 266 FunctionDecl *D = E->getCallOperator(); 267 if (!E->hasExplicitResultType()) 268 addReturnTypeHint(D, E->hasExplicitParameters() 269 ? D->getFunctionTypeLoc().getRParenLoc() 270 : E->getIntroducerRange().getEnd()); 271 return true; 272 } 273 274 void addReturnTypeHint(FunctionDecl *D, SourceLocation Loc) { 275 auto *AT = D->getReturnType()->getContainedAutoType(); 276 if (!AT || AT->getDeducedType().isNull()) 277 return; 278 addTypeHint(Loc, D->getReturnType(), /*Prefix=*/"-> "); 279 } 280 281 bool VisitVarDecl(VarDecl *D) { 282 // Do not show hints for the aggregate in a structured binding, 283 // but show hints for the individual bindings. 284 if (auto *DD = dyn_cast<DecompositionDecl>(D)) { 285 for (auto *Binding : DD->bindings()) { 286 addTypeHint(Binding->getLocation(), Binding->getType(), /*Prefix=*/": ", 287 StructuredBindingPolicy); 288 } 289 return true; 290 } 291 292 if (D->getType()->getContainedAutoType()) { 293 if (!D->getType()->isDependentType()) { 294 // Our current approach is to place the hint on the variable 295 // and accordingly print the full type 296 // (e.g. for `const auto& x = 42`, print `const int&`). 297 // Alternatively, we could place the hint on the `auto` 298 // (and then just print the type deduced for the `auto`). 299 addTypeHint(D->getLocation(), D->getType(), /*Prefix=*/": "); 300 } 301 } 302 return true; 303 } 304 305 bool VisitInitListExpr(InitListExpr *Syn) { 306 // We receive the syntactic form here (shouldVisitImplicitCode() is false). 307 // This is the one we will ultimately attach designators to. 308 // It may have subobject initializers inlined without braces. The *semantic* 309 // form of the init-list has nested init-lists for these. 310 // getDesignators will look at the semantic form to determine the labels. 311 assert(Syn->isSyntacticForm() && "RAV should not visit implicit code!"); 312 if (!Cfg.InlayHints.Designators) 313 return true; 314 if (Syn->isIdiomaticZeroInitializer(AST.getLangOpts())) 315 return true; 316 llvm::DenseMap<SourceLocation, std::string> Designators = 317 getDesignators(Syn); 318 for (const Expr *Init : Syn->inits()) { 319 if (llvm::isa<DesignatedInitExpr>(Init)) 320 continue; 321 auto It = Designators.find(Init->getBeginLoc()); 322 if (It != Designators.end() && 323 !isPrecededByParamNameComment(Init, It->second)) 324 addDesignatorHint(Init->getSourceRange(), It->second); 325 } 326 return true; 327 } 328 329 // FIXME: Handle RecoveryExpr to try to hint some invalid calls. 330 331 private: 332 using NameVec = SmallVector<StringRef, 8>; 333 334 // The purpose of Anchor is to deal with macros. It should be the call's 335 // opening or closing parenthesis or brace. (Always using the opening would 336 // make more sense but CallExpr only exposes the closing.) We heuristically 337 // assume that if this location does not come from a macro definition, then 338 // the entire argument list likely appears in the main file and can be hinted. 339 void processCall(SourceLocation Anchor, const FunctionDecl *Callee, 340 llvm::ArrayRef<const Expr *const> Args) { 341 if (!Cfg.InlayHints.Parameters || Args.size() == 0 || !Callee) 342 return; 343 344 // If the anchor location comes from a macro defintion, there's nowhere to 345 // put hints. 346 if (!AST.getSourceManager().getTopMacroCallerLoc(Anchor).isFileID()) 347 return; 348 349 // The parameter name of a move or copy constructor is not very interesting. 350 if (auto *Ctor = dyn_cast<CXXConstructorDecl>(Callee)) 351 if (Ctor->isCopyOrMoveConstructor()) 352 return; 353 354 // Don't show hints for variadic parameters. 355 size_t FixedParamCount = getFixedParamCount(Callee); 356 size_t ArgCount = std::min(FixedParamCount, Args.size()); 357 358 NameVec ParameterNames = chooseParameterNames(Callee, ArgCount); 359 360 // Exclude setters (i.e. functions with one argument whose name begins with 361 // "set"), as their parameter name is also not likely to be interesting. 362 if (isSetter(Callee, ParameterNames)) 363 return; 364 365 for (size_t I = 0; I < ArgCount; ++I) { 366 StringRef Name = ParameterNames[I]; 367 if (!shouldHint(Args[I], Name)) 368 continue; 369 370 addInlayHint(Args[I]->getSourceRange(), HintSide::Left, 371 InlayHintKind::ParameterHint, /*Prefix=*/"", Name, 372 /*Suffix=*/": "); 373 } 374 } 375 376 static bool isSetter(const FunctionDecl *Callee, const NameVec &ParamNames) { 377 if (ParamNames.size() != 1) 378 return false; 379 380 StringRef Name = getSimpleName(*Callee); 381 if (!Name.startswith_insensitive("set")) 382 return false; 383 384 // In addition to checking that the function has one parameter and its 385 // name starts with "set", also check that the part after "set" matches 386 // the name of the parameter (ignoring case). The idea here is that if 387 // the parameter name differs, it may contain extra information that 388 // may be useful to show in a hint, as in: 389 // void setTimeout(int timeoutMillis); 390 // This currently doesn't handle cases where params use snake_case 391 // and functions don't, e.g. 392 // void setExceptionHandler(EHFunc exception_handler); 393 // We could improve this by replacing `equals_insensitive` with some 394 // `sloppy_equals` which ignores case and also skips underscores. 395 StringRef WhatItIsSetting = Name.substr(3).ltrim("_"); 396 return WhatItIsSetting.equals_insensitive(ParamNames[0]); 397 } 398 399 bool shouldHint(const Expr *Arg, StringRef ParamName) { 400 if (ParamName.empty()) 401 return false; 402 403 // If the argument expression is a single name and it matches the 404 // parameter name exactly, omit the hint. 405 if (ParamName == getSpelledIdentifier(Arg)) 406 return false; 407 408 // Exclude argument expressions preceded by a /*paramName*/. 409 if (isPrecededByParamNameComment(Arg, ParamName)) 410 return false; 411 412 return true; 413 } 414 415 // Checks if "E" is spelled in the main file and preceded by a C-style comment 416 // whose contents match ParamName (allowing for whitespace and an optional "=" 417 // at the end. 418 bool isPrecededByParamNameComment(const Expr *E, StringRef ParamName) { 419 auto &SM = AST.getSourceManager(); 420 auto ExprStartLoc = SM.getTopMacroCallerLoc(E->getBeginLoc()); 421 auto Decomposed = SM.getDecomposedLoc(ExprStartLoc); 422 if (Decomposed.first != MainFileID) 423 return false; 424 425 StringRef SourcePrefix = MainFileBuf.substr(0, Decomposed.second); 426 // Allow whitespace between comment and expression. 427 SourcePrefix = SourcePrefix.rtrim(); 428 // Check for comment ending. 429 if (!SourcePrefix.consume_back("*/")) 430 return false; 431 // Ignore some punctuation and whitespace around comment. 432 // In particular this allows designators to match nicely. 433 llvm::StringLiteral IgnoreChars = " =."; 434 SourcePrefix = SourcePrefix.rtrim(IgnoreChars); 435 ParamName = ParamName.trim(IgnoreChars); 436 // Other than that, the comment must contain exactly ParamName. 437 if (!SourcePrefix.consume_back(ParamName)) 438 return false; 439 SourcePrefix = SourcePrefix.rtrim(IgnoreChars); 440 return SourcePrefix.endswith("/*"); 441 } 442 443 // If "E" spells a single unqualified identifier, return that name. 444 // Otherwise, return an empty string. 445 static StringRef getSpelledIdentifier(const Expr *E) { 446 E = E->IgnoreUnlessSpelledInSource(); 447 448 if (auto *DRE = dyn_cast<DeclRefExpr>(E)) 449 if (!DRE->getQualifier()) 450 return getSimpleName(*DRE->getDecl()); 451 452 if (auto *ME = dyn_cast<MemberExpr>(E)) 453 if (!ME->getQualifier() && ME->isImplicitAccess()) 454 return getSimpleName(*ME->getMemberDecl()); 455 456 return {}; 457 } 458 459 NameVec chooseParameterNames(const FunctionDecl *Callee, size_t ArgCount) { 460 // The current strategy here is to use all the parameter names from the 461 // canonical declaration, unless they're all empty, in which case we 462 // use all the parameter names from the definition (in present in the 463 // translation unit). 464 // We could try a bit harder, e.g.: 465 // - try all re-declarations, not just canonical + definition 466 // - fall back arg-by-arg rather than wholesale 467 468 NameVec ParameterNames = getParameterNamesForDecl(Callee, ArgCount); 469 470 if (llvm::all_of(ParameterNames, std::mem_fn(&StringRef::empty))) { 471 if (const FunctionDecl *Def = Callee->getDefinition()) { 472 ParameterNames = getParameterNamesForDecl(Def, ArgCount); 473 } 474 } 475 assert(ParameterNames.size() == ArgCount); 476 477 // Standard library functions often have parameter names that start 478 // with underscores, which makes the hints noisy, so strip them out. 479 for (auto &Name : ParameterNames) 480 stripLeadingUnderscores(Name); 481 482 return ParameterNames; 483 } 484 485 static void stripLeadingUnderscores(StringRef &Name) { 486 Name = Name.ltrim('_'); 487 } 488 489 // Return the number of fixed parameters Function has, that is, not counting 490 // parameters that are variadic (instantiated from a parameter pack) or 491 // C-style varargs. 492 static size_t getFixedParamCount(const FunctionDecl *Function) { 493 if (FunctionTemplateDecl *Template = Function->getPrimaryTemplate()) { 494 FunctionDecl *F = Template->getTemplatedDecl(); 495 size_t Result = 0; 496 for (ParmVarDecl *Parm : F->parameters()) { 497 if (Parm->isParameterPack()) { 498 break; 499 } 500 ++Result; 501 } 502 return Result; 503 } 504 // C-style varargs don't need special handling, they're already 505 // not included in getNumParams(). 506 return Function->getNumParams(); 507 } 508 509 static StringRef getSimpleName(const NamedDecl &D) { 510 if (IdentifierInfo *Ident = D.getDeclName().getAsIdentifierInfo()) { 511 return Ident->getName(); 512 } 513 514 return StringRef(); 515 } 516 517 NameVec getParameterNamesForDecl(const FunctionDecl *Function, 518 size_t ArgCount) { 519 NameVec Result; 520 for (size_t I = 0; I < ArgCount; ++I) { 521 const ParmVarDecl *Parm = Function->getParamDecl(I); 522 assert(Parm); 523 Result.emplace_back(getSimpleName(*Parm)); 524 } 525 return Result; 526 } 527 528 // We pass HintSide rather than SourceLocation because we want to ensure 529 // it is in the same file as the common file range. 530 void addInlayHint(SourceRange R, HintSide Side, InlayHintKind Kind, 531 llvm::StringRef Prefix, llvm::StringRef Label, 532 llvm::StringRef Suffix) { 533 // We shouldn't get as far as adding a hint if the category is disabled. 534 // We'd like to disable as much of the analysis as possible above instead. 535 // Assert in debug mode but add a dynamic check in production. 536 assert(Cfg.InlayHints.Enabled && "Shouldn't get here if disabled!"); 537 switch (Kind) { 538 #define CHECK_KIND(Enumerator, ConfigProperty) \ 539 case InlayHintKind::Enumerator: \ 540 assert(Cfg.InlayHints.ConfigProperty && \ 541 "Shouldn't get here if kind is disabled!"); \ 542 if (!Cfg.InlayHints.ConfigProperty) \ 543 return; \ 544 break 545 CHECK_KIND(ParameterHint, Parameters); 546 CHECK_KIND(TypeHint, DeducedTypes); 547 CHECK_KIND(DesignatorHint, Designators); 548 #undef CHECK_KIND 549 } 550 551 auto FileRange = 552 toHalfOpenFileRange(AST.getSourceManager(), AST.getLangOpts(), R); 553 if (!FileRange) 554 return; 555 Range LSPRange{ 556 sourceLocToPosition(AST.getSourceManager(), FileRange->getBegin()), 557 sourceLocToPosition(AST.getSourceManager(), FileRange->getEnd())}; 558 Position LSPPos = Side == HintSide::Left ? LSPRange.start : LSPRange.end; 559 if (RestrictRange && 560 (LSPPos < RestrictRange->start || !(LSPPos < RestrictRange->end))) 561 return; 562 // The hint may be in a file other than the main file (for example, a header 563 // file that was included after the preamble), do not show in that case. 564 if (!AST.getSourceManager().isWrittenInMainFile(FileRange->getBegin())) 565 return; 566 Results.push_back( 567 InlayHint{LSPPos, LSPRange, Kind, (Prefix + Label + Suffix).str()}); 568 } 569 570 void addTypeHint(SourceRange R, QualType T, llvm::StringRef Prefix) { 571 addTypeHint(R, T, Prefix, TypeHintPolicy); 572 } 573 574 void addTypeHint(SourceRange R, QualType T, llvm::StringRef Prefix, 575 const PrintingPolicy &Policy) { 576 if (!Cfg.InlayHints.DeducedTypes || T.isNull()) 577 return; 578 579 std::string TypeName = T.getAsString(Policy); 580 if (TypeName.length() < TypeNameLimit) 581 addInlayHint(R, HintSide::Right, InlayHintKind::TypeHint, Prefix, 582 TypeName, /*Suffix=*/""); 583 } 584 585 void addDesignatorHint(SourceRange R, llvm::StringRef Text) { 586 addInlayHint(R, HintSide::Left, InlayHintKind::DesignatorHint, 587 /*Prefix=*/"", Text, /*Suffix=*/"="); 588 } 589 590 std::vector<InlayHint> &Results; 591 ASTContext &AST; 592 const Config &Cfg; 593 llvm::Optional<Range> RestrictRange; 594 FileID MainFileID; 595 StringRef MainFileBuf; 596 const HeuristicResolver *Resolver; 597 // We want to suppress default template arguments, but otherwise print 598 // canonical types. Unfortunately, they're conflicting policies so we can't 599 // have both. For regular types, suppressing template arguments is more 600 // important, whereas printing canonical types is crucial for structured 601 // bindings, so we use two separate policies. (See the constructor where 602 // the policies are initialized for more details.) 603 PrintingPolicy TypeHintPolicy; 604 PrintingPolicy StructuredBindingPolicy; 605 606 static const size_t TypeNameLimit = 32; 607 }; 608 609 } // namespace 610 611 std::vector<InlayHint> inlayHints(ParsedAST &AST, 612 llvm::Optional<Range> RestrictRange) { 613 std::vector<InlayHint> Results; 614 const auto &Cfg = Config::current(); 615 if (!Cfg.InlayHints.Enabled) 616 return Results; 617 InlayHintVisitor Visitor(Results, AST, Cfg, std::move(RestrictRange)); 618 Visitor.TraverseAST(AST.getASTContext()); 619 620 // De-duplicate hints. Duplicates can sometimes occur due to e.g. explicit 621 // template instantiations. 622 llvm::sort(Results); 623 Results.erase(std::unique(Results.begin(), Results.end()), Results.end()); 624 625 return Results; 626 } 627 628 } // namespace clangd 629 } // namespace clang 630