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