10505 lines · cpp
1//===---------------- SemaCodeComplete.cpp - Code Completion ----*- 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-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines the code-completion semantic actions.10//11//===----------------------------------------------------------------------===//12#include "clang/AST/ASTConcept.h"13#include "clang/AST/Decl.h"14#include "clang/AST/DeclBase.h"15#include "clang/AST/DeclCXX.h"16#include "clang/AST/DeclObjC.h"17#include "clang/AST/DeclTemplate.h"18#include "clang/AST/DynamicRecursiveASTVisitor.h"19#include "clang/AST/Expr.h"20#include "clang/AST/ExprCXX.h"21#include "clang/AST/ExprConcepts.h"22#include "clang/AST/ExprObjC.h"23#include "clang/AST/NestedNameSpecifier.h"24#include "clang/AST/OperationKinds.h"25#include "clang/AST/QualTypeNames.h"26#include "clang/AST/Type.h"27#include "clang/Basic/AttributeCommonInfo.h"28#include "clang/Basic/CharInfo.h"29#include "clang/Basic/ExceptionSpecificationType.h"30#include "clang/Basic/OperatorKinds.h"31#include "clang/Basic/Specifiers.h"32#include "clang/Lex/HeaderSearch.h"33#include "clang/Lex/MacroInfo.h"34#include "clang/Lex/Preprocessor.h"35#include "clang/Sema/CodeCompleteConsumer.h"36#include "clang/Sema/DeclSpec.h"37#include "clang/Sema/Designator.h"38#include "clang/Sema/HeuristicResolver.h"39#include "clang/Sema/Lookup.h"40#include "clang/Sema/Overload.h"41#include "clang/Sema/ParsedAttr.h"42#include "clang/Sema/ParsedTemplate.h"43#include "clang/Sema/Scope.h"44#include "clang/Sema/ScopeInfo.h"45#include "clang/Sema/Sema.h"46#include "clang/Sema/SemaCodeCompletion.h"47#include "clang/Sema/SemaObjC.h"48#include "llvm/ADT/ArrayRef.h"49#include "llvm/ADT/DenseSet.h"50#include "llvm/ADT/SmallBitVector.h"51#include "llvm/ADT/SmallPtrSet.h"52#include "llvm/ADT/SmallString.h"53#include "llvm/ADT/StringSwitch.h"54#include "llvm/ADT/Twine.h"55#include "llvm/ADT/iterator_range.h"56#include "llvm/Support/Casting.h"57#include "llvm/Support/Path.h"58#include "llvm/Support/raw_ostream.h"59 60#include <list>61#include <map>62#include <optional>63#include <string>64#include <vector>65 66using namespace clang;67using namespace sema;68 69namespace {70/// A container of code-completion results.71class ResultBuilder {72public:73 /// The type of a name-lookup filter, which can be provided to the74 /// name-lookup routines to specify which declarations should be included in75 /// the result set (when it returns true) and which declarations should be76 /// filtered out (returns false).77 typedef bool (ResultBuilder::*LookupFilter)(const NamedDecl *) const;78 79 typedef CodeCompletionResult Result;80 81private:82 /// The actual results we have found.83 std::vector<Result> Results;84 85 /// A record of all of the declarations we have found and placed86 /// into the result set, used to ensure that no declaration ever gets into87 /// the result set twice.88 llvm::SmallPtrSet<const Decl *, 16> AllDeclsFound;89 90 typedef std::pair<const NamedDecl *, unsigned> DeclIndexPair;91 92 /// An entry in the shadow map, which is optimized to store93 /// a single (declaration, index) mapping (the common case) but94 /// can also store a list of (declaration, index) mappings.95 class ShadowMapEntry {96 typedef SmallVector<DeclIndexPair, 4> DeclIndexPairVector;97 98 /// Contains either the solitary NamedDecl * or a vector99 /// of (declaration, index) pairs.100 llvm::PointerUnion<const NamedDecl *, DeclIndexPairVector *> DeclOrVector;101 102 /// When the entry contains a single declaration, this is103 /// the index associated with that entry.104 unsigned SingleDeclIndex = 0;105 106 public:107 ShadowMapEntry() = default;108 ShadowMapEntry(const ShadowMapEntry &) = delete;109 ShadowMapEntry(ShadowMapEntry &&Move) { *this = std::move(Move); }110 ShadowMapEntry &operator=(const ShadowMapEntry &) = delete;111 ShadowMapEntry &operator=(ShadowMapEntry &&Move) {112 SingleDeclIndex = Move.SingleDeclIndex;113 DeclOrVector = Move.DeclOrVector;114 Move.DeclOrVector = nullptr;115 return *this;116 }117 118 void Add(const NamedDecl *ND, unsigned Index) {119 if (DeclOrVector.isNull()) {120 // 0 - > 1 elements: just set the single element information.121 DeclOrVector = ND;122 SingleDeclIndex = Index;123 return;124 }125 126 if (const NamedDecl *PrevND = dyn_cast<const NamedDecl *>(DeclOrVector)) {127 // 1 -> 2 elements: create the vector of results and push in the128 // existing declaration.129 DeclIndexPairVector *Vec = new DeclIndexPairVector;130 Vec->push_back(DeclIndexPair(PrevND, SingleDeclIndex));131 DeclOrVector = Vec;132 }133 134 // Add the new element to the end of the vector.135 cast<DeclIndexPairVector *>(DeclOrVector)136 ->push_back(DeclIndexPair(ND, Index));137 }138 139 ~ShadowMapEntry() {140 if (DeclIndexPairVector *Vec =141 dyn_cast_if_present<DeclIndexPairVector *>(DeclOrVector)) {142 delete Vec;143 DeclOrVector = ((NamedDecl *)nullptr);144 }145 }146 147 // Iteration.148 class iterator;149 iterator begin() const;150 iterator end() const;151 };152 153 /// A mapping from declaration names to the declarations that have154 /// this name within a particular scope and their index within the list of155 /// results.156 typedef llvm::DenseMap<DeclarationName, ShadowMapEntry> ShadowMap;157 158 /// The semantic analysis object for which results are being159 /// produced.160 Sema &SemaRef;161 162 /// The allocator used to allocate new code-completion strings.163 CodeCompletionAllocator &Allocator;164 165 CodeCompletionTUInfo &CCTUInfo;166 167 /// If non-NULL, a filter function used to remove any code-completion168 /// results that are not desirable.169 LookupFilter Filter;170 171 /// Whether we should allow declarations as172 /// nested-name-specifiers that would otherwise be filtered out.173 bool AllowNestedNameSpecifiers;174 175 /// If set, the type that we would prefer our resulting value176 /// declarations to have.177 ///178 /// Closely matching the preferred type gives a boost to a result's179 /// priority.180 CanQualType PreferredType;181 182 /// A list of shadow maps, which is used to model name hiding at183 /// different levels of, e.g., the inheritance hierarchy.184 std::list<ShadowMap> ShadowMaps;185 186 /// Overloaded C++ member functions found by SemaLookup.187 /// Used to determine when one overload is dominated by another.188 llvm::DenseMap<std::pair<DeclContext *, /*Name*/uintptr_t>, ShadowMapEntry>189 OverloadMap;190 191 /// If we're potentially referring to a C++ member function, the set192 /// of qualifiers applied to the object type.193 Qualifiers ObjectTypeQualifiers;194 /// The kind of the object expression, for rvalue/lvalue overloads.195 ExprValueKind ObjectKind;196 197 /// Whether the \p ObjectTypeQualifiers field is active.198 bool HasObjectTypeQualifiers;199 200 // Whether the member function is using an explicit object parameter201 bool IsExplicitObjectMemberFunction;202 203 /// The selector that we prefer.204 Selector PreferredSelector;205 206 /// The completion context in which we are gathering results.207 CodeCompletionContext CompletionContext;208 209 /// If we are in an instance method definition, the \@implementation210 /// object.211 ObjCImplementationDecl *ObjCImplementation;212 213 void AdjustResultPriorityForDecl(Result &R);214 215 void MaybeAddConstructorResults(Result R);216 217public:218 explicit ResultBuilder(Sema &SemaRef, CodeCompletionAllocator &Allocator,219 CodeCompletionTUInfo &CCTUInfo,220 const CodeCompletionContext &CompletionContext,221 LookupFilter Filter = nullptr)222 : SemaRef(SemaRef), Allocator(Allocator), CCTUInfo(CCTUInfo),223 Filter(Filter), AllowNestedNameSpecifiers(false),224 HasObjectTypeQualifiers(false), IsExplicitObjectMemberFunction(false),225 CompletionContext(CompletionContext), ObjCImplementation(nullptr) {226 // If this is an Objective-C instance method definition, dig out the227 // corresponding implementation.228 switch (CompletionContext.getKind()) {229 case CodeCompletionContext::CCC_Expression:230 case CodeCompletionContext::CCC_ObjCMessageReceiver:231 case CodeCompletionContext::CCC_ParenthesizedExpression:232 case CodeCompletionContext::CCC_Statement:233 case CodeCompletionContext::CCC_TopLevelOrExpression:234 case CodeCompletionContext::CCC_Recovery:235 if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl())236 if (Method->isInstanceMethod())237 if (ObjCInterfaceDecl *Interface = Method->getClassInterface())238 ObjCImplementation = Interface->getImplementation();239 break;240 241 default:242 break;243 }244 }245 246 /// Determine the priority for a reference to the given declaration.247 unsigned getBasePriority(const NamedDecl *D);248 249 /// Whether we should include code patterns in the completion250 /// results.251 bool includeCodePatterns() const {252 return SemaRef.CodeCompletion().CodeCompleter &&253 SemaRef.CodeCompletion().CodeCompleter->includeCodePatterns();254 }255 256 /// Set the filter used for code-completion results.257 void setFilter(LookupFilter Filter) { this->Filter = Filter; }258 259 Result *data() { return Results.empty() ? nullptr : &Results.front(); }260 unsigned size() const { return Results.size(); }261 bool empty() const { return Results.empty(); }262 263 /// Specify the preferred type.264 void setPreferredType(QualType T) {265 PreferredType = SemaRef.Context.getCanonicalType(T);266 }267 268 /// Set the cv-qualifiers on the object type, for us in filtering269 /// calls to member functions.270 ///271 /// When there are qualifiers in this set, they will be used to filter272 /// out member functions that aren't available (because there will be a273 /// cv-qualifier mismatch) or prefer functions with an exact qualifier274 /// match.275 void setObjectTypeQualifiers(Qualifiers Quals, ExprValueKind Kind) {276 ObjectTypeQualifiers = Quals;277 ObjectKind = Kind;278 HasObjectTypeQualifiers = true;279 }280 281 void setExplicitObjectMemberFn(bool IsExplicitObjectFn) {282 IsExplicitObjectMemberFunction = IsExplicitObjectFn;283 }284 285 /// Set the preferred selector.286 ///287 /// When an Objective-C method declaration result is added, and that288 /// method's selector matches this preferred selector, we give that method289 /// a slight priority boost.290 void setPreferredSelector(Selector Sel) { PreferredSelector = Sel; }291 292 /// Retrieve the code-completion context for which results are293 /// being collected.294 const CodeCompletionContext &getCompletionContext() const {295 return CompletionContext;296 }297 298 /// Specify whether nested-name-specifiers are allowed.299 void allowNestedNameSpecifiers(bool Allow = true) {300 AllowNestedNameSpecifiers = Allow;301 }302 303 /// Return the semantic analysis object for which we are collecting304 /// code completion results.305 Sema &getSema() const { return SemaRef; }306 307 /// Retrieve the allocator used to allocate code completion strings.308 CodeCompletionAllocator &getAllocator() const { return Allocator; }309 310 CodeCompletionTUInfo &getCodeCompletionTUInfo() const { return CCTUInfo; }311 312 /// Determine whether the given declaration is at all interesting313 /// as a code-completion result.314 ///315 /// \param ND the declaration that we are inspecting.316 ///317 /// \param AsNestedNameSpecifier will be set true if this declaration is318 /// only interesting when it is a nested-name-specifier.319 bool isInterestingDecl(const NamedDecl *ND,320 bool &AsNestedNameSpecifier) const;321 322 /// Decide whether or not a use of function Decl can be a call.323 ///324 /// \param ND the function declaration.325 ///326 /// \param BaseExprType the object type in a member access expression,327 /// if any.328 bool canFunctionBeCalled(const NamedDecl *ND, QualType BaseExprType) const;329 330 /// Decide whether or not a use of member function Decl can be a call.331 ///332 /// \param Method the function declaration.333 ///334 /// \param BaseExprType the object type in a member access expression,335 /// if any.336 bool canCxxMethodBeCalled(const CXXMethodDecl *Method,337 QualType BaseExprType) const;338 339 /// Check whether the result is hidden by the Hiding declaration.340 ///341 /// \returns true if the result is hidden and cannot be found, false if342 /// the hidden result could still be found. When false, \p R may be343 /// modified to describe how the result can be found (e.g., via extra344 /// qualification).345 bool CheckHiddenResult(Result &R, DeclContext *CurContext,346 const NamedDecl *Hiding);347 348 /// Add a new result to this result set (if it isn't already in one349 /// of the shadow maps), or replace an existing result (for, e.g., a350 /// redeclaration).351 ///352 /// \param R the result to add (if it is unique).353 ///354 /// \param CurContext the context in which this result will be named.355 void MaybeAddResult(Result R, DeclContext *CurContext = nullptr);356 357 /// Add a new result to this result set, where we already know358 /// the hiding declaration (if any).359 ///360 /// \param R the result to add (if it is unique).361 ///362 /// \param CurContext the context in which this result will be named.363 ///364 /// \param Hiding the declaration that hides the result.365 ///366 /// \param InBaseClass whether the result was found in a base367 /// class of the searched context.368 ///369 /// \param BaseExprType the type of expression that precedes the "." or "->"370 /// in a member access expression.371 void AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding,372 bool InBaseClass, QualType BaseExprType);373 374 /// Add a new non-declaration result to this result set.375 void AddResult(Result R);376 377 /// Enter into a new scope.378 void EnterNewScope();379 380 /// Exit from the current scope.381 void ExitScope();382 383 /// Ignore this declaration, if it is seen again.384 void Ignore(const Decl *D) { AllDeclsFound.insert(D->getCanonicalDecl()); }385 386 /// Add a visited context.387 void addVisitedContext(DeclContext *Ctx) {388 CompletionContext.addVisitedContext(Ctx);389 }390 391 /// \name Name lookup predicates392 ///393 /// These predicates can be passed to the name lookup functions to filter the394 /// results of name lookup. All of the predicates have the same type, so that395 ///396 //@{397 bool IsOrdinaryName(const NamedDecl *ND) const;398 bool IsOrdinaryNonTypeName(const NamedDecl *ND) const;399 bool IsIntegralConstantValue(const NamedDecl *ND) const;400 bool IsOrdinaryNonValueName(const NamedDecl *ND) const;401 bool IsNestedNameSpecifier(const NamedDecl *ND) const;402 bool IsEnum(const NamedDecl *ND) const;403 bool IsClassOrStruct(const NamedDecl *ND) const;404 bool IsUnion(const NamedDecl *ND) const;405 bool IsNamespace(const NamedDecl *ND) const;406 bool IsNamespaceOrAlias(const NamedDecl *ND) const;407 bool IsType(const NamedDecl *ND) const;408 bool IsMember(const NamedDecl *ND) const;409 bool IsObjCIvar(const NamedDecl *ND) const;410 bool IsObjCMessageReceiver(const NamedDecl *ND) const;411 bool IsObjCMessageReceiverOrLambdaCapture(const NamedDecl *ND) const;412 bool IsObjCCollection(const NamedDecl *ND) const;413 bool IsImpossibleToSatisfy(const NamedDecl *ND) const;414 //@}415};416} // namespace417 418void PreferredTypeBuilder::enterReturn(Sema &S, SourceLocation Tok) {419 if (!Enabled)420 return;421 if (isa<BlockDecl>(S.CurContext)) {422 if (sema::BlockScopeInfo *BSI = S.getCurBlock()) {423 ComputeType = nullptr;424 Type = BSI->ReturnType;425 ExpectedLoc = Tok;426 }427 } else if (const auto *Function = dyn_cast<FunctionDecl>(S.CurContext)) {428 ComputeType = nullptr;429 Type = Function->getReturnType();430 ExpectedLoc = Tok;431 } else if (const auto *Method = dyn_cast<ObjCMethodDecl>(S.CurContext)) {432 ComputeType = nullptr;433 Type = Method->getReturnType();434 ExpectedLoc = Tok;435 }436}437 438void PreferredTypeBuilder::enterVariableInit(SourceLocation Tok, Decl *D) {439 if (!Enabled)440 return;441 auto *VD = llvm::dyn_cast_or_null<ValueDecl>(D);442 ComputeType = nullptr;443 Type = VD ? VD->getType() : QualType();444 ExpectedLoc = Tok;445}446 447static QualType getDesignatedType(QualType BaseType, const Designation &Desig,448 HeuristicResolver &Resolver);449 450void PreferredTypeBuilder::enterDesignatedInitializer(SourceLocation Tok,451 QualType BaseType,452 const Designation &D) {453 if (!Enabled)454 return;455 ComputeType = nullptr;456 HeuristicResolver Resolver(*Ctx);457 Type = getDesignatedType(BaseType, D, Resolver);458 ExpectedLoc = Tok;459}460 461void PreferredTypeBuilder::enterFunctionArgument(462 SourceLocation Tok, llvm::function_ref<QualType()> ComputeType) {463 if (!Enabled)464 return;465 this->ComputeType = ComputeType;466 Type = QualType();467 ExpectedLoc = Tok;468}469 470void PreferredTypeBuilder::enterParenExpr(SourceLocation Tok,471 SourceLocation LParLoc) {472 if (!Enabled)473 return;474 // expected type for parenthesized expression does not change.475 if (ExpectedLoc == LParLoc)476 ExpectedLoc = Tok;477}478 479static QualType getPreferredTypeOfBinaryRHS(Sema &S, Expr *LHS,480 tok::TokenKind Op) {481 if (!LHS)482 return QualType();483 484 QualType LHSType = LHS->getType();485 if (LHSType->isPointerType()) {486 if (Op == tok::plus || Op == tok::plusequal || Op == tok::minusequal)487 return S.getASTContext().getPointerDiffType();488 // Pointer difference is more common than subtracting an int from a pointer.489 if (Op == tok::minus)490 return LHSType;491 }492 493 switch (Op) {494 // No way to infer the type of RHS from LHS.495 case tok::comma:496 return QualType();497 // Prefer the type of the left operand for all of these.498 // Arithmetic operations.499 case tok::plus:500 case tok::plusequal:501 case tok::minus:502 case tok::minusequal:503 case tok::percent:504 case tok::percentequal:505 case tok::slash:506 case tok::slashequal:507 case tok::star:508 case tok::starequal:509 // Assignment.510 case tok::equal:511 // Comparison operators.512 case tok::equalequal:513 case tok::exclaimequal:514 case tok::less:515 case tok::lessequal:516 case tok::greater:517 case tok::greaterequal:518 case tok::spaceship:519 return LHS->getType();520 // Binary shifts are often overloaded, so don't try to guess those.521 case tok::greatergreater:522 case tok::greatergreaterequal:523 case tok::lessless:524 case tok::lesslessequal:525 if (LHSType->isIntegralOrEnumerationType())526 return S.getASTContext().IntTy;527 return QualType();528 // Logical operators, assume we want bool.529 case tok::ampamp:530 case tok::pipepipe:531 return S.getASTContext().BoolTy;532 // Operators often used for bit manipulation are typically used with the type533 // of the left argument.534 case tok::pipe:535 case tok::pipeequal:536 case tok::caret:537 case tok::caretequal:538 case tok::amp:539 case tok::ampequal:540 if (LHSType->isIntegralOrEnumerationType())541 return LHSType;542 return QualType();543 // RHS should be a pointer to a member of the 'LHS' type, but we can't give544 // any particular type here.545 case tok::periodstar:546 case tok::arrowstar:547 return QualType();548 default:549 // FIXME(ibiryukov): handle the missing op, re-add the assertion.550 // assert(false && "unhandled binary op");551 return QualType();552 }553}554 555/// Get preferred type for an argument of an unary expression. \p ContextType is556/// preferred type of the whole unary expression.557static QualType getPreferredTypeOfUnaryArg(Sema &S, QualType ContextType,558 tok::TokenKind Op) {559 switch (Op) {560 case tok::exclaim:561 return S.getASTContext().BoolTy;562 case tok::amp:563 if (!ContextType.isNull() && ContextType->isPointerType())564 return ContextType->getPointeeType();565 return QualType();566 case tok::star:567 if (ContextType.isNull())568 return QualType();569 return S.getASTContext().getPointerType(ContextType.getNonReferenceType());570 case tok::plus:571 case tok::minus:572 case tok::tilde:573 case tok::minusminus:574 case tok::plusplus:575 if (ContextType.isNull())576 return S.getASTContext().IntTy;577 // leave as is, these operators typically return the same type.578 return ContextType;579 case tok::kw___real:580 case tok::kw___imag:581 return QualType();582 default:583 assert(false && "unhandled unary op");584 return QualType();585 }586}587 588void PreferredTypeBuilder::enterBinary(Sema &S, SourceLocation Tok, Expr *LHS,589 tok::TokenKind Op) {590 if (!Enabled)591 return;592 ComputeType = nullptr;593 Type = getPreferredTypeOfBinaryRHS(S, LHS, Op);594 ExpectedLoc = Tok;595}596 597void PreferredTypeBuilder::enterMemAccess(Sema &S, SourceLocation Tok,598 Expr *Base) {599 if (!Enabled || !Base)600 return;601 // Do we have expected type for Base?602 if (ExpectedLoc != Base->getBeginLoc())603 return;604 // Keep the expected type, only update the location.605 ExpectedLoc = Tok;606}607 608void PreferredTypeBuilder::enterUnary(Sema &S, SourceLocation Tok,609 tok::TokenKind OpKind,610 SourceLocation OpLoc) {611 if (!Enabled)612 return;613 ComputeType = nullptr;614 Type = getPreferredTypeOfUnaryArg(S, this->get(OpLoc), OpKind);615 ExpectedLoc = Tok;616}617 618void PreferredTypeBuilder::enterSubscript(Sema &S, SourceLocation Tok,619 Expr *LHS) {620 if (!Enabled)621 return;622 ComputeType = nullptr;623 Type = S.getASTContext().IntTy;624 ExpectedLoc = Tok;625}626 627void PreferredTypeBuilder::enterTypeCast(SourceLocation Tok,628 QualType CastType) {629 if (!Enabled)630 return;631 ComputeType = nullptr;632 Type = !CastType.isNull() ? CastType.getCanonicalType() : QualType();633 ExpectedLoc = Tok;634}635 636void PreferredTypeBuilder::enterCondition(Sema &S, SourceLocation Tok) {637 if (!Enabled)638 return;639 ComputeType = nullptr;640 Type = S.getASTContext().BoolTy;641 ExpectedLoc = Tok;642}643 644class ResultBuilder::ShadowMapEntry::iterator {645 llvm::PointerUnion<const NamedDecl *, const DeclIndexPair *> DeclOrIterator;646 unsigned SingleDeclIndex;647 648public:649 typedef DeclIndexPair value_type;650 typedef value_type reference;651 typedef std::ptrdiff_t difference_type;652 typedef std::input_iterator_tag iterator_category;653 654 class pointer {655 DeclIndexPair Value;656 657 public:658 pointer(const DeclIndexPair &Value) : Value(Value) {}659 660 const DeclIndexPair *operator->() const { return &Value; }661 };662 663 iterator() : DeclOrIterator((NamedDecl *)nullptr), SingleDeclIndex(0) {}664 665 iterator(const NamedDecl *SingleDecl, unsigned Index)666 : DeclOrIterator(SingleDecl), SingleDeclIndex(Index) {}667 668 iterator(const DeclIndexPair *Iterator)669 : DeclOrIterator(Iterator), SingleDeclIndex(0) {}670 671 iterator &operator++() {672 if (isa<const NamedDecl *>(DeclOrIterator)) {673 DeclOrIterator = (NamedDecl *)nullptr;674 SingleDeclIndex = 0;675 return *this;676 }677 678 const DeclIndexPair *I = cast<const DeclIndexPair *>(DeclOrIterator);679 ++I;680 DeclOrIterator = I;681 return *this;682 }683 684 /*iterator operator++(int) {685 iterator tmp(*this);686 ++(*this);687 return tmp;688 }*/689 690 reference operator*() const {691 if (const NamedDecl *ND = dyn_cast<const NamedDecl *>(DeclOrIterator))692 return reference(ND, SingleDeclIndex);693 694 return *cast<const DeclIndexPair *>(DeclOrIterator);695 }696 697 pointer operator->() const { return pointer(**this); }698 699 friend bool operator==(const iterator &X, const iterator &Y) {700 return X.DeclOrIterator.getOpaqueValue() ==701 Y.DeclOrIterator.getOpaqueValue() &&702 X.SingleDeclIndex == Y.SingleDeclIndex;703 }704 705 friend bool operator!=(const iterator &X, const iterator &Y) {706 return !(X == Y);707 }708};709 710ResultBuilder::ShadowMapEntry::iterator711ResultBuilder::ShadowMapEntry::begin() const {712 if (DeclOrVector.isNull())713 return iterator();714 715 if (const NamedDecl *ND = dyn_cast<const NamedDecl *>(DeclOrVector))716 return iterator(ND, SingleDeclIndex);717 718 return iterator(cast<DeclIndexPairVector *>(DeclOrVector)->begin());719}720 721ResultBuilder::ShadowMapEntry::iterator722ResultBuilder::ShadowMapEntry::end() const {723 if (isa<const NamedDecl *>(DeclOrVector) || DeclOrVector.isNull())724 return iterator();725 726 return iterator(cast<DeclIndexPairVector *>(DeclOrVector)->end());727}728 729/// Compute the qualification required to get from the current context730/// (\p CurContext) to the target context (\p TargetContext).731///732/// \param Context the AST context in which the qualification will be used.733///734/// \param CurContext the context where an entity is being named, which is735/// typically based on the current scope.736///737/// \param TargetContext the context in which the named entity actually738/// resides.739///740/// \returns a nested name specifier that refers into the target context, or741/// NULL if no qualification is needed.742static NestedNameSpecifier743getRequiredQualification(ASTContext &Context, const DeclContext *CurContext,744 const DeclContext *TargetContext) {745 SmallVector<const DeclContext *, 4> TargetParents;746 747 for (const DeclContext *CommonAncestor = TargetContext;748 CommonAncestor && !CommonAncestor->Encloses(CurContext);749 CommonAncestor = CommonAncestor->getLookupParent()) {750 if (CommonAncestor->isTransparentContext() ||751 CommonAncestor->isFunctionOrMethod())752 continue;753 754 TargetParents.push_back(CommonAncestor);755 }756 757 NestedNameSpecifier Result = std::nullopt;758 while (!TargetParents.empty()) {759 const DeclContext *Parent = TargetParents.pop_back_val();760 761 if (const auto *Namespace = dyn_cast<NamespaceDecl>(Parent)) {762 if (!Namespace->getIdentifier())763 continue;764 765 Result = NestedNameSpecifier(Context, Namespace, Result);766 } else if (const auto *TD = dyn_cast<TagDecl>(Parent)) {767 QualType TT = Context.getTagType(ElaboratedTypeKeyword::None, Result, TD,768 /*OwnsTag=*/false);769 Result = NestedNameSpecifier(TT.getTypePtr());770 }771 }772 return Result;773}774 775// Some declarations have reserved names that we don't want to ever show.776// Filter out names reserved for the implementation if they come from a777// system header.778static bool shouldIgnoreDueToReservedName(const NamedDecl *ND, Sema &SemaRef) {779 // Debuggers want access to all identifiers, including reserved ones.780 if (SemaRef.getLangOpts().DebuggerSupport)781 return false;782 783 ReservedIdentifierStatus Status = ND->isReserved(SemaRef.getLangOpts());784 // Ignore reserved names for compiler provided decls.785 if (isReservedInAllContexts(Status) && ND->getLocation().isInvalid())786 return true;787 788 // For system headers ignore only double-underscore names.789 // This allows for system headers providing private symbols with a single790 // underscore.791 if (Status == ReservedIdentifierStatus::StartsWithDoubleUnderscore &&792 SemaRef.SourceMgr.isInSystemHeader(793 SemaRef.SourceMgr.getSpellingLoc(ND->getLocation())))794 return true;795 796 return false;797}798 799bool ResultBuilder::isInterestingDecl(const NamedDecl *ND,800 bool &AsNestedNameSpecifier) const {801 AsNestedNameSpecifier = false;802 803 auto *Named = ND;804 ND = ND->getUnderlyingDecl();805 806 // Skip unnamed entities.807 if (!ND->getDeclName())808 return false;809 810 // Friend declarations and declarations introduced due to friends are never811 // added as results.812 if (ND->getFriendObjectKind() == Decl::FOK_Undeclared)813 return false;814 815 // Class template (partial) specializations are never added as results.816 if (isa<ClassTemplateSpecializationDecl>(ND) ||817 isa<ClassTemplatePartialSpecializationDecl>(ND))818 return false;819 820 // Using declarations themselves are never added as results.821 if (isa<UsingDecl>(ND))822 return false;823 824 if (shouldIgnoreDueToReservedName(ND, SemaRef))825 return false;826 827 if (Filter == &ResultBuilder::IsNestedNameSpecifier ||828 (isa<NamespaceDecl>(ND) && Filter != &ResultBuilder::IsNamespace &&829 Filter != &ResultBuilder::IsNamespaceOrAlias && Filter != nullptr))830 AsNestedNameSpecifier = true;831 832 // Filter out any unwanted results.833 if (Filter && !(this->*Filter)(Named)) {834 // Check whether it is interesting as a nested-name-specifier.835 if (AllowNestedNameSpecifiers && SemaRef.getLangOpts().CPlusPlus &&836 IsNestedNameSpecifier(ND) &&837 (Filter != &ResultBuilder::IsMember ||838 (isa<CXXRecordDecl>(ND) &&839 cast<CXXRecordDecl>(ND)->isInjectedClassName()))) {840 AsNestedNameSpecifier = true;841 return true;842 }843 844 return false;845 }846 // ... then it must be interesting!847 return true;848}849 850bool ResultBuilder::CheckHiddenResult(Result &R, DeclContext *CurContext,851 const NamedDecl *Hiding) {852 // In C, there is no way to refer to a hidden name.853 // FIXME: This isn't true; we can find a tag name hidden by an ordinary854 // name if we introduce the tag type.855 if (!SemaRef.getLangOpts().CPlusPlus)856 return true;857 858 const DeclContext *HiddenCtx =859 R.Declaration->getDeclContext()->getRedeclContext();860 861 // There is no way to qualify a name declared in a function or method.862 if (HiddenCtx->isFunctionOrMethod())863 return true;864 865 if (HiddenCtx == Hiding->getDeclContext()->getRedeclContext())866 return true;867 868 // We can refer to the result with the appropriate qualification. Do it.869 R.Hidden = true;870 R.QualifierIsInformative = false;871 872 if (!R.Qualifier)873 R.Qualifier = getRequiredQualification(SemaRef.Context, CurContext,874 R.Declaration->getDeclContext());875 return false;876}877 878/// A simplified classification of types used to determine whether two879/// types are "similar enough" when adjusting priorities.880SimplifiedTypeClass clang::getSimplifiedTypeClass(CanQualType T) {881 switch (T->getTypeClass()) {882 case Type::Builtin:883 switch (cast<BuiltinType>(T)->getKind()) {884 case BuiltinType::Void:885 return STC_Void;886 887 case BuiltinType::NullPtr:888 return STC_Pointer;889 890 case BuiltinType::Overload:891 case BuiltinType::Dependent:892 return STC_Other;893 894 case BuiltinType::ObjCId:895 case BuiltinType::ObjCClass:896 case BuiltinType::ObjCSel:897 return STC_ObjectiveC;898 899 default:900 return STC_Arithmetic;901 }902 903 case Type::Complex:904 return STC_Arithmetic;905 906 case Type::Pointer:907 return STC_Pointer;908 909 case Type::BlockPointer:910 return STC_Block;911 912 case Type::LValueReference:913 case Type::RValueReference:914 return getSimplifiedTypeClass(T->getAs<ReferenceType>()->getPointeeType());915 916 case Type::ConstantArray:917 case Type::IncompleteArray:918 case Type::VariableArray:919 case Type::DependentSizedArray:920 return STC_Array;921 922 case Type::DependentSizedExtVector:923 case Type::Vector:924 case Type::ExtVector:925 return STC_Arithmetic;926 927 case Type::FunctionProto:928 case Type::FunctionNoProto:929 return STC_Function;930 931 case Type::Record:932 return STC_Record;933 934 case Type::Enum:935 return STC_Arithmetic;936 937 case Type::ObjCObject:938 case Type::ObjCInterface:939 case Type::ObjCObjectPointer:940 return STC_ObjectiveC;941 942 default:943 return STC_Other;944 }945}946 947/// Get the type that a given expression will have if this declaration948/// is used as an expression in its "typical" code-completion form.949QualType clang::getDeclUsageType(ASTContext &C, NestedNameSpecifier Qualifier,950 const NamedDecl *ND) {951 ND = ND->getUnderlyingDecl();952 953 if (const auto *Type = dyn_cast<TypeDecl>(ND))954 return C.getTypeDeclType(ElaboratedTypeKeyword::None, Qualifier, Type);955 if (const auto *Iface = dyn_cast<ObjCInterfaceDecl>(ND))956 return C.getObjCInterfaceType(Iface);957 958 QualType T;959 if (const FunctionDecl *Function = ND->getAsFunction())960 T = Function->getCallResultType();961 else if (const auto *Method = dyn_cast<ObjCMethodDecl>(ND))962 T = Method->getSendResultType();963 else if (const auto *Enumerator = dyn_cast<EnumConstantDecl>(ND))964 T = C.getTagType(ElaboratedTypeKeyword::None, Qualifier,965 cast<EnumDecl>(Enumerator->getDeclContext()),966 /*OwnsTag=*/false);967 else if (const auto *Property = dyn_cast<ObjCPropertyDecl>(ND))968 T = Property->getType();969 else if (const auto *Value = dyn_cast<ValueDecl>(ND))970 T = Value->getType();971 972 if (T.isNull())973 return QualType();974 975 // Dig through references, function pointers, and block pointers to976 // get down to the likely type of an expression when the entity is977 // used.978 do {979 if (const auto *Ref = T->getAs<ReferenceType>()) {980 T = Ref->getPointeeType();981 continue;982 }983 984 if (const auto *Pointer = T->getAs<PointerType>()) {985 if (Pointer->getPointeeType()->isFunctionType()) {986 T = Pointer->getPointeeType();987 continue;988 }989 990 break;991 }992 993 if (const auto *Block = T->getAs<BlockPointerType>()) {994 T = Block->getPointeeType();995 continue;996 }997 998 if (const auto *Function = T->getAs<FunctionType>()) {999 T = Function->getReturnType();1000 continue;1001 }1002 1003 break;1004 } while (true);1005 1006 return T;1007}1008 1009unsigned ResultBuilder::getBasePriority(const NamedDecl *ND) {1010 if (!ND)1011 return CCP_Unlikely;1012 1013 // Context-based decisions.1014 const DeclContext *LexicalDC = ND->getLexicalDeclContext();1015 if (LexicalDC->isFunctionOrMethod()) {1016 // _cmd is relatively rare1017 if (const auto *ImplicitParam = dyn_cast<ImplicitParamDecl>(ND))1018 if (ImplicitParam->getIdentifier() &&1019 ImplicitParam->getIdentifier()->isStr("_cmd"))1020 return CCP_ObjC_cmd;1021 1022 return CCP_LocalDeclaration;1023 }1024 1025 const DeclContext *DC = ND->getDeclContext()->getRedeclContext();1026 if (DC->isRecord() || isa<ObjCContainerDecl>(DC)) {1027 // Explicit destructor calls are very rare.1028 if (isa<CXXDestructorDecl>(ND))1029 return CCP_Unlikely;1030 // Explicit operator and conversion function calls are also very rare.1031 auto DeclNameKind = ND->getDeclName().getNameKind();1032 if (DeclNameKind == DeclarationName::CXXOperatorName ||1033 DeclNameKind == DeclarationName::CXXLiteralOperatorName ||1034 DeclNameKind == DeclarationName::CXXConversionFunctionName)1035 return CCP_Unlikely;1036 return CCP_MemberDeclaration;1037 }1038 1039 // Content-based decisions.1040 if (isa<EnumConstantDecl>(ND))1041 return CCP_Constant;1042 1043 // Use CCP_Type for type declarations unless we're in a statement, Objective-C1044 // message receiver, or parenthesized expression context. There, it's as1045 // likely that the user will want to write a type as other declarations.1046 if ((isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) &&1047 !(CompletionContext.getKind() == CodeCompletionContext::CCC_Statement ||1048 CompletionContext.getKind() ==1049 CodeCompletionContext::CCC_ObjCMessageReceiver ||1050 CompletionContext.getKind() ==1051 CodeCompletionContext::CCC_ParenthesizedExpression))1052 return CCP_Type;1053 1054 return CCP_Declaration;1055}1056 1057void ResultBuilder::AdjustResultPriorityForDecl(Result &R) {1058 // If this is an Objective-C method declaration whose selector matches our1059 // preferred selector, give it a priority boost.1060 if (!PreferredSelector.isNull())1061 if (const auto *Method = dyn_cast<ObjCMethodDecl>(R.Declaration))1062 if (PreferredSelector == Method->getSelector())1063 R.Priority += CCD_SelectorMatch;1064 1065 // If we have a preferred type, adjust the priority for results with exactly-1066 // matching or nearly-matching types.1067 if (!PreferredType.isNull()) {1068 QualType T = getDeclUsageType(SemaRef.Context, R.Qualifier, R.Declaration);1069 if (!T.isNull()) {1070 CanQualType TC = SemaRef.Context.getCanonicalType(T);1071 // Check for exactly-matching types (modulo qualifiers).1072 if (SemaRef.Context.hasSameUnqualifiedType(PreferredType, TC))1073 R.Priority /= CCF_ExactTypeMatch;1074 // Check for nearly-matching types, based on classification of each.1075 else if ((getSimplifiedTypeClass(PreferredType) ==1076 getSimplifiedTypeClass(TC)) &&1077 !(PreferredType->isEnumeralType() && TC->isEnumeralType()))1078 R.Priority /= CCF_SimilarTypeMatch;1079 }1080 }1081}1082 1083static DeclContext::lookup_result getConstructors(ASTContext &Context,1084 const CXXRecordDecl *Record) {1085 CanQualType RecordTy = Context.getCanonicalTagType(Record);1086 DeclarationName ConstructorName =1087 Context.DeclarationNames.getCXXConstructorName(RecordTy);1088 return Record->lookup(ConstructorName);1089}1090 1091void ResultBuilder::MaybeAddConstructorResults(Result R) {1092 if (!SemaRef.getLangOpts().CPlusPlus || !R.Declaration ||1093 !CompletionContext.wantConstructorResults())1094 return;1095 1096 const NamedDecl *D = R.Declaration;1097 const CXXRecordDecl *Record = nullptr;1098 if (const ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(D))1099 Record = ClassTemplate->getTemplatedDecl();1100 else if ((Record = dyn_cast<CXXRecordDecl>(D))) {1101 // Skip specializations and partial specializations.1102 if (isa<ClassTemplateSpecializationDecl>(Record))1103 return;1104 } else {1105 // There are no constructors here.1106 return;1107 }1108 1109 Record = Record->getDefinition();1110 if (!Record)1111 return;1112 1113 for (NamedDecl *Ctor : getConstructors(SemaRef.Context, Record)) {1114 R.Declaration = Ctor;1115 R.CursorKind = getCursorKindForDecl(R.Declaration);1116 Results.push_back(R);1117 }1118}1119 1120static bool isConstructor(const Decl *ND) {1121 if (const auto *Tmpl = dyn_cast<FunctionTemplateDecl>(ND))1122 ND = Tmpl->getTemplatedDecl();1123 return isa<CXXConstructorDecl>(ND);1124}1125 1126void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {1127 assert(!ShadowMaps.empty() && "Must enter into a results scope");1128 1129 if (R.Kind != Result::RK_Declaration) {1130 // For non-declaration results, just add the result.1131 Results.push_back(R);1132 return;1133 }1134 1135 // Look through using declarations.1136 if (const UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) {1137 CodeCompletionResult Result(Using->getTargetDecl(),1138 getBasePriority(Using->getTargetDecl()),1139 R.Qualifier, false,1140 (R.Availability == CXAvailability_Available ||1141 R.Availability == CXAvailability_Deprecated),1142 std::move(R.FixIts));1143 Result.ShadowDecl = Using;1144 MaybeAddResult(Result, CurContext);1145 return;1146 }1147 1148 const Decl *CanonDecl = R.Declaration->getCanonicalDecl();1149 unsigned IDNS = CanonDecl->getIdentifierNamespace();1150 1151 bool AsNestedNameSpecifier = false;1152 if (!isInterestingDecl(R.Declaration, AsNestedNameSpecifier))1153 return;1154 1155 // C++ constructors are never found by name lookup.1156 if (isConstructor(R.Declaration))1157 return;1158 1159 ShadowMap &SMap = ShadowMaps.back();1160 ShadowMapEntry::iterator I, IEnd;1161 ShadowMap::iterator NamePos = SMap.find(R.Declaration->getDeclName());1162 if (NamePos != SMap.end()) {1163 I = NamePos->second.begin();1164 IEnd = NamePos->second.end();1165 }1166 1167 for (; I != IEnd; ++I) {1168 const NamedDecl *ND = I->first;1169 unsigned Index = I->second;1170 if (ND->getCanonicalDecl() == CanonDecl) {1171 // This is a redeclaration. Always pick the newer declaration.1172 Results[Index].Declaration = R.Declaration;1173 1174 // We're done.1175 return;1176 }1177 }1178 1179 // This is a new declaration in this scope. However, check whether this1180 // declaration name is hidden by a similarly-named declaration in an outer1181 // scope.1182 std::list<ShadowMap>::iterator SM, SMEnd = ShadowMaps.end();1183 --SMEnd;1184 for (SM = ShadowMaps.begin(); SM != SMEnd; ++SM) {1185 ShadowMapEntry::iterator I, IEnd;1186 ShadowMap::iterator NamePos = SM->find(R.Declaration->getDeclName());1187 if (NamePos != SM->end()) {1188 I = NamePos->second.begin();1189 IEnd = NamePos->second.end();1190 }1191 for (; I != IEnd; ++I) {1192 // A tag declaration does not hide a non-tag declaration.1193 if (I->first->hasTagIdentifierNamespace() &&1194 (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |1195 Decl::IDNS_LocalExtern | Decl::IDNS_ObjCProtocol)))1196 continue;1197 1198 // Protocols are in distinct namespaces from everything else.1199 if (((I->first->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol) ||1200 (IDNS & Decl::IDNS_ObjCProtocol)) &&1201 I->first->getIdentifierNamespace() != IDNS)1202 continue;1203 1204 // The newly-added result is hidden by an entry in the shadow map.1205 if (CheckHiddenResult(R, CurContext, I->first))1206 return;1207 1208 break;1209 }1210 }1211 1212 // Make sure that any given declaration only shows up in the result set once.1213 if (!AllDeclsFound.insert(CanonDecl).second)1214 return;1215 1216 // If the filter is for nested-name-specifiers, then this result starts a1217 // nested-name-specifier.1218 if (AsNestedNameSpecifier) {1219 R.StartsNestedNameSpecifier = true;1220 R.Priority = CCP_NestedNameSpecifier;1221 } else1222 AdjustResultPriorityForDecl(R);1223 1224 // If this result is supposed to have an informative qualifier, add one.1225 if (R.QualifierIsInformative && !R.Qualifier &&1226 !R.StartsNestedNameSpecifier) {1227 const DeclContext *Ctx = R.Declaration->getDeclContext();1228 if (const NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Ctx))1229 R.Qualifier =1230 NestedNameSpecifier(SemaRef.Context, Namespace, std::nullopt);1231 else if (const TagDecl *Tag = dyn_cast<TagDecl>(Ctx))1232 R.Qualifier = NestedNameSpecifier(1233 SemaRef.Context1234 .getTagType(ElaboratedTypeKeyword::None,1235 /*Qualifier=*/std::nullopt, Tag, /*OwnsTag=*/false)1236 .getTypePtr());1237 else1238 R.QualifierIsInformative = false;1239 }1240 1241 // Insert this result into the set of results and into the current shadow1242 // map.1243 SMap[R.Declaration->getDeclName()].Add(R.Declaration, Results.size());1244 Results.push_back(R);1245 1246 if (!AsNestedNameSpecifier)1247 MaybeAddConstructorResults(R);1248}1249 1250static void setInBaseClass(ResultBuilder::Result &R) {1251 R.Priority += CCD_InBaseClass;1252 R.InBaseClass = true;1253}1254 1255enum class OverloadCompare { BothViable, Dominates, Dominated };1256// Will Candidate ever be called on the object, when overloaded with Incumbent?1257// Returns Dominates if Candidate is always called, Dominated if Incumbent is1258// always called, BothViable if either may be called depending on arguments.1259// Precondition: must actually be overloads!1260static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate,1261 const CXXMethodDecl &Incumbent,1262 const Qualifiers &ObjectQuals,1263 ExprValueKind ObjectKind,1264 const ASTContext &Ctx) {1265 // Base/derived shadowing is handled elsewhere.1266 if (Candidate.getDeclContext() != Incumbent.getDeclContext())1267 return OverloadCompare::BothViable;1268 if (Candidate.isVariadic() != Incumbent.isVariadic() ||1269 Candidate.getNumParams() != Incumbent.getNumParams() ||1270 Candidate.getMinRequiredArguments() !=1271 Incumbent.getMinRequiredArguments())1272 return OverloadCompare::BothViable;1273 for (unsigned I = 0, E = Candidate.getNumParams(); I != E; ++I)1274 if (Candidate.parameters()[I]->getType().getCanonicalType() !=1275 Incumbent.parameters()[I]->getType().getCanonicalType())1276 return OverloadCompare::BothViable;1277 if (!Candidate.specific_attrs<EnableIfAttr>().empty() ||1278 !Incumbent.specific_attrs<EnableIfAttr>().empty())1279 return OverloadCompare::BothViable;1280 // At this point, we know calls can't pick one or the other based on1281 // arguments, so one of the two must win. (Or both fail, handled elsewhere).1282 RefQualifierKind CandidateRef = Candidate.getRefQualifier();1283 RefQualifierKind IncumbentRef = Incumbent.getRefQualifier();1284 if (CandidateRef != IncumbentRef) {1285 // If the object kind is LValue/RValue, there's one acceptable ref-qualifier1286 // and it can't be mixed with ref-unqualified overloads (in valid code).1287 1288 // For xvalue objects, we prefer the rvalue overload even if we have to1289 // add qualifiers (which is rare, because const&& is rare).1290 if (ObjectKind == clang::VK_XValue)1291 return CandidateRef == RQ_RValue ? OverloadCompare::Dominates1292 : OverloadCompare::Dominated;1293 }1294 // Now the ref qualifiers are the same (or we're in some invalid state).1295 // So make some decision based on the qualifiers.1296 Qualifiers CandidateQual = Candidate.getMethodQualifiers();1297 Qualifiers IncumbentQual = Incumbent.getMethodQualifiers();1298 bool CandidateSuperset = CandidateQual.compatiblyIncludes(IncumbentQual, Ctx);1299 bool IncumbentSuperset = IncumbentQual.compatiblyIncludes(CandidateQual, Ctx);1300 if (CandidateSuperset == IncumbentSuperset)1301 return OverloadCompare::BothViable;1302 return IncumbentSuperset ? OverloadCompare::Dominates1303 : OverloadCompare::Dominated;1304}1305 1306bool ResultBuilder::canCxxMethodBeCalled(const CXXMethodDecl *Method,1307 QualType BaseExprType) const {1308 // Find the class scope that we're currently in.1309 // We could e.g. be inside a lambda, so walk up the DeclContext until we1310 // find a CXXMethodDecl.1311 DeclContext *CurContext = SemaRef.CurContext;1312 const auto *CurrentClassScope = [&]() -> const CXXRecordDecl * {1313 for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getParent()) {1314 const auto *CtxMethod = llvm::dyn_cast<CXXMethodDecl>(Ctx);1315 if (CtxMethod && !CtxMethod->getParent()->isLambda()) {1316 return CtxMethod->getParent();1317 }1318 }1319 return nullptr;1320 }();1321 1322 // If we're not inside the scope of the method's class, it can't be a call.1323 bool FunctionCanBeCall =1324 CurrentClassScope &&1325 (CurrentClassScope == Method->getParent() ||1326 CurrentClassScope->isDerivedFrom(Method->getParent()));1327 1328 // We skip the following calculation for exceptions if it's already true.1329 if (FunctionCanBeCall)1330 return true;1331 1332 // Exception: foo->FooBase::bar() or foo->Foo::bar() *is* a call.1333 if (const CXXRecordDecl *MaybeDerived =1334 BaseExprType.isNull() ? nullptr1335 : BaseExprType->getAsCXXRecordDecl()) {1336 auto *MaybeBase = Method->getParent();1337 FunctionCanBeCall =1338 MaybeDerived == MaybeBase || MaybeDerived->isDerivedFrom(MaybeBase);1339 }1340 1341 return FunctionCanBeCall;1342}1343 1344bool ResultBuilder::canFunctionBeCalled(const NamedDecl *ND,1345 QualType BaseExprType) const {1346 // We apply heuristics only to CCC_Symbol:1347 // * CCC_{Arrow,Dot}MemberAccess reflect member access expressions:1348 // f.method() and f->method(). These are always calls.1349 // * A qualified name to a member function may *not* be a call. We have to1350 // subdivide the cases: For example, f.Base::method(), which is regarded as1351 // CCC_Symbol, should be a call.1352 // * Non-member functions and static member functions are always considered1353 // calls.1354 if (CompletionContext.getKind() == clang::CodeCompletionContext::CCC_Symbol) {1355 if (const auto *FuncTmpl = dyn_cast<FunctionTemplateDecl>(ND)) {1356 ND = FuncTmpl->getTemplatedDecl();1357 }1358 const auto *Method = dyn_cast<CXXMethodDecl>(ND);1359 if (Method && !Method->isStatic()) {1360 return canCxxMethodBeCalled(Method, BaseExprType);1361 }1362 }1363 return true;1364}1365 1366void ResultBuilder::AddResult(Result R, DeclContext *CurContext,1367 NamedDecl *Hiding, bool InBaseClass = false,1368 QualType BaseExprType = QualType()) {1369 if (R.Kind != Result::RK_Declaration) {1370 // For non-declaration results, just add the result.1371 Results.push_back(R);1372 return;1373 }1374 1375 // Look through using declarations.1376 if (const auto *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) {1377 CodeCompletionResult Result(Using->getTargetDecl(),1378 getBasePriority(Using->getTargetDecl()),1379 R.Qualifier, false,1380 (R.Availability == CXAvailability_Available ||1381 R.Availability == CXAvailability_Deprecated),1382 std::move(R.FixIts));1383 Result.ShadowDecl = Using;1384 AddResult(Result, CurContext, Hiding, /*InBaseClass=*/false,1385 /*BaseExprType=*/BaseExprType);1386 return;1387 }1388 1389 bool AsNestedNameSpecifier = false;1390 if (!isInterestingDecl(R.Declaration, AsNestedNameSpecifier))1391 return;1392 1393 // C++ constructors are never found by name lookup.1394 if (isConstructor(R.Declaration))1395 return;1396 1397 if (Hiding && CheckHiddenResult(R, CurContext, Hiding))1398 return;1399 1400 // Make sure that any given declaration only shows up in the result set once.1401 if (!AllDeclsFound.insert(R.Declaration->getCanonicalDecl()).second)1402 return;1403 1404 // If the filter is for nested-name-specifiers, then this result starts a1405 // nested-name-specifier.1406 if (AsNestedNameSpecifier) {1407 R.StartsNestedNameSpecifier = true;1408 R.Priority = CCP_NestedNameSpecifier;1409 } else if (Filter == &ResultBuilder::IsMember && !R.Qualifier &&1410 InBaseClass &&1411 isa<CXXRecordDecl>(1412 R.Declaration->getDeclContext()->getRedeclContext()))1413 R.QualifierIsInformative = true;1414 1415 // If this result is supposed to have an informative qualifier, add one.1416 if (R.QualifierIsInformative && !R.Qualifier &&1417 !R.StartsNestedNameSpecifier) {1418 const DeclContext *Ctx = R.Declaration->getDeclContext();1419 if (const auto *Namespace = dyn_cast<NamespaceDecl>(Ctx))1420 R.Qualifier =1421 NestedNameSpecifier(SemaRef.Context, Namespace, std::nullopt);1422 else if (const auto *Tag = dyn_cast<TagDecl>(Ctx))1423 R.Qualifier = NestedNameSpecifier(1424 SemaRef.Context1425 .getTagType(ElaboratedTypeKeyword::None,1426 /*Qualifier=*/std::nullopt, Tag, /*OwnsTag=*/false)1427 .getTypePtr());1428 else1429 R.QualifierIsInformative = false;1430 }1431 1432 // Adjust the priority if this result comes from a base class.1433 if (InBaseClass)1434 setInBaseClass(R);1435 1436 AdjustResultPriorityForDecl(R);1437 1438 // Account for explicit object parameter1439 const auto GetQualifiers = [&](const CXXMethodDecl *MethodDecl) {1440 if (MethodDecl->isExplicitObjectMemberFunction())1441 return MethodDecl->getFunctionObjectParameterType().getQualifiers();1442 else1443 return MethodDecl->getMethodQualifiers();1444 };1445 1446 if (IsExplicitObjectMemberFunction &&1447 R.Kind == CodeCompletionResult::RK_Declaration &&1448 (isa<CXXMethodDecl>(R.Declaration) || isa<FieldDecl>(R.Declaration))) {1449 // If result is a member in the context of an explicit-object member1450 // function, drop it because it must be accessed through the object1451 // parameter1452 return;1453 }1454 1455 if (HasObjectTypeQualifiers)1456 if (const auto *Method = dyn_cast<CXXMethodDecl>(R.Declaration))1457 if (Method->isInstance()) {1458 Qualifiers MethodQuals = GetQualifiers(Method);1459 if (ObjectTypeQualifiers == MethodQuals)1460 R.Priority += CCD_ObjectQualifierMatch;1461 else if (ObjectTypeQualifiers - MethodQuals) {1462 // The method cannot be invoked, because doing so would drop1463 // qualifiers.1464 return;1465 }1466 // Detect cases where a ref-qualified method cannot be invoked.1467 switch (Method->getRefQualifier()) {1468 case RQ_LValue:1469 if (ObjectKind != VK_LValue && !MethodQuals.hasConst())1470 return;1471 break;1472 case RQ_RValue:1473 if (ObjectKind == VK_LValue)1474 return;1475 break;1476 case RQ_None:1477 break;1478 }1479 1480 /// Check whether this dominates another overloaded method, which should1481 /// be suppressed (or vice versa).1482 /// Motivating case is const_iterator begin() const vs iterator begin().1483 auto &OverloadSet = OverloadMap[std::make_pair(1484 CurContext, Method->getDeclName().getAsOpaqueInteger())];1485 for (const DeclIndexPair Entry : OverloadSet) {1486 Result &Incumbent = Results[Entry.second];1487 switch (compareOverloads(*Method,1488 *cast<CXXMethodDecl>(Incumbent.Declaration),1489 ObjectTypeQualifiers, ObjectKind,1490 CurContext->getParentASTContext())) {1491 case OverloadCompare::Dominates:1492 // Replace the dominated overload with this one.1493 // FIXME: if the overload dominates multiple incumbents then we1494 // should remove all. But two overloads is by far the common case.1495 Incumbent = std::move(R);1496 return;1497 case OverloadCompare::Dominated:1498 // This overload can't be called, drop it.1499 return;1500 case OverloadCompare::BothViable:1501 break;1502 }1503 }1504 OverloadSet.Add(Method, Results.size());1505 }1506 1507 R.FunctionCanBeCall = canFunctionBeCalled(R.getDeclaration(), BaseExprType);1508 1509 // Insert this result into the set of results.1510 Results.push_back(R);1511 1512 if (!AsNestedNameSpecifier)1513 MaybeAddConstructorResults(R);1514}1515 1516void ResultBuilder::AddResult(Result R) {1517 assert(R.Kind != Result::RK_Declaration &&1518 "Declaration results need more context");1519 Results.push_back(R);1520}1521 1522/// Enter into a new scope.1523void ResultBuilder::EnterNewScope() { ShadowMaps.emplace_back(); }1524 1525/// Exit from the current scope.1526void ResultBuilder::ExitScope() {1527 ShadowMaps.pop_back();1528}1529 1530/// Determines whether this given declaration will be found by1531/// ordinary name lookup.1532bool ResultBuilder::IsOrdinaryName(const NamedDecl *ND) const {1533 ND = ND->getUnderlyingDecl();1534 1535 // If name lookup finds a local extern declaration, then we are in a1536 // context where it behaves like an ordinary name.1537 unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern;1538 if (SemaRef.getLangOpts().CPlusPlus)1539 IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace | Decl::IDNS_Member;1540 else if (SemaRef.getLangOpts().ObjC) {1541 if (isa<ObjCIvarDecl>(ND))1542 return true;1543 }1544 1545 return ND->getIdentifierNamespace() & IDNS;1546}1547 1548/// Determines whether this given declaration will be found by1549/// ordinary name lookup but is not a type name.1550bool ResultBuilder::IsOrdinaryNonTypeName(const NamedDecl *ND) const {1551 ND = ND->getUnderlyingDecl();1552 if (isa<TypeDecl>(ND))1553 return false;1554 // Objective-C interfaces names are not filtered by this method because they1555 // can be used in a class property expression. We can still filter out1556 // @class declarations though.1557 if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(ND)) {1558 if (!ID->getDefinition())1559 return false;1560 }1561 1562 unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern;1563 if (SemaRef.getLangOpts().CPlusPlus)1564 IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace | Decl::IDNS_Member;1565 else if (SemaRef.getLangOpts().ObjC) {1566 if (isa<ObjCIvarDecl>(ND))1567 return true;1568 }1569 1570 return ND->getIdentifierNamespace() & IDNS;1571}1572 1573bool ResultBuilder::IsIntegralConstantValue(const NamedDecl *ND) const {1574 if (!IsOrdinaryNonTypeName(ND))1575 return false;1576 1577 if (const auto *VD = dyn_cast<ValueDecl>(ND->getUnderlyingDecl()))1578 if (VD->getType()->isIntegralOrEnumerationType())1579 return true;1580 1581 return false;1582}1583 1584/// Determines whether this given declaration will be found by1585/// ordinary name lookup.1586bool ResultBuilder::IsOrdinaryNonValueName(const NamedDecl *ND) const {1587 ND = ND->getUnderlyingDecl();1588 1589 unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern;1590 if (SemaRef.getLangOpts().CPlusPlus)1591 IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace;1592 1593 return (ND->getIdentifierNamespace() & IDNS) && !isa<ValueDecl>(ND) &&1594 !isa<FunctionTemplateDecl>(ND) && !isa<ObjCPropertyDecl>(ND);1595}1596 1597/// Determines whether the given declaration is suitable as the1598/// start of a C++ nested-name-specifier, e.g., a class or namespace.1599bool ResultBuilder::IsNestedNameSpecifier(const NamedDecl *ND) const {1600 // Allow us to find class templates, too.1601 if (const auto *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))1602 ND = ClassTemplate->getTemplatedDecl();1603 1604 return SemaRef.isAcceptableNestedNameSpecifier(ND);1605}1606 1607/// Determines whether the given declaration is an enumeration.1608bool ResultBuilder::IsEnum(const NamedDecl *ND) const {1609 return isa<EnumDecl>(ND);1610}1611 1612/// Determines whether the given declaration is a class or struct.1613bool ResultBuilder::IsClassOrStruct(const NamedDecl *ND) const {1614 // Allow us to find class templates, too.1615 if (const auto *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))1616 ND = ClassTemplate->getTemplatedDecl();1617 1618 // For purposes of this check, interfaces match too.1619 if (const auto *RD = dyn_cast<RecordDecl>(ND))1620 return RD->getTagKind() == TagTypeKind::Class ||1621 RD->getTagKind() == TagTypeKind::Struct ||1622 RD->getTagKind() == TagTypeKind::Interface;1623 1624 return false;1625}1626 1627/// Determines whether the given declaration is a union.1628bool ResultBuilder::IsUnion(const NamedDecl *ND) const {1629 // Allow us to find class templates, too.1630 if (const auto *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))1631 ND = ClassTemplate->getTemplatedDecl();1632 1633 if (const auto *RD = dyn_cast<RecordDecl>(ND))1634 return RD->getTagKind() == TagTypeKind::Union;1635 1636 return false;1637}1638 1639/// Determines whether the given declaration is a namespace.1640bool ResultBuilder::IsNamespace(const NamedDecl *ND) const {1641 return isa<NamespaceDecl>(ND);1642}1643 1644/// Determines whether the given declaration is a namespace or1645/// namespace alias.1646bool ResultBuilder::IsNamespaceOrAlias(const NamedDecl *ND) const {1647 return isa<NamespaceDecl>(ND->getUnderlyingDecl());1648}1649 1650/// Determines whether the given declaration is a type.1651bool ResultBuilder::IsType(const NamedDecl *ND) const {1652 ND = ND->getUnderlyingDecl();1653 return isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND);1654}1655 1656/// Determines which members of a class should be visible via1657/// "." or "->". Only value declarations, nested name specifiers, and1658/// using declarations thereof should show up.1659bool ResultBuilder::IsMember(const NamedDecl *ND) const {1660 ND = ND->getUnderlyingDecl();1661 return isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND) ||1662 isa<ObjCPropertyDecl>(ND);1663}1664 1665static bool isObjCReceiverType(ASTContext &C, QualType T) {1666 T = C.getCanonicalType(T);1667 switch (T->getTypeClass()) {1668 case Type::ObjCObject:1669 case Type::ObjCInterface:1670 case Type::ObjCObjectPointer:1671 return true;1672 1673 case Type::Builtin:1674 switch (cast<BuiltinType>(T)->getKind()) {1675 case BuiltinType::ObjCId:1676 case BuiltinType::ObjCClass:1677 case BuiltinType::ObjCSel:1678 return true;1679 1680 default:1681 break;1682 }1683 return false;1684 1685 default:1686 break;1687 }1688 1689 if (!C.getLangOpts().CPlusPlus)1690 return false;1691 1692 // FIXME: We could perform more analysis here to determine whether a1693 // particular class type has any conversions to Objective-C types. For now,1694 // just accept all class types.1695 return T->isDependentType() || T->isRecordType();1696}1697 1698bool ResultBuilder::IsObjCMessageReceiver(const NamedDecl *ND) const {1699 QualType T =1700 getDeclUsageType(SemaRef.Context, /*Qualifier=*/std::nullopt, ND);1701 if (T.isNull())1702 return false;1703 1704 T = SemaRef.Context.getBaseElementType(T);1705 return isObjCReceiverType(SemaRef.Context, T);1706}1707 1708bool ResultBuilder::IsObjCMessageReceiverOrLambdaCapture(1709 const NamedDecl *ND) const {1710 if (IsObjCMessageReceiver(ND))1711 return true;1712 1713 const auto *Var = dyn_cast<VarDecl>(ND);1714 if (!Var)1715 return false;1716 1717 return Var->hasLocalStorage() && !Var->hasAttr<BlocksAttr>();1718}1719 1720bool ResultBuilder::IsObjCCollection(const NamedDecl *ND) const {1721 if ((SemaRef.getLangOpts().CPlusPlus && !IsOrdinaryName(ND)) ||1722 (!SemaRef.getLangOpts().CPlusPlus && !IsOrdinaryNonTypeName(ND)))1723 return false;1724 1725 QualType T =1726 getDeclUsageType(SemaRef.Context, /*Qualifier=*/std::nullopt, ND);1727 if (T.isNull())1728 return false;1729 1730 T = SemaRef.Context.getBaseElementType(T);1731 return T->isObjCObjectType() || T->isObjCObjectPointerType() ||1732 T->isObjCIdType() ||1733 (SemaRef.getLangOpts().CPlusPlus && T->isRecordType());1734}1735 1736bool ResultBuilder::IsImpossibleToSatisfy(const NamedDecl *ND) const {1737 return false;1738}1739 1740/// Determines whether the given declaration is an Objective-C1741/// instance variable.1742bool ResultBuilder::IsObjCIvar(const NamedDecl *ND) const {1743 return isa<ObjCIvarDecl>(ND);1744}1745 1746namespace {1747 1748/// Visible declaration consumer that adds a code-completion result1749/// for each visible declaration.1750class CodeCompletionDeclConsumer : public VisibleDeclConsumer {1751 ResultBuilder &Results;1752 DeclContext *InitialLookupCtx;1753 // NamingClass and BaseType are used for access-checking. See1754 // Sema::IsSimplyAccessible for details.1755 CXXRecordDecl *NamingClass;1756 QualType BaseType;1757 std::vector<FixItHint> FixIts;1758 1759public:1760 CodeCompletionDeclConsumer(1761 ResultBuilder &Results, DeclContext *InitialLookupCtx,1762 QualType BaseType = QualType(),1763 std::vector<FixItHint> FixIts = std::vector<FixItHint>())1764 : Results(Results), InitialLookupCtx(InitialLookupCtx),1765 FixIts(std::move(FixIts)) {1766 NamingClass = llvm::dyn_cast<CXXRecordDecl>(InitialLookupCtx);1767 // If BaseType was not provided explicitly, emulate implicit 'this->'.1768 if (BaseType.isNull()) {1769 auto ThisType = Results.getSema().getCurrentThisType();1770 if (!ThisType.isNull()) {1771 assert(ThisType->isPointerType());1772 BaseType = ThisType->getPointeeType();1773 if (!NamingClass)1774 NamingClass = BaseType->getAsCXXRecordDecl();1775 }1776 }1777 this->BaseType = BaseType;1778 }1779 1780 void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,1781 bool InBaseClass) override {1782 ResultBuilder::Result Result(ND, Results.getBasePriority(ND),1783 /*Qualifier=*/std::nullopt,1784 /*QualifierIsInformative=*/false,1785 IsAccessible(ND, Ctx), FixIts);1786 Results.AddResult(Result, InitialLookupCtx, Hiding, InBaseClass, BaseType);1787 }1788 1789 void EnteredContext(DeclContext *Ctx) override {1790 Results.addVisitedContext(Ctx);1791 }1792 1793private:1794 bool IsAccessible(NamedDecl *ND, DeclContext *Ctx) {1795 // Naming class to use for access check. In most cases it was provided1796 // explicitly (e.g. member access (lhs.foo) or qualified lookup (X::)),1797 // for unqualified lookup we fallback to the \p Ctx in which we found the1798 // member.1799 auto *NamingClass = this->NamingClass;1800 QualType BaseType = this->BaseType;1801 if (auto *Cls = llvm::dyn_cast_or_null<CXXRecordDecl>(Ctx)) {1802 if (!NamingClass)1803 NamingClass = Cls;1804 // When we emulate implicit 'this->' in an unqualified lookup, we might1805 // end up with an invalid naming class. In that case, we avoid emulating1806 // 'this->' qualifier to satisfy preconditions of the access checking.1807 if (NamingClass->getCanonicalDecl() != Cls->getCanonicalDecl() &&1808 !NamingClass->isDerivedFrom(Cls)) {1809 NamingClass = Cls;1810 BaseType = QualType();1811 }1812 } else {1813 // The decl was found outside the C++ class, so only ObjC access checks1814 // apply. Those do not rely on NamingClass and BaseType, so we clear them1815 // out.1816 NamingClass = nullptr;1817 BaseType = QualType();1818 }1819 return Results.getSema().IsSimplyAccessible(ND, NamingClass, BaseType);1820 }1821};1822} // namespace1823 1824/// Add type specifiers for the current language as keyword results.1825static void AddTypeSpecifierResults(const LangOptions &LangOpts,1826 ResultBuilder &Results) {1827 typedef CodeCompletionResult Result;1828 Results.AddResult(Result("short", CCP_Type));1829 Results.AddResult(Result("long", CCP_Type));1830 Results.AddResult(Result("signed", CCP_Type));1831 Results.AddResult(Result("unsigned", CCP_Type));1832 Results.AddResult(Result("void", CCP_Type));1833 Results.AddResult(Result("char", CCP_Type));1834 Results.AddResult(Result("int", CCP_Type));1835 Results.AddResult(Result("float", CCP_Type));1836 Results.AddResult(Result("double", CCP_Type));1837 Results.AddResult(Result("enum", CCP_Type));1838 Results.AddResult(Result("struct", CCP_Type));1839 Results.AddResult(Result("union", CCP_Type));1840 Results.AddResult(Result("const", CCP_Type));1841 Results.AddResult(Result("volatile", CCP_Type));1842 1843 if (LangOpts.C99) {1844 // C99-specific1845 Results.AddResult(Result("_Complex", CCP_Type));1846 if (!LangOpts.C2y)1847 Results.AddResult(Result("_Imaginary", CCP_Type));1848 Results.AddResult(Result("_Bool", CCP_Type));1849 Results.AddResult(Result("restrict", CCP_Type));1850 }1851 1852 CodeCompletionBuilder Builder(Results.getAllocator(),1853 Results.getCodeCompletionTUInfo());1854 if (LangOpts.CPlusPlus) {1855 // C++-specific1856 Results.AddResult(1857 Result("bool", CCP_Type + (LangOpts.ObjC ? CCD_bool_in_ObjC : 0)));1858 Results.AddResult(Result("class", CCP_Type));1859 Results.AddResult(Result("wchar_t", CCP_Type));1860 1861 // typename name1862 Builder.AddTypedTextChunk("typename");1863 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);1864 Builder.AddPlaceholderChunk("name");1865 Results.AddResult(Result(Builder.TakeString()));1866 1867 if (LangOpts.CPlusPlus11) {1868 Results.AddResult(Result("auto", CCP_Type));1869 Results.AddResult(Result("char16_t", CCP_Type));1870 Results.AddResult(Result("char32_t", CCP_Type));1871 1872 Builder.AddTypedTextChunk("decltype");1873 Builder.AddChunk(CodeCompletionString::CK_LeftParen);1874 Builder.AddPlaceholderChunk("expression");1875 Builder.AddChunk(CodeCompletionString::CK_RightParen);1876 Results.AddResult(Result(Builder.TakeString()));1877 }1878 1879 if (LangOpts.Char8 || LangOpts.CPlusPlus20)1880 Results.AddResult(Result("char8_t", CCP_Type));1881 } else1882 Results.AddResult(Result("__auto_type", CCP_Type));1883 1884 // GNU keywords1885 if (LangOpts.GNUKeywords) {1886 // FIXME: Enable when we actually support decimal floating point.1887 // Results.AddResult(Result("_Decimal32"));1888 // Results.AddResult(Result("_Decimal64"));1889 // Results.AddResult(Result("_Decimal128"));1890 1891 Builder.AddTypedTextChunk("typeof");1892 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);1893 Builder.AddPlaceholderChunk("expression");1894 Results.AddResult(Result(Builder.TakeString()));1895 1896 Builder.AddTypedTextChunk("typeof");1897 Builder.AddChunk(CodeCompletionString::CK_LeftParen);1898 Builder.AddPlaceholderChunk("type");1899 Builder.AddChunk(CodeCompletionString::CK_RightParen);1900 Results.AddResult(Result(Builder.TakeString()));1901 }1902 1903 // Nullability1904 Results.AddResult(Result("_Nonnull", CCP_Type));1905 Results.AddResult(Result("_Null_unspecified", CCP_Type));1906 Results.AddResult(Result("_Nullable", CCP_Type));1907}1908 1909static void1910AddStorageSpecifiers(SemaCodeCompletion::ParserCompletionContext CCC,1911 const LangOptions &LangOpts, ResultBuilder &Results) {1912 typedef CodeCompletionResult Result;1913 // Note: we don't suggest either "auto" or "register", because both1914 // are pointless as storage specifiers. Elsewhere, we suggest "auto"1915 // in C++0x as a type specifier.1916 Results.AddResult(Result("extern"));1917 Results.AddResult(Result("static"));1918 1919 if (LangOpts.CPlusPlus11) {1920 CodeCompletionAllocator &Allocator = Results.getAllocator();1921 CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo());1922 1923 // alignas1924 Builder.AddTypedTextChunk("alignas");1925 Builder.AddChunk(CodeCompletionString::CK_LeftParen);1926 Builder.AddPlaceholderChunk("expression");1927 Builder.AddChunk(CodeCompletionString::CK_RightParen);1928 Results.AddResult(Result(Builder.TakeString()));1929 1930 Results.AddResult(Result("constexpr"));1931 Results.AddResult(Result("thread_local"));1932 }1933 1934 if (LangOpts.CPlusPlus20)1935 Results.AddResult(Result("constinit"));1936}1937 1938static void1939AddFunctionSpecifiers(SemaCodeCompletion::ParserCompletionContext CCC,1940 const LangOptions &LangOpts, ResultBuilder &Results) {1941 typedef CodeCompletionResult Result;1942 switch (CCC) {1943 case SemaCodeCompletion::PCC_Class:1944 case SemaCodeCompletion::PCC_MemberTemplate:1945 if (LangOpts.CPlusPlus) {1946 Results.AddResult(Result("explicit"));1947 Results.AddResult(Result("friend"));1948 Results.AddResult(Result("mutable"));1949 Results.AddResult(Result("virtual"));1950 }1951 [[fallthrough]];1952 1953 case SemaCodeCompletion::PCC_ObjCInterface:1954 case SemaCodeCompletion::PCC_ObjCImplementation:1955 case SemaCodeCompletion::PCC_Namespace:1956 case SemaCodeCompletion::PCC_Template:1957 if (LangOpts.CPlusPlus || LangOpts.C99)1958 Results.AddResult(Result("inline"));1959 1960 if (LangOpts.CPlusPlus20)1961 Results.AddResult(Result("consteval"));1962 break;1963 1964 case SemaCodeCompletion::PCC_ObjCInstanceVariableList:1965 case SemaCodeCompletion::PCC_Expression:1966 case SemaCodeCompletion::PCC_Statement:1967 case SemaCodeCompletion::PCC_TopLevelOrExpression:1968 case SemaCodeCompletion::PCC_ForInit:1969 case SemaCodeCompletion::PCC_Condition:1970 case SemaCodeCompletion::PCC_RecoveryInFunction:1971 case SemaCodeCompletion::PCC_Type:1972 case SemaCodeCompletion::PCC_ParenthesizedExpression:1973 case SemaCodeCompletion::PCC_LocalDeclarationSpecifiers:1974 break;1975 }1976}1977 1978static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt);1979static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt);1980static void AddObjCVisibilityResults(const LangOptions &LangOpts,1981 ResultBuilder &Results, bool NeedAt);1982static void AddObjCImplementationResults(const LangOptions &LangOpts,1983 ResultBuilder &Results, bool NeedAt);1984static void AddObjCInterfaceResults(const LangOptions &LangOpts,1985 ResultBuilder &Results, bool NeedAt);1986static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt);1987 1988static void AddTypedefResult(ResultBuilder &Results) {1989 CodeCompletionBuilder Builder(Results.getAllocator(),1990 Results.getCodeCompletionTUInfo());1991 Builder.AddTypedTextChunk("typedef");1992 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);1993 Builder.AddPlaceholderChunk("type");1994 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);1995 Builder.AddPlaceholderChunk("name");1996 Builder.AddChunk(CodeCompletionString::CK_SemiColon);1997 Results.AddResult(CodeCompletionResult(Builder.TakeString()));1998}1999 2000// using name = type2001static void AddUsingAliasResult(CodeCompletionBuilder &Builder,2002 ResultBuilder &Results) {2003 Builder.AddTypedTextChunk("using");2004 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2005 Builder.AddPlaceholderChunk("name");2006 Builder.AddChunk(CodeCompletionString::CK_Equal);2007 Builder.AddPlaceholderChunk("type");2008 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2009 Results.AddResult(CodeCompletionResult(Builder.TakeString()));2010}2011 2012static bool WantTypesInContext(SemaCodeCompletion::ParserCompletionContext CCC,2013 const LangOptions &LangOpts) {2014 switch (CCC) {2015 case SemaCodeCompletion::PCC_Namespace:2016 case SemaCodeCompletion::PCC_Class:2017 case SemaCodeCompletion::PCC_ObjCInstanceVariableList:2018 case SemaCodeCompletion::PCC_Template:2019 case SemaCodeCompletion::PCC_MemberTemplate:2020 case SemaCodeCompletion::PCC_Statement:2021 case SemaCodeCompletion::PCC_RecoveryInFunction:2022 case SemaCodeCompletion::PCC_Type:2023 case SemaCodeCompletion::PCC_ParenthesizedExpression:2024 case SemaCodeCompletion::PCC_LocalDeclarationSpecifiers:2025 case SemaCodeCompletion::PCC_TopLevelOrExpression:2026 return true;2027 2028 case SemaCodeCompletion::PCC_Expression:2029 case SemaCodeCompletion::PCC_Condition:2030 return LangOpts.CPlusPlus;2031 2032 case SemaCodeCompletion::PCC_ObjCInterface:2033 case SemaCodeCompletion::PCC_ObjCImplementation:2034 return false;2035 2036 case SemaCodeCompletion::PCC_ForInit:2037 return LangOpts.CPlusPlus || LangOpts.ObjC || LangOpts.C99;2038 }2039 2040 llvm_unreachable("Invalid ParserCompletionContext!");2041}2042 2043static PrintingPolicy getCompletionPrintingPolicy(const ASTContext &Context,2044 const Preprocessor &PP) {2045 PrintingPolicy Policy = Sema::getPrintingPolicy(Context, PP);2046 Policy.AnonymousTagLocations = false;2047 Policy.SuppressStrongLifetime = true;2048 Policy.SuppressUnwrittenScope = true;2049 Policy.CleanUglifiedParameters = true;2050 return Policy;2051}2052 2053/// Retrieve a printing policy suitable for code completion.2054static PrintingPolicy getCompletionPrintingPolicy(Sema &S) {2055 return getCompletionPrintingPolicy(S.Context, S.PP);2056}2057 2058/// Retrieve the string representation of the given type as a string2059/// that has the appropriate lifetime for code completion.2060///2061/// This routine provides a fast path where we provide constant strings for2062/// common type names.2063static const char *GetCompletionTypeString(QualType T, ASTContext &Context,2064 const PrintingPolicy &Policy,2065 CodeCompletionAllocator &Allocator) {2066 if (!T.getLocalQualifiers()) {2067 // Built-in type names are constant strings.2068 if (const BuiltinType *BT = dyn_cast<BuiltinType>(T))2069 return BT->getNameAsCString(Policy);2070 2071 // Anonymous tag types are constant strings.2072 if (const TagType *TagT = dyn_cast<TagType>(T))2073 if (TagDecl *Tag = TagT->getDecl())2074 if (!Tag->hasNameForLinkage()) {2075 switch (Tag->getTagKind()) {2076 case TagTypeKind::Struct:2077 return "struct <anonymous>";2078 case TagTypeKind::Interface:2079 return "__interface <anonymous>";2080 case TagTypeKind::Class:2081 return "class <anonymous>";2082 case TagTypeKind::Union:2083 return "union <anonymous>";2084 case TagTypeKind::Enum:2085 return "enum <anonymous>";2086 }2087 }2088 }2089 2090 // Slow path: format the type as a string.2091 std::string Result;2092 T.getAsStringInternal(Result, Policy);2093 return Allocator.CopyString(Result);2094}2095 2096/// Add a completion for "this", if we're in a member function.2097static void addThisCompletion(Sema &S, ResultBuilder &Results) {2098 QualType ThisTy = S.getCurrentThisType();2099 if (ThisTy.isNull())2100 return;2101 2102 CodeCompletionAllocator &Allocator = Results.getAllocator();2103 CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo());2104 PrintingPolicy Policy = getCompletionPrintingPolicy(S);2105 Builder.AddResultTypeChunk(2106 GetCompletionTypeString(ThisTy, S.Context, Policy, Allocator));2107 Builder.AddTypedTextChunk("this");2108 Results.AddResult(CodeCompletionResult(Builder.TakeString()));2109}2110 2111static void AddStaticAssertResult(CodeCompletionBuilder &Builder,2112 ResultBuilder &Results,2113 const LangOptions &LangOpts) {2114 if (!LangOpts.CPlusPlus11)2115 return;2116 2117 Builder.AddTypedTextChunk("static_assert");2118 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2119 Builder.AddPlaceholderChunk("expression");2120 Builder.AddChunk(CodeCompletionString::CK_Comma);2121 Builder.AddPlaceholderChunk("message");2122 Builder.AddChunk(CodeCompletionString::CK_RightParen);2123 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2124 Results.AddResult(CodeCompletionResult(Builder.TakeString()));2125}2126 2127static void AddOverrideResults(ResultBuilder &Results,2128 const CodeCompletionContext &CCContext,2129 CodeCompletionBuilder &Builder) {2130 Sema &S = Results.getSema();2131 const auto *CR = llvm::dyn_cast<CXXRecordDecl>(S.CurContext);2132 // If not inside a class/struct/union return empty.2133 if (!CR)2134 return;2135 // First store overrides within current class.2136 // These are stored by name to make querying fast in the later step.2137 llvm::StringMap<std::vector<FunctionDecl *>> Overrides;2138 for (auto *Method : CR->methods()) {2139 if (!Method->isVirtual() || !Method->getIdentifier())2140 continue;2141 Overrides[Method->getName()].push_back(Method);2142 }2143 2144 for (const auto &Base : CR->bases()) {2145 const auto *BR = Base.getType().getTypePtr()->getAsCXXRecordDecl();2146 if (!BR)2147 continue;2148 for (auto *Method : BR->methods()) {2149 if (!Method->isVirtual() || !Method->getIdentifier())2150 continue;2151 const auto it = Overrides.find(Method->getName());2152 bool IsOverriden = false;2153 if (it != Overrides.end()) {2154 for (auto *MD : it->second) {2155 // If the method in current body is not an overload of this virtual2156 // function, then it overrides this one.2157 if (!S.IsOverload(MD, Method, false)) {2158 IsOverriden = true;2159 break;2160 }2161 }2162 }2163 if (!IsOverriden) {2164 // Generates a new CodeCompletionResult by taking this function and2165 // converting it into an override declaration with only one chunk in the2166 // final CodeCompletionString as a TypedTextChunk.2167 CodeCompletionResult CCR(Method, 0);2168 PrintingPolicy Policy =2169 getCompletionPrintingPolicy(S.getASTContext(), S.getPreprocessor());2170 auto *CCS = CCR.createCodeCompletionStringForOverride(2171 S.getPreprocessor(), S.getASTContext(), Builder,2172 /*IncludeBriefComments=*/false, CCContext, Policy);2173 Results.AddResult(CodeCompletionResult(CCS, Method, CCP_CodePattern));2174 }2175 }2176 }2177}2178 2179/// Add language constructs that show up for "ordinary" names.2180static void2181AddOrdinaryNameResults(SemaCodeCompletion::ParserCompletionContext CCC,2182 Scope *S, Sema &SemaRef, ResultBuilder &Results) {2183 CodeCompletionAllocator &Allocator = Results.getAllocator();2184 CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo());2185 2186 typedef CodeCompletionResult Result;2187 switch (CCC) {2188 case SemaCodeCompletion::PCC_Namespace:2189 if (SemaRef.getLangOpts().CPlusPlus) {2190 if (Results.includeCodePatterns()) {2191 // namespace <identifier> { declarations }2192 Builder.AddTypedTextChunk("namespace");2193 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2194 Builder.AddPlaceholderChunk("identifier");2195 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2196 Builder.AddChunk(CodeCompletionString::CK_LeftBrace);2197 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2198 Builder.AddPlaceholderChunk("declarations");2199 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2200 Builder.AddChunk(CodeCompletionString::CK_RightBrace);2201 Results.AddResult(Result(Builder.TakeString()));2202 }2203 2204 // namespace identifier = identifier ;2205 Builder.AddTypedTextChunk("namespace");2206 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2207 Builder.AddPlaceholderChunk("name");2208 Builder.AddChunk(CodeCompletionString::CK_Equal);2209 Builder.AddPlaceholderChunk("namespace");2210 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2211 Results.AddResult(Result(Builder.TakeString()));2212 2213 // Using directives2214 Builder.AddTypedTextChunk("using namespace");2215 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2216 Builder.AddPlaceholderChunk("identifier");2217 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2218 Results.AddResult(Result(Builder.TakeString()));2219 2220 // asm(string-literal)2221 Builder.AddTypedTextChunk("asm");2222 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2223 Builder.AddPlaceholderChunk("string-literal");2224 Builder.AddChunk(CodeCompletionString::CK_RightParen);2225 Results.AddResult(Result(Builder.TakeString()));2226 2227 if (Results.includeCodePatterns()) {2228 // Explicit template instantiation2229 Builder.AddTypedTextChunk("template");2230 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2231 Builder.AddPlaceholderChunk("declaration");2232 Results.AddResult(Result(Builder.TakeString()));2233 } else {2234 Results.AddResult(Result("template", CodeCompletionResult::RK_Keyword));2235 }2236 2237 if (SemaRef.getLangOpts().CPlusPlus20 &&2238 SemaRef.getLangOpts().CPlusPlusModules) {2239 clang::Module *CurrentModule = SemaRef.getCurrentModule();2240 if (SemaRef.CurContext->isTranslationUnit()) {2241 /// Global module fragment can only be declared in the beginning of2242 /// the file. CurrentModule should be null in this case.2243 if (!CurrentModule) {2244 // module;2245 Builder.AddTypedTextChunk("module");2246 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2247 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2248 Results.AddResult(Result(Builder.TakeString()));2249 }2250 2251 /// Named module should be declared in the beginning of the file,2252 /// or after the global module fragment.2253 if (!CurrentModule ||2254 CurrentModule->Kind == Module::ExplicitGlobalModuleFragment ||2255 CurrentModule->Kind == Module::ImplicitGlobalModuleFragment) {2256 // export module;2257 // module name;2258 Builder.AddTypedTextChunk("module");2259 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2260 Builder.AddPlaceholderChunk("name");2261 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2262 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2263 Results.AddResult(Result(Builder.TakeString()));2264 }2265 2266 /// Import can occur in non module file or after the named module2267 /// declaration.2268 if (!CurrentModule ||2269 CurrentModule->Kind == Module::ModuleInterfaceUnit ||2270 CurrentModule->Kind == Module::ModulePartitionInterface) {2271 // import name;2272 Builder.AddTypedTextChunk("import");2273 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2274 Builder.AddPlaceholderChunk("name");2275 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2276 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2277 Results.AddResult(Result(Builder.TakeString()));2278 }2279 2280 if (CurrentModule &&2281 (CurrentModule->Kind == Module::ModuleInterfaceUnit ||2282 CurrentModule->Kind == Module::ModulePartitionInterface)) {2283 // module: private;2284 Builder.AddTypedTextChunk("module");2285 Builder.AddChunk(CodeCompletionString::CK_Colon);2286 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2287 Builder.AddTypedTextChunk("private");2288 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2289 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2290 Results.AddResult(Result(Builder.TakeString()));2291 }2292 }2293 2294 // export2295 if (!CurrentModule ||2296 CurrentModule->Kind != Module::ModuleKind::PrivateModuleFragment)2297 Results.AddResult(Result("export", CodeCompletionResult::RK_Keyword));2298 }2299 }2300 2301 if (SemaRef.getLangOpts().ObjC)2302 AddObjCTopLevelResults(Results, true);2303 2304 AddTypedefResult(Results);2305 [[fallthrough]];2306 2307 case SemaCodeCompletion::PCC_Class:2308 if (SemaRef.getLangOpts().CPlusPlus) {2309 // Using declaration2310 Builder.AddTypedTextChunk("using");2311 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2312 Builder.AddPlaceholderChunk("qualifier");2313 Builder.AddTextChunk("::");2314 Builder.AddPlaceholderChunk("name");2315 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2316 Results.AddResult(Result(Builder.TakeString()));2317 2318 if (SemaRef.getLangOpts().CPlusPlus11)2319 AddUsingAliasResult(Builder, Results);2320 2321 // using typename qualifier::name (only in a dependent context)2322 if (SemaRef.CurContext->isDependentContext()) {2323 Builder.AddTypedTextChunk("using typename");2324 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2325 Builder.AddPlaceholderChunk("qualifier");2326 Builder.AddTextChunk("::");2327 Builder.AddPlaceholderChunk("name");2328 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2329 Results.AddResult(Result(Builder.TakeString()));2330 }2331 2332 AddStaticAssertResult(Builder, Results, SemaRef.getLangOpts());2333 2334 if (CCC == SemaCodeCompletion::PCC_Class) {2335 AddTypedefResult(Results);2336 2337 bool IsNotInheritanceScope = !S->isClassInheritanceScope();2338 // public:2339 Builder.AddTypedTextChunk("public");2340 if (IsNotInheritanceScope && Results.includeCodePatterns())2341 Builder.AddChunk(CodeCompletionString::CK_Colon);2342 Results.AddResult(Result(Builder.TakeString()));2343 2344 // protected:2345 Builder.AddTypedTextChunk("protected");2346 if (IsNotInheritanceScope && Results.includeCodePatterns())2347 Builder.AddChunk(CodeCompletionString::CK_Colon);2348 Results.AddResult(Result(Builder.TakeString()));2349 2350 // private:2351 Builder.AddTypedTextChunk("private");2352 if (IsNotInheritanceScope && Results.includeCodePatterns())2353 Builder.AddChunk(CodeCompletionString::CK_Colon);2354 Results.AddResult(Result(Builder.TakeString()));2355 2356 // FIXME: This adds override results only if we are at the first word of2357 // the declaration/definition. Also call this from other sides to have2358 // more use-cases.2359 AddOverrideResults(Results, CodeCompletionContext::CCC_ClassStructUnion,2360 Builder);2361 }2362 }2363 [[fallthrough]];2364 2365 case SemaCodeCompletion::PCC_Template:2366 if (SemaRef.getLangOpts().CPlusPlus20 &&2367 CCC == SemaCodeCompletion::PCC_Template)2368 Results.AddResult(Result("concept", CCP_Keyword));2369 [[fallthrough]];2370 2371 case SemaCodeCompletion::PCC_MemberTemplate:2372 if (SemaRef.getLangOpts().CPlusPlus && Results.includeCodePatterns()) {2373 // template < parameters >2374 Builder.AddTypedTextChunk("template");2375 Builder.AddChunk(CodeCompletionString::CK_LeftAngle);2376 Builder.AddPlaceholderChunk("parameters");2377 Builder.AddChunk(CodeCompletionString::CK_RightAngle);2378 Results.AddResult(Result(Builder.TakeString()));2379 } else {2380 Results.AddResult(Result("template", CodeCompletionResult::RK_Keyword));2381 }2382 2383 if (SemaRef.getLangOpts().CPlusPlus20 &&2384 (CCC == SemaCodeCompletion::PCC_Template ||2385 CCC == SemaCodeCompletion::PCC_MemberTemplate))2386 Results.AddResult(Result("requires", CCP_Keyword));2387 2388 AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results);2389 AddFunctionSpecifiers(CCC, SemaRef.getLangOpts(), Results);2390 break;2391 2392 case SemaCodeCompletion::PCC_ObjCInterface:2393 AddObjCInterfaceResults(SemaRef.getLangOpts(), Results, true);2394 AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results);2395 AddFunctionSpecifiers(CCC, SemaRef.getLangOpts(), Results);2396 break;2397 2398 case SemaCodeCompletion::PCC_ObjCImplementation:2399 AddObjCImplementationResults(SemaRef.getLangOpts(), Results, true);2400 AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results);2401 AddFunctionSpecifiers(CCC, SemaRef.getLangOpts(), Results);2402 break;2403 2404 case SemaCodeCompletion::PCC_ObjCInstanceVariableList:2405 AddObjCVisibilityResults(SemaRef.getLangOpts(), Results, true);2406 break;2407 2408 case SemaCodeCompletion::PCC_RecoveryInFunction:2409 case SemaCodeCompletion::PCC_TopLevelOrExpression:2410 case SemaCodeCompletion::PCC_Statement: {2411 if (SemaRef.getLangOpts().CPlusPlus11)2412 AddUsingAliasResult(Builder, Results);2413 2414 AddTypedefResult(Results);2415 2416 if (SemaRef.getLangOpts().CPlusPlus && Results.includeCodePatterns() &&2417 SemaRef.getLangOpts().CXXExceptions) {2418 Builder.AddTypedTextChunk("try");2419 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2420 Builder.AddChunk(CodeCompletionString::CK_LeftBrace);2421 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2422 Builder.AddPlaceholderChunk("statements");2423 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2424 Builder.AddChunk(CodeCompletionString::CK_RightBrace);2425 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2426 Builder.AddTextChunk("catch");2427 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2428 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2429 Builder.AddPlaceholderChunk("declaration");2430 Builder.AddChunk(CodeCompletionString::CK_RightParen);2431 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2432 Builder.AddChunk(CodeCompletionString::CK_LeftBrace);2433 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2434 Builder.AddPlaceholderChunk("statements");2435 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2436 Builder.AddChunk(CodeCompletionString::CK_RightBrace);2437 Results.AddResult(Result(Builder.TakeString()));2438 }2439 if (SemaRef.getLangOpts().ObjC)2440 AddObjCStatementResults(Results, true);2441 2442 if (Results.includeCodePatterns()) {2443 // if (condition) { statements }2444 Builder.AddTypedTextChunk("if");2445 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2446 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2447 if (SemaRef.getLangOpts().CPlusPlus)2448 Builder.AddPlaceholderChunk("condition");2449 else2450 Builder.AddPlaceholderChunk("expression");2451 Builder.AddChunk(CodeCompletionString::CK_RightParen);2452 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2453 Builder.AddChunk(CodeCompletionString::CK_LeftBrace);2454 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2455 Builder.AddPlaceholderChunk("statements");2456 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2457 Builder.AddChunk(CodeCompletionString::CK_RightBrace);2458 Results.AddResult(Result(Builder.TakeString()));2459 2460 // switch (condition) { }2461 Builder.AddTypedTextChunk("switch");2462 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2463 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2464 if (SemaRef.getLangOpts().CPlusPlus)2465 Builder.AddPlaceholderChunk("condition");2466 else2467 Builder.AddPlaceholderChunk("expression");2468 Builder.AddChunk(CodeCompletionString::CK_RightParen);2469 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2470 Builder.AddChunk(CodeCompletionString::CK_LeftBrace);2471 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2472 Builder.AddPlaceholderChunk("cases");2473 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2474 Builder.AddChunk(CodeCompletionString::CK_RightBrace);2475 Results.AddResult(Result(Builder.TakeString()));2476 }2477 2478 // Switch-specific statements.2479 if (SemaRef.getCurFunction() &&2480 !SemaRef.getCurFunction()->SwitchStack.empty()) {2481 // case expression:2482 Builder.AddTypedTextChunk("case");2483 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2484 Builder.AddPlaceholderChunk("expression");2485 Builder.AddChunk(CodeCompletionString::CK_Colon);2486 Results.AddResult(Result(Builder.TakeString()));2487 2488 // default:2489 Builder.AddTypedTextChunk("default");2490 Builder.AddChunk(CodeCompletionString::CK_Colon);2491 Results.AddResult(Result(Builder.TakeString()));2492 }2493 2494 if (Results.includeCodePatterns()) {2495 /// while (condition) { statements }2496 Builder.AddTypedTextChunk("while");2497 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2498 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2499 if (SemaRef.getLangOpts().CPlusPlus)2500 Builder.AddPlaceholderChunk("condition");2501 else2502 Builder.AddPlaceholderChunk("expression");2503 Builder.AddChunk(CodeCompletionString::CK_RightParen);2504 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2505 Builder.AddChunk(CodeCompletionString::CK_LeftBrace);2506 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2507 Builder.AddPlaceholderChunk("statements");2508 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2509 Builder.AddChunk(CodeCompletionString::CK_RightBrace);2510 Results.AddResult(Result(Builder.TakeString()));2511 2512 // do { statements } while ( expression );2513 Builder.AddTypedTextChunk("do");2514 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2515 Builder.AddChunk(CodeCompletionString::CK_LeftBrace);2516 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2517 Builder.AddPlaceholderChunk("statements");2518 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2519 Builder.AddChunk(CodeCompletionString::CK_RightBrace);2520 Builder.AddTextChunk("while");2521 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2522 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2523 Builder.AddPlaceholderChunk("expression");2524 Builder.AddChunk(CodeCompletionString::CK_RightParen);2525 Results.AddResult(Result(Builder.TakeString()));2526 2527 // for ( for-init-statement ; condition ; expression ) { statements }2528 Builder.AddTypedTextChunk("for");2529 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2530 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2531 if (SemaRef.getLangOpts().CPlusPlus || SemaRef.getLangOpts().C99)2532 Builder.AddPlaceholderChunk("init-statement");2533 else2534 Builder.AddPlaceholderChunk("init-expression");2535 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2536 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2537 Builder.AddPlaceholderChunk("condition");2538 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2539 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2540 Builder.AddPlaceholderChunk("inc-expression");2541 Builder.AddChunk(CodeCompletionString::CK_RightParen);2542 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2543 Builder.AddChunk(CodeCompletionString::CK_LeftBrace);2544 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2545 Builder.AddPlaceholderChunk("statements");2546 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2547 Builder.AddChunk(CodeCompletionString::CK_RightBrace);2548 Results.AddResult(Result(Builder.TakeString()));2549 2550 if (SemaRef.getLangOpts().CPlusPlus11 || SemaRef.getLangOpts().ObjC) {2551 // for ( range_declaration (:|in) range_expression ) { statements }2552 Builder.AddTypedTextChunk("for");2553 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2554 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2555 Builder.AddPlaceholderChunk("range-declaration");2556 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2557 if (SemaRef.getLangOpts().ObjC)2558 Builder.AddTextChunk("in");2559 else2560 Builder.AddChunk(CodeCompletionString::CK_Colon);2561 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2562 Builder.AddPlaceholderChunk("range-expression");2563 Builder.AddChunk(CodeCompletionString::CK_RightParen);2564 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2565 Builder.AddChunk(CodeCompletionString::CK_LeftBrace);2566 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2567 Builder.AddPlaceholderChunk("statements");2568 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2569 Builder.AddChunk(CodeCompletionString::CK_RightBrace);2570 Results.AddResult(Result(Builder.TakeString()));2571 }2572 }2573 2574 if (S->getContinueParent()) {2575 // continue ;2576 Builder.AddTypedTextChunk("continue");2577 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2578 Results.AddResult(Result(Builder.TakeString()));2579 }2580 2581 if (S->getBreakParent()) {2582 // break ;2583 Builder.AddTypedTextChunk("break");2584 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2585 Results.AddResult(Result(Builder.TakeString()));2586 }2587 2588 // "return expression ;" or "return ;", depending on the return type.2589 QualType ReturnType;2590 if (const auto *Function = dyn_cast<FunctionDecl>(SemaRef.CurContext))2591 ReturnType = Function->getReturnType();2592 else if (const auto *Method = dyn_cast<ObjCMethodDecl>(SemaRef.CurContext))2593 ReturnType = Method->getReturnType();2594 else if (SemaRef.getCurBlock() &&2595 !SemaRef.getCurBlock()->ReturnType.isNull())2596 ReturnType = SemaRef.getCurBlock()->ReturnType;;2597 if (ReturnType.isNull() || ReturnType->isVoidType()) {2598 Builder.AddTypedTextChunk("return");2599 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2600 Results.AddResult(Result(Builder.TakeString()));2601 } else {2602 assert(!ReturnType.isNull());2603 // "return expression ;"2604 Builder.AddTypedTextChunk("return");2605 Builder.AddChunk(clang::CodeCompletionString::CK_HorizontalSpace);2606 Builder.AddPlaceholderChunk("expression");2607 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2608 Results.AddResult(Result(Builder.TakeString()));2609 // "co_return expression ;" for coroutines(C++20).2610 if (SemaRef.getLangOpts().CPlusPlus20) {2611 Builder.AddTypedTextChunk("co_return");2612 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2613 Builder.AddPlaceholderChunk("expression");2614 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2615 Results.AddResult(Result(Builder.TakeString()));2616 }2617 // When boolean, also add 'return true;' and 'return false;'.2618 if (ReturnType->isBooleanType()) {2619 Builder.AddTypedTextChunk("return true");2620 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2621 Results.AddResult(Result(Builder.TakeString()));2622 2623 Builder.AddTypedTextChunk("return false");2624 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2625 Results.AddResult(Result(Builder.TakeString()));2626 }2627 // For pointers, suggest 'return nullptr' in C++.2628 if (SemaRef.getLangOpts().CPlusPlus11 &&2629 (ReturnType->isPointerType() || ReturnType->isMemberPointerType())) {2630 Builder.AddTypedTextChunk("return nullptr");2631 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2632 Results.AddResult(Result(Builder.TakeString()));2633 }2634 }2635 2636 // goto identifier ;2637 Builder.AddTypedTextChunk("goto");2638 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2639 Builder.AddPlaceholderChunk("label");2640 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2641 Results.AddResult(Result(Builder.TakeString()));2642 2643 // Using directives2644 Builder.AddTypedTextChunk("using namespace");2645 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2646 Builder.AddPlaceholderChunk("identifier");2647 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2648 Results.AddResult(Result(Builder.TakeString()));2649 2650 AddStaticAssertResult(Builder, Results, SemaRef.getLangOpts());2651 }2652 [[fallthrough]];2653 2654 // Fall through (for statement expressions).2655 case SemaCodeCompletion::PCC_ForInit:2656 case SemaCodeCompletion::PCC_Condition:2657 AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results);2658 // Fall through: conditions and statements can have expressions.2659 [[fallthrough]];2660 2661 case SemaCodeCompletion::PCC_ParenthesizedExpression:2662 if (SemaRef.getLangOpts().ObjCAutoRefCount &&2663 CCC == SemaCodeCompletion::PCC_ParenthesizedExpression) {2664 // (__bridge <type>)<expression>2665 Builder.AddTypedTextChunk("__bridge");2666 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2667 Builder.AddPlaceholderChunk("type");2668 Builder.AddChunk(CodeCompletionString::CK_RightParen);2669 Builder.AddPlaceholderChunk("expression");2670 Results.AddResult(Result(Builder.TakeString()));2671 2672 // (__bridge_transfer <Objective-C type>)<expression>2673 Builder.AddTypedTextChunk("__bridge_transfer");2674 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2675 Builder.AddPlaceholderChunk("Objective-C type");2676 Builder.AddChunk(CodeCompletionString::CK_RightParen);2677 Builder.AddPlaceholderChunk("expression");2678 Results.AddResult(Result(Builder.TakeString()));2679 2680 // (__bridge_retained <CF type>)<expression>2681 Builder.AddTypedTextChunk("__bridge_retained");2682 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2683 Builder.AddPlaceholderChunk("CF type");2684 Builder.AddChunk(CodeCompletionString::CK_RightParen);2685 Builder.AddPlaceholderChunk("expression");2686 Results.AddResult(Result(Builder.TakeString()));2687 }2688 // Fall through2689 [[fallthrough]];2690 2691 case SemaCodeCompletion::PCC_Expression: {2692 if (SemaRef.getLangOpts().CPlusPlus) {2693 // 'this', if we're in a non-static member function.2694 addThisCompletion(SemaRef, Results);2695 2696 // true2697 Builder.AddResultTypeChunk("bool");2698 Builder.AddTypedTextChunk("true");2699 Results.AddResult(Result(Builder.TakeString()));2700 2701 // false2702 Builder.AddResultTypeChunk("bool");2703 Builder.AddTypedTextChunk("false");2704 Results.AddResult(Result(Builder.TakeString()));2705 2706 if (SemaRef.getLangOpts().RTTI) {2707 // dynamic_cast < type-id > ( expression )2708 Builder.AddTypedTextChunk("dynamic_cast");2709 Builder.AddChunk(CodeCompletionString::CK_LeftAngle);2710 Builder.AddPlaceholderChunk("type");2711 Builder.AddChunk(CodeCompletionString::CK_RightAngle);2712 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2713 Builder.AddPlaceholderChunk("expression");2714 Builder.AddChunk(CodeCompletionString::CK_RightParen);2715 Results.AddResult(Result(Builder.TakeString()));2716 }2717 2718 // static_cast < type-id > ( expression )2719 Builder.AddTypedTextChunk("static_cast");2720 Builder.AddChunk(CodeCompletionString::CK_LeftAngle);2721 Builder.AddPlaceholderChunk("type");2722 Builder.AddChunk(CodeCompletionString::CK_RightAngle);2723 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2724 Builder.AddPlaceholderChunk("expression");2725 Builder.AddChunk(CodeCompletionString::CK_RightParen);2726 Results.AddResult(Result(Builder.TakeString()));2727 2728 // reinterpret_cast < type-id > ( expression )2729 Builder.AddTypedTextChunk("reinterpret_cast");2730 Builder.AddChunk(CodeCompletionString::CK_LeftAngle);2731 Builder.AddPlaceholderChunk("type");2732 Builder.AddChunk(CodeCompletionString::CK_RightAngle);2733 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2734 Builder.AddPlaceholderChunk("expression");2735 Builder.AddChunk(CodeCompletionString::CK_RightParen);2736 Results.AddResult(Result(Builder.TakeString()));2737 2738 // const_cast < type-id > ( expression )2739 Builder.AddTypedTextChunk("const_cast");2740 Builder.AddChunk(CodeCompletionString::CK_LeftAngle);2741 Builder.AddPlaceholderChunk("type");2742 Builder.AddChunk(CodeCompletionString::CK_RightAngle);2743 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2744 Builder.AddPlaceholderChunk("expression");2745 Builder.AddChunk(CodeCompletionString::CK_RightParen);2746 Results.AddResult(Result(Builder.TakeString()));2747 2748 if (SemaRef.getLangOpts().RTTI) {2749 // typeid ( expression-or-type )2750 Builder.AddResultTypeChunk("std::type_info");2751 Builder.AddTypedTextChunk("typeid");2752 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2753 Builder.AddPlaceholderChunk("expression-or-type");2754 Builder.AddChunk(CodeCompletionString::CK_RightParen);2755 Results.AddResult(Result(Builder.TakeString()));2756 }2757 2758 // new T ( ... )2759 Builder.AddTypedTextChunk("new");2760 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2761 Builder.AddPlaceholderChunk("type");2762 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2763 Builder.AddPlaceholderChunk("expressions");2764 Builder.AddChunk(CodeCompletionString::CK_RightParen);2765 Results.AddResult(Result(Builder.TakeString()));2766 2767 // new T [ ] ( ... )2768 Builder.AddTypedTextChunk("new");2769 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2770 Builder.AddPlaceholderChunk("type");2771 Builder.AddChunk(CodeCompletionString::CK_LeftBracket);2772 Builder.AddPlaceholderChunk("size");2773 Builder.AddChunk(CodeCompletionString::CK_RightBracket);2774 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2775 Builder.AddPlaceholderChunk("expressions");2776 Builder.AddChunk(CodeCompletionString::CK_RightParen);2777 Results.AddResult(Result(Builder.TakeString()));2778 2779 // delete expression2780 Builder.AddResultTypeChunk("void");2781 Builder.AddTypedTextChunk("delete");2782 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2783 Builder.AddPlaceholderChunk("expression");2784 Results.AddResult(Result(Builder.TakeString()));2785 2786 // delete [] expression2787 Builder.AddResultTypeChunk("void");2788 Builder.AddTypedTextChunk("delete");2789 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2790 Builder.AddChunk(CodeCompletionString::CK_LeftBracket);2791 Builder.AddChunk(CodeCompletionString::CK_RightBracket);2792 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2793 Builder.AddPlaceholderChunk("expression");2794 Results.AddResult(Result(Builder.TakeString()));2795 2796 if (SemaRef.getLangOpts().CXXExceptions) {2797 // throw expression2798 Builder.AddResultTypeChunk("void");2799 Builder.AddTypedTextChunk("throw");2800 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2801 Builder.AddPlaceholderChunk("expression");2802 Results.AddResult(Result(Builder.TakeString()));2803 }2804 2805 // FIXME: Rethrow?2806 2807 if (SemaRef.getLangOpts().CPlusPlus11) {2808 // nullptr2809 Builder.AddResultTypeChunk("std::nullptr_t");2810 Builder.AddTypedTextChunk("nullptr");2811 Results.AddResult(Result(Builder.TakeString()));2812 2813 // alignof2814 Builder.AddResultTypeChunk("size_t");2815 Builder.AddTypedTextChunk("alignof");2816 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2817 Builder.AddPlaceholderChunk("type");2818 Builder.AddChunk(CodeCompletionString::CK_RightParen);2819 Results.AddResult(Result(Builder.TakeString()));2820 2821 // noexcept2822 Builder.AddResultTypeChunk("bool");2823 Builder.AddTypedTextChunk("noexcept");2824 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2825 Builder.AddPlaceholderChunk("expression");2826 Builder.AddChunk(CodeCompletionString::CK_RightParen);2827 Results.AddResult(Result(Builder.TakeString()));2828 2829 // sizeof... expression2830 Builder.AddResultTypeChunk("size_t");2831 Builder.AddTypedTextChunk("sizeof...");2832 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2833 Builder.AddPlaceholderChunk("parameter-pack");2834 Builder.AddChunk(CodeCompletionString::CK_RightParen);2835 Results.AddResult(Result(Builder.TakeString()));2836 }2837 2838 if (SemaRef.getLangOpts().CPlusPlus20) {2839 // co_await expression2840 Builder.AddTypedTextChunk("co_await");2841 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2842 Builder.AddPlaceholderChunk("expression");2843 Results.AddResult(Result(Builder.TakeString()));2844 2845 // co_yield expression2846 Builder.AddTypedTextChunk("co_yield");2847 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2848 Builder.AddPlaceholderChunk("expression");2849 Results.AddResult(Result(Builder.TakeString()));2850 2851 // requires (parameters) { requirements }2852 Builder.AddResultTypeChunk("bool");2853 Builder.AddTypedTextChunk("requires");2854 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2855 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2856 Builder.AddPlaceholderChunk("parameters");2857 Builder.AddChunk(CodeCompletionString::CK_RightParen);2858 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2859 Builder.AddChunk(CodeCompletionString::CK_LeftBrace);2860 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2861 Builder.AddPlaceholderChunk("requirements");2862 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);2863 Builder.AddChunk(CodeCompletionString::CK_RightBrace);2864 Results.AddResult(Result(Builder.TakeString()));2865 2866 if (SemaRef.CurContext->isRequiresExprBody()) {2867 // requires expression ;2868 Builder.AddTypedTextChunk("requires");2869 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);2870 Builder.AddPlaceholderChunk("expression");2871 Builder.AddChunk(CodeCompletionString::CK_SemiColon);2872 Results.AddResult(Result(Builder.TakeString()));2873 }2874 }2875 }2876 2877 if (SemaRef.getLangOpts().ObjC) {2878 // Add "super", if we're in an Objective-C class with a superclass.2879 if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl()) {2880 // The interface can be NULL.2881 if (ObjCInterfaceDecl *ID = Method->getClassInterface())2882 if (ID->getSuperClass()) {2883 std::string SuperType;2884 SuperType = ID->getSuperClass()->getNameAsString();2885 if (Method->isInstanceMethod())2886 SuperType += " *";2887 2888 Builder.AddResultTypeChunk(Allocator.CopyString(SuperType));2889 Builder.AddTypedTextChunk("super");2890 Results.AddResult(Result(Builder.TakeString()));2891 }2892 }2893 2894 AddObjCExpressionResults(Results, true);2895 }2896 2897 if (SemaRef.getLangOpts().C11) {2898 // _Alignof2899 Builder.AddResultTypeChunk("size_t");2900 if (SemaRef.PP.isMacroDefined("alignof"))2901 Builder.AddTypedTextChunk("alignof");2902 else2903 Builder.AddTypedTextChunk("_Alignof");2904 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2905 Builder.AddPlaceholderChunk("type");2906 Builder.AddChunk(CodeCompletionString::CK_RightParen);2907 Results.AddResult(Result(Builder.TakeString()));2908 }2909 2910 if (SemaRef.getLangOpts().C23) {2911 // nullptr2912 Builder.AddResultTypeChunk("nullptr_t");2913 Builder.AddTypedTextChunk("nullptr");2914 Results.AddResult(Result(Builder.TakeString()));2915 }2916 2917 // sizeof expression2918 Builder.AddResultTypeChunk("size_t");2919 Builder.AddTypedTextChunk("sizeof");2920 Builder.AddChunk(CodeCompletionString::CK_LeftParen);2921 Builder.AddPlaceholderChunk("expression-or-type");2922 Builder.AddChunk(CodeCompletionString::CK_RightParen);2923 Results.AddResult(Result(Builder.TakeString()));2924 break;2925 }2926 2927 case SemaCodeCompletion::PCC_Type:2928 case SemaCodeCompletion::PCC_LocalDeclarationSpecifiers:2929 break;2930 }2931 2932 if (WantTypesInContext(CCC, SemaRef.getLangOpts()))2933 AddTypeSpecifierResults(SemaRef.getLangOpts(), Results);2934 2935 if (SemaRef.getLangOpts().CPlusPlus && CCC != SemaCodeCompletion::PCC_Type)2936 Results.AddResult(Result("operator"));2937}2938 2939/// If the given declaration has an associated type, add it as a result2940/// type chunk.2941static void AddResultTypeChunk(ASTContext &Context,2942 const PrintingPolicy &Policy,2943 const NamedDecl *ND, QualType BaseType,2944 CodeCompletionBuilder &Result) {2945 if (!ND)2946 return;2947 2948 // Skip constructors and conversion functions, which have their return types2949 // built into their names.2950 if (isConstructor(ND) || isa<CXXConversionDecl>(ND))2951 return;2952 2953 // Determine the type of the declaration (if it has a type).2954 QualType T;2955 if (const FunctionDecl *Function = ND->getAsFunction())2956 T = Function->getReturnType();2957 else if (const auto *Method = dyn_cast<ObjCMethodDecl>(ND)) {2958 if (!BaseType.isNull())2959 T = Method->getSendResultType(BaseType);2960 else2961 T = Method->getReturnType();2962 } else if (const auto *Enumerator = dyn_cast<EnumConstantDecl>(ND)) {2963 T = Context.getCanonicalTagType(2964 cast<EnumDecl>(Enumerator->getDeclContext()));2965 } else if (isa<UnresolvedUsingValueDecl>(ND)) {2966 /* Do nothing: ignore unresolved using declarations*/2967 } else if (const auto *Ivar = dyn_cast<ObjCIvarDecl>(ND)) {2968 if (!BaseType.isNull())2969 T = Ivar->getUsageType(BaseType);2970 else2971 T = Ivar->getType();2972 } else if (const auto *Value = dyn_cast<ValueDecl>(ND)) {2973 T = Value->getType();2974 } else if (const auto *Property = dyn_cast<ObjCPropertyDecl>(ND)) {2975 if (!BaseType.isNull())2976 T = Property->getUsageType(BaseType);2977 else2978 T = Property->getType();2979 }2980 2981 if (T.isNull() || Context.hasSameType(T, Context.DependentTy))2982 return;2983 2984 Result.AddResultTypeChunk(2985 GetCompletionTypeString(T, Context, Policy, Result.getAllocator()));2986}2987 2988static void MaybeAddSentinel(Preprocessor &PP,2989 const NamedDecl *FunctionOrMethod,2990 CodeCompletionBuilder &Result) {2991 if (SentinelAttr *Sentinel = FunctionOrMethod->getAttr<SentinelAttr>())2992 if (Sentinel->getSentinel() == 0) {2993 if (PP.getLangOpts().ObjC && PP.isMacroDefined("nil"))2994 Result.AddTextChunk(", nil");2995 else if (PP.isMacroDefined("NULL"))2996 Result.AddTextChunk(", NULL");2997 else2998 Result.AddTextChunk(", (void*)0");2999 }3000}3001 3002static std::string formatObjCParamQualifiers(unsigned ObjCQuals,3003 QualType &Type) {3004 std::string Result;3005 if (ObjCQuals & Decl::OBJC_TQ_In)3006 Result += "in ";3007 else if (ObjCQuals & Decl::OBJC_TQ_Inout)3008 Result += "inout ";3009 else if (ObjCQuals & Decl::OBJC_TQ_Out)3010 Result += "out ";3011 if (ObjCQuals & Decl::OBJC_TQ_Bycopy)3012 Result += "bycopy ";3013 else if (ObjCQuals & Decl::OBJC_TQ_Byref)3014 Result += "byref ";3015 if (ObjCQuals & Decl::OBJC_TQ_Oneway)3016 Result += "oneway ";3017 if (ObjCQuals & Decl::OBJC_TQ_CSNullability) {3018 if (auto nullability = AttributedType::stripOuterNullability(Type)) {3019 switch (*nullability) {3020 case NullabilityKind::NonNull:3021 Result += "nonnull ";3022 break;3023 3024 case NullabilityKind::Nullable:3025 Result += "nullable ";3026 break;3027 3028 case NullabilityKind::Unspecified:3029 Result += "null_unspecified ";3030 break;3031 3032 case NullabilityKind::NullableResult:3033 llvm_unreachable("Not supported as a context-sensitive keyword!");3034 break;3035 }3036 }3037 }3038 return Result;3039}3040 3041/// Tries to find the most appropriate type location for an Objective-C3042/// block placeholder.3043///3044/// This function ignores things like typedefs and qualifiers in order to3045/// present the most relevant and accurate block placeholders in code completion3046/// results.3047static void findTypeLocationForBlockDecl(const TypeSourceInfo *TSInfo,3048 FunctionTypeLoc &Block,3049 FunctionProtoTypeLoc &BlockProto,3050 bool SuppressBlock = false) {3051 if (!TSInfo)3052 return;3053 TypeLoc TL = TSInfo->getTypeLoc().getUnqualifiedLoc();3054 while (true) {3055 // Look through typedefs.3056 if (!SuppressBlock) {3057 if (TypedefTypeLoc TypedefTL = TL.getAsAdjusted<TypedefTypeLoc>()) {3058 if (TypeSourceInfo *InnerTSInfo =3059 TypedefTL.getDecl()->getTypeSourceInfo()) {3060 TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc();3061 continue;3062 }3063 }3064 3065 // Look through qualified types3066 if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) {3067 TL = QualifiedTL.getUnqualifiedLoc();3068 continue;3069 }3070 3071 if (AttributedTypeLoc AttrTL = TL.getAs<AttributedTypeLoc>()) {3072 TL = AttrTL.getModifiedLoc();3073 continue;3074 }3075 }3076 3077 // Try to get the function prototype behind the block pointer type,3078 // then we're done.3079 if (BlockPointerTypeLoc BlockPtr = TL.getAs<BlockPointerTypeLoc>()) {3080 TL = BlockPtr.getPointeeLoc().IgnoreParens();3081 Block = TL.getAs<FunctionTypeLoc>();3082 BlockProto = TL.getAs<FunctionProtoTypeLoc>();3083 }3084 break;3085 }3086}3087 3088static std::string formatBlockPlaceholder(3089 const PrintingPolicy &Policy, const NamedDecl *BlockDecl,3090 FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto,3091 bool SuppressBlockName = false, bool SuppressBlock = false,3092 std::optional<ArrayRef<QualType>> ObjCSubsts = std::nullopt);3093 3094static std::string FormatFunctionParameter(3095 const PrintingPolicy &Policy, const DeclaratorDecl *Param,3096 bool SuppressName = false, bool SuppressBlock = false,3097 std::optional<ArrayRef<QualType>> ObjCSubsts = std::nullopt) {3098 // Params are unavailable in FunctionTypeLoc if the FunctionType is invalid.3099 // It would be better to pass in the param Type, which is usually available.3100 // But this case is rare, so just pretend we fell back to int as elsewhere.3101 if (!Param)3102 return "int";3103 Decl::ObjCDeclQualifier ObjCQual = Decl::OBJC_TQ_None;3104 if (const auto *PVD = dyn_cast<ParmVarDecl>(Param))3105 ObjCQual = PVD->getObjCDeclQualifier();3106 bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext());3107 if (Param->getType()->isDependentType() ||3108 !Param->getType()->isBlockPointerType()) {3109 // The argument for a dependent or non-block parameter is a placeholder3110 // containing that parameter's type.3111 std::string Result;3112 3113 if (Param->getIdentifier() && !ObjCMethodParam && !SuppressName)3114 Result = std::string(Param->getIdentifier()->deuglifiedName());3115 3116 QualType Type = Param->getType();3117 if (ObjCSubsts)3118 Type = Type.substObjCTypeArgs(Param->getASTContext(), *ObjCSubsts,3119 ObjCSubstitutionContext::Parameter);3120 if (ObjCMethodParam) {3121 Result = "(" + formatObjCParamQualifiers(ObjCQual, Type);3122 Result += Type.getAsString(Policy) + ")";3123 if (Param->getIdentifier() && !SuppressName)3124 Result += Param->getIdentifier()->deuglifiedName();3125 } else {3126 Type.getAsStringInternal(Result, Policy);3127 }3128 return Result;3129 }3130 3131 // The argument for a block pointer parameter is a block literal with3132 // the appropriate type.3133 FunctionTypeLoc Block;3134 FunctionProtoTypeLoc BlockProto;3135 findTypeLocationForBlockDecl(Param->getTypeSourceInfo(), Block, BlockProto,3136 SuppressBlock);3137 // Try to retrieve the block type information from the property if this is a3138 // parameter in a setter.3139 if (!Block && ObjCMethodParam &&3140 cast<ObjCMethodDecl>(Param->getDeclContext())->isPropertyAccessor()) {3141 if (const auto *PD = cast<ObjCMethodDecl>(Param->getDeclContext())3142 ->findPropertyDecl(/*CheckOverrides=*/false))3143 findTypeLocationForBlockDecl(PD->getTypeSourceInfo(), Block, BlockProto,3144 SuppressBlock);3145 }3146 3147 if (!Block) {3148 // We were unable to find a FunctionProtoTypeLoc with parameter names3149 // for the block; just use the parameter type as a placeholder.3150 std::string Result;3151 if (!ObjCMethodParam && Param->getIdentifier())3152 Result = std::string(Param->getIdentifier()->deuglifiedName());3153 3154 QualType Type = Param->getType().getUnqualifiedType();3155 3156 if (ObjCMethodParam) {3157 Result = Type.getAsString(Policy);3158 std::string Quals = formatObjCParamQualifiers(ObjCQual, Type);3159 if (!Quals.empty())3160 Result = "(" + Quals + " " + Result + ")";3161 if (Result.back() != ')')3162 Result += " ";3163 if (Param->getIdentifier())3164 Result += Param->getIdentifier()->deuglifiedName();3165 } else {3166 Type.getAsStringInternal(Result, Policy);3167 }3168 3169 return Result;3170 }3171 3172 // We have the function prototype behind the block pointer type, as it was3173 // written in the source.3174 return formatBlockPlaceholder(Policy, Param, Block, BlockProto,3175 /*SuppressBlockName=*/false, SuppressBlock,3176 ObjCSubsts);3177}3178 3179/// Returns a placeholder string that corresponds to an Objective-C block3180/// declaration.3181///3182/// \param BlockDecl A declaration with an Objective-C block type.3183///3184/// \param Block The most relevant type location for that block type.3185///3186/// \param SuppressBlockName Determines whether or not the name of the block3187/// declaration is included in the resulting string.3188static std::string3189formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl,3190 FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto,3191 bool SuppressBlockName, bool SuppressBlock,3192 std::optional<ArrayRef<QualType>> ObjCSubsts) {3193 std::string Result;3194 QualType ResultType = Block.getTypePtr()->getReturnType();3195 if (ObjCSubsts)3196 ResultType =3197 ResultType.substObjCTypeArgs(BlockDecl->getASTContext(), *ObjCSubsts,3198 ObjCSubstitutionContext::Result);3199 if (!ResultType->isVoidType() || SuppressBlock)3200 ResultType.getAsStringInternal(Result, Policy);3201 3202 // Format the parameter list.3203 std::string Params;3204 if (!BlockProto || Block.getNumParams() == 0) {3205 if (BlockProto && BlockProto.getTypePtr()->isVariadic())3206 Params = "(...)";3207 else3208 Params = "(void)";3209 } else {3210 Params += "(";3211 for (unsigned I = 0, N = Block.getNumParams(); I != N; ++I) {3212 if (I)3213 Params += ", ";3214 Params += FormatFunctionParameter(Policy, Block.getParam(I),3215 /*SuppressName=*/false,3216 /*SuppressBlock=*/true, ObjCSubsts);3217 3218 if (I == N - 1 && BlockProto.getTypePtr()->isVariadic())3219 Params += ", ...";3220 }3221 Params += ")";3222 }3223 3224 if (SuppressBlock) {3225 // Format as a parameter.3226 Result = Result + " (^";3227 if (!SuppressBlockName && BlockDecl->getIdentifier())3228 Result += BlockDecl->getIdentifier()->getName();3229 Result += ")";3230 Result += Params;3231 } else {3232 // Format as a block literal argument.3233 Result = '^' + Result;3234 Result += Params;3235 3236 if (!SuppressBlockName && BlockDecl->getIdentifier())3237 Result += BlockDecl->getIdentifier()->getName();3238 }3239 3240 return Result;3241}3242 3243static std::string GetDefaultValueString(const ParmVarDecl *Param,3244 const SourceManager &SM,3245 const LangOptions &LangOpts) {3246 const SourceRange SrcRange = Param->getDefaultArgRange();3247 CharSourceRange CharSrcRange = CharSourceRange::getTokenRange(SrcRange);3248 bool Invalid = CharSrcRange.isInvalid();3249 if (Invalid)3250 return "";3251 StringRef srcText =3252 Lexer::getSourceText(CharSrcRange, SM, LangOpts, &Invalid);3253 if (Invalid)3254 return "";3255 3256 if (srcText.empty() || srcText == "=") {3257 // Lexer can't determine the value.3258 // This happens if the code is incorrect (for example class is forward3259 // declared).3260 return "";3261 }3262 std::string DefValue(srcText.str());3263 // FIXME: remove this check if the Lexer::getSourceText value is fixed and3264 // this value always has (or always does not have) '=' in front of it3265 if (DefValue.at(0) != '=') {3266 // If we don't have '=' in front of value.3267 // Lexer returns built-in types values without '=' and user-defined types3268 // values with it.3269 return " = " + DefValue;3270 }3271 return " " + DefValue;3272}3273 3274/// Add function parameter chunks to the given code completion string.3275static void AddFunctionParameterChunks(Preprocessor &PP,3276 const PrintingPolicy &Policy,3277 const FunctionDecl *Function,3278 CodeCompletionBuilder &Result,3279 unsigned Start = 0,3280 bool InOptional = false) {3281 bool FirstParameter = true;3282 3283 for (unsigned P = Start, N = Function->getNumParams(); P != N; ++P) {3284 const ParmVarDecl *Param = Function->getParamDecl(P);3285 3286 if (Param->hasDefaultArg() && !InOptional) {3287 // When we see an optional default argument, put that argument and3288 // the remaining default arguments into a new, optional string.3289 CodeCompletionBuilder Opt(Result.getAllocator(),3290 Result.getCodeCompletionTUInfo());3291 if (!FirstParameter)3292 Opt.AddChunk(CodeCompletionString::CK_Comma);3293 AddFunctionParameterChunks(PP, Policy, Function, Opt, P, true);3294 Result.AddOptionalChunk(Opt.TakeString());3295 break;3296 }3297 3298 // C++23 introduces an explicit object parameter, a.k.a. "deducing this"3299 // Skip it for autocomplete and treat the next parameter as the first3300 // parameter3301 if (FirstParameter && Param->isExplicitObjectParameter()) {3302 continue;3303 }3304 3305 if (FirstParameter)3306 FirstParameter = false;3307 else3308 Result.AddChunk(CodeCompletionString::CK_Comma);3309 3310 InOptional = false;3311 3312 // Format the placeholder string.3313 std::string PlaceholderStr = FormatFunctionParameter(Policy, Param);3314 if (Param->hasDefaultArg())3315 PlaceholderStr +=3316 GetDefaultValueString(Param, PP.getSourceManager(), PP.getLangOpts());3317 3318 if (Function->isVariadic() && P == N - 1)3319 PlaceholderStr += ", ...";3320 3321 // Add the placeholder string.3322 Result.AddPlaceholderChunk(3323 Result.getAllocator().CopyString(PlaceholderStr));3324 }3325 3326 if (const auto *Proto = Function->getType()->getAs<FunctionProtoType>())3327 if (Proto->isVariadic()) {3328 if (Proto->getNumParams() == 0)3329 Result.AddPlaceholderChunk("...");3330 3331 MaybeAddSentinel(PP, Function, Result);3332 }3333}3334 3335/// Add template parameter chunks to the given code completion string.3336static void AddTemplateParameterChunks(3337 ASTContext &Context, const PrintingPolicy &Policy,3338 const TemplateDecl *Template, CodeCompletionBuilder &Result,3339 unsigned MaxParameters = 0, unsigned Start = 0, bool InDefaultArg = false) {3340 bool FirstParameter = true;3341 3342 // Prefer to take the template parameter names from the first declaration of3343 // the template.3344 Template = cast<TemplateDecl>(Template->getCanonicalDecl());3345 3346 TemplateParameterList *Params = Template->getTemplateParameters();3347 TemplateParameterList::iterator PEnd = Params->end();3348 if (MaxParameters)3349 PEnd = Params->begin() + MaxParameters;3350 for (TemplateParameterList::iterator P = Params->begin() + Start; P != PEnd;3351 ++P) {3352 bool HasDefaultArg = false;3353 std::string PlaceholderStr;3354 if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) {3355 if (TTP->wasDeclaredWithTypename())3356 PlaceholderStr = "typename";3357 else if (const auto *TC = TTP->getTypeConstraint()) {3358 llvm::raw_string_ostream OS(PlaceholderStr);3359 TC->print(OS, Policy);3360 } else3361 PlaceholderStr = "class";3362 3363 if (TTP->getIdentifier()) {3364 PlaceholderStr += ' ';3365 PlaceholderStr += TTP->getIdentifier()->deuglifiedName();3366 }3367 3368 HasDefaultArg = TTP->hasDefaultArgument();3369 } else if (NonTypeTemplateParmDecl *NTTP =3370 dyn_cast<NonTypeTemplateParmDecl>(*P)) {3371 if (NTTP->getIdentifier())3372 PlaceholderStr = std::string(NTTP->getIdentifier()->deuglifiedName());3373 NTTP->getType().getAsStringInternal(PlaceholderStr, Policy);3374 HasDefaultArg = NTTP->hasDefaultArgument();3375 } else {3376 assert(isa<TemplateTemplateParmDecl>(*P));3377 TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P);3378 3379 // Since putting the template argument list into the placeholder would3380 // be very, very long, we just use an abbreviation.3381 PlaceholderStr = "template<...> class";3382 if (TTP->getIdentifier()) {3383 PlaceholderStr += ' ';3384 PlaceholderStr += TTP->getIdentifier()->deuglifiedName();3385 }3386 3387 HasDefaultArg = TTP->hasDefaultArgument();3388 }3389 3390 if (HasDefaultArg && !InDefaultArg) {3391 // When we see an optional default argument, put that argument and3392 // the remaining default arguments into a new, optional string.3393 CodeCompletionBuilder Opt(Result.getAllocator(),3394 Result.getCodeCompletionTUInfo());3395 if (!FirstParameter)3396 Opt.AddChunk(CodeCompletionString::CK_Comma);3397 AddTemplateParameterChunks(Context, Policy, Template, Opt, MaxParameters,3398 P - Params->begin(), true);3399 Result.AddOptionalChunk(Opt.TakeString());3400 break;3401 }3402 3403 InDefaultArg = false;3404 3405 if (FirstParameter)3406 FirstParameter = false;3407 else3408 Result.AddChunk(CodeCompletionString::CK_Comma);3409 3410 // Add the placeholder string.3411 Result.AddPlaceholderChunk(3412 Result.getAllocator().CopyString(PlaceholderStr));3413 }3414}3415 3416/// Add a qualifier to the given code-completion string, if the3417/// provided nested-name-specifier is non-NULL.3418static void AddQualifierToCompletionString(CodeCompletionBuilder &Result,3419 NestedNameSpecifier Qualifier,3420 bool QualifierIsInformative,3421 ASTContext &Context,3422 const PrintingPolicy &Policy) {3423 if (!Qualifier)3424 return;3425 3426 std::string PrintedNNS;3427 {3428 llvm::raw_string_ostream OS(PrintedNNS);3429 Qualifier.print(OS, Policy);3430 }3431 if (QualifierIsInformative)3432 Result.AddInformativeChunk(Result.getAllocator().CopyString(PrintedNNS));3433 else3434 Result.AddTextChunk(Result.getAllocator().CopyString(PrintedNNS));3435}3436 3437static void AddFunctionTypeQuals(CodeCompletionBuilder &Result,3438 const Qualifiers Quals) {3439 // FIXME: Add ref-qualifier!3440 3441 // Handle single qualifiers without copying3442 if (Quals.hasOnlyConst()) {3443 Result.AddInformativeChunk(" const");3444 return;3445 }3446 3447 if (Quals.hasOnlyVolatile()) {3448 Result.AddInformativeChunk(" volatile");3449 return;3450 }3451 3452 if (Quals.hasOnlyRestrict()) {3453 Result.AddInformativeChunk(" restrict");3454 return;3455 }3456 3457 // Handle multiple qualifiers.3458 std::string QualsStr;3459 if (Quals.hasConst())3460 QualsStr += " const";3461 if (Quals.hasVolatile())3462 QualsStr += " volatile";3463 if (Quals.hasRestrict())3464 QualsStr += " restrict";3465 Result.AddInformativeChunk(Result.getAllocator().CopyString(QualsStr));3466}3467 3468static void3469AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result,3470 const FunctionDecl *Function) {3471 if (auto *CxxMethodDecl = llvm::dyn_cast_if_present<CXXMethodDecl>(Function);3472 CxxMethodDecl && CxxMethodDecl->hasCXXExplicitFunctionObjectParameter()) {3473 // if explicit object method, infer quals from the object parameter3474 const auto Quals = CxxMethodDecl->getFunctionObjectParameterType();3475 if (!Quals.hasQualifiers())3476 return;3477 3478 AddFunctionTypeQuals(Result, Quals.getQualifiers());3479 } else {3480 const auto *Proto = Function->getType()->getAs<FunctionProtoType>();3481 if (!Proto || !Proto->getMethodQuals())3482 return;3483 3484 AddFunctionTypeQuals(Result, Proto->getMethodQuals());3485 }3486}3487 3488static void3489AddFunctionExceptSpecToCompletionString(std::string &NameAndSignature,3490 const FunctionDecl *Function) {3491 const auto *Proto = Function->getType()->getAs<FunctionProtoType>();3492 if (!Proto)3493 return;3494 3495 auto ExceptInfo = Proto->getExceptionSpecInfo();3496 switch (ExceptInfo.Type) {3497 case EST_BasicNoexcept:3498 case EST_NoexceptTrue:3499 NameAndSignature += " noexcept";3500 break;3501 3502 default:3503 break;3504 }3505}3506 3507/// Add the name of the given declaration3508static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy,3509 const NamedDecl *ND,3510 CodeCompletionBuilder &Result) {3511 DeclarationName Name = ND->getDeclName();3512 if (!Name)3513 return;3514 3515 switch (Name.getNameKind()) {3516 case DeclarationName::CXXOperatorName: {3517 const char *OperatorName = nullptr;3518 switch (Name.getCXXOverloadedOperator()) {3519 case OO_None:3520 case OO_Conditional:3521 case NUM_OVERLOADED_OPERATORS:3522 OperatorName = "operator";3523 break;3524 3525#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \3526 case OO_##Name: \3527 OperatorName = "operator" Spelling; \3528 break;3529#define OVERLOADED_OPERATOR_MULTI(Name, Spelling, Unary, Binary, MemberOnly)3530#include "clang/Basic/OperatorKinds.def"3531 3532 case OO_New:3533 OperatorName = "operator new";3534 break;3535 case OO_Delete:3536 OperatorName = "operator delete";3537 break;3538 case OO_Array_New:3539 OperatorName = "operator new[]";3540 break;3541 case OO_Array_Delete:3542 OperatorName = "operator delete[]";3543 break;3544 case OO_Call:3545 OperatorName = "operator()";3546 break;3547 case OO_Subscript:3548 OperatorName = "operator[]";3549 break;3550 }3551 Result.AddTypedTextChunk(OperatorName);3552 break;3553 }3554 3555 case DeclarationName::Identifier:3556 case DeclarationName::CXXConversionFunctionName:3557 case DeclarationName::CXXDestructorName:3558 case DeclarationName::CXXLiteralOperatorName:3559 Result.AddTypedTextChunk(3560 Result.getAllocator().CopyString(ND->getNameAsString()));3561 break;3562 3563 case DeclarationName::CXXDeductionGuideName:3564 case DeclarationName::CXXUsingDirective:3565 case DeclarationName::ObjCZeroArgSelector:3566 case DeclarationName::ObjCOneArgSelector:3567 case DeclarationName::ObjCMultiArgSelector:3568 break;3569 3570 case DeclarationName::CXXConstructorName: {3571 CXXRecordDecl *Record = nullptr;3572 QualType Ty = Name.getCXXNameType();3573 if (auto *RD = Ty->getAsCXXRecordDecl()) {3574 Record = RD;3575 } else {3576 Result.AddTypedTextChunk(3577 Result.getAllocator().CopyString(ND->getNameAsString()));3578 break;3579 }3580 3581 Result.AddTypedTextChunk(3582 Result.getAllocator().CopyString(Record->getNameAsString()));3583 if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) {3584 Result.AddChunk(CodeCompletionString::CK_LeftAngle);3585 AddTemplateParameterChunks(Context, Policy, Template, Result);3586 Result.AddChunk(CodeCompletionString::CK_RightAngle);3587 }3588 break;3589 }3590 }3591}3592 3593CodeCompletionString *CodeCompletionResult::CreateCodeCompletionString(3594 Sema &S, const CodeCompletionContext &CCContext,3595 CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo,3596 bool IncludeBriefComments) {3597 return CreateCodeCompletionString(S.Context, S.PP, CCContext, Allocator,3598 CCTUInfo, IncludeBriefComments);3599}3600 3601CodeCompletionString *CodeCompletionResult::CreateCodeCompletionStringForMacro(3602 Preprocessor &PP, CodeCompletionAllocator &Allocator,3603 CodeCompletionTUInfo &CCTUInfo) {3604 assert(Kind == RK_Macro);3605 CodeCompletionBuilder Result(Allocator, CCTUInfo, Priority, Availability);3606 const MacroInfo *MI = PP.getMacroInfo(Macro);3607 Result.AddTypedTextChunk(Result.getAllocator().CopyString(Macro->getName()));3608 3609 if (!MI || !MI->isFunctionLike())3610 return Result.TakeString();3611 3612 // Format a function-like macro with placeholders for the arguments.3613 Result.AddChunk(CodeCompletionString::CK_LeftParen);3614 MacroInfo::param_iterator A = MI->param_begin(), AEnd = MI->param_end();3615 3616 // C99 variadic macros add __VA_ARGS__ at the end. Skip it.3617 if (MI->isC99Varargs()) {3618 --AEnd;3619 3620 if (A == AEnd) {3621 Result.AddPlaceholderChunk("...");3622 }3623 }3624 3625 for (MacroInfo::param_iterator A = MI->param_begin(); A != AEnd; ++A) {3626 if (A != MI->param_begin())3627 Result.AddChunk(CodeCompletionString::CK_Comma);3628 3629 if (MI->isVariadic() && (A + 1) == AEnd) {3630 SmallString<32> Arg = (*A)->getName();3631 if (MI->isC99Varargs())3632 Arg += ", ...";3633 else3634 Arg += "...";3635 Result.AddPlaceholderChunk(Result.getAllocator().CopyString(Arg));3636 break;3637 }3638 3639 // Non-variadic macros are simple.3640 Result.AddPlaceholderChunk(3641 Result.getAllocator().CopyString((*A)->getName()));3642 }3643 Result.AddChunk(CodeCompletionString::CK_RightParen);3644 return Result.TakeString();3645}3646 3647/// If possible, create a new code completion string for the given3648/// result.3649///3650/// \returns Either a new, heap-allocated code completion string describing3651/// how to use this result, or NULL to indicate that the string or name of the3652/// result is all that is needed.3653CodeCompletionString *CodeCompletionResult::CreateCodeCompletionString(3654 ASTContext &Ctx, Preprocessor &PP, const CodeCompletionContext &CCContext,3655 CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo,3656 bool IncludeBriefComments) {3657 if (Kind == RK_Macro)3658 return CreateCodeCompletionStringForMacro(PP, Allocator, CCTUInfo);3659 3660 CodeCompletionBuilder Result(Allocator, CCTUInfo, Priority, Availability);3661 3662 PrintingPolicy Policy = getCompletionPrintingPolicy(Ctx, PP);3663 if (Kind == RK_Pattern) {3664 Pattern->Priority = Priority;3665 Pattern->Availability = Availability;3666 3667 if (Declaration) {3668 Result.addParentContext(Declaration->getDeclContext());3669 Pattern->ParentName = Result.getParentName();3670 if (const RawComment *RC =3671 getPatternCompletionComment(Ctx, Declaration)) {3672 Result.addBriefComment(RC->getBriefText(Ctx));3673 Pattern->BriefComment = Result.getBriefComment();3674 }3675 }3676 3677 return Pattern;3678 }3679 3680 if (Kind == RK_Keyword) {3681 Result.AddTypedTextChunk(Keyword);3682 return Result.TakeString();3683 }3684 assert(Kind == RK_Declaration && "Missed a result kind?");3685 return createCodeCompletionStringForDecl(3686 PP, Ctx, Result, IncludeBriefComments, CCContext, Policy);3687}3688 3689static void printOverrideString(const CodeCompletionString &CCS,3690 std::string &BeforeName,3691 std::string &NameAndSignature) {3692 bool SeenTypedChunk = false;3693 for (auto &Chunk : CCS) {3694 if (Chunk.Kind == CodeCompletionString::CK_Optional) {3695 assert(SeenTypedChunk && "optional parameter before name");3696 // Note that we put all chunks inside into NameAndSignature.3697 printOverrideString(*Chunk.Optional, NameAndSignature, NameAndSignature);3698 continue;3699 }3700 SeenTypedChunk |= Chunk.Kind == CodeCompletionString::CK_TypedText;3701 if (SeenTypedChunk)3702 NameAndSignature += Chunk.Text;3703 else3704 BeforeName += Chunk.Text;3705 }3706}3707 3708CodeCompletionString *3709CodeCompletionResult::createCodeCompletionStringForOverride(3710 Preprocessor &PP, ASTContext &Ctx, CodeCompletionBuilder &Result,3711 bool IncludeBriefComments, const CodeCompletionContext &CCContext,3712 PrintingPolicy &Policy) {3713 auto *CCS = createCodeCompletionStringForDecl(PP, Ctx, Result,3714 /*IncludeBriefComments=*/false,3715 CCContext, Policy);3716 std::string BeforeName;3717 std::string NameAndSignature;3718 // For overrides all chunks go into the result, none are informative.3719 printOverrideString(*CCS, BeforeName, NameAndSignature);3720 3721 // If the virtual function is declared with "noexcept", add it in the result3722 // code completion string.3723 const auto *VirtualFunc = dyn_cast<FunctionDecl>(Declaration);3724 assert(VirtualFunc && "overridden decl must be a function");3725 AddFunctionExceptSpecToCompletionString(NameAndSignature, VirtualFunc);3726 3727 NameAndSignature += " override";3728 3729 Result.AddTextChunk(Result.getAllocator().CopyString(BeforeName));3730 Result.AddChunk(CodeCompletionString::CK_HorizontalSpace);3731 Result.AddTypedTextChunk(Result.getAllocator().CopyString(NameAndSignature));3732 return Result.TakeString();3733}3734 3735// FIXME: Right now this works well with lambdas. Add support for other functor3736// types like std::function.3737static const NamedDecl *extractFunctorCallOperator(const NamedDecl *ND) {3738 const auto *VD = dyn_cast<VarDecl>(ND);3739 if (!VD)3740 return nullptr;3741 const auto *RecordDecl = VD->getType()->getAsCXXRecordDecl();3742 if (!RecordDecl || !RecordDecl->isLambda())3743 return nullptr;3744 return RecordDecl->getLambdaCallOperator();3745}3746 3747CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(3748 Preprocessor &PP, ASTContext &Ctx, CodeCompletionBuilder &Result,3749 bool IncludeBriefComments, const CodeCompletionContext &CCContext,3750 PrintingPolicy &Policy) {3751 const NamedDecl *ND = Declaration;3752 Result.addParentContext(ND->getDeclContext());3753 3754 if (IncludeBriefComments) {3755 // Add documentation comment, if it exists.3756 if (const RawComment *RC = getCompletionComment(Ctx, Declaration)) {3757 Result.addBriefComment(RC->getBriefText(Ctx));3758 }3759 }3760 3761 if (StartsNestedNameSpecifier) {3762 Result.AddTypedTextChunk(3763 Result.getAllocator().CopyString(ND->getNameAsString()));3764 Result.AddTextChunk("::");3765 return Result.TakeString();3766 }3767 3768 for (const auto *I : ND->specific_attrs<AnnotateAttr>())3769 Result.AddAnnotation(Result.getAllocator().CopyString(I->getAnnotation()));3770 3771 auto AddFunctionTypeAndResult = [&](const FunctionDecl *Function) {3772 AddResultTypeChunk(Ctx, Policy, Function, CCContext.getBaseType(), Result);3773 AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,3774 Ctx, Policy);3775 AddTypedNameChunk(Ctx, Policy, ND, Result);3776 Result.AddChunk(CodeCompletionString::CK_LeftParen);3777 AddFunctionParameterChunks(PP, Policy, Function, Result);3778 Result.AddChunk(CodeCompletionString::CK_RightParen);3779 AddFunctionTypeQualsToCompletionString(Result, Function);3780 };3781 3782 if (const auto *Function = dyn_cast<FunctionDecl>(ND)) {3783 AddFunctionTypeAndResult(Function);3784 return Result.TakeString();3785 }3786 3787 if (const auto *CallOperator =3788 dyn_cast_or_null<FunctionDecl>(extractFunctorCallOperator(ND))) {3789 AddFunctionTypeAndResult(CallOperator);3790 return Result.TakeString();3791 }3792 3793 AddResultTypeChunk(Ctx, Policy, ND, CCContext.getBaseType(), Result);3794 3795 if (const FunctionTemplateDecl *FunTmpl =3796 dyn_cast<FunctionTemplateDecl>(ND)) {3797 AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,3798 Ctx, Policy);3799 FunctionDecl *Function = FunTmpl->getTemplatedDecl();3800 AddTypedNameChunk(Ctx, Policy, Function, Result);3801 3802 // Figure out which template parameters are deduced (or have default3803 // arguments).3804 // Note that we're creating a non-empty bit vector so that we can go3805 // through the loop below to omit default template parameters for non-call3806 // cases.3807 llvm::SmallBitVector Deduced(FunTmpl->getTemplateParameters()->size());3808 // Avoid running it if this is not a call: We should emit *all* template3809 // parameters.3810 if (FunctionCanBeCall)3811 Sema::MarkDeducedTemplateParameters(Ctx, FunTmpl, Deduced);3812 unsigned LastDeducibleArgument;3813 for (LastDeducibleArgument = Deduced.size(); LastDeducibleArgument > 0;3814 --LastDeducibleArgument) {3815 if (!Deduced[LastDeducibleArgument - 1]) {3816 // C++0x: Figure out if the template argument has a default. If so,3817 // the user doesn't need to type this argument.3818 // FIXME: We need to abstract template parameters better!3819 bool HasDefaultArg = false;3820 NamedDecl *Param = FunTmpl->getTemplateParameters()->getParam(3821 LastDeducibleArgument - 1);3822 if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))3823 HasDefaultArg = TTP->hasDefaultArgument();3824 else if (NonTypeTemplateParmDecl *NTTP =3825 dyn_cast<NonTypeTemplateParmDecl>(Param))3826 HasDefaultArg = NTTP->hasDefaultArgument();3827 else {3828 assert(isa<TemplateTemplateParmDecl>(Param));3829 HasDefaultArg =3830 cast<TemplateTemplateParmDecl>(Param)->hasDefaultArgument();3831 }3832 3833 if (!HasDefaultArg)3834 break;3835 }3836 }3837 3838 if (LastDeducibleArgument || !FunctionCanBeCall) {3839 // Some of the function template arguments cannot be deduced from a3840 // function call, so we introduce an explicit template argument list3841 // containing all of the arguments up to the first deducible argument.3842 //3843 // Or, if this isn't a call, emit all the template arguments3844 // to disambiguate the (potential) overloads.3845 //3846 // FIXME: Detect cases where the function parameters can be deduced from3847 // the surrounding context, as per [temp.deduct.funcaddr].3848 // e.g.,3849 // template <class T> void foo(T);3850 // void (*f)(int) = foo;3851 Result.AddChunk(CodeCompletionString::CK_LeftAngle);3852 AddTemplateParameterChunks(Ctx, Policy, FunTmpl, Result,3853 LastDeducibleArgument);3854 Result.AddChunk(CodeCompletionString::CK_RightAngle);3855 }3856 3857 // Add the function parameters3858 Result.AddChunk(CodeCompletionString::CK_LeftParen);3859 AddFunctionParameterChunks(PP, Policy, Function, Result);3860 Result.AddChunk(CodeCompletionString::CK_RightParen);3861 AddFunctionTypeQualsToCompletionString(Result, Function);3862 return Result.TakeString();3863 }3864 3865 if (const auto *Template = dyn_cast<TemplateDecl>(ND)) {3866 AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,3867 Ctx, Policy);3868 Result.AddTypedTextChunk(3869 Result.getAllocator().CopyString(Template->getNameAsString()));3870 Result.AddChunk(CodeCompletionString::CK_LeftAngle);3871 AddTemplateParameterChunks(Ctx, Policy, Template, Result);3872 Result.AddChunk(CodeCompletionString::CK_RightAngle);3873 return Result.TakeString();3874 }3875 3876 if (const auto *Method = dyn_cast<ObjCMethodDecl>(ND)) {3877 Selector Sel = Method->getSelector();3878 if (Sel.isUnarySelector()) {3879 Result.AddTypedTextChunk(3880 Result.getAllocator().CopyString(Sel.getNameForSlot(0)));3881 return Result.TakeString();3882 }3883 3884 std::string SelName = Sel.getNameForSlot(0).str();3885 SelName += ':';3886 if (StartParameter == 0)3887 Result.AddTypedTextChunk(Result.getAllocator().CopyString(SelName));3888 else {3889 Result.AddInformativeChunk(Result.getAllocator().CopyString(SelName));3890 3891 // If there is only one parameter, and we're past it, add an empty3892 // typed-text chunk since there is nothing to type.3893 if (Method->param_size() == 1)3894 Result.AddTypedTextChunk("");3895 }3896 unsigned Idx = 0;3897 // The extra Idx < Sel.getNumArgs() check is needed due to legacy C-style3898 // method parameters.3899 for (ObjCMethodDecl::param_const_iterator P = Method->param_begin(),3900 PEnd = Method->param_end();3901 P != PEnd && Idx < Sel.getNumArgs(); (void)++P, ++Idx) {3902 if (Idx > 0) {3903 std::string Keyword;3904 if (Idx > StartParameter)3905 Result.AddChunk(CodeCompletionString::CK_HorizontalSpace);3906 if (const IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Idx))3907 Keyword += II->getName();3908 Keyword += ":";3909 if (Idx < StartParameter || AllParametersAreInformative)3910 Result.AddInformativeChunk(Result.getAllocator().CopyString(Keyword));3911 else3912 Result.AddTypedTextChunk(Result.getAllocator().CopyString(Keyword));3913 }3914 3915 // If we're before the starting parameter, skip the placeholder.3916 if (Idx < StartParameter)3917 continue;3918 3919 std::string Arg;3920 QualType ParamType = (*P)->getType();3921 std::optional<ArrayRef<QualType>> ObjCSubsts;3922 if (!CCContext.getBaseType().isNull())3923 ObjCSubsts = CCContext.getBaseType()->getObjCSubstitutions(Method);3924 3925 if (ParamType->isBlockPointerType() && !DeclaringEntity)3926 Arg = FormatFunctionParameter(Policy, *P, true,3927 /*SuppressBlock=*/false, ObjCSubsts);3928 else {3929 if (ObjCSubsts)3930 ParamType = ParamType.substObjCTypeArgs(3931 Ctx, *ObjCSubsts, ObjCSubstitutionContext::Parameter);3932 Arg = "(" + formatObjCParamQualifiers((*P)->getObjCDeclQualifier(),3933 ParamType);3934 Arg += ParamType.getAsString(Policy) + ")";3935 if (const IdentifierInfo *II = (*P)->getIdentifier())3936 if (DeclaringEntity || AllParametersAreInformative)3937 Arg += II->getName();3938 }3939 3940 if (Method->isVariadic() && (P + 1) == PEnd)3941 Arg += ", ...";3942 3943 if (DeclaringEntity)3944 Result.AddTextChunk(Result.getAllocator().CopyString(Arg));3945 else if (AllParametersAreInformative)3946 Result.AddInformativeChunk(Result.getAllocator().CopyString(Arg));3947 else3948 Result.AddPlaceholderChunk(Result.getAllocator().CopyString(Arg));3949 }3950 3951 if (Method->isVariadic()) {3952 if (Method->param_size() == 0) {3953 if (DeclaringEntity)3954 Result.AddTextChunk(", ...");3955 else if (AllParametersAreInformative)3956 Result.AddInformativeChunk(", ...");3957 else3958 Result.AddPlaceholderChunk(", ...");3959 }3960 3961 MaybeAddSentinel(PP, Method, Result);3962 }3963 3964 return Result.TakeString();3965 }3966 3967 if (Qualifier)3968 AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,3969 Ctx, Policy);3970 3971 Result.AddTypedTextChunk(3972 Result.getAllocator().CopyString(ND->getNameAsString()));3973 return Result.TakeString();3974}3975 3976const RawComment *clang::getCompletionComment(const ASTContext &Ctx,3977 const NamedDecl *ND) {3978 if (!ND)3979 return nullptr;3980 if (auto *RC = Ctx.getRawCommentForAnyRedecl(ND))3981 return RC;3982 3983 // Try to find comment from a property for ObjC methods.3984 const auto *M = dyn_cast<ObjCMethodDecl>(ND);3985 if (!M)3986 return nullptr;3987 const ObjCPropertyDecl *PDecl = M->findPropertyDecl();3988 if (!PDecl)3989 return nullptr;3990 3991 return Ctx.getRawCommentForAnyRedecl(PDecl);3992}3993 3994const RawComment *clang::getPatternCompletionComment(const ASTContext &Ctx,3995 const NamedDecl *ND) {3996 const auto *M = dyn_cast_or_null<ObjCMethodDecl>(ND);3997 if (!M || !M->isPropertyAccessor())3998 return nullptr;3999 4000 // Provide code completion comment for self.GetterName where4001 // GetterName is the getter method for a property with name4002 // different from the property name (declared via a property4003 // getter attribute.4004 const ObjCPropertyDecl *PDecl = M->findPropertyDecl();4005 if (!PDecl)4006 return nullptr;4007 if (PDecl->getGetterName() == M->getSelector() &&4008 PDecl->getIdentifier() != M->getIdentifier()) {4009 if (auto *RC = Ctx.getRawCommentForAnyRedecl(M))4010 return RC;4011 if (auto *RC = Ctx.getRawCommentForAnyRedecl(PDecl))4012 return RC;4013 }4014 return nullptr;4015}4016 4017const RawComment *clang::getParameterComment(4018 const ASTContext &Ctx,4019 const CodeCompleteConsumer::OverloadCandidate &Result, unsigned ArgIndex) {4020 auto FDecl = Result.getFunction();4021 if (!FDecl)4022 return nullptr;4023 if (ArgIndex < FDecl->getNumParams())4024 return Ctx.getRawCommentForAnyRedecl(FDecl->getParamDecl(ArgIndex));4025 return nullptr;4026}4027 4028static void AddOverloadAggregateChunks(const RecordDecl *RD,4029 const PrintingPolicy &Policy,4030 CodeCompletionBuilder &Result,4031 unsigned CurrentArg) {4032 unsigned ChunkIndex = 0;4033 auto AddChunk = [&](llvm::StringRef Placeholder) {4034 if (ChunkIndex > 0)4035 Result.AddChunk(CodeCompletionString::CK_Comma);4036 const char *Copy = Result.getAllocator().CopyString(Placeholder);4037 if (ChunkIndex == CurrentArg)4038 Result.AddCurrentParameterChunk(Copy);4039 else4040 Result.AddPlaceholderChunk(Copy);4041 ++ChunkIndex;4042 };4043 // Aggregate initialization has all bases followed by all fields.4044 // (Bases are not legal in C++11 but in that case we never get here).4045 if (auto *CRD = llvm::dyn_cast<CXXRecordDecl>(RD)) {4046 for (const auto &Base : CRD->bases())4047 AddChunk(Base.getType().getAsString(Policy));4048 }4049 for (const auto &Field : RD->fields())4050 AddChunk(FormatFunctionParameter(Policy, Field));4051}4052 4053/// Add function overload parameter chunks to the given code completion4054/// string.4055static void AddOverloadParameterChunks(4056 ASTContext &Context, const PrintingPolicy &Policy,4057 const FunctionDecl *Function, const FunctionProtoType *Prototype,4058 FunctionProtoTypeLoc PrototypeLoc, CodeCompletionBuilder &Result,4059 unsigned CurrentArg, unsigned Start = 0, bool InOptional = false) {4060 if (!Function && !Prototype) {4061 Result.AddChunk(CodeCompletionString::CK_CurrentParameter, "...");4062 return;4063 }4064 4065 bool FirstParameter = true;4066 unsigned NumParams =4067 Function ? Function->getNumParams() : Prototype->getNumParams();4068 4069 for (unsigned P = Start; P != NumParams; ++P) {4070 if (Function && Function->getParamDecl(P)->hasDefaultArg() && !InOptional) {4071 // When we see an optional default argument, put that argument and4072 // the remaining default arguments into a new, optional string.4073 CodeCompletionBuilder Opt(Result.getAllocator(),4074 Result.getCodeCompletionTUInfo());4075 if (!FirstParameter)4076 Opt.AddChunk(CodeCompletionString::CK_Comma);4077 // Optional sections are nested.4078 AddOverloadParameterChunks(Context, Policy, Function, Prototype,4079 PrototypeLoc, Opt, CurrentArg, P,4080 /*InOptional=*/true);4081 Result.AddOptionalChunk(Opt.TakeString());4082 return;4083 }4084 4085 // C++23 introduces an explicit object parameter, a.k.a. "deducing this"4086 // Skip it for autocomplete and treat the next parameter as the first4087 // parameter4088 if (Function && FirstParameter &&4089 Function->getParamDecl(P)->isExplicitObjectParameter()) {4090 continue;4091 }4092 4093 if (FirstParameter)4094 FirstParameter = false;4095 else4096 Result.AddChunk(CodeCompletionString::CK_Comma);4097 4098 InOptional = false;4099 4100 // Format the placeholder string.4101 std::string Placeholder;4102 assert(P < Prototype->getNumParams());4103 if (Function || PrototypeLoc) {4104 const ParmVarDecl *Param =4105 Function ? Function->getParamDecl(P) : PrototypeLoc.getParam(P);4106 Placeholder = FormatFunctionParameter(Policy, Param);4107 if (Param->hasDefaultArg())4108 Placeholder += GetDefaultValueString(Param, Context.getSourceManager(),4109 Context.getLangOpts());4110 } else {4111 Placeholder = Prototype->getParamType(P).getAsString(Policy);4112 }4113 4114 if (P == CurrentArg)4115 Result.AddCurrentParameterChunk(4116 Result.getAllocator().CopyString(Placeholder));4117 else4118 Result.AddPlaceholderChunk(Result.getAllocator().CopyString(Placeholder));4119 }4120 4121 if (Prototype && Prototype->isVariadic()) {4122 CodeCompletionBuilder Opt(Result.getAllocator(),4123 Result.getCodeCompletionTUInfo());4124 if (!FirstParameter)4125 Opt.AddChunk(CodeCompletionString::CK_Comma);4126 4127 if (CurrentArg < NumParams)4128 Opt.AddPlaceholderChunk("...");4129 else4130 Opt.AddCurrentParameterChunk("...");4131 4132 Result.AddOptionalChunk(Opt.TakeString());4133 }4134}4135 4136static std::string4137formatTemplateParameterPlaceholder(const NamedDecl *Param, bool &Optional,4138 const PrintingPolicy &Policy) {4139 if (const auto *Type = dyn_cast<TemplateTypeParmDecl>(Param)) {4140 Optional = Type->hasDefaultArgument();4141 } else if (const auto *NonType = dyn_cast<NonTypeTemplateParmDecl>(Param)) {4142 Optional = NonType->hasDefaultArgument();4143 } else if (const auto *Template = dyn_cast<TemplateTemplateParmDecl>(Param)) {4144 Optional = Template->hasDefaultArgument();4145 }4146 std::string Result;4147 llvm::raw_string_ostream OS(Result);4148 Param->print(OS, Policy);4149 return Result;4150}4151 4152static std::string templateResultType(const TemplateDecl *TD,4153 const PrintingPolicy &Policy) {4154 if (const auto *CTD = dyn_cast<ClassTemplateDecl>(TD))4155 return CTD->getTemplatedDecl()->getKindName().str();4156 if (const auto *VTD = dyn_cast<VarTemplateDecl>(TD))4157 return VTD->getTemplatedDecl()->getType().getAsString(Policy);4158 if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(TD))4159 return FTD->getTemplatedDecl()->getReturnType().getAsString(Policy);4160 if (isa<TypeAliasTemplateDecl>(TD))4161 return "type";4162 if (isa<TemplateTemplateParmDecl>(TD))4163 return "class";4164 if (isa<ConceptDecl>(TD))4165 return "concept";4166 return "";4167}4168 4169static CodeCompletionString *createTemplateSignatureString(4170 const TemplateDecl *TD, CodeCompletionBuilder &Builder, unsigned CurrentArg,4171 const PrintingPolicy &Policy) {4172 llvm::ArrayRef<NamedDecl *> Params = TD->getTemplateParameters()->asArray();4173 CodeCompletionBuilder OptionalBuilder(Builder.getAllocator(),4174 Builder.getCodeCompletionTUInfo());4175 std::string ResultType = templateResultType(TD, Policy);4176 if (!ResultType.empty())4177 Builder.AddResultTypeChunk(Builder.getAllocator().CopyString(ResultType));4178 Builder.AddTextChunk(4179 Builder.getAllocator().CopyString(TD->getNameAsString()));4180 Builder.AddChunk(CodeCompletionString::CK_LeftAngle);4181 // Initially we're writing into the main string. Once we see an optional arg4182 // (with default), we're writing into the nested optional chunk.4183 CodeCompletionBuilder *Current = &Builder;4184 for (unsigned I = 0; I < Params.size(); ++I) {4185 bool Optional = false;4186 std::string Placeholder =4187 formatTemplateParameterPlaceholder(Params[I], Optional, Policy);4188 if (Optional)4189 Current = &OptionalBuilder;4190 if (I > 0)4191 Current->AddChunk(CodeCompletionString::CK_Comma);4192 Current->AddChunk(I == CurrentArg4193 ? CodeCompletionString::CK_CurrentParameter4194 : CodeCompletionString::CK_Placeholder,4195 Current->getAllocator().CopyString(Placeholder));4196 }4197 // Add the optional chunk to the main string if we ever used it.4198 if (Current == &OptionalBuilder)4199 Builder.AddOptionalChunk(OptionalBuilder.TakeString());4200 Builder.AddChunk(CodeCompletionString::CK_RightAngle);4201 // For function templates, ResultType was the function's return type.4202 // Give some clue this is a function. (Don't show the possibly-bulky params).4203 if (isa<FunctionTemplateDecl>(TD))4204 Builder.AddInformativeChunk("()");4205 return Builder.TakeString();4206}4207 4208CodeCompletionString *4209CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(4210 unsigned CurrentArg, Sema &S, CodeCompletionAllocator &Allocator,4211 CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments,4212 bool Braced) const {4213 PrintingPolicy Policy = getCompletionPrintingPolicy(S);4214 // Show signatures of constructors as they are declared:4215 // vector(int n) rather than vector<string>(int n)4216 // This is less noisy without being less clear, and avoids tricky cases.4217 Policy.SuppressTemplateArgsInCXXConstructors = true;4218 4219 // FIXME: Set priority, availability appropriately.4220 CodeCompletionBuilder Result(Allocator, CCTUInfo, 1,4221 CXAvailability_Available);4222 4223 if (getKind() == CK_Template)4224 return createTemplateSignatureString(getTemplate(), Result, CurrentArg,4225 Policy);4226 4227 FunctionDecl *FDecl = getFunction();4228 const FunctionProtoType *Proto =4229 dyn_cast_or_null<FunctionProtoType>(getFunctionType());4230 4231 // First, the name/type of the callee.4232 if (getKind() == CK_Aggregate) {4233 Result.AddTextChunk(4234 Result.getAllocator().CopyString(getAggregate()->getName()));4235 } else if (FDecl) {4236 if (IncludeBriefComments) {4237 if (auto RC = getParameterComment(S.getASTContext(), *this, CurrentArg))4238 Result.addBriefComment(RC->getBriefText(S.getASTContext()));4239 }4240 AddResultTypeChunk(S.Context, Policy, FDecl, QualType(), Result);4241 4242 std::string Name;4243 llvm::raw_string_ostream OS(Name);4244 FDecl->getDeclName().print(OS, Policy);4245 Result.AddTextChunk(Result.getAllocator().CopyString(Name));4246 } else {4247 // Function without a declaration. Just give the return type.4248 Result.AddResultTypeChunk(Result.getAllocator().CopyString(4249 getFunctionType()->getReturnType().getAsString(Policy)));4250 }4251 4252 // Next, the brackets and parameters.4253 Result.AddChunk(Braced ? CodeCompletionString::CK_LeftBrace4254 : CodeCompletionString::CK_LeftParen);4255 if (getKind() == CK_Aggregate)4256 AddOverloadAggregateChunks(getAggregate(), Policy, Result, CurrentArg);4257 else4258 AddOverloadParameterChunks(S.getASTContext(), Policy, FDecl, Proto,4259 getFunctionProtoTypeLoc(), Result, CurrentArg);4260 Result.AddChunk(Braced ? CodeCompletionString::CK_RightBrace4261 : CodeCompletionString::CK_RightParen);4262 4263 return Result.TakeString();4264}4265 4266unsigned clang::getMacroUsagePriority(StringRef MacroName,4267 const LangOptions &LangOpts,4268 bool PreferredTypeIsPointer) {4269 unsigned Priority = CCP_Macro;4270 4271 // Treat the "nil", "Nil" and "NULL" macros as null pointer constants.4272 if (MacroName == "nil" || MacroName == "NULL" || MacroName == "Nil") {4273 Priority = CCP_Constant;4274 if (PreferredTypeIsPointer)4275 Priority = Priority / CCF_SimilarTypeMatch;4276 }4277 // Treat "YES", "NO", "true", and "false" as constants.4278 else if (MacroName == "YES" || MacroName == "NO" || MacroName == "true" ||4279 MacroName == "false")4280 Priority = CCP_Constant;4281 // Treat "bool" as a type.4282 else if (MacroName == "bool")4283 Priority = CCP_Type + (LangOpts.ObjC ? CCD_bool_in_ObjC : 0);4284 4285 return Priority;4286}4287 4288CXCursorKind clang::getCursorKindForDecl(const Decl *D) {4289 if (!D)4290 return CXCursor_UnexposedDecl;4291 4292 switch (D->getKind()) {4293 case Decl::Enum:4294 return CXCursor_EnumDecl;4295 case Decl::EnumConstant:4296 return CXCursor_EnumConstantDecl;4297 case Decl::Field:4298 return CXCursor_FieldDecl;4299 case Decl::Function:4300 return CXCursor_FunctionDecl;4301 case Decl::ObjCCategory:4302 return CXCursor_ObjCCategoryDecl;4303 case Decl::ObjCCategoryImpl:4304 return CXCursor_ObjCCategoryImplDecl;4305 case Decl::ObjCImplementation:4306 return CXCursor_ObjCImplementationDecl;4307 4308 case Decl::ObjCInterface:4309 return CXCursor_ObjCInterfaceDecl;4310 case Decl::ObjCIvar:4311 return CXCursor_ObjCIvarDecl;4312 case Decl::ObjCMethod:4313 return cast<ObjCMethodDecl>(D)->isInstanceMethod()4314 ? CXCursor_ObjCInstanceMethodDecl4315 : CXCursor_ObjCClassMethodDecl;4316 case Decl::CXXMethod:4317 return CXCursor_CXXMethod;4318 case Decl::CXXConstructor:4319 return CXCursor_Constructor;4320 case Decl::CXXDestructor:4321 return CXCursor_Destructor;4322 case Decl::CXXConversion:4323 return CXCursor_ConversionFunction;4324 case Decl::ObjCProperty:4325 return CXCursor_ObjCPropertyDecl;4326 case Decl::ObjCProtocol:4327 return CXCursor_ObjCProtocolDecl;4328 case Decl::ParmVar:4329 return CXCursor_ParmDecl;4330 case Decl::Typedef:4331 return CXCursor_TypedefDecl;4332 case Decl::TypeAlias:4333 return CXCursor_TypeAliasDecl;4334 case Decl::TypeAliasTemplate:4335 return CXCursor_TypeAliasTemplateDecl;4336 case Decl::Var:4337 return CXCursor_VarDecl;4338 case Decl::Namespace:4339 return CXCursor_Namespace;4340 case Decl::NamespaceAlias:4341 return CXCursor_NamespaceAlias;4342 case Decl::TemplateTypeParm:4343 return CXCursor_TemplateTypeParameter;4344 case Decl::NonTypeTemplateParm:4345 return CXCursor_NonTypeTemplateParameter;4346 case Decl::TemplateTemplateParm:4347 return CXCursor_TemplateTemplateParameter;4348 case Decl::FunctionTemplate:4349 return CXCursor_FunctionTemplate;4350 case Decl::ClassTemplate:4351 return CXCursor_ClassTemplate;4352 case Decl::AccessSpec:4353 return CXCursor_CXXAccessSpecifier;4354 case Decl::ClassTemplatePartialSpecialization:4355 return CXCursor_ClassTemplatePartialSpecialization;4356 case Decl::UsingDirective:4357 return CXCursor_UsingDirective;4358 case Decl::StaticAssert:4359 return CXCursor_StaticAssert;4360 case Decl::Friend:4361 return CXCursor_FriendDecl;4362 case Decl::TranslationUnit:4363 return CXCursor_TranslationUnit;4364 4365 case Decl::Using:4366 case Decl::UnresolvedUsingValue:4367 case Decl::UnresolvedUsingTypename:4368 return CXCursor_UsingDeclaration;4369 4370 case Decl::UsingEnum:4371 return CXCursor_EnumDecl;4372 4373 case Decl::ObjCPropertyImpl:4374 switch (cast<ObjCPropertyImplDecl>(D)->getPropertyImplementation()) {4375 case ObjCPropertyImplDecl::Dynamic:4376 return CXCursor_ObjCDynamicDecl;4377 4378 case ObjCPropertyImplDecl::Synthesize:4379 return CXCursor_ObjCSynthesizeDecl;4380 }4381 llvm_unreachable("Unexpected Kind!");4382 4383 case Decl::Import:4384 return CXCursor_ModuleImportDecl;4385 4386 case Decl::ObjCTypeParam:4387 return CXCursor_TemplateTypeParameter;4388 4389 case Decl::Concept:4390 return CXCursor_ConceptDecl;4391 4392 case Decl::LinkageSpec:4393 return CXCursor_LinkageSpec;4394 4395 default:4396 if (const auto *TD = dyn_cast<TagDecl>(D)) {4397 switch (TD->getTagKind()) {4398 case TagTypeKind::Interface: // fall through4399 case TagTypeKind::Struct:4400 return CXCursor_StructDecl;4401 case TagTypeKind::Class:4402 return CXCursor_ClassDecl;4403 case TagTypeKind::Union:4404 return CXCursor_UnionDecl;4405 case TagTypeKind::Enum:4406 return CXCursor_EnumDecl;4407 }4408 }4409 }4410 4411 return CXCursor_UnexposedDecl;4412}4413 4414static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results,4415 bool LoadExternal, bool IncludeUndefined,4416 bool TargetTypeIsPointer = false) {4417 typedef CodeCompletionResult Result;4418 4419 Results.EnterNewScope();4420 4421 for (Preprocessor::macro_iterator M = PP.macro_begin(LoadExternal),4422 MEnd = PP.macro_end(LoadExternal);4423 M != MEnd; ++M) {4424 auto MD = PP.getMacroDefinition(M->first);4425 if (IncludeUndefined || MD) {4426 MacroInfo *MI = MD.getMacroInfo();4427 if (MI && MI->isUsedForHeaderGuard())4428 continue;4429 4430 Results.AddResult(4431 Result(M->first, MI,4432 getMacroUsagePriority(M->first->getName(), PP.getLangOpts(),4433 TargetTypeIsPointer)));4434 }4435 }4436 4437 Results.ExitScope();4438}4439 4440static void AddPrettyFunctionResults(const LangOptions &LangOpts,4441 ResultBuilder &Results) {4442 typedef CodeCompletionResult Result;4443 4444 Results.EnterNewScope();4445 4446 Results.AddResult(Result("__PRETTY_FUNCTION__", CCP_Constant));4447 Results.AddResult(Result("__FUNCTION__", CCP_Constant));4448 if (LangOpts.C99 || LangOpts.CPlusPlus11)4449 Results.AddResult(Result("__func__", CCP_Constant));4450 Results.ExitScope();4451}4452 4453static void HandleCodeCompleteResults(Sema *S,4454 CodeCompleteConsumer *CodeCompleter,4455 const CodeCompletionContext &Context,4456 CodeCompletionResult *Results,4457 unsigned NumResults) {4458 if (CodeCompleter)4459 CodeCompleter->ProcessCodeCompleteResults(*S, Context, Results, NumResults);4460}4461 4462static CodeCompletionContext4463mapCodeCompletionContext(Sema &S,4464 SemaCodeCompletion::ParserCompletionContext PCC) {4465 switch (PCC) {4466 case SemaCodeCompletion::PCC_Namespace:4467 return CodeCompletionContext::CCC_TopLevel;4468 4469 case SemaCodeCompletion::PCC_Class:4470 return CodeCompletionContext::CCC_ClassStructUnion;4471 4472 case SemaCodeCompletion::PCC_ObjCInterface:4473 return CodeCompletionContext::CCC_ObjCInterface;4474 4475 case SemaCodeCompletion::PCC_ObjCImplementation:4476 return CodeCompletionContext::CCC_ObjCImplementation;4477 4478 case SemaCodeCompletion::PCC_ObjCInstanceVariableList:4479 return CodeCompletionContext::CCC_ObjCIvarList;4480 4481 case SemaCodeCompletion::PCC_Template:4482 case SemaCodeCompletion::PCC_MemberTemplate:4483 if (S.CurContext->isFileContext())4484 return CodeCompletionContext::CCC_TopLevel;4485 if (S.CurContext->isRecord())4486 return CodeCompletionContext::CCC_ClassStructUnion;4487 return CodeCompletionContext::CCC_Other;4488 4489 case SemaCodeCompletion::PCC_RecoveryInFunction:4490 return CodeCompletionContext::CCC_Recovery;4491 4492 case SemaCodeCompletion::PCC_ForInit:4493 if (S.getLangOpts().CPlusPlus || S.getLangOpts().C99 ||4494 S.getLangOpts().ObjC)4495 return CodeCompletionContext::CCC_ParenthesizedExpression;4496 else4497 return CodeCompletionContext::CCC_Expression;4498 4499 case SemaCodeCompletion::PCC_Expression:4500 return CodeCompletionContext::CCC_Expression;4501 case SemaCodeCompletion::PCC_Condition:4502 return CodeCompletionContext(CodeCompletionContext::CCC_Expression,4503 S.getASTContext().BoolTy);4504 4505 case SemaCodeCompletion::PCC_Statement:4506 return CodeCompletionContext::CCC_Statement;4507 4508 case SemaCodeCompletion::PCC_Type:4509 return CodeCompletionContext::CCC_Type;4510 4511 case SemaCodeCompletion::PCC_ParenthesizedExpression:4512 return CodeCompletionContext::CCC_ParenthesizedExpression;4513 4514 case SemaCodeCompletion::PCC_LocalDeclarationSpecifiers:4515 return CodeCompletionContext::CCC_Type;4516 case SemaCodeCompletion::PCC_TopLevelOrExpression:4517 return CodeCompletionContext::CCC_TopLevelOrExpression;4518 }4519 4520 llvm_unreachable("Invalid ParserCompletionContext!");4521}4522 4523/// If we're in a C++ virtual member function, add completion results4524/// that invoke the functions we override, since it's common to invoke the4525/// overridden function as well as adding new functionality.4526///4527/// \param S The semantic analysis object for which we are generating results.4528///4529/// \param InContext This context in which the nested-name-specifier preceding4530/// the code-completion point4531static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,4532 ResultBuilder &Results) {4533 // Look through blocks.4534 DeclContext *CurContext = S.CurContext;4535 while (isa<BlockDecl>(CurContext))4536 CurContext = CurContext->getParent();4537 4538 CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(CurContext);4539 if (!Method || !Method->isVirtual())4540 return;4541 4542 // We need to have names for all of the parameters, if we're going to4543 // generate a forwarding call.4544 for (auto *P : Method->parameters())4545 if (!P->getDeclName())4546 return;4547 4548 PrintingPolicy Policy = getCompletionPrintingPolicy(S);4549 for (const CXXMethodDecl *Overridden : Method->overridden_methods()) {4550 CodeCompletionBuilder Builder(Results.getAllocator(),4551 Results.getCodeCompletionTUInfo());4552 if (Overridden->getCanonicalDecl() == Method->getCanonicalDecl())4553 continue;4554 4555 // If we need a nested-name-specifier, add one now.4556 if (!InContext) {4557 NestedNameSpecifier NNS = getRequiredQualification(4558 S.Context, CurContext, Overridden->getDeclContext());4559 if (NNS) {4560 std::string Str;4561 llvm::raw_string_ostream OS(Str);4562 NNS.print(OS, Policy);4563 Builder.AddTextChunk(Results.getAllocator().CopyString(Str));4564 }4565 } else if (!InContext->Equals(Overridden->getDeclContext()))4566 continue;4567 4568 Builder.AddTypedTextChunk(4569 Results.getAllocator().CopyString(Overridden->getNameAsString()));4570 Builder.AddChunk(CodeCompletionString::CK_LeftParen);4571 bool FirstParam = true;4572 for (auto *P : Method->parameters()) {4573 if (FirstParam)4574 FirstParam = false;4575 else4576 Builder.AddChunk(CodeCompletionString::CK_Comma);4577 4578 Builder.AddPlaceholderChunk(4579 Results.getAllocator().CopyString(P->getIdentifier()->getName()));4580 }4581 Builder.AddChunk(CodeCompletionString::CK_RightParen);4582 Results.AddResult(CodeCompletionResult(4583 Builder.TakeString(), CCP_SuperCompletion, CXCursor_CXXMethod,4584 CXAvailability_Available, Overridden));4585 Results.Ignore(Overridden);4586 }4587}4588 4589void SemaCodeCompletion::CodeCompleteModuleImport(SourceLocation ImportLoc,4590 ModuleIdPath Path) {4591 typedef CodeCompletionResult Result;4592 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),4593 CodeCompleter->getCodeCompletionTUInfo(),4594 CodeCompletionContext::CCC_Other);4595 Results.EnterNewScope();4596 4597 CodeCompletionAllocator &Allocator = Results.getAllocator();4598 CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo());4599 typedef CodeCompletionResult Result;4600 if (Path.empty()) {4601 // Enumerate all top-level modules.4602 SmallVector<Module *, 8> Modules;4603 SemaRef.PP.getHeaderSearchInfo().collectAllModules(Modules);4604 for (unsigned I = 0, N = Modules.size(); I != N; ++I) {4605 Builder.AddTypedTextChunk(4606 Builder.getAllocator().CopyString(Modules[I]->Name));4607 Results.AddResult(Result(4608 Builder.TakeString(), CCP_Declaration, CXCursor_ModuleImportDecl,4609 Modules[I]->isAvailable() ? CXAvailability_Available4610 : CXAvailability_NotAvailable));4611 }4612 } else if (getLangOpts().Modules) {4613 // Load the named module.4614 Module *Mod = SemaRef.PP.getModuleLoader().loadModule(4615 ImportLoc, Path, Module::AllVisible,4616 /*IsInclusionDirective=*/false);4617 // Enumerate submodules.4618 if (Mod) {4619 for (auto *Submodule : Mod->submodules()) {4620 Builder.AddTypedTextChunk(4621 Builder.getAllocator().CopyString(Submodule->Name));4622 Results.AddResult(Result(4623 Builder.TakeString(), CCP_Declaration, CXCursor_ModuleImportDecl,4624 Submodule->isAvailable() ? CXAvailability_Available4625 : CXAvailability_NotAvailable));4626 }4627 }4628 }4629 Results.ExitScope();4630 HandleCodeCompleteResults(&SemaRef, CodeCompleter,4631 Results.getCompletionContext(), Results.data(),4632 Results.size());4633}4634 4635void SemaCodeCompletion::CodeCompleteOrdinaryName(4636 Scope *S, SemaCodeCompletion::ParserCompletionContext CompletionContext) {4637 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),4638 CodeCompleter->getCodeCompletionTUInfo(),4639 mapCodeCompletionContext(SemaRef, CompletionContext));4640 Results.EnterNewScope();4641 4642 // Determine how to filter results, e.g., so that the names of4643 // values (functions, enumerators, function templates, etc.) are4644 // only allowed where we can have an expression.4645 switch (CompletionContext) {4646 case PCC_Namespace:4647 case PCC_Class:4648 case PCC_ObjCInterface:4649 case PCC_ObjCImplementation:4650 case PCC_ObjCInstanceVariableList:4651 case PCC_Template:4652 case PCC_MemberTemplate:4653 case PCC_Type:4654 case PCC_LocalDeclarationSpecifiers:4655 Results.setFilter(&ResultBuilder::IsOrdinaryNonValueName);4656 break;4657 4658 case PCC_Statement:4659 case PCC_TopLevelOrExpression:4660 case PCC_ParenthesizedExpression:4661 case PCC_Expression:4662 case PCC_ForInit:4663 case PCC_Condition:4664 if (WantTypesInContext(CompletionContext, getLangOpts()))4665 Results.setFilter(&ResultBuilder::IsOrdinaryName);4666 else4667 Results.setFilter(&ResultBuilder::IsOrdinaryNonTypeName);4668 4669 if (getLangOpts().CPlusPlus)4670 MaybeAddOverrideCalls(SemaRef, /*InContext=*/nullptr, Results);4671 break;4672 4673 case PCC_RecoveryInFunction:4674 // Unfiltered4675 break;4676 }4677 4678 auto ThisType = SemaRef.getCurrentThisType();4679 if (ThisType.isNull()) {4680 // check if function scope is an explicit object function4681 if (auto *MethodDecl = llvm::dyn_cast_if_present<CXXMethodDecl>(4682 SemaRef.getCurFunctionDecl()))4683 Results.setExplicitObjectMemberFn(4684 MethodDecl->isExplicitObjectMemberFunction());4685 } else {4686 // If we are in a C++ non-static member function, check the qualifiers on4687 // the member function to filter/prioritize the results list.4688 Results.setObjectTypeQualifiers(ThisType->getPointeeType().getQualifiers(),4689 VK_LValue);4690 }4691 4692 CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext);4693 SemaRef.LookupVisibleDecls(S, SemaRef.LookupOrdinaryName, Consumer,4694 CodeCompleter->includeGlobals(),4695 CodeCompleter->loadExternal());4696 4697 AddOrdinaryNameResults(CompletionContext, S, SemaRef, Results);4698 Results.ExitScope();4699 4700 switch (CompletionContext) {4701 case PCC_ParenthesizedExpression:4702 case PCC_Expression:4703 case PCC_Statement:4704 case PCC_TopLevelOrExpression:4705 case PCC_RecoveryInFunction:4706 if (S->getFnParent())4707 AddPrettyFunctionResults(getLangOpts(), Results);4708 break;4709 4710 case PCC_Namespace:4711 case PCC_Class:4712 case PCC_ObjCInterface:4713 case PCC_ObjCImplementation:4714 case PCC_ObjCInstanceVariableList:4715 case PCC_Template:4716 case PCC_MemberTemplate:4717 case PCC_ForInit:4718 case PCC_Condition:4719 case PCC_Type:4720 case PCC_LocalDeclarationSpecifiers:4721 break;4722 }4723 4724 if (CodeCompleter->includeMacros())4725 AddMacroResults(SemaRef.PP, Results, CodeCompleter->loadExternal(), false);4726 4727 HandleCodeCompleteResults(&SemaRef, CodeCompleter,4728 Results.getCompletionContext(), Results.data(),4729 Results.size());4730}4731 4732static void4733AddClassMessageCompletions(Sema &SemaRef, Scope *S, ParsedType Receiver,4734 ArrayRef<const IdentifierInfo *> SelIdents,4735 bool AtArgumentExpression, bool IsSuper,4736 ResultBuilder &Results);4737 4738void SemaCodeCompletion::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS,4739 bool AllowNonIdentifiers,4740 bool AllowNestedNameSpecifiers) {4741 typedef CodeCompletionResult Result;4742 ResultBuilder Results(4743 SemaRef, CodeCompleter->getAllocator(),4744 CodeCompleter->getCodeCompletionTUInfo(),4745 AllowNestedNameSpecifiers4746 // FIXME: Try to separate codepath leading here to deduce whether we4747 // need an existing symbol or a new one.4748 ? CodeCompletionContext::CCC_SymbolOrNewName4749 : CodeCompletionContext::CCC_NewName);4750 Results.EnterNewScope();4751 4752 // Type qualifiers can come after names.4753 Results.AddResult(Result("const"));4754 Results.AddResult(Result("volatile"));4755 if (getLangOpts().C99)4756 Results.AddResult(Result("restrict"));4757 4758 if (getLangOpts().CPlusPlus) {4759 if (getLangOpts().CPlusPlus11 &&4760 (DS.getTypeSpecType() == DeclSpec::TST_class ||4761 DS.getTypeSpecType() == DeclSpec::TST_struct))4762 Results.AddResult("final");4763 4764 if (AllowNonIdentifiers) {4765 Results.AddResult(Result("operator"));4766 }4767 4768 // Add nested-name-specifiers.4769 if (AllowNestedNameSpecifiers) {4770 Results.allowNestedNameSpecifiers();4771 Results.setFilter(&ResultBuilder::IsImpossibleToSatisfy);4772 CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext);4773 SemaRef.LookupVisibleDecls(S, Sema::LookupNestedNameSpecifierName,4774 Consumer, CodeCompleter->includeGlobals(),4775 CodeCompleter->loadExternal());4776 Results.setFilter(nullptr);4777 }4778 }4779 Results.ExitScope();4780 4781 // If we're in a context where we might have an expression (rather than a4782 // declaration), and what we've seen so far is an Objective-C type that could4783 // be a receiver of a class message, this may be a class message send with4784 // the initial opening bracket '[' missing. Add appropriate completions.4785 if (AllowNonIdentifiers && !AllowNestedNameSpecifiers &&4786 DS.getParsedSpecifiers() == DeclSpec::PQ_TypeSpecifier &&4787 DS.getTypeSpecType() == DeclSpec::TST_typename &&4788 DS.getTypeSpecComplex() == DeclSpec::TSC_unspecified &&4789 DS.getTypeSpecSign() == TypeSpecifierSign::Unspecified &&4790 !DS.isTypeAltiVecVector() && S &&4791 (S->getFlags() & Scope::DeclScope) != 0 &&4792 (S->getFlags() & (Scope::ClassScope | Scope::TemplateParamScope |4793 Scope::FunctionPrototypeScope | Scope::AtCatchScope)) ==4794 0) {4795 ParsedType T = DS.getRepAsType();4796 if (!T.get().isNull() && T.get()->isObjCObjectOrInterfaceType())4797 AddClassMessageCompletions(SemaRef, S, T, {}, false, false, Results);4798 }4799 4800 // Note that we intentionally suppress macro results here, since we do not4801 // encourage using macros to produce the names of entities.4802 4803 HandleCodeCompleteResults(&SemaRef, CodeCompleter,4804 Results.getCompletionContext(), Results.data(),4805 Results.size());4806}4807 4808static const char *underscoreAttrScope(llvm::StringRef Scope) {4809 if (Scope == "clang")4810 return "_Clang";4811 if (Scope == "gnu")4812 return "__gnu__";4813 return nullptr;4814}4815 4816static const char *noUnderscoreAttrScope(llvm::StringRef Scope) {4817 if (Scope == "_Clang")4818 return "clang";4819 if (Scope == "__gnu__")4820 return "gnu";4821 return nullptr;4822}4823 4824void SemaCodeCompletion::CodeCompleteAttribute(4825 AttributeCommonInfo::Syntax Syntax, AttributeCompletion Completion,4826 const IdentifierInfo *InScope) {4827 if (Completion == AttributeCompletion::None)4828 return;4829 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),4830 CodeCompleter->getCodeCompletionTUInfo(),4831 CodeCompletionContext::CCC_Attribute);4832 4833 // We're going to iterate over the normalized spellings of the attribute.4834 // These don't include "underscore guarding": the normalized spelling is4835 // clang::foo but you can also write _Clang::__foo__.4836 //4837 // (Clang supports a mix like clang::__foo__ but we won't suggest it: either4838 // you care about clashing with macros or you don't).4839 //4840 // So if we're already in a scope, we determine its canonical spellings4841 // (for comparison with normalized attr spelling) and remember whether it was4842 // underscore-guarded (so we know how to spell contained attributes).4843 llvm::StringRef InScopeName;4844 bool InScopeUnderscore = false;4845 if (InScope) {4846 InScopeName = InScope->getName();4847 if (const char *NoUnderscore = noUnderscoreAttrScope(InScopeName)) {4848 InScopeName = NoUnderscore;4849 InScopeUnderscore = true;4850 }4851 }4852 bool SyntaxSupportsGuards = Syntax == AttributeCommonInfo::AS_GNU ||4853 Syntax == AttributeCommonInfo::AS_CXX11 ||4854 Syntax == AttributeCommonInfo::AS_C23;4855 4856 llvm::DenseSet<llvm::StringRef> FoundScopes;4857 auto AddCompletions = [&](const ParsedAttrInfo &A) {4858 if (A.IsTargetSpecific &&4859 !A.existsInTarget(getASTContext().getTargetInfo()))4860 return;4861 if (!A.acceptsLangOpts(getLangOpts()))4862 return;4863 for (const auto &S : A.Spellings) {4864 if (S.Syntax != Syntax)4865 continue;4866 llvm::StringRef Name = S.NormalizedFullName;4867 llvm::StringRef Scope;4868 if ((Syntax == AttributeCommonInfo::AS_CXX11 ||4869 Syntax == AttributeCommonInfo::AS_C23)) {4870 std::tie(Scope, Name) = Name.split("::");4871 if (Name.empty()) // oops, unscoped4872 std::swap(Name, Scope);4873 }4874 4875 // Do we just want a list of scopes rather than attributes?4876 if (Completion == AttributeCompletion::Scope) {4877 // Make sure to emit each scope only once.4878 if (!Scope.empty() && FoundScopes.insert(Scope).second) {4879 Results.AddResult(4880 CodeCompletionResult(Results.getAllocator().CopyString(Scope)));4881 // Include alternate form (__gnu__ instead of gnu).4882 if (const char *Scope2 = underscoreAttrScope(Scope))4883 Results.AddResult(CodeCompletionResult(Scope2));4884 }4885 continue;4886 }4887 4888 // If a scope was specified, it must match but we don't need to print it.4889 if (!InScopeName.empty()) {4890 if (Scope != InScopeName)4891 continue;4892 Scope = "";4893 }4894 4895 auto Add = [&](llvm::StringRef Scope, llvm::StringRef Name,4896 bool Underscores) {4897 CodeCompletionBuilder Builder(Results.getAllocator(),4898 Results.getCodeCompletionTUInfo());4899 llvm::SmallString<32> Text;4900 if (!Scope.empty()) {4901 Text.append(Scope);4902 Text.append("::");4903 }4904 if (Underscores)4905 Text.append("__");4906 Text.append(Name);4907 if (Underscores)4908 Text.append("__");4909 Builder.AddTypedTextChunk(Results.getAllocator().CopyString(Text));4910 4911 if (!A.ArgNames.empty()) {4912 Builder.AddChunk(CodeCompletionString::CK_LeftParen, "(");4913 bool First = true;4914 for (const char *Arg : A.ArgNames) {4915 if (!First)4916 Builder.AddChunk(CodeCompletionString::CK_Comma, ", ");4917 First = false;4918 Builder.AddPlaceholderChunk(Arg);4919 }4920 Builder.AddChunk(CodeCompletionString::CK_RightParen, ")");4921 }4922 4923 Results.AddResult(Builder.TakeString());4924 };4925 4926 // Generate the non-underscore-guarded result.4927 // Note this is (a suffix of) the NormalizedFullName, no need to copy.4928 // If an underscore-guarded scope was specified, only the4929 // underscore-guarded attribute name is relevant.4930 if (!InScopeUnderscore)4931 Add(Scope, Name, /*Underscores=*/false);4932 4933 // Generate the underscore-guarded version, for syntaxes that support it.4934 // We skip this if the scope was already spelled and not guarded, or4935 // we must spell it and can't guard it.4936 if (!(InScope && !InScopeUnderscore) && SyntaxSupportsGuards) {4937 if (Scope.empty()) {4938 Add(Scope, Name, /*Underscores=*/true);4939 } else {4940 const char *GuardedScope = underscoreAttrScope(Scope);4941 if (!GuardedScope)4942 continue;4943 Add(GuardedScope, Name, /*Underscores=*/true);4944 }4945 }4946 4947 // It may be nice to include the Kind so we can look up the docs later.4948 }4949 };4950 4951 for (const auto *A : ParsedAttrInfo::getAllBuiltin())4952 AddCompletions(*A);4953 for (const auto &Entry : ParsedAttrInfoRegistry::entries())4954 AddCompletions(*Entry.instantiate());4955 4956 HandleCodeCompleteResults(&SemaRef, CodeCompleter,4957 Results.getCompletionContext(), Results.data(),4958 Results.size());4959}4960 4961struct SemaCodeCompletion::CodeCompleteExpressionData {4962 CodeCompleteExpressionData(QualType PreferredType = QualType(),4963 bool IsParenthesized = false)4964 : PreferredType(PreferredType), IntegralConstantExpression(false),4965 ObjCCollection(false), IsParenthesized(IsParenthesized) {}4966 4967 QualType PreferredType;4968 bool IntegralConstantExpression;4969 bool ObjCCollection;4970 bool IsParenthesized;4971 SmallVector<Decl *, 4> IgnoreDecls;4972};4973 4974namespace {4975/// Information that allows to avoid completing redundant enumerators.4976struct CoveredEnumerators {4977 llvm::SmallPtrSet<EnumConstantDecl *, 8> Seen;4978 NestedNameSpecifier SuggestedQualifier = std::nullopt;4979};4980} // namespace4981 4982static void AddEnumerators(ResultBuilder &Results, ASTContext &Context,4983 EnumDecl *Enum, DeclContext *CurContext,4984 const CoveredEnumerators &Enumerators) {4985 NestedNameSpecifier Qualifier = Enumerators.SuggestedQualifier;4986 if (Context.getLangOpts().CPlusPlus && !Qualifier && Enumerators.Seen.empty()) {4987 // If there are no prior enumerators in C++, check whether we have to4988 // qualify the names of the enumerators that we suggest, because they4989 // may not be visible in this scope.4990 Qualifier = getRequiredQualification(Context, CurContext, Enum);4991 }4992 4993 Results.EnterNewScope();4994 for (auto *E : Enum->enumerators()) {4995 if (Enumerators.Seen.count(E))4996 continue;4997 4998 CodeCompletionResult R(E, CCP_EnumInCase, Qualifier);4999 Results.AddResult(R, CurContext, nullptr, false);5000 }5001 Results.ExitScope();5002}5003 5004/// Try to find a corresponding FunctionProtoType for function-like types (e.g.5005/// function pointers, std::function, etc).5006static const FunctionProtoType *TryDeconstructFunctionLike(QualType T) {5007 assert(!T.isNull());5008 // Try to extract first template argument from std::function<> and similar.5009 // Note we only handle the sugared types, they closely match what users wrote.5010 // We explicitly choose to not handle ClassTemplateSpecializationDecl.5011 if (auto *Specialization = T->getAs<TemplateSpecializationType>()) {5012 if (Specialization->template_arguments().size() != 1)5013 return nullptr;5014 const TemplateArgument &Argument = Specialization->template_arguments()[0];5015 if (Argument.getKind() != TemplateArgument::Type)5016 return nullptr;5017 return Argument.getAsType()->getAs<FunctionProtoType>();5018 }5019 // Handle other cases.5020 if (T->isPointerType())5021 T = T->getPointeeType();5022 return T->getAs<FunctionProtoType>();5023}5024 5025/// Adds a pattern completion for a lambda expression with the specified5026/// parameter types and placeholders for parameter names.5027static void AddLambdaCompletion(ResultBuilder &Results,5028 llvm::ArrayRef<QualType> Parameters,5029 const LangOptions &LangOpts) {5030 if (!Results.includeCodePatterns())5031 return;5032 CodeCompletionBuilder Completion(Results.getAllocator(),5033 Results.getCodeCompletionTUInfo());5034 // [](<parameters>) {}5035 Completion.AddChunk(CodeCompletionString::CK_LeftBracket);5036 Completion.AddPlaceholderChunk("=");5037 Completion.AddChunk(CodeCompletionString::CK_RightBracket);5038 if (!Parameters.empty()) {5039 Completion.AddChunk(CodeCompletionString::CK_LeftParen);5040 bool First = true;5041 for (auto Parameter : Parameters) {5042 if (!First)5043 Completion.AddChunk(CodeCompletionString::ChunkKind::CK_Comma);5044 else5045 First = false;5046 5047 constexpr llvm::StringLiteral NamePlaceholder = "!#!NAME_GOES_HERE!#!";5048 std::string Type = std::string(NamePlaceholder);5049 Parameter.getAsStringInternal(Type, PrintingPolicy(LangOpts));5050 llvm::StringRef Prefix, Suffix;5051 std::tie(Prefix, Suffix) = llvm::StringRef(Type).split(NamePlaceholder);5052 Prefix = Prefix.rtrim();5053 Suffix = Suffix.ltrim();5054 5055 Completion.AddTextChunk(Completion.getAllocator().CopyString(Prefix));5056 Completion.AddChunk(CodeCompletionString::CK_HorizontalSpace);5057 Completion.AddPlaceholderChunk("parameter");5058 Completion.AddTextChunk(Completion.getAllocator().CopyString(Suffix));5059 };5060 Completion.AddChunk(CodeCompletionString::CK_RightParen);5061 }5062 Completion.AddChunk(clang::CodeCompletionString::CK_HorizontalSpace);5063 Completion.AddChunk(CodeCompletionString::CK_LeftBrace);5064 Completion.AddChunk(CodeCompletionString::CK_HorizontalSpace);5065 Completion.AddPlaceholderChunk("body");5066 Completion.AddChunk(CodeCompletionString::CK_HorizontalSpace);5067 Completion.AddChunk(CodeCompletionString::CK_RightBrace);5068 5069 Results.AddResult(Completion.TakeString());5070}5071 5072/// Perform code-completion in an expression context when we know what5073/// type we're looking for.5074void SemaCodeCompletion::CodeCompleteExpression(5075 Scope *S, const CodeCompleteExpressionData &Data) {5076 ResultBuilder Results(5077 SemaRef, CodeCompleter->getAllocator(),5078 CodeCompleter->getCodeCompletionTUInfo(),5079 CodeCompletionContext(5080 Data.IsParenthesized5081 ? CodeCompletionContext::CCC_ParenthesizedExpression5082 : CodeCompletionContext::CCC_Expression,5083 Data.PreferredType));5084 auto PCC =5085 Data.IsParenthesized ? PCC_ParenthesizedExpression : PCC_Expression;5086 if (Data.ObjCCollection)5087 Results.setFilter(&ResultBuilder::IsObjCCollection);5088 else if (Data.IntegralConstantExpression)5089 Results.setFilter(&ResultBuilder::IsIntegralConstantValue);5090 else if (WantTypesInContext(PCC, getLangOpts()))5091 Results.setFilter(&ResultBuilder::IsOrdinaryName);5092 else5093 Results.setFilter(&ResultBuilder::IsOrdinaryNonTypeName);5094 5095 if (!Data.PreferredType.isNull())5096 Results.setPreferredType(Data.PreferredType.getNonReferenceType());5097 5098 // Ignore any declarations that we were told that we don't care about.5099 for (unsigned I = 0, N = Data.IgnoreDecls.size(); I != N; ++I)5100 Results.Ignore(Data.IgnoreDecls[I]);5101 5102 CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext);5103 SemaRef.LookupVisibleDecls(S, Sema::LookupOrdinaryName, Consumer,5104 CodeCompleter->includeGlobals(),5105 CodeCompleter->loadExternal());5106 5107 Results.EnterNewScope();5108 AddOrdinaryNameResults(PCC, S, SemaRef, Results);5109 Results.ExitScope();5110 5111 bool PreferredTypeIsPointer = false;5112 if (!Data.PreferredType.isNull()) {5113 PreferredTypeIsPointer = Data.PreferredType->isAnyPointerType() ||5114 Data.PreferredType->isMemberPointerType() ||5115 Data.PreferredType->isBlockPointerType();5116 if (auto *Enum = Data.PreferredType->getAsEnumDecl()) {5117 // FIXME: collect covered enumerators in cases like:5118 // if (x == my_enum::one) { ... } else if (x == ^) {}5119 AddEnumerators(Results, getASTContext(), Enum, SemaRef.CurContext,5120 CoveredEnumerators());5121 }5122 }5123 5124 if (S->getFnParent() && !Data.ObjCCollection &&5125 !Data.IntegralConstantExpression)5126 AddPrettyFunctionResults(getLangOpts(), Results);5127 5128 if (CodeCompleter->includeMacros())5129 AddMacroResults(SemaRef.PP, Results, CodeCompleter->loadExternal(), false,5130 PreferredTypeIsPointer);5131 5132 // Complete a lambda expression when preferred type is a function.5133 if (!Data.PreferredType.isNull() && getLangOpts().CPlusPlus11) {5134 if (const FunctionProtoType *F =5135 TryDeconstructFunctionLike(Data.PreferredType))5136 AddLambdaCompletion(Results, F->getParamTypes(), getLangOpts());5137 }5138 5139 HandleCodeCompleteResults(&SemaRef, CodeCompleter,5140 Results.getCompletionContext(), Results.data(),5141 Results.size());5142}5143 5144void SemaCodeCompletion::CodeCompleteExpression(Scope *S,5145 QualType PreferredType,5146 bool IsParenthesized) {5147 return CodeCompleteExpression(5148 S, CodeCompleteExpressionData(PreferredType, IsParenthesized));5149}5150 5151void SemaCodeCompletion::CodeCompletePostfixExpression(Scope *S, ExprResult E,5152 QualType PreferredType) {5153 if (E.isInvalid())5154 CodeCompleteExpression(S, PreferredType);5155 else if (getLangOpts().ObjC)5156 CodeCompleteObjCInstanceMessage(S, E.get(), {}, false);5157}5158 5159/// The set of properties that have already been added, referenced by5160/// property name.5161typedef llvm::SmallPtrSet<const IdentifierInfo *, 16> AddedPropertiesSet;5162 5163/// Retrieve the container definition, if any?5164static ObjCContainerDecl *getContainerDef(ObjCContainerDecl *Container) {5165 if (ObjCInterfaceDecl *Interface = dyn_cast<ObjCInterfaceDecl>(Container)) {5166 if (Interface->hasDefinition())5167 return Interface->getDefinition();5168 5169 return Interface;5170 }5171 5172 if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {5173 if (Protocol->hasDefinition())5174 return Protocol->getDefinition();5175 5176 return Protocol;5177 }5178 return Container;5179}5180 5181/// Adds a block invocation code completion result for the given block5182/// declaration \p BD.5183static void AddObjCBlockCall(ASTContext &Context, const PrintingPolicy &Policy,5184 CodeCompletionBuilder &Builder,5185 const NamedDecl *BD,5186 const FunctionTypeLoc &BlockLoc,5187 const FunctionProtoTypeLoc &BlockProtoLoc) {5188 Builder.AddResultTypeChunk(5189 GetCompletionTypeString(BlockLoc.getReturnLoc().getType(), Context,5190 Policy, Builder.getAllocator()));5191 5192 AddTypedNameChunk(Context, Policy, BD, Builder);5193 Builder.AddChunk(CodeCompletionString::CK_LeftParen);5194 5195 if (BlockProtoLoc && BlockProtoLoc.getTypePtr()->isVariadic()) {5196 Builder.AddPlaceholderChunk("...");5197 } else {5198 for (unsigned I = 0, N = BlockLoc.getNumParams(); I != N; ++I) {5199 if (I)5200 Builder.AddChunk(CodeCompletionString::CK_Comma);5201 5202 // Format the placeholder string.5203 std::string PlaceholderStr =5204 FormatFunctionParameter(Policy, BlockLoc.getParam(I));5205 5206 if (I == N - 1 && BlockProtoLoc &&5207 BlockProtoLoc.getTypePtr()->isVariadic())5208 PlaceholderStr += ", ...";5209 5210 // Add the placeholder string.5211 Builder.AddPlaceholderChunk(5212 Builder.getAllocator().CopyString(PlaceholderStr));5213 }5214 }5215 5216 Builder.AddChunk(CodeCompletionString::CK_RightParen);5217}5218 5219static void5220AddObjCProperties(const CodeCompletionContext &CCContext,5221 ObjCContainerDecl *Container, bool AllowCategories,5222 bool AllowNullaryMethods, DeclContext *CurContext,5223 AddedPropertiesSet &AddedProperties, ResultBuilder &Results,5224 bool IsBaseExprStatement = false,5225 bool IsClassProperty = false, bool InOriginalClass = true) {5226 typedef CodeCompletionResult Result;5227 5228 // Retrieve the definition.5229 Container = getContainerDef(Container);5230 5231 // Add properties in this container.5232 const auto AddProperty = [&](const ObjCPropertyDecl *P) {5233 if (!AddedProperties.insert(P->getIdentifier()).second)5234 return;5235 5236 // FIXME: Provide block invocation completion for non-statement5237 // expressions.5238 if (!P->getType().getTypePtr()->isBlockPointerType() ||5239 !IsBaseExprStatement) {5240 Result R =5241 Result(P, Results.getBasePriority(P), /*Qualifier=*/std::nullopt);5242 if (!InOriginalClass)5243 setInBaseClass(R);5244 Results.MaybeAddResult(R, CurContext);5245 return;5246 }5247 5248 // Block setter and invocation completion is provided only when we are able5249 // to find the FunctionProtoTypeLoc with parameter names for the block.5250 FunctionTypeLoc BlockLoc;5251 FunctionProtoTypeLoc BlockProtoLoc;5252 findTypeLocationForBlockDecl(P->getTypeSourceInfo(), BlockLoc,5253 BlockProtoLoc);5254 if (!BlockLoc) {5255 Result R =5256 Result(P, Results.getBasePriority(P), /*Qualifier=*/std::nullopt);5257 if (!InOriginalClass)5258 setInBaseClass(R);5259 Results.MaybeAddResult(R, CurContext);5260 return;5261 }5262 5263 // The default completion result for block properties should be the block5264 // invocation completion when the base expression is a statement.5265 CodeCompletionBuilder Builder(Results.getAllocator(),5266 Results.getCodeCompletionTUInfo());5267 AddObjCBlockCall(Container->getASTContext(),5268 getCompletionPrintingPolicy(Results.getSema()), Builder, P,5269 BlockLoc, BlockProtoLoc);5270 Result R = Result(Builder.TakeString(), P, Results.getBasePriority(P));5271 if (!InOriginalClass)5272 setInBaseClass(R);5273 Results.MaybeAddResult(R, CurContext);5274 5275 // Provide additional block setter completion iff the base expression is a5276 // statement and the block property is mutable.5277 if (!P->isReadOnly()) {5278 CodeCompletionBuilder Builder(Results.getAllocator(),5279 Results.getCodeCompletionTUInfo());5280 AddResultTypeChunk(Container->getASTContext(),5281 getCompletionPrintingPolicy(Results.getSema()), P,5282 CCContext.getBaseType(), Builder);5283 Builder.AddTypedTextChunk(5284 Results.getAllocator().CopyString(P->getName()));5285 Builder.AddChunk(CodeCompletionString::CK_Equal);5286 5287 std::string PlaceholderStr = formatBlockPlaceholder(5288 getCompletionPrintingPolicy(Results.getSema()), P, BlockLoc,5289 BlockProtoLoc, /*SuppressBlockName=*/true);5290 // Add the placeholder string.5291 Builder.AddPlaceholderChunk(5292 Builder.getAllocator().CopyString(PlaceholderStr));5293 5294 // When completing blocks properties that return void the default5295 // property completion result should show up before the setter,5296 // otherwise the setter completion should show up before the default5297 // property completion, as we normally want to use the result of the5298 // call.5299 Result R =5300 Result(Builder.TakeString(), P,5301 Results.getBasePriority(P) +5302 (BlockLoc.getTypePtr()->getReturnType()->isVoidType()5303 ? CCD_BlockPropertySetter5304 : -CCD_BlockPropertySetter));5305 if (!InOriginalClass)5306 setInBaseClass(R);5307 Results.MaybeAddResult(R, CurContext);5308 }5309 };5310 5311 if (IsClassProperty) {5312 for (const auto *P : Container->class_properties())5313 AddProperty(P);5314 } else {5315 for (const auto *P : Container->instance_properties())5316 AddProperty(P);5317 }5318 5319 // Add nullary methods or implicit class properties5320 if (AllowNullaryMethods) {5321 ASTContext &Context = Container->getASTContext();5322 PrintingPolicy Policy = getCompletionPrintingPolicy(Results.getSema());5323 // Adds a method result5324 const auto AddMethod = [&](const ObjCMethodDecl *M) {5325 const IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0);5326 if (!Name)5327 return;5328 if (!AddedProperties.insert(Name).second)5329 return;5330 CodeCompletionBuilder Builder(Results.getAllocator(),5331 Results.getCodeCompletionTUInfo());5332 AddResultTypeChunk(Context, Policy, M, CCContext.getBaseType(), Builder);5333 Builder.AddTypedTextChunk(5334 Results.getAllocator().CopyString(Name->getName()));5335 Result R = Result(Builder.TakeString(), M,5336 CCP_MemberDeclaration + CCD_MethodAsProperty);5337 if (!InOriginalClass)5338 setInBaseClass(R);5339 Results.MaybeAddResult(R, CurContext);5340 };5341 5342 if (IsClassProperty) {5343 for (const auto *M : Container->methods()) {5344 // Gather the class method that can be used as implicit property5345 // getters. Methods with arguments or methods that return void aren't5346 // added to the results as they can't be used as a getter.5347 if (!M->getSelector().isUnarySelector() ||5348 M->getReturnType()->isVoidType() || M->isInstanceMethod())5349 continue;5350 AddMethod(M);5351 }5352 } else {5353 for (auto *M : Container->methods()) {5354 if (M->getSelector().isUnarySelector())5355 AddMethod(M);5356 }5357 }5358 }5359 5360 // Add properties in referenced protocols.5361 if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {5362 for (auto *P : Protocol->protocols())5363 AddObjCProperties(CCContext, P, AllowCategories, AllowNullaryMethods,5364 CurContext, AddedProperties, Results,5365 IsBaseExprStatement, IsClassProperty,5366 /*InOriginalClass*/ false);5367 } else if (ObjCInterfaceDecl *IFace =5368 dyn_cast<ObjCInterfaceDecl>(Container)) {5369 if (AllowCategories) {5370 // Look through categories.5371 for (auto *Cat : IFace->known_categories())5372 AddObjCProperties(CCContext, Cat, AllowCategories, AllowNullaryMethods,5373 CurContext, AddedProperties, Results,5374 IsBaseExprStatement, IsClassProperty,5375 InOriginalClass);5376 }5377 5378 // Look through protocols.5379 for (auto *I : IFace->all_referenced_protocols())5380 AddObjCProperties(CCContext, I, AllowCategories, AllowNullaryMethods,5381 CurContext, AddedProperties, Results,5382 IsBaseExprStatement, IsClassProperty,5383 /*InOriginalClass*/ false);5384 5385 // Look in the superclass.5386 if (IFace->getSuperClass())5387 AddObjCProperties(CCContext, IFace->getSuperClass(), AllowCategories,5388 AllowNullaryMethods, CurContext, AddedProperties,5389 Results, IsBaseExprStatement, IsClassProperty,5390 /*InOriginalClass*/ false);5391 } else if (const auto *Category =5392 dyn_cast<ObjCCategoryDecl>(Container)) {5393 // Look through protocols.5394 for (auto *P : Category->protocols())5395 AddObjCProperties(CCContext, P, AllowCategories, AllowNullaryMethods,5396 CurContext, AddedProperties, Results,5397 IsBaseExprStatement, IsClassProperty,5398 /*InOriginalClass*/ false);5399 }5400}5401 5402static void5403AddRecordMembersCompletionResults(Sema &SemaRef, ResultBuilder &Results,5404 Scope *S, QualType BaseType,5405 ExprValueKind BaseKind, RecordDecl *RD,5406 std::optional<FixItHint> AccessOpFixIt) {5407 // Indicate that we are performing a member access, and the cv-qualifiers5408 // for the base object type.5409 Results.setObjectTypeQualifiers(BaseType.getQualifiers(), BaseKind);5410 5411 // Access to a C/C++ class, struct, or union.5412 Results.allowNestedNameSpecifiers();5413 std::vector<FixItHint> FixIts;5414 if (AccessOpFixIt)5415 FixIts.emplace_back(*AccessOpFixIt);5416 CodeCompletionDeclConsumer Consumer(Results, RD, BaseType, std::move(FixIts));5417 SemaRef.LookupVisibleDecls(5418 RD, Sema::LookupMemberName, Consumer,5419 SemaRef.CodeCompletion().CodeCompleter->includeGlobals(),5420 /*IncludeDependentBases=*/true,5421 SemaRef.CodeCompletion().CodeCompleter->loadExternal());5422 5423 if (SemaRef.getLangOpts().CPlusPlus) {5424 if (!Results.empty()) {5425 // The "template" keyword can follow "->" or "." in the grammar.5426 // However, we only want to suggest the template keyword if something5427 // is dependent.5428 bool IsDependent = BaseType->isDependentType();5429 if (!IsDependent) {5430 for (Scope *DepScope = S; DepScope; DepScope = DepScope->getParent())5431 if (DeclContext *Ctx = DepScope->getEntity()) {5432 IsDependent = Ctx->isDependentContext();5433 break;5434 }5435 }5436 5437 if (IsDependent)5438 Results.AddResult(CodeCompletionResult("template"));5439 }5440 }5441}5442 5443// Returns the RecordDecl inside the BaseType, falling back to primary template5444// in case of specializations. Since we might not have a decl for the5445// instantiation/specialization yet, e.g. dependent code.5446static RecordDecl *getAsRecordDecl(QualType BaseType,5447 HeuristicResolver &Resolver) {5448 BaseType = Resolver.simplifyType(BaseType, nullptr, /*UnwrapPointer=*/false);5449 return dyn_cast_if_present<RecordDecl>(5450 Resolver.resolveTypeToTagDecl(BaseType));5451}5452 5453namespace {5454// Collects completion-relevant information about a concept-constrainted type T.5455// In particular, examines the constraint expressions to find members of T.5456//5457// The design is very simple: we walk down each constraint looking for5458// expressions of the form T.foo().5459// If we're extra lucky, the return type is specified.5460// We don't do any clever handling of && or || in constraint expressions, we5461// take members from both branches.5462//5463// For example, given:5464// template <class T> concept X = requires (T t, string& s) { t.print(s); };5465// template <X U> void foo(U u) { u.^ }5466// We want to suggest the inferred member function 'print(string)'.5467// We see that u has type U, so X<U> holds.5468// X<U> requires t.print(s) to be valid, where t has type U (substituted for T).5469// By looking at the CallExpr we find the signature of print().5470//5471// While we tend to know in advance which kind of members (access via . -> ::)5472// we want, it's simpler just to gather them all and post-filter.5473//5474// FIXME: some of this machinery could be used for non-concept type-parms too,5475// enabling completion for type parameters based on other uses of that param.5476//5477// FIXME: there are other cases where a type can be constrained by a concept,5478// e.g. inside `if constexpr(ConceptSpecializationExpr) { ... }`5479class ConceptInfo {5480public:5481 // Describes a likely member of a type, inferred by concept constraints.5482 // Offered as a code completion for T. T-> and T:: contexts.5483 struct Member {5484 // Always non-null: we only handle members with ordinary identifier names.5485 const IdentifierInfo *Name = nullptr;5486 // Set for functions we've seen called.5487 // We don't have the declared parameter types, only the actual types of5488 // arguments we've seen. These are still valuable, as it's hard to render5489 // a useful function completion with neither parameter types nor names!5490 std::optional<SmallVector<QualType, 1>> ArgTypes;5491 // Whether this is accessed as T.member, T->member, or T::member.5492 enum AccessOperator {5493 Colons,5494 Arrow,5495 Dot,5496 } Operator = Dot;5497 // What's known about the type of a variable or return type of a function.5498 const TypeConstraint *ResultType = nullptr;5499 // FIXME: also track:5500 // - kind of entity (function/variable/type), to expose structured results5501 // - template args kinds/types, as a proxy for template params5502 5503 // For now we simply return these results as "pattern" strings.5504 CodeCompletionString *render(Sema &S, CodeCompletionAllocator &Alloc,5505 CodeCompletionTUInfo &Info) const {5506 CodeCompletionBuilder B(Alloc, Info);5507 // Result type5508 if (ResultType) {5509 std::string AsString;5510 {5511 llvm::raw_string_ostream OS(AsString);5512 QualType ExactType = deduceType(*ResultType);5513 if (!ExactType.isNull())5514 ExactType.print(OS, getCompletionPrintingPolicy(S));5515 else5516 ResultType->print(OS, getCompletionPrintingPolicy(S));5517 }5518 B.AddResultTypeChunk(Alloc.CopyString(AsString));5519 }5520 // Member name5521 B.AddTypedTextChunk(Alloc.CopyString(Name->getName()));5522 // Function argument list5523 if (ArgTypes) {5524 B.AddChunk(clang::CodeCompletionString::CK_LeftParen);5525 bool First = true;5526 for (QualType Arg : *ArgTypes) {5527 if (First)5528 First = false;5529 else {5530 B.AddChunk(clang::CodeCompletionString::CK_Comma);5531 B.AddChunk(clang::CodeCompletionString::CK_HorizontalSpace);5532 }5533 B.AddPlaceholderChunk(Alloc.CopyString(5534 Arg.getAsString(getCompletionPrintingPolicy(S))));5535 }5536 B.AddChunk(clang::CodeCompletionString::CK_RightParen);5537 }5538 return B.TakeString();5539 }5540 };5541 5542 // BaseType is the type parameter T to infer members from.5543 // T must be accessible within S, as we use it to find the template entity5544 // that T is attached to in order to gather the relevant constraints.5545 ConceptInfo(const TemplateTypeParmType &BaseType, Scope *S) {5546 auto *TemplatedEntity = getTemplatedEntity(BaseType.getDecl(), S);5547 for (const AssociatedConstraint &AC :5548 constraintsForTemplatedEntity(TemplatedEntity))5549 believe(AC.ConstraintExpr, &BaseType);5550 }5551 5552 std::vector<Member> members() {5553 std::vector<Member> Results;5554 for (const auto &E : this->Results)5555 Results.push_back(E.second);5556 llvm::sort(Results, [](const Member &L, const Member &R) {5557 return L.Name->getName() < R.Name->getName();5558 });5559 return Results;5560 }5561 5562private:5563 // Infer members of T, given that the expression E (dependent on T) is true.5564 void believe(const Expr *E, const TemplateTypeParmType *T) {5565 if (!E || !T)5566 return;5567 if (auto *CSE = dyn_cast<ConceptSpecializationExpr>(E)) {5568 // If the concept is5569 // template <class A, class B> concept CD = f<A, B>();5570 // And the concept specialization is5571 // CD<int, T>5572 // Then we're substituting T for B, so we want to make f<A, B>() true5573 // by adding members to B - i.e. believe(f<A, B>(), B);5574 //5575 // For simplicity:5576 // - we don't attempt to substitute int for A5577 // - when T is used in other ways (like CD<T*>) we ignore it5578 ConceptDecl *CD = CSE->getNamedConcept();5579 TemplateParameterList *Params = CD->getTemplateParameters();5580 unsigned Index = 0;5581 for (const auto &Arg : CSE->getTemplateArguments()) {5582 if (Index >= Params->size())5583 break; // Won't happen in valid code.5584 if (isApprox(Arg, T)) {5585 auto *TTPD = dyn_cast<TemplateTypeParmDecl>(Params->getParam(Index));5586 if (!TTPD)5587 continue;5588 // T was used as an argument, and bound to the parameter TT.5589 auto *TT = cast<TemplateTypeParmType>(TTPD->getTypeForDecl());5590 // So now we know the constraint as a function of TT is true.5591 believe(CD->getConstraintExpr(), TT);5592 // (concepts themselves have no associated constraints to require)5593 }5594 5595 ++Index;5596 }5597 } else if (auto *BO = dyn_cast<BinaryOperator>(E)) {5598 // For A && B, we can infer members from both branches.5599 // For A || B, the union is still more useful than the intersection.5600 if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) {5601 believe(BO->getLHS(), T);5602 believe(BO->getRHS(), T);5603 }5604 } else if (auto *RE = dyn_cast<RequiresExpr>(E)) {5605 // A requires(){...} lets us infer members from each requirement.5606 for (const concepts::Requirement *Req : RE->getRequirements()) {5607 if (!Req->isDependent())5608 continue; // Can't tell us anything about T.5609 // Now Req cannot a substitution-error: those aren't dependent.5610 5611 if (auto *TR = dyn_cast<concepts::TypeRequirement>(Req)) {5612 // Do a full traversal so we get `foo` from `typename T::foo::bar`.5613 QualType AssertedType = TR->getType()->getType();5614 ValidVisitor(this, T).TraverseType(AssertedType);5615 } else if (auto *ER = dyn_cast<concepts::ExprRequirement>(Req)) {5616 ValidVisitor Visitor(this, T);5617 // If we have a type constraint on the value of the expression,5618 // AND the whole outer expression describes a member, then we'll5619 // be able to use the constraint to provide the return type.5620 if (ER->getReturnTypeRequirement().isTypeConstraint()) {5621 Visitor.OuterType =5622 ER->getReturnTypeRequirement().getTypeConstraint();5623 Visitor.OuterExpr = ER->getExpr();5624 }5625 Visitor.TraverseStmt(ER->getExpr());5626 } else if (auto *NR = dyn_cast<concepts::NestedRequirement>(Req)) {5627 believe(NR->getConstraintExpr(), T);5628 }5629 }5630 }5631 }5632 5633 // This visitor infers members of T based on traversing expressions/types5634 // that involve T. It is invoked with code known to be valid for T.5635 class ValidVisitor : public DynamicRecursiveASTVisitor {5636 ConceptInfo *Outer;5637 const TemplateTypeParmType *T;5638 5639 CallExpr *Caller = nullptr;5640 Expr *Callee = nullptr;5641 5642 public:5643 // If set, OuterExpr is constrained by OuterType.5644 Expr *OuterExpr = nullptr;5645 const TypeConstraint *OuterType = nullptr;5646 5647 ValidVisitor(ConceptInfo *Outer, const TemplateTypeParmType *T)5648 : Outer(Outer), T(T) {5649 assert(T);5650 }5651 5652 // In T.foo or T->foo, `foo` is a member function/variable.5653 bool5654 VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) override {5655 const Type *Base = E->getBaseType().getTypePtr();5656 bool IsArrow = E->isArrow();5657 if (Base->isPointerType() && IsArrow) {5658 IsArrow = false;5659 Base = Base->getPointeeType().getTypePtr();5660 }5661 if (isApprox(Base, T))5662 addValue(E, E->getMember(), IsArrow ? Member::Arrow : Member::Dot);5663 return true;5664 }5665 5666 // In T::foo, `foo` is a static member function/variable.5667 bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) override {5668 NestedNameSpecifier Qualifier = E->getQualifier();5669 if (Qualifier.getKind() == NestedNameSpecifier::Kind::Type &&5670 isApprox(Qualifier.getAsType(), T))5671 addValue(E, E->getDeclName(), Member::Colons);5672 return true;5673 }5674 5675 // In T::typename foo, `foo` is a type.5676 bool VisitDependentNameType(DependentNameType *DNT) override {5677 NestedNameSpecifier Q = DNT->getQualifier();5678 if (Q.getKind() == NestedNameSpecifier::Kind::Type &&5679 isApprox(Q.getAsType(), T))5680 addType(DNT->getIdentifier());5681 return true;5682 }5683 5684 // In T::foo::bar, `foo` must be a type.5685 // VisitNNS() doesn't exist, and TraverseNNS isn't always called :-(5686 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSL) override {5687 if (NNSL) {5688 NestedNameSpecifier NNS = NNSL.getNestedNameSpecifier();5689 if (NNS.getKind() == NestedNameSpecifier::Kind::Type) {5690 const Type *NNST = NNS.getAsType();5691 if (NestedNameSpecifier Q = NNST->getPrefix();5692 Q.getKind() == NestedNameSpecifier::Kind::Type &&5693 isApprox(Q.getAsType(), T))5694 if (const auto *DNT = dyn_cast_or_null<DependentNameType>(NNST))5695 addType(DNT->getIdentifier());5696 }5697 }5698 // FIXME: also handle T::foo<X>::bar5699 return DynamicRecursiveASTVisitor::TraverseNestedNameSpecifierLoc(NNSL);5700 }5701 5702 // FIXME also handle T::foo<X>5703 5704 // Track the innermost caller/callee relationship so we can tell if a5705 // nested expr is being called as a function.5706 bool VisitCallExpr(CallExpr *CE) override {5707 Caller = CE;5708 Callee = CE->getCallee();5709 return true;5710 }5711 5712 private:5713 void addResult(Member &&M) {5714 auto R = Outer->Results.try_emplace(M.Name);5715 Member &O = R.first->second;5716 // Overwrite existing if the new member has more info.5717 // The preference of . vs :: vs -> is fairly arbitrary.5718 if (/*Inserted*/ R.second ||5719 std::make_tuple(M.ArgTypes.has_value(), M.ResultType != nullptr,5720 M.Operator) > std::make_tuple(O.ArgTypes.has_value(),5721 O.ResultType != nullptr,5722 O.Operator))5723 O = std::move(M);5724 }5725 5726 void addType(const IdentifierInfo *Name) {5727 if (!Name)5728 return;5729 Member M;5730 M.Name = Name;5731 M.Operator = Member::Colons;5732 addResult(std::move(M));5733 }5734 5735 void addValue(Expr *E, DeclarationName Name,5736 Member::AccessOperator Operator) {5737 if (!Name.isIdentifier())5738 return;5739 Member Result;5740 Result.Name = Name.getAsIdentifierInfo();5741 Result.Operator = Operator;5742 // If this is the callee of an immediately-enclosing CallExpr, then5743 // treat it as a method, otherwise it's a variable.5744 if (Caller != nullptr && Callee == E) {5745 Result.ArgTypes.emplace();5746 for (const auto *Arg : Caller->arguments())5747 Result.ArgTypes->push_back(Arg->getType());5748 if (Caller == OuterExpr) {5749 Result.ResultType = OuterType;5750 }5751 } else {5752 if (E == OuterExpr)5753 Result.ResultType = OuterType;5754 }5755 addResult(std::move(Result));5756 }5757 };5758 5759 static bool isApprox(const TemplateArgument &Arg, const Type *T) {5760 return Arg.getKind() == TemplateArgument::Type &&5761 isApprox(Arg.getAsType().getTypePtr(), T);5762 }5763 5764 static bool isApprox(const Type *T1, const Type *T2) {5765 return T1 && T2 &&5766 T1->getCanonicalTypeUnqualified() ==5767 T2->getCanonicalTypeUnqualified();5768 }5769 5770 // Returns the DeclContext immediately enclosed by the template parameter5771 // scope. For primary templates, this is the templated (e.g.) CXXRecordDecl.5772 // For specializations, this is e.g. ClassTemplatePartialSpecializationDecl.5773 static DeclContext *getTemplatedEntity(const TemplateTypeParmDecl *D,5774 Scope *S) {5775 if (D == nullptr)5776 return nullptr;5777 Scope *Inner = nullptr;5778 while (S) {5779 if (S->isTemplateParamScope() && S->isDeclScope(D))5780 return Inner ? Inner->getEntity() : nullptr;5781 Inner = S;5782 S = S->getParent();5783 }5784 return nullptr;5785 }5786 5787 // Gets all the type constraint expressions that might apply to the type5788 // variables associated with DC (as returned by getTemplatedEntity()).5789 static SmallVector<AssociatedConstraint, 1>5790 constraintsForTemplatedEntity(DeclContext *DC) {5791 SmallVector<AssociatedConstraint, 1> Result;5792 if (DC == nullptr)5793 return Result;5794 // Primary templates can have constraints.5795 if (const auto *TD = cast<Decl>(DC)->getDescribedTemplate())5796 TD->getAssociatedConstraints(Result);5797 // Partial specializations may have constraints.5798 if (const auto *CTPSD =5799 dyn_cast<ClassTemplatePartialSpecializationDecl>(DC))5800 CTPSD->getAssociatedConstraints(Result);5801 if (const auto *VTPSD = dyn_cast<VarTemplatePartialSpecializationDecl>(DC))5802 VTPSD->getAssociatedConstraints(Result);5803 return Result;5804 }5805 5806 // Attempt to find the unique type satisfying a constraint.5807 // This lets us show e.g. `int` instead of `std::same_as<int>`.5808 static QualType deduceType(const TypeConstraint &T) {5809 // Assume a same_as<T> return type constraint is std::same_as or equivalent.5810 // In this case the return type is T.5811 DeclarationName DN = T.getNamedConcept()->getDeclName();5812 if (DN.isIdentifier() && DN.getAsIdentifierInfo()->isStr("same_as"))5813 if (const auto *Args = T.getTemplateArgsAsWritten())5814 if (Args->getNumTemplateArgs() == 1) {5815 const auto &Arg = Args->arguments().front().getArgument();5816 if (Arg.getKind() == TemplateArgument::Type)5817 return Arg.getAsType();5818 }5819 return {};5820 }5821 5822 llvm::DenseMap<const IdentifierInfo *, Member> Results;5823};5824 5825// Returns a type for E that yields acceptable member completions.5826// In particular, when E->getType() is DependentTy, try to guess a likely type.5827// We accept some lossiness (like dropping parameters).5828// We only try to handle common expressions on the LHS of MemberExpr.5829QualType getApproximateType(const Expr *E, HeuristicResolver &Resolver) {5830 QualType Result = Resolver.resolveExprToType(E);5831 if (Result.isNull())5832 return Result;5833 Result = Resolver.simplifyType(Result.getNonReferenceType(), E, false);5834 if (Result.isNull())5835 return Result;5836 return Result.getNonReferenceType();5837}5838 5839// If \p Base is ParenListExpr, assume a chain of comma operators and pick the5840// last expr. We expect other ParenListExprs to be resolved to e.g. constructor5841// calls before here. (So the ParenListExpr should be nonempty, but check just5842// in case)5843Expr *unwrapParenList(Expr *Base) {5844 if (auto *PLE = llvm::dyn_cast_or_null<ParenListExpr>(Base)) {5845 if (PLE->getNumExprs() == 0)5846 return nullptr;5847 Base = PLE->getExpr(PLE->getNumExprs() - 1);5848 }5849 return Base;5850}5851 5852} // namespace5853 5854void SemaCodeCompletion::CodeCompleteMemberReferenceExpr(5855 Scope *S, Expr *Base, Expr *OtherOpBase, SourceLocation OpLoc, bool IsArrow,5856 bool IsBaseExprStatement, QualType PreferredType) {5857 Base = unwrapParenList(Base);5858 OtherOpBase = unwrapParenList(OtherOpBase);5859 if (!Base || !CodeCompleter)5860 return;5861 5862 ExprResult ConvertedBase =5863 SemaRef.PerformMemberExprBaseConversion(Base, IsArrow);5864 if (ConvertedBase.isInvalid())5865 return;5866 QualType ConvertedBaseType =5867 getApproximateType(ConvertedBase.get(), Resolver);5868 5869 enum CodeCompletionContext::Kind contextKind;5870 5871 if (IsArrow) {5872 if (QualType PointeeType = Resolver.getPointeeType(ConvertedBaseType);5873 !PointeeType.isNull()) {5874 ConvertedBaseType = PointeeType;5875 }5876 }5877 5878 if (IsArrow) {5879 contextKind = CodeCompletionContext::CCC_ArrowMemberAccess;5880 } else {5881 if (ConvertedBaseType->isObjCObjectPointerType() ||5882 ConvertedBaseType->isObjCObjectOrInterfaceType()) {5883 contextKind = CodeCompletionContext::CCC_ObjCPropertyAccess;5884 } else {5885 contextKind = CodeCompletionContext::CCC_DotMemberAccess;5886 }5887 }5888 5889 CodeCompletionContext CCContext(contextKind, ConvertedBaseType);5890 CCContext.setPreferredType(PreferredType);5891 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),5892 CodeCompleter->getCodeCompletionTUInfo(), CCContext,5893 &ResultBuilder::IsMember);5894 5895 auto DoCompletion = [&](Expr *Base, bool IsArrow,5896 std::optional<FixItHint> AccessOpFixIt) -> bool {5897 if (!Base)5898 return false;5899 5900 ExprResult ConvertedBase =5901 SemaRef.PerformMemberExprBaseConversion(Base, IsArrow);5902 if (ConvertedBase.isInvalid())5903 return false;5904 Base = ConvertedBase.get();5905 5906 QualType BaseType = getApproximateType(Base, Resolver);5907 if (BaseType.isNull())5908 return false;5909 ExprValueKind BaseKind = Base->getValueKind();5910 5911 if (IsArrow) {5912 if (QualType PointeeType = Resolver.getPointeeType(BaseType);5913 !PointeeType.isNull()) {5914 BaseType = PointeeType;5915 BaseKind = VK_LValue;5916 } else if (BaseType->isObjCObjectPointerType() ||5917 BaseType->isTemplateTypeParmType()) {5918 // Both cases (dot/arrow) handled below.5919 } else {5920 return false;5921 }5922 }5923 5924 if (RecordDecl *RD = getAsRecordDecl(BaseType, Resolver)) {5925 AddRecordMembersCompletionResults(SemaRef, Results, S, BaseType, BaseKind,5926 RD, std::move(AccessOpFixIt));5927 } else if (const auto *TTPT =5928 dyn_cast<TemplateTypeParmType>(BaseType.getTypePtr())) {5929 auto Operator =5930 IsArrow ? ConceptInfo::Member::Arrow : ConceptInfo::Member::Dot;5931 for (const auto &R : ConceptInfo(*TTPT, S).members()) {5932 if (R.Operator != Operator)5933 continue;5934 CodeCompletionResult Result(5935 R.render(SemaRef, CodeCompleter->getAllocator(),5936 CodeCompleter->getCodeCompletionTUInfo()));5937 if (AccessOpFixIt)5938 Result.FixIts.push_back(*AccessOpFixIt);5939 Results.AddResult(std::move(Result));5940 }5941 } else if (!IsArrow && BaseType->isObjCObjectPointerType()) {5942 // Objective-C property reference. Bail if we're performing fix-it code5943 // completion since Objective-C properties are normally backed by ivars,5944 // most Objective-C fix-its here would have little value.5945 if (AccessOpFixIt) {5946 return false;5947 }5948 AddedPropertiesSet AddedProperties;5949 5950 if (const ObjCObjectPointerType *ObjCPtr =5951 BaseType->getAsObjCInterfacePointerType()) {5952 // Add property results based on our interface.5953 assert(ObjCPtr && "Non-NULL pointer guaranteed above!");5954 AddObjCProperties(CCContext, ObjCPtr->getInterfaceDecl(), true,5955 /*AllowNullaryMethods=*/true, SemaRef.CurContext,5956 AddedProperties, Results, IsBaseExprStatement);5957 }5958 5959 // Add properties from the protocols in a qualified interface.5960 for (auto *I : BaseType->castAs<ObjCObjectPointerType>()->quals())5961 AddObjCProperties(CCContext, I, true, /*AllowNullaryMethods=*/true,5962 SemaRef.CurContext, AddedProperties, Results,5963 IsBaseExprStatement, /*IsClassProperty*/ false,5964 /*InOriginalClass*/ false);5965 } else if ((IsArrow && BaseType->isObjCObjectPointerType()) ||5966 (!IsArrow && BaseType->isObjCObjectType())) {5967 // Objective-C instance variable access. Bail if we're performing fix-it5968 // code completion since Objective-C properties are normally backed by5969 // ivars, most Objective-C fix-its here would have little value.5970 if (AccessOpFixIt) {5971 return false;5972 }5973 ObjCInterfaceDecl *Class = nullptr;5974 if (const ObjCObjectPointerType *ObjCPtr =5975 BaseType->getAs<ObjCObjectPointerType>())5976 Class = ObjCPtr->getInterfaceDecl();5977 else5978 Class = BaseType->castAs<ObjCObjectType>()->getInterface();5979 5980 // Add all ivars from this class and its superclasses.5981 if (Class) {5982 CodeCompletionDeclConsumer Consumer(Results, Class, BaseType);5983 Results.setFilter(&ResultBuilder::IsObjCIvar);5984 SemaRef.LookupVisibleDecls(Class, Sema::LookupMemberName, Consumer,5985 CodeCompleter->includeGlobals(),5986 /*IncludeDependentBases=*/false,5987 CodeCompleter->loadExternal());5988 }5989 }5990 5991 // FIXME: How do we cope with isa?5992 return true;5993 };5994 5995 Results.EnterNewScope();5996 5997 bool CompletionSucceded = DoCompletion(Base, IsArrow, std::nullopt);5998 if (CodeCompleter->includeFixIts()) {5999 const CharSourceRange OpRange =6000 CharSourceRange::getTokenRange(OpLoc, OpLoc);6001 CompletionSucceded |= DoCompletion(6002 OtherOpBase, !IsArrow,6003 FixItHint::CreateReplacement(OpRange, IsArrow ? "." : "->"));6004 }6005 6006 Results.ExitScope();6007 6008 if (!CompletionSucceded)6009 return;6010 6011 // Hand off the results found for code completion.6012 HandleCodeCompleteResults(&SemaRef, CodeCompleter,6013 Results.getCompletionContext(), Results.data(),6014 Results.size());6015}6016 6017void SemaCodeCompletion::CodeCompleteObjCClassPropertyRefExpr(6018 Scope *S, const IdentifierInfo &ClassName, SourceLocation ClassNameLoc,6019 bool IsBaseExprStatement) {6020 const IdentifierInfo *ClassNamePtr = &ClassName;6021 ObjCInterfaceDecl *IFace =6022 SemaRef.ObjC().getObjCInterfaceDecl(ClassNamePtr, ClassNameLoc);6023 if (!IFace)6024 return;6025 CodeCompletionContext CCContext(6026 CodeCompletionContext::CCC_ObjCPropertyAccess);6027 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),6028 CodeCompleter->getCodeCompletionTUInfo(), CCContext,6029 &ResultBuilder::IsMember);6030 Results.EnterNewScope();6031 AddedPropertiesSet AddedProperties;6032 AddObjCProperties(CCContext, IFace, true,6033 /*AllowNullaryMethods=*/true, SemaRef.CurContext,6034 AddedProperties, Results, IsBaseExprStatement,6035 /*IsClassProperty=*/true);6036 Results.ExitScope();6037 HandleCodeCompleteResults(&SemaRef, CodeCompleter,6038 Results.getCompletionContext(), Results.data(),6039 Results.size());6040}6041 6042void SemaCodeCompletion::CodeCompleteTag(Scope *S, unsigned TagSpec) {6043 if (!CodeCompleter)6044 return;6045 6046 ResultBuilder::LookupFilter Filter = nullptr;6047 enum CodeCompletionContext::Kind ContextKind =6048 CodeCompletionContext::CCC_Other;6049 switch ((DeclSpec::TST)TagSpec) {6050 case DeclSpec::TST_enum:6051 Filter = &ResultBuilder::IsEnum;6052 ContextKind = CodeCompletionContext::CCC_EnumTag;6053 break;6054 6055 case DeclSpec::TST_union:6056 Filter = &ResultBuilder::IsUnion;6057 ContextKind = CodeCompletionContext::CCC_UnionTag;6058 break;6059 6060 case DeclSpec::TST_struct:6061 case DeclSpec::TST_class:6062 case DeclSpec::TST_interface:6063 Filter = &ResultBuilder::IsClassOrStruct;6064 ContextKind = CodeCompletionContext::CCC_ClassOrStructTag;6065 break;6066 6067 default:6068 llvm_unreachable("Unknown type specifier kind in CodeCompleteTag");6069 }6070 6071 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),6072 CodeCompleter->getCodeCompletionTUInfo(), ContextKind);6073 CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext);6074 6075 // First pass: look for tags.6076 Results.setFilter(Filter);6077 SemaRef.LookupVisibleDecls(S, Sema::LookupTagName, Consumer,6078 CodeCompleter->includeGlobals(),6079 CodeCompleter->loadExternal());6080 6081 if (CodeCompleter->includeGlobals()) {6082 // Second pass: look for nested name specifiers.6083 Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);6084 SemaRef.LookupVisibleDecls(S, Sema::LookupNestedNameSpecifierName, Consumer,6085 CodeCompleter->includeGlobals(),6086 CodeCompleter->loadExternal());6087 }6088 6089 HandleCodeCompleteResults(&SemaRef, CodeCompleter,6090 Results.getCompletionContext(), Results.data(),6091 Results.size());6092}6093 6094static void AddTypeQualifierResults(DeclSpec &DS, ResultBuilder &Results,6095 const LangOptions &LangOpts) {6096 if (!(DS.getTypeQualifiers() & DeclSpec::TQ_const))6097 Results.AddResult("const");6098 if (!(DS.getTypeQualifiers() & DeclSpec::TQ_volatile))6099 Results.AddResult("volatile");6100 if (LangOpts.C99 && !(DS.getTypeQualifiers() & DeclSpec::TQ_restrict))6101 Results.AddResult("restrict");6102 if (LangOpts.C11 && !(DS.getTypeQualifiers() & DeclSpec::TQ_atomic))6103 Results.AddResult("_Atomic");6104 if (LangOpts.MSVCCompat && !(DS.getTypeQualifiers() & DeclSpec::TQ_unaligned))6105 Results.AddResult("__unaligned");6106}6107 6108void SemaCodeCompletion::CodeCompleteTypeQualifiers(DeclSpec &DS) {6109 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),6110 CodeCompleter->getCodeCompletionTUInfo(),6111 CodeCompletionContext::CCC_TypeQualifiers);6112 Results.EnterNewScope();6113 AddTypeQualifierResults(DS, Results, getLangOpts());6114 Results.ExitScope();6115 HandleCodeCompleteResults(&SemaRef, CodeCompleter,6116 Results.getCompletionContext(), Results.data(),6117 Results.size());6118}6119 6120void SemaCodeCompletion::CodeCompleteFunctionQualifiers(6121 DeclSpec &DS, Declarator &D, const VirtSpecifiers *VS) {6122 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),6123 CodeCompleter->getCodeCompletionTUInfo(),6124 CodeCompletionContext::CCC_TypeQualifiers);6125 Results.EnterNewScope();6126 AddTypeQualifierResults(DS, Results, getLangOpts());6127 if (getLangOpts().CPlusPlus11) {6128 Results.AddResult("noexcept");6129 if (D.getContext() == DeclaratorContext::Member && !D.isCtorOrDtor() &&6130 !D.isStaticMember()) {6131 if (!VS || !VS->isFinalSpecified())6132 Results.AddResult("final");6133 if (!VS || !VS->isOverrideSpecified())6134 Results.AddResult("override");6135 }6136 }6137 Results.ExitScope();6138 HandleCodeCompleteResults(&SemaRef, CodeCompleter,6139 Results.getCompletionContext(), Results.data(),6140 Results.size());6141}6142 6143void SemaCodeCompletion::CodeCompleteBracketDeclarator(Scope *S) {6144 CodeCompleteExpression(S, QualType(getASTContext().getSizeType()));6145}6146 6147void SemaCodeCompletion::CodeCompleteCase(Scope *S) {6148 if (SemaRef.getCurFunction()->SwitchStack.empty() || !CodeCompleter)6149 return;6150 6151 SwitchStmt *Switch =6152 SemaRef.getCurFunction()->SwitchStack.back().getPointer();6153 // Condition expression might be invalid, do not continue in this case.6154 if (!Switch->getCond())6155 return;6156 QualType type = Switch->getCond()->IgnoreImplicit()->getType();6157 EnumDecl *Enum = type->getAsEnumDecl();6158 if (!Enum) {6159 CodeCompleteExpressionData Data(type);6160 Data.IntegralConstantExpression = true;6161 CodeCompleteExpression(S, Data);6162 return;6163 }6164 6165 // Determine which enumerators we have already seen in the switch statement.6166 // FIXME: Ideally, we would also be able to look *past* the code-completion6167 // token, in case we are code-completing in the middle of the switch and not6168 // at the end. However, we aren't able to do so at the moment.6169 CoveredEnumerators Enumerators;6170 for (SwitchCase *SC = Switch->getSwitchCaseList(); SC;6171 SC = SC->getNextSwitchCase()) {6172 CaseStmt *Case = dyn_cast<CaseStmt>(SC);6173 if (!Case)6174 continue;6175 6176 Expr *CaseVal = Case->getLHS()->IgnoreParenCasts();6177 if (auto *DRE = dyn_cast<DeclRefExpr>(CaseVal))6178 if (auto *Enumerator =6179 dyn_cast<EnumConstantDecl>(DRE->getDecl())) {6180 // We look into the AST of the case statement to determine which6181 // enumerator was named. Alternatively, we could compute the value of6182 // the integral constant expression, then compare it against the6183 // values of each enumerator. However, value-based approach would not6184 // work as well with C++ templates where enumerators declared within a6185 // template are type- and value-dependent.6186 Enumerators.Seen.insert(Enumerator);6187 6188 // If this is a qualified-id, keep track of the nested-name-specifier6189 // so that we can reproduce it as part of code completion, e.g.,6190 //6191 // switch (TagD.getKind()) {6192 // case TagDecl::TK_enum:6193 // break;6194 // case XXX6195 //6196 // At the XXX, our completions are TagDecl::TK_union,6197 // TagDecl::TK_struct, and TagDecl::TK_class, rather than TK_union,6198 // TK_struct, and TK_class.6199 Enumerators.SuggestedQualifier = DRE->getQualifier();6200 }6201 }6202 6203 // Add any enumerators that have not yet been mentioned.6204 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),6205 CodeCompleter->getCodeCompletionTUInfo(),6206 CodeCompletionContext::CCC_Expression);6207 AddEnumerators(Results, getASTContext(), Enum, SemaRef.CurContext,6208 Enumerators);6209 6210 if (CodeCompleter->includeMacros()) {6211 AddMacroResults(SemaRef.PP, Results, CodeCompleter->loadExternal(), false);6212 }6213 HandleCodeCompleteResults(&SemaRef, CodeCompleter,6214 Results.getCompletionContext(), Results.data(),6215 Results.size());6216}6217 6218static bool anyNullArguments(ArrayRef<Expr *> Args) {6219 if (Args.size() && !Args.data())6220 return true;6221 6222 for (unsigned I = 0; I != Args.size(); ++I)6223 if (!Args[I])6224 return true;6225 6226 return false;6227}6228 6229typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate;6230 6231static void mergeCandidatesWithResults(6232 Sema &SemaRef, SmallVectorImpl<ResultCandidate> &Results,6233 OverloadCandidateSet &CandidateSet, SourceLocation Loc, size_t ArgSize) {6234 // Sort the overload candidate set by placing the best overloads first.6235 llvm::stable_sort(CandidateSet, [&](const OverloadCandidate &X,6236 const OverloadCandidate &Y) {6237 return isBetterOverloadCandidate(SemaRef, X, Y, Loc, CandidateSet.getKind(),6238 /*PartialOverloading=*/true);6239 });6240 6241 // Add the remaining viable overload candidates as code-completion results.6242 for (OverloadCandidate &Candidate : CandidateSet) {6243 if (Candidate.Function) {6244 if (Candidate.Function->isDeleted())6245 continue;6246 if (shouldEnforceArgLimit(/*PartialOverloading=*/true,6247 Candidate.Function) &&6248 Candidate.Function->getNumParams() <= ArgSize &&6249 // Having zero args is annoying, normally we don't surface a function6250 // with 2 params, if you already have 2 params, because you are6251 // inserting the 3rd now. But with zero, it helps the user to figure6252 // out there are no overloads that take any arguments. Hence we are6253 // keeping the overload.6254 ArgSize > 0)6255 continue;6256 }6257 if (Candidate.Viable)6258 Results.push_back(ResultCandidate(Candidate.Function));6259 }6260}6261 6262/// Get the type of the Nth parameter from a given set of overload6263/// candidates.6264static QualType getParamType(Sema &SemaRef,6265 ArrayRef<ResultCandidate> Candidates, unsigned N) {6266 6267 // Given the overloads 'Candidates' for a function call matching all arguments6268 // up to N, return the type of the Nth parameter if it is the same for all6269 // overload candidates.6270 QualType ParamType;6271 for (auto &Candidate : Candidates) {6272 QualType CandidateParamType = Candidate.getParamType(N);6273 if (CandidateParamType.isNull())6274 continue;6275 if (ParamType.isNull()) {6276 ParamType = CandidateParamType;6277 continue;6278 }6279 if (!SemaRef.Context.hasSameUnqualifiedType(6280 ParamType.getNonReferenceType(),6281 CandidateParamType.getNonReferenceType()))6282 // Two conflicting types, give up.6283 return QualType();6284 }6285 6286 return ParamType;6287}6288 6289static QualType6290ProduceSignatureHelp(Sema &SemaRef, MutableArrayRef<ResultCandidate> Candidates,6291 unsigned CurrentArg, SourceLocation OpenParLoc,6292 bool Braced) {6293 if (Candidates.empty())6294 return QualType();6295 if (SemaRef.getPreprocessor().isCodeCompletionReached())6296 SemaRef.CodeCompletion().CodeCompleter->ProcessOverloadCandidates(6297 SemaRef, CurrentArg, Candidates.data(), Candidates.size(), OpenParLoc,6298 Braced);6299 return getParamType(SemaRef, Candidates, CurrentArg);6300}6301 6302QualType6303SemaCodeCompletion::ProduceCallSignatureHelp(Expr *Fn, ArrayRef<Expr *> Args,6304 SourceLocation OpenParLoc) {6305 Fn = unwrapParenList(Fn);6306 if (!CodeCompleter || !Fn)6307 return QualType();6308 6309 // FIXME: Provide support for variadic template functions.6310 // Ignore type-dependent call expressions entirely.6311 if (Fn->isTypeDependent() || anyNullArguments(Args))6312 return QualType();6313 // In presence of dependent args we surface all possible signatures using the6314 // non-dependent args in the prefix. Afterwards we do a post filtering to make6315 // sure provided candidates satisfy parameter count restrictions.6316 auto ArgsWithoutDependentTypes =6317 Args.take_while([](Expr *Arg) { return !Arg->isTypeDependent(); });6318 6319 SmallVector<ResultCandidate, 8> Results;6320 6321 Expr *NakedFn = Fn->IgnoreParenCasts();6322 // Build an overload candidate set based on the functions we find.6323 SourceLocation Loc = Fn->getExprLoc();6324 OverloadCandidateSet CandidateSet(Loc,6325 OverloadCandidateSet::CSK_CodeCompletion);6326 6327 if (auto ULE = dyn_cast<UnresolvedLookupExpr>(NakedFn)) {6328 SemaRef.AddOverloadedCallCandidates(ULE, ArgsWithoutDependentTypes,6329 CandidateSet,6330 /*PartialOverloading=*/true);6331 } else if (auto UME = dyn_cast<UnresolvedMemberExpr>(NakedFn)) {6332 TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = nullptr;6333 if (UME->hasExplicitTemplateArgs()) {6334 UME->copyTemplateArgumentsInto(TemplateArgsBuffer);6335 TemplateArgs = &TemplateArgsBuffer;6336 }6337 6338 // Add the base as first argument (use a nullptr if the base is implicit).6339 SmallVector<Expr *, 12> ArgExprs(6340 1, UME->isImplicitAccess() ? nullptr : UME->getBase());6341 ArgExprs.append(ArgsWithoutDependentTypes.begin(),6342 ArgsWithoutDependentTypes.end());6343 UnresolvedSet<8> Decls;6344 Decls.append(UME->decls_begin(), UME->decls_end());6345 const bool FirstArgumentIsBase = !UME->isImplicitAccess() && UME->getBase();6346 SemaRef.AddFunctionCandidates(Decls, ArgExprs, CandidateSet, TemplateArgs,6347 /*SuppressUserConversions=*/false,6348 /*PartialOverloading=*/true,6349 FirstArgumentIsBase);6350 } else {6351 FunctionDecl *FD = nullptr;6352 if (auto *MCE = dyn_cast<MemberExpr>(NakedFn))6353 FD = dyn_cast<FunctionDecl>(MCE->getMemberDecl());6354 else if (auto *DRE = dyn_cast<DeclRefExpr>(NakedFn))6355 FD = dyn_cast<FunctionDecl>(DRE->getDecl());6356 if (FD) { // We check whether it's a resolved function declaration.6357 if (!getLangOpts().CPlusPlus ||6358 !FD->getType()->getAs<FunctionProtoType>())6359 Results.push_back(ResultCandidate(FD));6360 else6361 SemaRef.AddOverloadCandidate(FD,6362 DeclAccessPair::make(FD, FD->getAccess()),6363 ArgsWithoutDependentTypes, CandidateSet,6364 /*SuppressUserConversions=*/false,6365 /*PartialOverloading=*/true);6366 6367 } else if (auto DC = NakedFn->getType()->getAsCXXRecordDecl()) {6368 // If expression's type is CXXRecordDecl, it may overload the function6369 // call operator, so we check if it does and add them as candidates.6370 // A complete type is needed to lookup for member function call operators.6371 if (SemaRef.isCompleteType(Loc, NakedFn->getType())) {6372 DeclarationName OpName =6373 getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);6374 LookupResult R(SemaRef, OpName, Loc, Sema::LookupOrdinaryName);6375 SemaRef.LookupQualifiedName(R, DC);6376 R.suppressDiagnostics();6377 SmallVector<Expr *, 12> ArgExprs(1, NakedFn);6378 ArgExprs.append(ArgsWithoutDependentTypes.begin(),6379 ArgsWithoutDependentTypes.end());6380 SemaRef.AddFunctionCandidates(R.asUnresolvedSet(), ArgExprs,6381 CandidateSet,6382 /*ExplicitArgs=*/nullptr,6383 /*SuppressUserConversions=*/false,6384 /*PartialOverloading=*/true);6385 }6386 } else {6387 // Lastly we check whether expression's type is function pointer or6388 // function.6389 6390 FunctionProtoTypeLoc P = Resolver.getFunctionProtoTypeLoc(NakedFn);6391 QualType T = NakedFn->getType();6392 if (!T->getPointeeType().isNull())6393 T = T->getPointeeType();6394 6395 if (auto FP = T->getAs<FunctionProtoType>()) {6396 if (!SemaRef.TooManyArguments(FP->getNumParams(),6397 ArgsWithoutDependentTypes.size(),6398 /*PartialOverloading=*/true) ||6399 FP->isVariadic()) {6400 if (P) {6401 Results.push_back(ResultCandidate(P));6402 } else {6403 Results.push_back(ResultCandidate(FP));6404 }6405 }6406 } else if (auto FT = T->getAs<FunctionType>())6407 // No prototype and declaration, it may be a K & R style function.6408 Results.push_back(ResultCandidate(FT));6409 }6410 }6411 mergeCandidatesWithResults(SemaRef, Results, CandidateSet, Loc, Args.size());6412 QualType ParamType = ProduceSignatureHelp(SemaRef, Results, Args.size(),6413 OpenParLoc, /*Braced=*/false);6414 return !CandidateSet.empty() ? ParamType : QualType();6415}6416 6417// Determine which param to continue aggregate initialization from after6418// a designated initializer.6419//6420// Given struct S { int a,b,c,d,e; }:6421// after `S{.b=1,` we want to suggest c to continue6422// after `S{.b=1, 2,` we continue with d (this is legal C and ext in C++)6423// after `S{.b=1, .a=2,` we continue with b (this is legal C and ext in C++)6424//6425// Possible outcomes:6426// - we saw a designator for a field, and continue from the returned index.6427// Only aggregate initialization is allowed.6428// - we saw a designator, but it was complex or we couldn't find the field.6429// Only aggregate initialization is possible, but we can't assist with it.6430// Returns an out-of-range index.6431// - we saw no designators, just positional arguments.6432// Returns std::nullopt.6433static std::optional<unsigned>6434getNextAggregateIndexAfterDesignatedInit(const ResultCandidate &Aggregate,6435 ArrayRef<Expr *> Args) {6436 static constexpr unsigned Invalid = std::numeric_limits<unsigned>::max();6437 assert(Aggregate.getKind() == ResultCandidate::CK_Aggregate);6438 6439 // Look for designated initializers.6440 // They're in their syntactic form, not yet resolved to fields.6441 const IdentifierInfo *DesignatedFieldName = nullptr;6442 unsigned ArgsAfterDesignator = 0;6443 for (const Expr *Arg : Args) {6444 if (const auto *DIE = dyn_cast<DesignatedInitExpr>(Arg)) {6445 if (DIE->size() == 1 && DIE->getDesignator(0)->isFieldDesignator()) {6446 DesignatedFieldName = DIE->getDesignator(0)->getFieldName();6447 ArgsAfterDesignator = 0;6448 } else {6449 return Invalid; // Complicated designator.6450 }6451 } else if (isa<DesignatedInitUpdateExpr>(Arg)) {6452 return Invalid; // Unsupported.6453 } else {6454 ++ArgsAfterDesignator;6455 }6456 }6457 if (!DesignatedFieldName)6458 return std::nullopt;6459 6460 // Find the index within the class's fields.6461 // (Probing getParamDecl() directly would be quadratic in number of fields).6462 unsigned DesignatedIndex = 0;6463 const FieldDecl *DesignatedField = nullptr;6464 for (const auto *Field : Aggregate.getAggregate()->fields()) {6465 if (Field->getIdentifier() == DesignatedFieldName) {6466 DesignatedField = Field;6467 break;6468 }6469 ++DesignatedIndex;6470 }6471 if (!DesignatedField)6472 return Invalid; // Designator referred to a missing field, give up.6473 6474 // Find the index within the aggregate (which may have leading bases).6475 unsigned AggregateSize = Aggregate.getNumParams();6476 while (DesignatedIndex < AggregateSize &&6477 Aggregate.getParamDecl(DesignatedIndex) != DesignatedField)6478 ++DesignatedIndex;6479 6480 // Continue from the index after the last named field.6481 return DesignatedIndex + ArgsAfterDesignator + 1;6482}6483 6484QualType SemaCodeCompletion::ProduceConstructorSignatureHelp(6485 QualType Type, SourceLocation Loc, ArrayRef<Expr *> Args,6486 SourceLocation OpenParLoc, bool Braced) {6487 if (!CodeCompleter)6488 return QualType();6489 SmallVector<ResultCandidate, 8> Results;6490 6491 // A complete type is needed to lookup for constructors.6492 RecordDecl *RD =6493 SemaRef.isCompleteType(Loc, Type) ? Type->getAsRecordDecl() : nullptr;6494 if (!RD)6495 return Type;6496 CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD);6497 6498 // Consider aggregate initialization.6499 // We don't check that types so far are correct.6500 // We also don't handle C99/C++17 brace-elision, we assume init-list elements6501 // are 1:1 with fields.6502 // FIXME: it would be nice to support "unwrapping" aggregates that contain6503 // a single subaggregate, like std::array<T, N> -> T __elements[N].6504 if (Braced && !RD->isUnion() &&6505 (!getLangOpts().CPlusPlus || (CRD && CRD->isAggregate()))) {6506 ResultCandidate AggregateSig(RD);6507 unsigned AggregateSize = AggregateSig.getNumParams();6508 6509 if (auto NextIndex =6510 getNextAggregateIndexAfterDesignatedInit(AggregateSig, Args)) {6511 // A designator was used, only aggregate init is possible.6512 if (*NextIndex >= AggregateSize)6513 return Type;6514 Results.push_back(AggregateSig);6515 return ProduceSignatureHelp(SemaRef, Results, *NextIndex, OpenParLoc,6516 Braced);6517 }6518 6519 // Describe aggregate initialization, but also constructors below.6520 if (Args.size() < AggregateSize)6521 Results.push_back(AggregateSig);6522 }6523 6524 // FIXME: Provide support for member initializers.6525 // FIXME: Provide support for variadic template constructors.6526 6527 if (CRD) {6528 OverloadCandidateSet CandidateSet(Loc,6529 OverloadCandidateSet::CSK_CodeCompletion);6530 for (NamedDecl *C : SemaRef.LookupConstructors(CRD)) {6531 if (auto *FD = dyn_cast<FunctionDecl>(C)) {6532 // FIXME: we can't yet provide correct signature help for initializer6533 // list constructors, so skip them entirely.6534 if (Braced && getLangOpts().CPlusPlus &&6535 SemaRef.isInitListConstructor(FD))6536 continue;6537 SemaRef.AddOverloadCandidate(6538 FD, DeclAccessPair::make(FD, C->getAccess()), Args, CandidateSet,6539 /*SuppressUserConversions=*/false,6540 /*PartialOverloading=*/true,6541 /*AllowExplicit*/ true);6542 } else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(C)) {6543 if (Braced && getLangOpts().CPlusPlus &&6544 SemaRef.isInitListConstructor(FTD->getTemplatedDecl()))6545 continue;6546 6547 SemaRef.AddTemplateOverloadCandidate(6548 FTD, DeclAccessPair::make(FTD, C->getAccess()),6549 /*ExplicitTemplateArgs=*/nullptr, Args, CandidateSet,6550 /*SuppressUserConversions=*/false,6551 /*PartialOverloading=*/true);6552 }6553 }6554 mergeCandidatesWithResults(SemaRef, Results, CandidateSet, Loc,6555 Args.size());6556 }6557 6558 return ProduceSignatureHelp(SemaRef, Results, Args.size(), OpenParLoc,6559 Braced);6560}6561 6562QualType SemaCodeCompletion::ProduceCtorInitMemberSignatureHelp(6563 Decl *ConstructorDecl, CXXScopeSpec SS, ParsedType TemplateTypeTy,6564 ArrayRef<Expr *> ArgExprs, IdentifierInfo *II, SourceLocation OpenParLoc,6565 bool Braced) {6566 if (!CodeCompleter)6567 return QualType();6568 6569 CXXConstructorDecl *Constructor =6570 dyn_cast<CXXConstructorDecl>(ConstructorDecl);6571 if (!Constructor)6572 return QualType();6573 // FIXME: Add support for Base class constructors as well.6574 if (ValueDecl *MemberDecl = SemaRef.tryLookupCtorInitMemberDecl(6575 Constructor->getParent(), SS, TemplateTypeTy, II))6576 return ProduceConstructorSignatureHelp(MemberDecl->getType(),6577 MemberDecl->getLocation(), ArgExprs,6578 OpenParLoc, Braced);6579 return QualType();6580}6581 6582static bool argMatchesTemplateParams(const ParsedTemplateArgument &Arg,6583 unsigned Index,6584 const TemplateParameterList &Params) {6585 const NamedDecl *Param;6586 if (Index < Params.size())6587 Param = Params.getParam(Index);6588 else if (Params.hasParameterPack())6589 Param = Params.asArray().back();6590 else6591 return false; // too many args6592 6593 switch (Arg.getKind()) {6594 case ParsedTemplateArgument::Type:6595 return llvm::isa<TemplateTypeParmDecl>(Param); // constraints not checked6596 case ParsedTemplateArgument::NonType:6597 return llvm::isa<NonTypeTemplateParmDecl>(Param); // type not checked6598 case ParsedTemplateArgument::Template:6599 return llvm::isa<TemplateTemplateParmDecl>(Param); // signature not checked6600 }6601 llvm_unreachable("Unhandled switch case");6602}6603 6604QualType SemaCodeCompletion::ProduceTemplateArgumentSignatureHelp(6605 TemplateTy ParsedTemplate, ArrayRef<ParsedTemplateArgument> Args,6606 SourceLocation LAngleLoc) {6607 if (!CodeCompleter || !ParsedTemplate)6608 return QualType();6609 6610 SmallVector<ResultCandidate, 8> Results;6611 auto Consider = [&](const TemplateDecl *TD) {6612 // Only add if the existing args are compatible with the template.6613 bool Matches = true;6614 for (unsigned I = 0; I < Args.size(); ++I) {6615 if (!argMatchesTemplateParams(Args[I], I, *TD->getTemplateParameters())) {6616 Matches = false;6617 break;6618 }6619 }6620 if (Matches)6621 Results.emplace_back(TD);6622 };6623 6624 TemplateName Template = ParsedTemplate.get();6625 if (const auto *TD = Template.getAsTemplateDecl()) {6626 Consider(TD);6627 } else if (const auto *OTS = Template.getAsOverloadedTemplate()) {6628 for (const NamedDecl *ND : *OTS)6629 if (const auto *TD = llvm::dyn_cast<TemplateDecl>(ND))6630 Consider(TD);6631 }6632 return ProduceSignatureHelp(SemaRef, Results, Args.size(), LAngleLoc,6633 /*Braced=*/false);6634}6635 6636static QualType getDesignatedType(QualType BaseType, const Designation &Desig,6637 HeuristicResolver &Resolver) {6638 for (unsigned I = 0; I < Desig.getNumDesignators(); ++I) {6639 if (BaseType.isNull())6640 break;6641 QualType NextType;6642 const auto &D = Desig.getDesignator(I);6643 if (D.isArrayDesignator() || D.isArrayRangeDesignator()) {6644 if (BaseType->isArrayType())6645 NextType = BaseType->getAsArrayTypeUnsafe()->getElementType();6646 } else {6647 assert(D.isFieldDesignator());6648 auto *RD = getAsRecordDecl(BaseType, Resolver);6649 if (RD && RD->isCompleteDefinition()) {6650 for (const auto *Member : RD->lookup(D.getFieldDecl()))6651 if (const FieldDecl *FD = llvm::dyn_cast<FieldDecl>(Member)) {6652 NextType = FD->getType();6653 break;6654 }6655 }6656 }6657 BaseType = NextType;6658 }6659 return BaseType;6660}6661 6662void SemaCodeCompletion::CodeCompleteDesignator(6663 QualType BaseType, llvm::ArrayRef<Expr *> InitExprs, const Designation &D) {6664 BaseType = getDesignatedType(BaseType, D, Resolver);6665 if (BaseType.isNull())6666 return;6667 const auto *RD = getAsRecordDecl(BaseType, Resolver);6668 if (!RD || RD->fields().empty())6669 return;6670 6671 CodeCompletionContext CCC(CodeCompletionContext::CCC_DotMemberAccess,6672 BaseType);6673 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),6674 CodeCompleter->getCodeCompletionTUInfo(), CCC);6675 6676 Results.EnterNewScope();6677 for (const Decl *D : RD->decls()) {6678 const FieldDecl *FD;6679 if (auto *IFD = dyn_cast<IndirectFieldDecl>(D))6680 FD = IFD->getAnonField();6681 else if (auto *DFD = dyn_cast<FieldDecl>(D))6682 FD = DFD;6683 else6684 continue;6685 6686 // FIXME: Make use of previous designators to mark any fields before those6687 // inaccessible, and also compute the next initializer priority.6688 ResultBuilder::Result Result(FD, Results.getBasePriority(FD));6689 Results.AddResult(Result, SemaRef.CurContext, /*Hiding=*/nullptr);6690 }6691 Results.ExitScope();6692 HandleCodeCompleteResults(&SemaRef, CodeCompleter,6693 Results.getCompletionContext(), Results.data(),6694 Results.size());6695}6696 6697void SemaCodeCompletion::CodeCompleteInitializer(Scope *S, Decl *D) {6698 ValueDecl *VD = dyn_cast_or_null<ValueDecl>(D);6699 if (!VD) {6700 CodeCompleteOrdinaryName(S, PCC_Expression);6701 return;6702 }6703 6704 CodeCompleteExpressionData Data;6705 Data.PreferredType = VD->getType();6706 // Ignore VD to avoid completing the variable itself, e.g. in 'int foo = ^'.6707 Data.IgnoreDecls.push_back(VD);6708 6709 CodeCompleteExpression(S, Data);6710}6711 6712void SemaCodeCompletion::CodeCompleteKeywordAfterIf(bool AfterExclaim) const {6713 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),6714 CodeCompleter->getCodeCompletionTUInfo(),6715 CodeCompletionContext::CCC_Other);6716 CodeCompletionBuilder Builder(Results.getAllocator(),6717 Results.getCodeCompletionTUInfo());6718 if (getLangOpts().CPlusPlus17) {6719 if (!AfterExclaim) {6720 if (Results.includeCodePatterns()) {6721 Builder.AddTypedTextChunk("constexpr");6722 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);6723 Builder.AddChunk(CodeCompletionString::CK_LeftParen);6724 Builder.AddPlaceholderChunk("condition");6725 Builder.AddChunk(CodeCompletionString::CK_RightParen);6726 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);6727 Builder.AddChunk(CodeCompletionString::CK_LeftBrace);6728 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);6729 Builder.AddPlaceholderChunk("statements");6730 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);6731 Builder.AddChunk(CodeCompletionString::CK_RightBrace);6732 Results.AddResult({Builder.TakeString()});6733 } else {6734 Results.AddResult({"constexpr"});6735 }6736 }6737 }6738 if (getLangOpts().CPlusPlus23) {6739 if (Results.includeCodePatterns()) {6740 Builder.AddTypedTextChunk("consteval");6741 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);6742 Builder.AddChunk(CodeCompletionString::CK_LeftBrace);6743 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);6744 Builder.AddPlaceholderChunk("statements");6745 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);6746 Builder.AddChunk(CodeCompletionString::CK_RightBrace);6747 Results.AddResult({Builder.TakeString()});6748 } else {6749 Results.AddResult({"consteval"});6750 }6751 }6752 6753 HandleCodeCompleteResults(&SemaRef, CodeCompleter,6754 Results.getCompletionContext(), Results.data(),6755 Results.size());6756}6757 6758void SemaCodeCompletion::CodeCompleteAfterIf(Scope *S, bool IsBracedThen) {6759 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),6760 CodeCompleter->getCodeCompletionTUInfo(),6761 mapCodeCompletionContext(SemaRef, PCC_Statement));6762 Results.setFilter(&ResultBuilder::IsOrdinaryName);6763 Results.EnterNewScope();6764 6765 CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext);6766 SemaRef.LookupVisibleDecls(S, Sema::LookupOrdinaryName, Consumer,6767 CodeCompleter->includeGlobals(),6768 CodeCompleter->loadExternal());6769 6770 AddOrdinaryNameResults(PCC_Statement, S, SemaRef, Results);6771 6772 // "else" block6773 CodeCompletionBuilder Builder(Results.getAllocator(),6774 Results.getCodeCompletionTUInfo());6775 6776 auto AddElseBodyPattern = [&] {6777 if (IsBracedThen) {6778 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);6779 Builder.AddChunk(CodeCompletionString::CK_LeftBrace);6780 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);6781 Builder.AddPlaceholderChunk("statements");6782 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);6783 Builder.AddChunk(CodeCompletionString::CK_RightBrace);6784 } else {6785 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);6786 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);6787 Builder.AddPlaceholderChunk("statement");6788 Builder.AddChunk(CodeCompletionString::CK_SemiColon);6789 }6790 };6791 Builder.AddTypedTextChunk("else");6792 if (Results.includeCodePatterns())6793 AddElseBodyPattern();6794 Results.AddResult(Builder.TakeString());6795 6796 // "else if" block6797 Builder.AddTypedTextChunk("else if");6798 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);6799 Builder.AddChunk(CodeCompletionString::CK_LeftParen);6800 if (getLangOpts().CPlusPlus)6801 Builder.AddPlaceholderChunk("condition");6802 else6803 Builder.AddPlaceholderChunk("expression");6804 Builder.AddChunk(CodeCompletionString::CK_RightParen);6805 if (Results.includeCodePatterns()) {6806 AddElseBodyPattern();6807 }6808 Results.AddResult(Builder.TakeString());6809 6810 Results.ExitScope();6811 6812 if (S->getFnParent())6813 AddPrettyFunctionResults(getLangOpts(), Results);6814 6815 if (CodeCompleter->includeMacros())6816 AddMacroResults(SemaRef.PP, Results, CodeCompleter->loadExternal(), false);6817 6818 HandleCodeCompleteResults(&SemaRef, CodeCompleter,6819 Results.getCompletionContext(), Results.data(),6820 Results.size());6821}6822 6823void SemaCodeCompletion::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,6824 bool EnteringContext,6825 bool IsUsingDeclaration,6826 QualType BaseType,6827 QualType PreferredType) {6828 if (SS.isEmpty() || !CodeCompleter)6829 return;6830 6831 CodeCompletionContext CC(CodeCompletionContext::CCC_Symbol, PreferredType);6832 CC.setIsUsingDeclaration(IsUsingDeclaration);6833 CC.setCXXScopeSpecifier(SS);6834 6835 // We want to keep the scope specifier even if it's invalid (e.g. the scope6836 // "a::b::" is not corresponding to any context/namespace in the AST), since6837 // it can be useful for global code completion which have information about6838 // contexts/symbols that are not in the AST.6839 if (SS.isInvalid()) {6840 // As SS is invalid, we try to collect accessible contexts from the current6841 // scope with a dummy lookup so that the completion consumer can try to6842 // guess what the specified scope is.6843 ResultBuilder DummyResults(SemaRef, CodeCompleter->getAllocator(),6844 CodeCompleter->getCodeCompletionTUInfo(), CC);6845 if (!PreferredType.isNull())6846 DummyResults.setPreferredType(PreferredType);6847 if (S->getEntity()) {6848 CodeCompletionDeclConsumer Consumer(DummyResults, S->getEntity(),6849 BaseType);6850 SemaRef.LookupVisibleDecls(S, Sema::LookupOrdinaryName, Consumer,6851 /*IncludeGlobalScope=*/false,6852 /*LoadExternal=*/false);6853 }6854 HandleCodeCompleteResults(&SemaRef, CodeCompleter,6855 DummyResults.getCompletionContext(), nullptr, 0);6856 return;6857 }6858 // Always pretend to enter a context to ensure that a dependent type6859 // resolves to a dependent record.6860 DeclContext *Ctx = SemaRef.computeDeclContext(SS, /*EnteringContext=*/true);6861 6862 // Try to instantiate any non-dependent declaration contexts before6863 // we look in them. Bail out if we fail.6864 NestedNameSpecifier NNS = SS.getScopeRep();6865 if (NNS && !NNS.isDependent()) {6866 if (Ctx == nullptr || SemaRef.RequireCompleteDeclContext(SS, Ctx))6867 return;6868 }6869 6870 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),6871 CodeCompleter->getCodeCompletionTUInfo(), CC);6872 if (!PreferredType.isNull())6873 Results.setPreferredType(PreferredType);6874 Results.EnterNewScope();6875 6876 // The "template" keyword can follow "::" in the grammar, but only6877 // put it into the grammar if the nested-name-specifier is dependent.6878 // FIXME: results is always empty, this appears to be dead.6879 if (!Results.empty() && NNS.isDependent())6880 Results.AddResult("template");6881 6882 // If the scope is a concept-constrained type parameter, infer nested6883 // members based on the constraints.6884 if (NNS.getKind() == NestedNameSpecifier::Kind::Type) {6885 if (const auto *TTPT = dyn_cast<TemplateTypeParmType>(NNS.getAsType())) {6886 for (const auto &R : ConceptInfo(*TTPT, S).members()) {6887 if (R.Operator != ConceptInfo::Member::Colons)6888 continue;6889 Results.AddResult(CodeCompletionResult(6890 R.render(SemaRef, CodeCompleter->getAllocator(),6891 CodeCompleter->getCodeCompletionTUInfo())));6892 }6893 }6894 }6895 6896 // Add calls to overridden virtual functions, if there are any.6897 //6898 // FIXME: This isn't wonderful, because we don't know whether we're actually6899 // in a context that permits expressions. This is a general issue with6900 // qualified-id completions.6901 if (Ctx && !EnteringContext)6902 MaybeAddOverrideCalls(SemaRef, Ctx, Results);6903 Results.ExitScope();6904 6905 if (Ctx &&6906 (CodeCompleter->includeNamespaceLevelDecls() || !Ctx->isFileContext())) {6907 CodeCompletionDeclConsumer Consumer(Results, Ctx, BaseType);6908 SemaRef.LookupVisibleDecls(Ctx, Sema::LookupOrdinaryName, Consumer,6909 /*IncludeGlobalScope=*/true,6910 /*IncludeDependentBases=*/true,6911 CodeCompleter->loadExternal());6912 }6913 6914 HandleCodeCompleteResults(&SemaRef, CodeCompleter,6915 Results.getCompletionContext(), Results.data(),6916 Results.size());6917}6918 6919void SemaCodeCompletion::CodeCompleteUsing(Scope *S) {6920 if (!CodeCompleter)6921 return;6922 6923 // This can be both a using alias or using declaration, in the former we6924 // expect a new name and a symbol in the latter case.6925 CodeCompletionContext Context(CodeCompletionContext::CCC_SymbolOrNewName);6926 Context.setIsUsingDeclaration(true);6927 6928 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),6929 CodeCompleter->getCodeCompletionTUInfo(), Context,6930 &ResultBuilder::IsNestedNameSpecifier);6931 Results.EnterNewScope();6932 6933 // If we aren't in class scope, we could see the "namespace" keyword.6934 if (!S->isClassScope())6935 Results.AddResult(CodeCompletionResult("namespace"));6936 6937 // After "using", we can see anything that would start a6938 // nested-name-specifier.6939 CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext);6940 SemaRef.LookupVisibleDecls(S, Sema::LookupOrdinaryName, Consumer,6941 CodeCompleter->includeGlobals(),6942 CodeCompleter->loadExternal());6943 Results.ExitScope();6944 6945 HandleCodeCompleteResults(&SemaRef, CodeCompleter,6946 Results.getCompletionContext(), Results.data(),6947 Results.size());6948}6949 6950void SemaCodeCompletion::CodeCompleteUsingDirective(Scope *S) {6951 if (!CodeCompleter)6952 return;6953 6954 // After "using namespace", we expect to see a namespace name or namespace6955 // alias.6956 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),6957 CodeCompleter->getCodeCompletionTUInfo(),6958 CodeCompletionContext::CCC_Namespace,6959 &ResultBuilder::IsNamespaceOrAlias);6960 Results.EnterNewScope();6961 CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext);6962 SemaRef.LookupVisibleDecls(S, Sema::LookupOrdinaryName, Consumer,6963 CodeCompleter->includeGlobals(),6964 CodeCompleter->loadExternal());6965 Results.ExitScope();6966 HandleCodeCompleteResults(&SemaRef, CodeCompleter,6967 Results.getCompletionContext(), Results.data(),6968 Results.size());6969}6970 6971void SemaCodeCompletion::CodeCompleteNamespaceDecl(Scope *S) {6972 if (!CodeCompleter)6973 return;6974 6975 DeclContext *Ctx = S->getEntity();6976 if (!S->getParent())6977 Ctx = getASTContext().getTranslationUnitDecl();6978 6979 bool SuppressedGlobalResults =6980 Ctx && !CodeCompleter->includeGlobals() && isa<TranslationUnitDecl>(Ctx);6981 6982 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),6983 CodeCompleter->getCodeCompletionTUInfo(),6984 SuppressedGlobalResults6985 ? CodeCompletionContext::CCC_Namespace6986 : CodeCompletionContext::CCC_Other,6987 &ResultBuilder::IsNamespace);6988 6989 if (Ctx && Ctx->isFileContext() && !SuppressedGlobalResults) {6990 // We only want to see those namespaces that have already been defined6991 // within this scope, because its likely that the user is creating an6992 // extended namespace declaration. Keep track of the most recent6993 // definition of each namespace.6994 std::map<NamespaceDecl *, NamespaceDecl *> OrigToLatest;6995 for (DeclContext::specific_decl_iterator<NamespaceDecl>6996 NS(Ctx->decls_begin()),6997 NSEnd(Ctx->decls_end());6998 NS != NSEnd; ++NS)6999 OrigToLatest[NS->getFirstDecl()] = *NS;7000 7001 // Add the most recent definition (or extended definition) of each7002 // namespace to the list of results.7003 Results.EnterNewScope();7004 for (std::map<NamespaceDecl *, NamespaceDecl *>::iterator7005 NS = OrigToLatest.begin(),7006 NSEnd = OrigToLatest.end();7007 NS != NSEnd; ++NS)7008 Results.AddResult(7009 CodeCompletionResult(NS->second, Results.getBasePriority(NS->second),7010 /*Qualifier=*/std::nullopt),7011 SemaRef.CurContext, nullptr, false);7012 Results.ExitScope();7013 }7014 7015 HandleCodeCompleteResults(&SemaRef, CodeCompleter,7016 Results.getCompletionContext(), Results.data(),7017 Results.size());7018}7019 7020void SemaCodeCompletion::CodeCompleteNamespaceAliasDecl(Scope *S) {7021 if (!CodeCompleter)7022 return;7023 7024 // After "namespace", we expect to see a namespace or alias.7025 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),7026 CodeCompleter->getCodeCompletionTUInfo(),7027 CodeCompletionContext::CCC_Namespace,7028 &ResultBuilder::IsNamespaceOrAlias);7029 CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext);7030 SemaRef.LookupVisibleDecls(S, Sema::LookupOrdinaryName, Consumer,7031 CodeCompleter->includeGlobals(),7032 CodeCompleter->loadExternal());7033 HandleCodeCompleteResults(&SemaRef, CodeCompleter,7034 Results.getCompletionContext(), Results.data(),7035 Results.size());7036}7037 7038void SemaCodeCompletion::CodeCompleteOperatorName(Scope *S) {7039 if (!CodeCompleter)7040 return;7041 7042 typedef CodeCompletionResult Result;7043 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),7044 CodeCompleter->getCodeCompletionTUInfo(),7045 CodeCompletionContext::CCC_Type,7046 &ResultBuilder::IsType);7047 Results.EnterNewScope();7048 7049 // Add the names of overloadable operators. Note that OO_Conditional is not7050 // actually overloadable.7051#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \7052 if (OO_##Name != OO_Conditional) \7053 Results.AddResult(Result(Spelling));7054#include "clang/Basic/OperatorKinds.def"7055 7056 // Add any type names visible from the current scope7057 Results.allowNestedNameSpecifiers();7058 CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext);7059 SemaRef.LookupVisibleDecls(S, Sema::LookupOrdinaryName, Consumer,7060 CodeCompleter->includeGlobals(),7061 CodeCompleter->loadExternal());7062 7063 // Add any type specifiers7064 AddTypeSpecifierResults(getLangOpts(), Results);7065 Results.ExitScope();7066 7067 HandleCodeCompleteResults(&SemaRef, CodeCompleter,7068 Results.getCompletionContext(), Results.data(),7069 Results.size());7070}7071 7072void SemaCodeCompletion::CodeCompleteConstructorInitializer(7073 Decl *ConstructorD, ArrayRef<CXXCtorInitializer *> Initializers) {7074 if (!ConstructorD)7075 return;7076 7077 SemaRef.AdjustDeclIfTemplate(ConstructorD);7078 7079 auto *Constructor = dyn_cast<CXXConstructorDecl>(ConstructorD);7080 if (!Constructor)7081 return;7082 7083 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),7084 CodeCompleter->getCodeCompletionTUInfo(),7085 CodeCompletionContext::CCC_Symbol);7086 Results.EnterNewScope();7087 7088 // Fill in any already-initialized fields or base classes.7089 llvm::SmallPtrSet<FieldDecl *, 4> InitializedFields;7090 llvm::SmallPtrSet<CanQualType, 4> InitializedBases;7091 for (unsigned I = 0, E = Initializers.size(); I != E; ++I) {7092 if (Initializers[I]->isBaseInitializer())7093 InitializedBases.insert(getASTContext().getCanonicalType(7094 QualType(Initializers[I]->getBaseClass(), 0)));7095 else7096 InitializedFields.insert(7097 cast<FieldDecl>(Initializers[I]->getAnyMember()));7098 }7099 7100 // Add completions for base classes.7101 PrintingPolicy Policy = getCompletionPrintingPolicy(SemaRef);7102 bool SawLastInitializer = Initializers.empty();7103 CXXRecordDecl *ClassDecl = Constructor->getParent();7104 7105 auto GenerateCCS = [&](const NamedDecl *ND, const char *Name) {7106 CodeCompletionBuilder Builder(Results.getAllocator(),7107 Results.getCodeCompletionTUInfo());7108 Builder.AddTypedTextChunk(Name);7109 Builder.AddChunk(CodeCompletionString::CK_LeftParen);7110 if (const auto *Function = dyn_cast<FunctionDecl>(ND))7111 AddFunctionParameterChunks(SemaRef.PP, Policy, Function, Builder);7112 else if (const auto *FunTemplDecl = dyn_cast<FunctionTemplateDecl>(ND))7113 AddFunctionParameterChunks(SemaRef.PP, Policy,7114 FunTemplDecl->getTemplatedDecl(), Builder);7115 Builder.AddChunk(CodeCompletionString::CK_RightParen);7116 return Builder.TakeString();7117 };7118 auto AddDefaultCtorInit = [&](const char *Name, const char *Type,7119 const NamedDecl *ND) {7120 CodeCompletionBuilder Builder(Results.getAllocator(),7121 Results.getCodeCompletionTUInfo());7122 Builder.AddTypedTextChunk(Name);7123 Builder.AddChunk(CodeCompletionString::CK_LeftParen);7124 Builder.AddPlaceholderChunk(Type);7125 Builder.AddChunk(CodeCompletionString::CK_RightParen);7126 if (ND) {7127 auto CCR = CodeCompletionResult(7128 Builder.TakeString(), ND,7129 SawLastInitializer ? CCP_NextInitializer : CCP_MemberDeclaration);7130 if (isa<FieldDecl>(ND))7131 CCR.CursorKind = CXCursor_MemberRef;7132 return Results.AddResult(CCR);7133 }7134 return Results.AddResult(CodeCompletionResult(7135 Builder.TakeString(),7136 SawLastInitializer ? CCP_NextInitializer : CCP_MemberDeclaration));7137 };7138 auto AddCtorsWithName = [&](const CXXRecordDecl *RD, unsigned int Priority,7139 const char *Name, const FieldDecl *FD) {7140 if (!RD)7141 return AddDefaultCtorInit(Name,7142 FD ? Results.getAllocator().CopyString(7143 FD->getType().getAsString(Policy))7144 : Name,7145 FD);7146 auto Ctors = getConstructors(getASTContext(), RD);7147 if (Ctors.begin() == Ctors.end())7148 return AddDefaultCtorInit(Name, Name, RD);7149 for (const NamedDecl *Ctor : Ctors) {7150 auto CCR = CodeCompletionResult(GenerateCCS(Ctor, Name), RD, Priority);7151 CCR.CursorKind = getCursorKindForDecl(Ctor);7152 Results.AddResult(CCR);7153 }7154 };7155 auto AddBase = [&](const CXXBaseSpecifier &Base) {7156 const char *BaseName =7157 Results.getAllocator().CopyString(Base.getType().getAsString(Policy));7158 const auto *RD = Base.getType()->getAsCXXRecordDecl();7159 AddCtorsWithName(7160 RD, SawLastInitializer ? CCP_NextInitializer : CCP_MemberDeclaration,7161 BaseName, nullptr);7162 };7163 auto AddField = [&](const FieldDecl *FD) {7164 const char *FieldName =7165 Results.getAllocator().CopyString(FD->getIdentifier()->getName());7166 const CXXRecordDecl *RD = FD->getType()->getAsCXXRecordDecl();7167 AddCtorsWithName(7168 RD, SawLastInitializer ? CCP_NextInitializer : CCP_MemberDeclaration,7169 FieldName, FD);7170 };7171 7172 for (const auto &Base : ClassDecl->bases()) {7173 if (!InitializedBases7174 .insert(getASTContext().getCanonicalType(Base.getType()))7175 .second) {7176 SawLastInitializer =7177 !Initializers.empty() && Initializers.back()->isBaseInitializer() &&7178 getASTContext().hasSameUnqualifiedType(7179 Base.getType(), QualType(Initializers.back()->getBaseClass(), 0));7180 continue;7181 }7182 7183 AddBase(Base);7184 SawLastInitializer = false;7185 }7186 7187 // Add completions for virtual base classes.7188 for (const auto &Base : ClassDecl->vbases()) {7189 if (!InitializedBases7190 .insert(getASTContext().getCanonicalType(Base.getType()))7191 .second) {7192 SawLastInitializer =7193 !Initializers.empty() && Initializers.back()->isBaseInitializer() &&7194 getASTContext().hasSameUnqualifiedType(7195 Base.getType(), QualType(Initializers.back()->getBaseClass(), 0));7196 continue;7197 }7198 7199 AddBase(Base);7200 SawLastInitializer = false;7201 }7202 7203 // Add completions for members.7204 for (auto *Field : ClassDecl->fields()) {7205 if (!InitializedFields.insert(cast<FieldDecl>(Field->getCanonicalDecl()))7206 .second) {7207 SawLastInitializer = !Initializers.empty() &&7208 Initializers.back()->isAnyMemberInitializer() &&7209 Initializers.back()->getAnyMember() == Field;7210 continue;7211 }7212 7213 if (!Field->getDeclName())7214 continue;7215 7216 AddField(Field);7217 SawLastInitializer = false;7218 }7219 Results.ExitScope();7220 7221 HandleCodeCompleteResults(&SemaRef, CodeCompleter,7222 Results.getCompletionContext(), Results.data(),7223 Results.size());7224}7225 7226/// Determine whether this scope denotes a namespace.7227static bool isNamespaceScope(Scope *S) {7228 DeclContext *DC = S->getEntity();7229 if (!DC)7230 return false;7231 7232 return DC->isFileContext();7233}7234 7235void SemaCodeCompletion::CodeCompleteLambdaIntroducer(Scope *S,7236 LambdaIntroducer &Intro,7237 bool AfterAmpersand) {7238 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),7239 CodeCompleter->getCodeCompletionTUInfo(),7240 CodeCompletionContext::CCC_Other);7241 Results.EnterNewScope();7242 7243 // Note what has already been captured.7244 llvm::SmallPtrSet<IdentifierInfo *, 4> Known;7245 bool IncludedThis = false;7246 for (const auto &C : Intro.Captures) {7247 if (C.Kind == LCK_This) {7248 IncludedThis = true;7249 continue;7250 }7251 7252 Known.insert(C.Id);7253 }7254 7255 // Look for other capturable variables.7256 for (; S && !isNamespaceScope(S); S = S->getParent()) {7257 for (const auto *D : S->decls()) {7258 const auto *Var = dyn_cast<VarDecl>(D);7259 if (!Var || !Var->hasLocalStorage() || Var->hasAttr<BlocksAttr>())7260 continue;7261 7262 if (Known.insert(Var->getIdentifier()).second)7263 Results.AddResult(CodeCompletionResult(Var, CCP_LocalDeclaration),7264 SemaRef.CurContext, nullptr, false);7265 }7266 }7267 7268 // Add 'this', if it would be valid.7269 if (!IncludedThis && !AfterAmpersand && Intro.Default != LCD_ByCopy)7270 addThisCompletion(SemaRef, Results);7271 7272 Results.ExitScope();7273 7274 HandleCodeCompleteResults(&SemaRef, CodeCompleter,7275 Results.getCompletionContext(), Results.data(),7276 Results.size());7277}7278 7279void SemaCodeCompletion::CodeCompleteAfterFunctionEquals(Declarator &D) {7280 if (!getLangOpts().CPlusPlus11)7281 return;7282 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),7283 CodeCompleter->getCodeCompletionTUInfo(),7284 CodeCompletionContext::CCC_Other);7285 auto ShouldAddDefault = [&D, this]() {7286 if (!D.isFunctionDeclarator())7287 return false;7288 auto &Id = D.getName();7289 if (Id.getKind() == UnqualifiedIdKind::IK_DestructorName)7290 return true;7291 // FIXME(liuhui): Ideally, we should check the constructor parameter list to7292 // verify that it is the default, copy or move constructor?7293 if (Id.getKind() == UnqualifiedIdKind::IK_ConstructorName &&7294 D.getFunctionTypeInfo().NumParams <= 1)7295 return true;7296 if (Id.getKind() == UnqualifiedIdKind::IK_OperatorFunctionId) {7297 auto Op = Id.OperatorFunctionId.Operator;7298 // FIXME(liuhui): Ideally, we should check the function parameter list to7299 // verify that it is the copy or move assignment?7300 if (Op == OverloadedOperatorKind::OO_Equal)7301 return true;7302 if (getLangOpts().CPlusPlus20 &&7303 (Op == OverloadedOperatorKind::OO_EqualEqual ||7304 Op == OverloadedOperatorKind::OO_ExclaimEqual ||7305 Op == OverloadedOperatorKind::OO_Less ||7306 Op == OverloadedOperatorKind::OO_LessEqual ||7307 Op == OverloadedOperatorKind::OO_Greater ||7308 Op == OverloadedOperatorKind::OO_GreaterEqual ||7309 Op == OverloadedOperatorKind::OO_Spaceship))7310 return true;7311 }7312 return false;7313 };7314 7315 Results.EnterNewScope();7316 if (ShouldAddDefault())7317 Results.AddResult("default");7318 // FIXME(liuhui): Ideally, we should only provide `delete` completion for the7319 // first function declaration.7320 Results.AddResult("delete");7321 Results.ExitScope();7322 HandleCodeCompleteResults(&SemaRef, CodeCompleter,7323 Results.getCompletionContext(), Results.data(),7324 Results.size());7325}7326 7327/// Macro that optionally prepends an "@" to the string literal passed in via7328/// Keyword, depending on whether NeedAt is true or false.7329#define OBJC_AT_KEYWORD_NAME(NeedAt, Keyword) ((NeedAt) ? "@" Keyword : Keyword)7330 7331static void AddObjCImplementationResults(const LangOptions &LangOpts,7332 ResultBuilder &Results, bool NeedAt) {7333 typedef CodeCompletionResult Result;7334 // Since we have an implementation, we can end it.7335 Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt, "end")));7336 7337 CodeCompletionBuilder Builder(Results.getAllocator(),7338 Results.getCodeCompletionTUInfo());7339 if (LangOpts.ObjC) {7340 // @dynamic7341 Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "dynamic"));7342 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);7343 Builder.AddPlaceholderChunk("property");7344 Results.AddResult(Result(Builder.TakeString()));7345 7346 // @synthesize7347 Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "synthesize"));7348 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);7349 Builder.AddPlaceholderChunk("property");7350 Results.AddResult(Result(Builder.TakeString()));7351 }7352}7353 7354static void AddObjCInterfaceResults(const LangOptions &LangOpts,7355 ResultBuilder &Results, bool NeedAt) {7356 typedef CodeCompletionResult Result;7357 7358 // Since we have an interface or protocol, we can end it.7359 Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt, "end")));7360 7361 if (LangOpts.ObjC) {7362 // @property7363 Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt, "property")));7364 7365 // @required7366 Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt, "required")));7367 7368 // @optional7369 Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt, "optional")));7370 }7371}7372 7373static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) {7374 typedef CodeCompletionResult Result;7375 CodeCompletionBuilder Builder(Results.getAllocator(),7376 Results.getCodeCompletionTUInfo());7377 7378 // @class name ;7379 Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "class"));7380 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);7381 Builder.AddPlaceholderChunk("name");7382 Results.AddResult(Result(Builder.TakeString()));7383 7384 if (Results.includeCodePatterns()) {7385 // @interface name7386 // FIXME: Could introduce the whole pattern, including superclasses and7387 // such.7388 Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "interface"));7389 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);7390 Builder.AddPlaceholderChunk("class");7391 Results.AddResult(Result(Builder.TakeString()));7392 7393 // @protocol name7394 Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "protocol"));7395 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);7396 Builder.AddPlaceholderChunk("protocol");7397 Results.AddResult(Result(Builder.TakeString()));7398 7399 // @implementation name7400 Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "implementation"));7401 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);7402 Builder.AddPlaceholderChunk("class");7403 Results.AddResult(Result(Builder.TakeString()));7404 }7405 7406 // @compatibility_alias name7407 Builder.AddTypedTextChunk(7408 OBJC_AT_KEYWORD_NAME(NeedAt, "compatibility_alias"));7409 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);7410 Builder.AddPlaceholderChunk("alias");7411 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);7412 Builder.AddPlaceholderChunk("class");7413 Results.AddResult(Result(Builder.TakeString()));7414 7415 if (Results.getSema().getLangOpts().Modules) {7416 // @import name7417 Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "import"));7418 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);7419 Builder.AddPlaceholderChunk("module");7420 Results.AddResult(Result(Builder.TakeString()));7421 }7422}7423 7424void SemaCodeCompletion::CodeCompleteObjCAtDirective(Scope *S) {7425 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),7426 CodeCompleter->getCodeCompletionTUInfo(),7427 CodeCompletionContext::CCC_Other);7428 Results.EnterNewScope();7429 if (isa<ObjCImplDecl>(SemaRef.CurContext))7430 AddObjCImplementationResults(getLangOpts(), Results, false);7431 else if (SemaRef.CurContext->isObjCContainer())7432 AddObjCInterfaceResults(getLangOpts(), Results, false);7433 else7434 AddObjCTopLevelResults(Results, false);7435 Results.ExitScope();7436 HandleCodeCompleteResults(&SemaRef, CodeCompleter,7437 Results.getCompletionContext(), Results.data(),7438 Results.size());7439}7440 7441static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) {7442 typedef CodeCompletionResult Result;7443 CodeCompletionBuilder Builder(Results.getAllocator(),7444 Results.getCodeCompletionTUInfo());7445 7446 // @encode ( type-name )7447 const char *EncodeType = "char[]";7448 if (Results.getSema().getLangOpts().CPlusPlus ||7449 Results.getSema().getLangOpts().ConstStrings)7450 EncodeType = "const char[]";7451 Builder.AddResultTypeChunk(EncodeType);7452 Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "encode"));7453 Builder.AddChunk(CodeCompletionString::CK_LeftParen);7454 Builder.AddPlaceholderChunk("type-name");7455 Builder.AddChunk(CodeCompletionString::CK_RightParen);7456 Results.AddResult(Result(Builder.TakeString()));7457 7458 // @protocol ( protocol-name )7459 Builder.AddResultTypeChunk("Protocol *");7460 Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "protocol"));7461 Builder.AddChunk(CodeCompletionString::CK_LeftParen);7462 Builder.AddPlaceholderChunk("protocol-name");7463 Builder.AddChunk(CodeCompletionString::CK_RightParen);7464 Results.AddResult(Result(Builder.TakeString()));7465 7466 // @selector ( selector )7467 Builder.AddResultTypeChunk("SEL");7468 Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "selector"));7469 Builder.AddChunk(CodeCompletionString::CK_LeftParen);7470 Builder.AddPlaceholderChunk("selector");7471 Builder.AddChunk(CodeCompletionString::CK_RightParen);7472 Results.AddResult(Result(Builder.TakeString()));7473 7474 // @"string"7475 Builder.AddResultTypeChunk("NSString *");7476 Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "\""));7477 Builder.AddPlaceholderChunk("string");7478 Builder.AddTextChunk("\"");7479 Results.AddResult(Result(Builder.TakeString()));7480 7481 // @[objects, ...]7482 Builder.AddResultTypeChunk("NSArray *");7483 Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "["));7484 Builder.AddPlaceholderChunk("objects, ...");7485 Builder.AddChunk(CodeCompletionString::CK_RightBracket);7486 Results.AddResult(Result(Builder.TakeString()));7487 7488 // @{key : object, ...}7489 Builder.AddResultTypeChunk("NSDictionary *");7490 Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "{"));7491 Builder.AddPlaceholderChunk("key");7492 Builder.AddChunk(CodeCompletionString::CK_Colon);7493 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);7494 Builder.AddPlaceholderChunk("object, ...");7495 Builder.AddChunk(CodeCompletionString::CK_RightBrace);7496 Results.AddResult(Result(Builder.TakeString()));7497 7498 // @(expression)7499 Builder.AddResultTypeChunk("id");7500 Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "("));7501 Builder.AddPlaceholderChunk("expression");7502 Builder.AddChunk(CodeCompletionString::CK_RightParen);7503 Results.AddResult(Result(Builder.TakeString()));7504}7505 7506static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) {7507 typedef CodeCompletionResult Result;7508 CodeCompletionBuilder Builder(Results.getAllocator(),7509 Results.getCodeCompletionTUInfo());7510 7511 if (Results.includeCodePatterns()) {7512 // @try { statements } @catch ( declaration ) { statements } @finally7513 // { statements }7514 Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "try"));7515 Builder.AddChunk(CodeCompletionString::CK_LeftBrace);7516 Builder.AddPlaceholderChunk("statements");7517 Builder.AddChunk(CodeCompletionString::CK_RightBrace);7518 Builder.AddTextChunk("@catch");7519 Builder.AddChunk(CodeCompletionString::CK_LeftParen);7520 Builder.AddPlaceholderChunk("parameter");7521 Builder.AddChunk(CodeCompletionString::CK_RightParen);7522 Builder.AddChunk(CodeCompletionString::CK_LeftBrace);7523 Builder.AddPlaceholderChunk("statements");7524 Builder.AddChunk(CodeCompletionString::CK_RightBrace);7525 Builder.AddTextChunk("@finally");7526 Builder.AddChunk(CodeCompletionString::CK_LeftBrace);7527 Builder.AddPlaceholderChunk("statements");7528 Builder.AddChunk(CodeCompletionString::CK_RightBrace);7529 Results.AddResult(Result(Builder.TakeString()));7530 }7531 7532 // @throw7533 Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "throw"));7534 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);7535 Builder.AddPlaceholderChunk("expression");7536 Results.AddResult(Result(Builder.TakeString()));7537 7538 if (Results.includeCodePatterns()) {7539 // @synchronized ( expression ) { statements }7540 Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "synchronized"));7541 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);7542 Builder.AddChunk(CodeCompletionString::CK_LeftParen);7543 Builder.AddPlaceholderChunk("expression");7544 Builder.AddChunk(CodeCompletionString::CK_RightParen);7545 Builder.AddChunk(CodeCompletionString::CK_LeftBrace);7546 Builder.AddPlaceholderChunk("statements");7547 Builder.AddChunk(CodeCompletionString::CK_RightBrace);7548 Results.AddResult(Result(Builder.TakeString()));7549 }7550}7551 7552static void AddObjCVisibilityResults(const LangOptions &LangOpts,7553 ResultBuilder &Results, bool NeedAt) {7554 typedef CodeCompletionResult Result;7555 Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt, "private")));7556 Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt, "protected")));7557 Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt, "public")));7558 if (LangOpts.ObjC)7559 Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt, "package")));7560}7561 7562void SemaCodeCompletion::CodeCompleteObjCAtVisibility(Scope *S) {7563 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),7564 CodeCompleter->getCodeCompletionTUInfo(),7565 CodeCompletionContext::CCC_Other);7566 Results.EnterNewScope();7567 AddObjCVisibilityResults(getLangOpts(), Results, false);7568 Results.ExitScope();7569 HandleCodeCompleteResults(&SemaRef, CodeCompleter,7570 Results.getCompletionContext(), Results.data(),7571 Results.size());7572}7573 7574void SemaCodeCompletion::CodeCompleteObjCAtStatement(Scope *S) {7575 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),7576 CodeCompleter->getCodeCompletionTUInfo(),7577 CodeCompletionContext::CCC_Other);7578 Results.EnterNewScope();7579 AddObjCStatementResults(Results, false);7580 AddObjCExpressionResults(Results, false);7581 Results.ExitScope();7582 HandleCodeCompleteResults(&SemaRef, CodeCompleter,7583 Results.getCompletionContext(), Results.data(),7584 Results.size());7585}7586 7587void SemaCodeCompletion::CodeCompleteObjCAtExpression(Scope *S) {7588 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),7589 CodeCompleter->getCodeCompletionTUInfo(),7590 CodeCompletionContext::CCC_Other);7591 Results.EnterNewScope();7592 AddObjCExpressionResults(Results, false);7593 Results.ExitScope();7594 HandleCodeCompleteResults(&SemaRef, CodeCompleter,7595 Results.getCompletionContext(), Results.data(),7596 Results.size());7597}7598 7599/// Determine whether the addition of the given flag to an Objective-C7600/// property's attributes will cause a conflict.7601static bool ObjCPropertyFlagConflicts(unsigned Attributes, unsigned NewFlag) {7602 // Check if we've already added this flag.7603 if (Attributes & NewFlag)7604 return true;7605 7606 Attributes |= NewFlag;7607 7608 // Check for collisions with "readonly".7609 if ((Attributes & ObjCPropertyAttribute::kind_readonly) &&7610 (Attributes & ObjCPropertyAttribute::kind_readwrite))7611 return true;7612 7613 // Check for more than one of { assign, copy, retain, strong, weak }.7614 unsigned AssignCopyRetMask =7615 Attributes &7616 (ObjCPropertyAttribute::kind_assign |7617 ObjCPropertyAttribute::kind_unsafe_unretained |7618 ObjCPropertyAttribute::kind_copy | ObjCPropertyAttribute::kind_retain |7619 ObjCPropertyAttribute::kind_strong | ObjCPropertyAttribute::kind_weak);7620 if (AssignCopyRetMask &&7621 AssignCopyRetMask != ObjCPropertyAttribute::kind_assign &&7622 AssignCopyRetMask != ObjCPropertyAttribute::kind_unsafe_unretained &&7623 AssignCopyRetMask != ObjCPropertyAttribute::kind_copy &&7624 AssignCopyRetMask != ObjCPropertyAttribute::kind_retain &&7625 AssignCopyRetMask != ObjCPropertyAttribute::kind_strong &&7626 AssignCopyRetMask != ObjCPropertyAttribute::kind_weak)7627 return true;7628 7629 return false;7630}7631 7632void SemaCodeCompletion::CodeCompleteObjCPropertyFlags(Scope *S,7633 ObjCDeclSpec &ODS) {7634 if (!CodeCompleter)7635 return;7636 7637 unsigned Attributes = ODS.getPropertyAttributes();7638 7639 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),7640 CodeCompleter->getCodeCompletionTUInfo(),7641 CodeCompletionContext::CCC_Other);7642 Results.EnterNewScope();7643 if (!ObjCPropertyFlagConflicts(Attributes,7644 ObjCPropertyAttribute::kind_readonly))7645 Results.AddResult(CodeCompletionResult("readonly"));7646 if (!ObjCPropertyFlagConflicts(Attributes,7647 ObjCPropertyAttribute::kind_assign))7648 Results.AddResult(CodeCompletionResult("assign"));7649 if (!ObjCPropertyFlagConflicts(Attributes,7650 ObjCPropertyAttribute::kind_unsafe_unretained))7651 Results.AddResult(CodeCompletionResult("unsafe_unretained"));7652 if (!ObjCPropertyFlagConflicts(Attributes,7653 ObjCPropertyAttribute::kind_readwrite))7654 Results.AddResult(CodeCompletionResult("readwrite"));7655 if (!ObjCPropertyFlagConflicts(Attributes,7656 ObjCPropertyAttribute::kind_retain))7657 Results.AddResult(CodeCompletionResult("retain"));7658 if (!ObjCPropertyFlagConflicts(Attributes,7659 ObjCPropertyAttribute::kind_strong))7660 Results.AddResult(CodeCompletionResult("strong"));7661 if (!ObjCPropertyFlagConflicts(Attributes, ObjCPropertyAttribute::kind_copy))7662 Results.AddResult(CodeCompletionResult("copy"));7663 if (!ObjCPropertyFlagConflicts(Attributes,7664 ObjCPropertyAttribute::kind_nonatomic))7665 Results.AddResult(CodeCompletionResult("nonatomic"));7666 if (!ObjCPropertyFlagConflicts(Attributes,7667 ObjCPropertyAttribute::kind_atomic))7668 Results.AddResult(CodeCompletionResult("atomic"));7669 7670 // Only suggest "weak" if we're compiling for ARC-with-weak-references or GC.7671 if (getLangOpts().ObjCWeak || getLangOpts().getGC() != LangOptions::NonGC)7672 if (!ObjCPropertyFlagConflicts(Attributes,7673 ObjCPropertyAttribute::kind_weak))7674 Results.AddResult(CodeCompletionResult("weak"));7675 7676 if (!ObjCPropertyFlagConflicts(Attributes,7677 ObjCPropertyAttribute::kind_setter)) {7678 CodeCompletionBuilder Setter(Results.getAllocator(),7679 Results.getCodeCompletionTUInfo());7680 Setter.AddTypedTextChunk("setter");7681 Setter.AddTextChunk("=");7682 Setter.AddPlaceholderChunk("method");7683 Results.AddResult(CodeCompletionResult(Setter.TakeString()));7684 }7685 if (!ObjCPropertyFlagConflicts(Attributes,7686 ObjCPropertyAttribute::kind_getter)) {7687 CodeCompletionBuilder Getter(Results.getAllocator(),7688 Results.getCodeCompletionTUInfo());7689 Getter.AddTypedTextChunk("getter");7690 Getter.AddTextChunk("=");7691 Getter.AddPlaceholderChunk("method");7692 Results.AddResult(CodeCompletionResult(Getter.TakeString()));7693 }7694 if (!ObjCPropertyFlagConflicts(Attributes,7695 ObjCPropertyAttribute::kind_nullability)) {7696 Results.AddResult(CodeCompletionResult("nonnull"));7697 Results.AddResult(CodeCompletionResult("nullable"));7698 Results.AddResult(CodeCompletionResult("null_unspecified"));7699 Results.AddResult(CodeCompletionResult("null_resettable"));7700 }7701 Results.ExitScope();7702 HandleCodeCompleteResults(&SemaRef, CodeCompleter,7703 Results.getCompletionContext(), Results.data(),7704 Results.size());7705}7706 7707/// Describes the kind of Objective-C method that we want to find7708/// via code completion.7709enum ObjCMethodKind {7710 MK_Any, ///< Any kind of method, provided it means other specified criteria.7711 MK_ZeroArgSelector, ///< Zero-argument (unary) selector.7712 MK_OneArgSelector ///< One-argument selector.7713};7714 7715static bool isAcceptableObjCSelector(Selector Sel, ObjCMethodKind WantKind,7716 ArrayRef<const IdentifierInfo *> SelIdents,7717 bool AllowSameLength = true) {7718 unsigned NumSelIdents = SelIdents.size();7719 if (NumSelIdents > Sel.getNumArgs())7720 return false;7721 7722 switch (WantKind) {7723 case MK_Any:7724 break;7725 case MK_ZeroArgSelector:7726 return Sel.isUnarySelector();7727 case MK_OneArgSelector:7728 return Sel.getNumArgs() == 1;7729 }7730 7731 if (!AllowSameLength && NumSelIdents && NumSelIdents == Sel.getNumArgs())7732 return false;7733 7734 for (unsigned I = 0; I != NumSelIdents; ++I)7735 if (SelIdents[I] != Sel.getIdentifierInfoForSlot(I))7736 return false;7737 7738 return true;7739}7740 7741static bool isAcceptableObjCMethod(ObjCMethodDecl *Method,7742 ObjCMethodKind WantKind,7743 ArrayRef<const IdentifierInfo *> SelIdents,7744 bool AllowSameLength = true) {7745 return isAcceptableObjCSelector(Method->getSelector(), WantKind, SelIdents,7746 AllowSameLength);7747}7748 7749/// A set of selectors, which is used to avoid introducing multiple7750/// completions with the same selector into the result set.7751typedef llvm::SmallPtrSet<Selector, 16> VisitedSelectorSet;7752 7753/// Add all of the Objective-C methods in the given Objective-C7754/// container to the set of results.7755///7756/// The container will be a class, protocol, category, or implementation of7757/// any of the above. This mether will recurse to include methods from7758/// the superclasses of classes along with their categories, protocols, and7759/// implementations.7760///7761/// \param Container the container in which we'll look to find methods.7762///7763/// \param WantInstanceMethods Whether to add instance methods (only); if7764/// false, this routine will add factory methods (only).7765///7766/// \param CurContext the context in which we're performing the lookup that7767/// finds methods.7768///7769/// \param AllowSameLength Whether we allow a method to be added to the list7770/// when it has the same number of parameters as we have selector identifiers.7771///7772/// \param Results the structure into which we'll add results.7773static void AddObjCMethods(ObjCContainerDecl *Container,7774 bool WantInstanceMethods, ObjCMethodKind WantKind,7775 ArrayRef<const IdentifierInfo *> SelIdents,7776 DeclContext *CurContext,7777 VisitedSelectorSet &Selectors, bool AllowSameLength,7778 ResultBuilder &Results, bool InOriginalClass = true,7779 bool IsRootClass = false) {7780 typedef CodeCompletionResult Result;7781 Container = getContainerDef(Container);7782 ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container);7783 IsRootClass = IsRootClass || (IFace && !IFace->getSuperClass());7784 for (ObjCMethodDecl *M : Container->methods()) {7785 // The instance methods on the root class can be messaged via the7786 // metaclass.7787 if (M->isInstanceMethod() == WantInstanceMethods ||7788 (IsRootClass && !WantInstanceMethods)) {7789 // Check whether the selector identifiers we've been given are a7790 // subset of the identifiers for this particular method.7791 if (!isAcceptableObjCMethod(M, WantKind, SelIdents, AllowSameLength))7792 continue;7793 7794 if (!Selectors.insert(M->getSelector()).second)7795 continue;7796 7797 Result R =7798 Result(M, Results.getBasePriority(M), /*Qualifier=*/std::nullopt);7799 R.StartParameter = SelIdents.size();7800 R.AllParametersAreInformative = (WantKind != MK_Any);7801 if (!InOriginalClass)7802 setInBaseClass(R);7803 Results.MaybeAddResult(R, CurContext);7804 }7805 }7806 7807 // Visit the protocols of protocols.7808 if (const auto *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {7809 if (Protocol->hasDefinition()) {7810 const ObjCList<ObjCProtocolDecl> &Protocols =7811 Protocol->getReferencedProtocols();7812 for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),7813 E = Protocols.end();7814 I != E; ++I)7815 AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, CurContext,7816 Selectors, AllowSameLength, Results, false, IsRootClass);7817 }7818 }7819 7820 if (!IFace || !IFace->hasDefinition())7821 return;7822 7823 // Add methods in protocols.7824 for (ObjCProtocolDecl *I : IFace->protocols())7825 AddObjCMethods(I, WantInstanceMethods, WantKind, SelIdents, CurContext,7826 Selectors, AllowSameLength, Results, false, IsRootClass);7827 7828 // Add methods in categories.7829 for (ObjCCategoryDecl *CatDecl : IFace->known_categories()) {7830 AddObjCMethods(CatDecl, WantInstanceMethods, WantKind, SelIdents,7831 CurContext, Selectors, AllowSameLength, Results,7832 InOriginalClass, IsRootClass);7833 7834 // Add a categories protocol methods.7835 const ObjCList<ObjCProtocolDecl> &Protocols =7836 CatDecl->getReferencedProtocols();7837 for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),7838 E = Protocols.end();7839 I != E; ++I)7840 AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, CurContext,7841 Selectors, AllowSameLength, Results, false, IsRootClass);7842 7843 // Add methods in category implementations.7844 if (ObjCCategoryImplDecl *Impl = CatDecl->getImplementation())7845 AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, CurContext,7846 Selectors, AllowSameLength, Results, InOriginalClass,7847 IsRootClass);7848 }7849 7850 // Add methods in superclass.7851 // Avoid passing in IsRootClass since root classes won't have super classes.7852 if (IFace->getSuperClass())7853 AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, WantKind,7854 SelIdents, CurContext, Selectors, AllowSameLength, Results,7855 /*IsRootClass=*/false);7856 7857 // Add methods in our implementation, if any.7858 if (ObjCImplementationDecl *Impl = IFace->getImplementation())7859 AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, CurContext,7860 Selectors, AllowSameLength, Results, InOriginalClass,7861 IsRootClass);7862}7863 7864void SemaCodeCompletion::CodeCompleteObjCPropertyGetter(Scope *S) {7865 // Try to find the interface where getters might live.7866 ObjCInterfaceDecl *Class =7867 dyn_cast_or_null<ObjCInterfaceDecl>(SemaRef.CurContext);7868 if (!Class) {7869 if (ObjCCategoryDecl *Category =7870 dyn_cast_or_null<ObjCCategoryDecl>(SemaRef.CurContext))7871 Class = Category->getClassInterface();7872 7873 if (!Class)7874 return;7875 }7876 7877 // Find all of the potential getters.7878 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),7879 CodeCompleter->getCodeCompletionTUInfo(),7880 CodeCompletionContext::CCC_Other);7881 Results.EnterNewScope();7882 7883 VisitedSelectorSet Selectors;7884 AddObjCMethods(Class, true, MK_ZeroArgSelector, {}, SemaRef.CurContext,7885 Selectors,7886 /*AllowSameLength=*/true, Results);7887 Results.ExitScope();7888 HandleCodeCompleteResults(&SemaRef, CodeCompleter,7889 Results.getCompletionContext(), Results.data(),7890 Results.size());7891}7892 7893void SemaCodeCompletion::CodeCompleteObjCPropertySetter(Scope *S) {7894 // Try to find the interface where setters might live.7895 ObjCInterfaceDecl *Class =7896 dyn_cast_or_null<ObjCInterfaceDecl>(SemaRef.CurContext);7897 if (!Class) {7898 if (ObjCCategoryDecl *Category =7899 dyn_cast_or_null<ObjCCategoryDecl>(SemaRef.CurContext))7900 Class = Category->getClassInterface();7901 7902 if (!Class)7903 return;7904 }7905 7906 // Find all of the potential getters.7907 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),7908 CodeCompleter->getCodeCompletionTUInfo(),7909 CodeCompletionContext::CCC_Other);7910 Results.EnterNewScope();7911 7912 VisitedSelectorSet Selectors;7913 AddObjCMethods(Class, true, MK_OneArgSelector, {}, SemaRef.CurContext,7914 Selectors,7915 /*AllowSameLength=*/true, Results);7916 7917 Results.ExitScope();7918 HandleCodeCompleteResults(&SemaRef, CodeCompleter,7919 Results.getCompletionContext(), Results.data(),7920 Results.size());7921}7922 7923void SemaCodeCompletion::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS,7924 bool IsParameter) {7925 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),7926 CodeCompleter->getCodeCompletionTUInfo(),7927 CodeCompletionContext::CCC_Type);7928 Results.EnterNewScope();7929 7930 // Add context-sensitive, Objective-C parameter-passing keywords.7931 bool AddedInOut = false;7932 if ((DS.getObjCDeclQualifier() &7933 (ObjCDeclSpec::DQ_In | ObjCDeclSpec::DQ_Inout)) == 0) {7934 Results.AddResult("in");7935 Results.AddResult("inout");7936 AddedInOut = true;7937 }7938 if ((DS.getObjCDeclQualifier() &7939 (ObjCDeclSpec::DQ_Out | ObjCDeclSpec::DQ_Inout)) == 0) {7940 Results.AddResult("out");7941 if (!AddedInOut)7942 Results.AddResult("inout");7943 }7944 if ((DS.getObjCDeclQualifier() &7945 (ObjCDeclSpec::DQ_Bycopy | ObjCDeclSpec::DQ_Byref |7946 ObjCDeclSpec::DQ_Oneway)) == 0) {7947 Results.AddResult("bycopy");7948 Results.AddResult("byref");7949 Results.AddResult("oneway");7950 }7951 if ((DS.getObjCDeclQualifier() & ObjCDeclSpec::DQ_CSNullability) == 0) {7952 Results.AddResult("nonnull");7953 Results.AddResult("nullable");7954 Results.AddResult("null_unspecified");7955 }7956 7957 // If we're completing the return type of an Objective-C method and the7958 // identifier IBAction refers to a macro, provide a completion item for7959 // an action, e.g.,7960 // IBAction)<#selector#>:(id)sender7961 if (DS.getObjCDeclQualifier() == 0 && !IsParameter &&7962 SemaRef.PP.isMacroDefined("IBAction")) {7963 CodeCompletionBuilder Builder(Results.getAllocator(),7964 Results.getCodeCompletionTUInfo(),7965 CCP_CodePattern, CXAvailability_Available);7966 Builder.AddTypedTextChunk("IBAction");7967 Builder.AddChunk(CodeCompletionString::CK_RightParen);7968 Builder.AddPlaceholderChunk("selector");7969 Builder.AddChunk(CodeCompletionString::CK_Colon);7970 Builder.AddChunk(CodeCompletionString::CK_LeftParen);7971 Builder.AddTextChunk("id");7972 Builder.AddChunk(CodeCompletionString::CK_RightParen);7973 Builder.AddTextChunk("sender");7974 Results.AddResult(CodeCompletionResult(Builder.TakeString()));7975 }7976 7977 // If we're completing the return type, provide 'instancetype'.7978 if (!IsParameter) {7979 Results.AddResult(CodeCompletionResult("instancetype"));7980 }7981 7982 // Add various builtin type names and specifiers.7983 AddOrdinaryNameResults(PCC_Type, S, SemaRef, Results);7984 Results.ExitScope();7985 7986 // Add the various type names7987 Results.setFilter(&ResultBuilder::IsOrdinaryNonValueName);7988 CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext);7989 SemaRef.LookupVisibleDecls(S, Sema::LookupOrdinaryName, Consumer,7990 CodeCompleter->includeGlobals(),7991 CodeCompleter->loadExternal());7992 7993 if (CodeCompleter->includeMacros())7994 AddMacroResults(SemaRef.PP, Results, CodeCompleter->loadExternal(), false);7995 7996 HandleCodeCompleteResults(&SemaRef, CodeCompleter,7997 Results.getCompletionContext(), Results.data(),7998 Results.size());7999}8000 8001/// When we have an expression with type "id", we may assume8002/// that it has some more-specific class type based on knowledge of8003/// common uses of Objective-C. This routine returns that class type,8004/// or NULL if no better result could be determined.8005static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) {8006 auto *Msg = dyn_cast_or_null<ObjCMessageExpr>(E);8007 if (!Msg)8008 return nullptr;8009 8010 Selector Sel = Msg->getSelector();8011 if (Sel.isNull())8012 return nullptr;8013 8014 const IdentifierInfo *Id = Sel.getIdentifierInfoForSlot(0);8015 if (!Id)8016 return nullptr;8017 8018 ObjCMethodDecl *Method = Msg->getMethodDecl();8019 if (!Method)8020 return nullptr;8021 8022 // Determine the class that we're sending the message to.8023 ObjCInterfaceDecl *IFace = nullptr;8024 switch (Msg->getReceiverKind()) {8025 case ObjCMessageExpr::Class:8026 if (const ObjCObjectType *ObjType =8027 Msg->getClassReceiver()->getAs<ObjCObjectType>())8028 IFace = ObjType->getInterface();8029 break;8030 8031 case ObjCMessageExpr::Instance: {8032 QualType T = Msg->getInstanceReceiver()->getType();8033 if (const ObjCObjectPointerType *Ptr = T->getAs<ObjCObjectPointerType>())8034 IFace = Ptr->getInterfaceDecl();8035 break;8036 }8037 8038 case ObjCMessageExpr::SuperInstance:8039 case ObjCMessageExpr::SuperClass:8040 break;8041 }8042 8043 if (!IFace)8044 return nullptr;8045 8046 ObjCInterfaceDecl *Super = IFace->getSuperClass();8047 if (Method->isInstanceMethod())8048 return llvm::StringSwitch<ObjCInterfaceDecl *>(Id->getName())8049 .Case("retain", IFace)8050 .Case("strong", IFace)8051 .Case("autorelease", IFace)8052 .Case("copy", IFace)8053 .Case("copyWithZone", IFace)8054 .Case("mutableCopy", IFace)8055 .Case("mutableCopyWithZone", IFace)8056 .Case("awakeFromCoder", IFace)8057 .Case("replacementObjectFromCoder", IFace)8058 .Case("class", IFace)8059 .Case("classForCoder", IFace)8060 .Case("superclass", Super)8061 .Default(nullptr);8062 8063 return llvm::StringSwitch<ObjCInterfaceDecl *>(Id->getName())8064 .Case("new", IFace)8065 .Case("alloc", IFace)8066 .Case("allocWithZone", IFace)8067 .Case("class", IFace)8068 .Case("superclass", Super)8069 .Default(nullptr);8070}8071 8072// Add a special completion for a message send to "super", which fills in the8073// most likely case of forwarding all of our arguments to the superclass8074// function.8075///8076/// \param S The semantic analysis object.8077///8078/// \param NeedSuperKeyword Whether we need to prefix this completion with8079/// the "super" keyword. Otherwise, we just need to provide the arguments.8080///8081/// \param SelIdents The identifiers in the selector that have already been8082/// provided as arguments for a send to "super".8083///8084/// \param Results The set of results to augment.8085///8086/// \returns the Objective-C method declaration that would be invoked by8087/// this "super" completion. If NULL, no completion was added.8088static ObjCMethodDecl *8089AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword,8090 ArrayRef<const IdentifierInfo *> SelIdents,8091 ResultBuilder &Results) {8092 ObjCMethodDecl *CurMethod = S.getCurMethodDecl();8093 if (!CurMethod)8094 return nullptr;8095 8096 ObjCInterfaceDecl *Class = CurMethod->getClassInterface();8097 if (!Class)8098 return nullptr;8099 8100 // Try to find a superclass method with the same selector.8101 ObjCMethodDecl *SuperMethod = nullptr;8102 while ((Class = Class->getSuperClass()) && !SuperMethod) {8103 // Check in the class8104 SuperMethod = Class->getMethod(CurMethod->getSelector(),8105 CurMethod->isInstanceMethod());8106 8107 // Check in categories or class extensions.8108 if (!SuperMethod) {8109 for (const auto *Cat : Class->known_categories()) {8110 if ((SuperMethod = Cat->getMethod(CurMethod->getSelector(),8111 CurMethod->isInstanceMethod())))8112 break;8113 }8114 }8115 }8116 8117 if (!SuperMethod)8118 return nullptr;8119 8120 // Check whether the superclass method has the same signature.8121 if (CurMethod->param_size() != SuperMethod->param_size() ||8122 CurMethod->isVariadic() != SuperMethod->isVariadic())8123 return nullptr;8124 8125 for (ObjCMethodDecl::param_iterator CurP = CurMethod->param_begin(),8126 CurPEnd = CurMethod->param_end(),8127 SuperP = SuperMethod->param_begin();8128 CurP != CurPEnd; ++CurP, ++SuperP) {8129 // Make sure the parameter types are compatible.8130 if (!S.Context.hasSameUnqualifiedType((*CurP)->getType(),8131 (*SuperP)->getType()))8132 return nullptr;8133 8134 // Make sure we have a parameter name to forward!8135 if (!(*CurP)->getIdentifier())8136 return nullptr;8137 }8138 8139 // We have a superclass method. Now, form the send-to-super completion.8140 CodeCompletionBuilder Builder(Results.getAllocator(),8141 Results.getCodeCompletionTUInfo());8142 8143 // Give this completion a return type.8144 AddResultTypeChunk(S.Context, getCompletionPrintingPolicy(S), SuperMethod,8145 Results.getCompletionContext().getBaseType(), Builder);8146 8147 // If we need the "super" keyword, add it (plus some spacing).8148 if (NeedSuperKeyword) {8149 Builder.AddTypedTextChunk("super");8150 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);8151 }8152 8153 Selector Sel = CurMethod->getSelector();8154 if (Sel.isUnarySelector()) {8155 if (NeedSuperKeyword)8156 Builder.AddTextChunk(8157 Builder.getAllocator().CopyString(Sel.getNameForSlot(0)));8158 else8159 Builder.AddTypedTextChunk(8160 Builder.getAllocator().CopyString(Sel.getNameForSlot(0)));8161 } else {8162 ObjCMethodDecl::param_iterator CurP = CurMethod->param_begin();8163 for (unsigned I = 0, N = Sel.getNumArgs(); I != N; ++I, ++CurP) {8164 if (I > SelIdents.size())8165 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);8166 8167 if (I < SelIdents.size())8168 Builder.AddInformativeChunk(8169 Builder.getAllocator().CopyString(Sel.getNameForSlot(I) + ":"));8170 else if (NeedSuperKeyword || I > SelIdents.size()) {8171 Builder.AddTextChunk(8172 Builder.getAllocator().CopyString(Sel.getNameForSlot(I) + ":"));8173 Builder.AddPlaceholderChunk(Builder.getAllocator().CopyString(8174 (*CurP)->getIdentifier()->getName()));8175 } else {8176 Builder.AddTypedTextChunk(8177 Builder.getAllocator().CopyString(Sel.getNameForSlot(I) + ":"));8178 Builder.AddPlaceholderChunk(Builder.getAllocator().CopyString(8179 (*CurP)->getIdentifier()->getName()));8180 }8181 }8182 }8183 8184 Results.AddResult(CodeCompletionResult(Builder.TakeString(), SuperMethod,8185 CCP_SuperCompletion));8186 return SuperMethod;8187}8188 8189void SemaCodeCompletion::CodeCompleteObjCMessageReceiver(Scope *S) {8190 typedef CodeCompletionResult Result;8191 ResultBuilder Results(8192 SemaRef, CodeCompleter->getAllocator(),8193 CodeCompleter->getCodeCompletionTUInfo(),8194 CodeCompletionContext::CCC_ObjCMessageReceiver,8195 getLangOpts().CPlusPlus118196 ? &ResultBuilder::IsObjCMessageReceiverOrLambdaCapture8197 : &ResultBuilder::IsObjCMessageReceiver);8198 8199 CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext);8200 Results.EnterNewScope();8201 SemaRef.LookupVisibleDecls(S, Sema::LookupOrdinaryName, Consumer,8202 CodeCompleter->includeGlobals(),8203 CodeCompleter->loadExternal());8204 8205 // If we are in an Objective-C method inside a class that has a superclass,8206 // add "super" as an option.8207 if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl())8208 if (ObjCInterfaceDecl *Iface = Method->getClassInterface())8209 if (Iface->getSuperClass()) {8210 Results.AddResult(Result("super"));8211 8212 AddSuperSendCompletion(SemaRef, /*NeedSuperKeyword=*/true, {}, Results);8213 }8214 8215 if (getLangOpts().CPlusPlus11)8216 addThisCompletion(SemaRef, Results);8217 8218 Results.ExitScope();8219 8220 if (CodeCompleter->includeMacros())8221 AddMacroResults(SemaRef.PP, Results, CodeCompleter->loadExternal(), false);8222 HandleCodeCompleteResults(&SemaRef, CodeCompleter,8223 Results.getCompletionContext(), Results.data(),8224 Results.size());8225}8226 8227void SemaCodeCompletion::CodeCompleteObjCSuperMessage(8228 Scope *S, SourceLocation SuperLoc,8229 ArrayRef<const IdentifierInfo *> SelIdents, bool AtArgumentExpression) {8230 ObjCInterfaceDecl *CDecl = nullptr;8231 if (ObjCMethodDecl *CurMethod = SemaRef.getCurMethodDecl()) {8232 // Figure out which interface we're in.8233 CDecl = CurMethod->getClassInterface();8234 if (!CDecl)8235 return;8236 8237 // Find the superclass of this class.8238 CDecl = CDecl->getSuperClass();8239 if (!CDecl)8240 return;8241 8242 if (CurMethod->isInstanceMethod()) {8243 // We are inside an instance method, which means that the message8244 // send [super ...] is actually calling an instance method on the8245 // current object.8246 return CodeCompleteObjCInstanceMessage(S, nullptr, SelIdents,8247 AtArgumentExpression, CDecl);8248 }8249 8250 // Fall through to send to the superclass in CDecl.8251 } else {8252 // "super" may be the name of a type or variable. Figure out which8253 // it is.8254 const IdentifierInfo *Super = SemaRef.getSuperIdentifier();8255 NamedDecl *ND =8256 SemaRef.LookupSingleName(S, Super, SuperLoc, Sema::LookupOrdinaryName);8257 if ((CDecl = dyn_cast_or_null<ObjCInterfaceDecl>(ND))) {8258 // "super" names an interface. Use it.8259 } else if (TypeDecl *TD = dyn_cast_or_null<TypeDecl>(ND)) {8260 if (const ObjCObjectType *Iface =8261 getASTContext().getTypeDeclType(TD)->getAs<ObjCObjectType>())8262 CDecl = Iface->getInterface();8263 } else if (ND && isa<UnresolvedUsingTypenameDecl>(ND)) {8264 // "super" names an unresolved type; we can't be more specific.8265 } else {8266 // Assume that "super" names some kind of value and parse that way.8267 CXXScopeSpec SS;8268 SourceLocation TemplateKWLoc;8269 UnqualifiedId id;8270 id.setIdentifier(Super, SuperLoc);8271 ExprResult SuperExpr =8272 SemaRef.ActOnIdExpression(S, SS, TemplateKWLoc, id,8273 /*HasTrailingLParen=*/false,8274 /*IsAddressOfOperand=*/false);8275 return CodeCompleteObjCInstanceMessage(S, (Expr *)SuperExpr.get(),8276 SelIdents, AtArgumentExpression);8277 }8278 8279 // Fall through8280 }8281 8282 ParsedType Receiver;8283 if (CDecl)8284 Receiver = ParsedType::make(getASTContext().getObjCInterfaceType(CDecl));8285 return CodeCompleteObjCClassMessage(S, Receiver, SelIdents,8286 AtArgumentExpression,8287 /*IsSuper=*/true);8288}8289 8290/// Given a set of code-completion results for the argument of a message8291/// send, determine the preferred type (if any) for that argument expression.8292static QualType getPreferredArgumentTypeForMessageSend(ResultBuilder &Results,8293 unsigned NumSelIdents) {8294 typedef CodeCompletionResult Result;8295 ASTContext &Context = Results.getSema().Context;8296 8297 QualType PreferredType;8298 unsigned BestPriority = CCP_Unlikely * 2;8299 Result *ResultsData = Results.data();8300 for (unsigned I = 0, N = Results.size(); I != N; ++I) {8301 Result &R = ResultsData[I];8302 if (R.Kind == Result::RK_Declaration &&8303 isa<ObjCMethodDecl>(R.Declaration)) {8304 if (R.Priority <= BestPriority) {8305 const ObjCMethodDecl *Method = cast<ObjCMethodDecl>(R.Declaration);8306 if (NumSelIdents <= Method->param_size()) {8307 QualType MyPreferredType =8308 Method->parameters()[NumSelIdents - 1]->getType();8309 if (R.Priority < BestPriority || PreferredType.isNull()) {8310 BestPriority = R.Priority;8311 PreferredType = MyPreferredType;8312 } else if (!Context.hasSameUnqualifiedType(PreferredType,8313 MyPreferredType)) {8314 PreferredType = QualType();8315 }8316 }8317 }8318 }8319 }8320 8321 return PreferredType;8322}8323 8324static void8325AddClassMessageCompletions(Sema &SemaRef, Scope *S, ParsedType Receiver,8326 ArrayRef<const IdentifierInfo *> SelIdents,8327 bool AtArgumentExpression, bool IsSuper,8328 ResultBuilder &Results) {8329 typedef CodeCompletionResult Result;8330 ObjCInterfaceDecl *CDecl = nullptr;8331 8332 // If the given name refers to an interface type, retrieve the8333 // corresponding declaration.8334 if (Receiver) {8335 QualType T = SemaRef.GetTypeFromParser(Receiver, nullptr);8336 if (!T.isNull())8337 if (const ObjCObjectType *Interface = T->getAs<ObjCObjectType>())8338 CDecl = Interface->getInterface();8339 }8340 8341 // Add all of the factory methods in this Objective-C class, its protocols,8342 // superclasses, categories, implementation, etc.8343 Results.EnterNewScope();8344 8345 // If this is a send-to-super, try to add the special "super" send8346 // completion.8347 if (IsSuper) {8348 if (ObjCMethodDecl *SuperMethod =8349 AddSuperSendCompletion(SemaRef, false, SelIdents, Results))8350 Results.Ignore(SuperMethod);8351 }8352 8353 // If we're inside an Objective-C method definition, prefer its selector to8354 // others.8355 if (ObjCMethodDecl *CurMethod = SemaRef.getCurMethodDecl())8356 Results.setPreferredSelector(CurMethod->getSelector());8357 8358 VisitedSelectorSet Selectors;8359 if (CDecl)8360 AddObjCMethods(CDecl, false, MK_Any, SelIdents, SemaRef.CurContext,8361 Selectors, AtArgumentExpression, Results);8362 else {8363 // We're messaging "id" as a type; provide all class/factory methods.8364 8365 // If we have an external source, load the entire class method8366 // pool from the AST file.8367 if (SemaRef.getExternalSource()) {8368 for (uint32_t I = 0,8369 N = SemaRef.getExternalSource()->GetNumExternalSelectors();8370 I != N; ++I) {8371 Selector Sel = SemaRef.getExternalSource()->GetExternalSelector(I);8372 if (Sel.isNull() || SemaRef.ObjC().MethodPool.count(Sel))8373 continue;8374 8375 SemaRef.ObjC().ReadMethodPool(Sel);8376 }8377 }8378 8379 for (SemaObjC::GlobalMethodPool::iterator8380 M = SemaRef.ObjC().MethodPool.begin(),8381 MEnd = SemaRef.ObjC().MethodPool.end();8382 M != MEnd; ++M) {8383 for (ObjCMethodList *MethList = &M->second.second;8384 MethList && MethList->getMethod(); MethList = MethList->getNext()) {8385 if (!isAcceptableObjCMethod(MethList->getMethod(), MK_Any, SelIdents))8386 continue;8387 8388 Result R(MethList->getMethod(),8389 Results.getBasePriority(MethList->getMethod()),8390 /*Qualifier=*/std::nullopt);8391 R.StartParameter = SelIdents.size();8392 R.AllParametersAreInformative = false;8393 Results.MaybeAddResult(R, SemaRef.CurContext);8394 }8395 }8396 }8397 8398 Results.ExitScope();8399}8400 8401void SemaCodeCompletion::CodeCompleteObjCClassMessage(8402 Scope *S, ParsedType Receiver, ArrayRef<const IdentifierInfo *> SelIdents,8403 bool AtArgumentExpression, bool IsSuper) {8404 8405 QualType T = SemaRef.GetTypeFromParser(Receiver);8406 8407 ResultBuilder Results(8408 SemaRef, CodeCompleter->getAllocator(),8409 CodeCompleter->getCodeCompletionTUInfo(),8410 CodeCompletionContext(CodeCompletionContext::CCC_ObjCClassMessage, T,8411 SelIdents));8412 8413 AddClassMessageCompletions(SemaRef, S, Receiver, SelIdents,8414 AtArgumentExpression, IsSuper, Results);8415 8416 // If we're actually at the argument expression (rather than prior to the8417 // selector), we're actually performing code completion for an expression.8418 // Determine whether we have a single, best method. If so, we can8419 // code-complete the expression using the corresponding parameter type as8420 // our preferred type, improving completion results.8421 if (AtArgumentExpression) {8422 QualType PreferredType =8423 getPreferredArgumentTypeForMessageSend(Results, SelIdents.size());8424 if (PreferredType.isNull())8425 CodeCompleteOrdinaryName(S, PCC_Expression);8426 else8427 CodeCompleteExpression(S, PreferredType);8428 return;8429 }8430 8431 HandleCodeCompleteResults(&SemaRef, CodeCompleter,8432 Results.getCompletionContext(), Results.data(),8433 Results.size());8434}8435 8436void SemaCodeCompletion::CodeCompleteObjCInstanceMessage(8437 Scope *S, Expr *RecExpr, ArrayRef<const IdentifierInfo *> SelIdents,8438 bool AtArgumentExpression, ObjCInterfaceDecl *Super) {8439 typedef CodeCompletionResult Result;8440 ASTContext &Context = getASTContext();8441 8442 // If necessary, apply function/array conversion to the receiver.8443 // C99 6.7.5.3p[7,8].8444 if (RecExpr) {8445 ExprResult Conv = SemaRef.DefaultFunctionArrayLvalueConversion(RecExpr);8446 if (Conv.isInvalid()) // conversion failed. bail.8447 return;8448 RecExpr = Conv.get();8449 }8450 QualType ReceiverType = RecExpr8451 ? RecExpr->getType()8452 : Super ? Context.getObjCObjectPointerType(8453 Context.getObjCInterfaceType(Super))8454 : Context.getObjCIdType();8455 8456 // If we're messaging an expression with type "id" or "Class", check8457 // whether we know something special about the receiver that allows8458 // us to assume a more-specific receiver type.8459 if (ReceiverType->isObjCIdType() || ReceiverType->isObjCClassType()) {8460 if (ObjCInterfaceDecl *IFace = GetAssumedMessageSendExprType(RecExpr)) {8461 if (ReceiverType->isObjCClassType())8462 return CodeCompleteObjCClassMessage(8463 S, ParsedType::make(Context.getObjCInterfaceType(IFace)), SelIdents,8464 AtArgumentExpression, Super);8465 8466 ReceiverType =8467 Context.getObjCObjectPointerType(Context.getObjCInterfaceType(IFace));8468 }8469 } else if (RecExpr && getLangOpts().CPlusPlus) {8470 ExprResult Conv = SemaRef.PerformContextuallyConvertToObjCPointer(RecExpr);8471 if (Conv.isUsable()) {8472 RecExpr = Conv.get();8473 ReceiverType = RecExpr->getType();8474 }8475 }8476 8477 // Build the set of methods we can see.8478 ResultBuilder Results(8479 SemaRef, CodeCompleter->getAllocator(),8480 CodeCompleter->getCodeCompletionTUInfo(),8481 CodeCompletionContext(CodeCompletionContext::CCC_ObjCInstanceMessage,8482 ReceiverType, SelIdents));8483 8484 Results.EnterNewScope();8485 8486 // If this is a send-to-super, try to add the special "super" send8487 // completion.8488 if (Super) {8489 if (ObjCMethodDecl *SuperMethod =8490 AddSuperSendCompletion(SemaRef, false, SelIdents, Results))8491 Results.Ignore(SuperMethod);8492 }8493 8494 // If we're inside an Objective-C method definition, prefer its selector to8495 // others.8496 if (ObjCMethodDecl *CurMethod = SemaRef.getCurMethodDecl())8497 Results.setPreferredSelector(CurMethod->getSelector());8498 8499 // Keep track of the selectors we've already added.8500 VisitedSelectorSet Selectors;8501 8502 // Handle messages to Class. This really isn't a message to an instance8503 // method, so we treat it the same way we would treat a message send to a8504 // class method.8505 if (ReceiverType->isObjCClassType() ||8506 ReceiverType->isObjCQualifiedClassType()) {8507 if (ObjCMethodDecl *CurMethod = SemaRef.getCurMethodDecl()) {8508 if (ObjCInterfaceDecl *ClassDecl = CurMethod->getClassInterface())8509 AddObjCMethods(ClassDecl, false, MK_Any, SelIdents, SemaRef.CurContext,8510 Selectors, AtArgumentExpression, Results);8511 }8512 }8513 // Handle messages to a qualified ID ("id<foo>").8514 else if (const ObjCObjectPointerType *QualID =8515 ReceiverType->getAsObjCQualifiedIdType()) {8516 // Search protocols for instance methods.8517 for (auto *I : QualID->quals())8518 AddObjCMethods(I, true, MK_Any, SelIdents, SemaRef.CurContext, Selectors,8519 AtArgumentExpression, Results);8520 }8521 // Handle messages to a pointer to interface type.8522 else if (const ObjCObjectPointerType *IFacePtr =8523 ReceiverType->getAsObjCInterfacePointerType()) {8524 // Search the class, its superclasses, etc., for instance methods.8525 AddObjCMethods(IFacePtr->getInterfaceDecl(), true, MK_Any, SelIdents,8526 SemaRef.CurContext, Selectors, AtArgumentExpression,8527 Results);8528 8529 // Search protocols for instance methods.8530 for (auto *I : IFacePtr->quals())8531 AddObjCMethods(I, true, MK_Any, SelIdents, SemaRef.CurContext, Selectors,8532 AtArgumentExpression, Results);8533 }8534 // Handle messages to "id".8535 else if (ReceiverType->isObjCIdType()) {8536 // We're messaging "id", so provide all instance methods we know8537 // about as code-completion results.8538 8539 // If we have an external source, load the entire class method8540 // pool from the AST file.8541 if (SemaRef.ExternalSource) {8542 for (uint32_t I = 0,8543 N = SemaRef.ExternalSource->GetNumExternalSelectors();8544 I != N; ++I) {8545 Selector Sel = SemaRef.ExternalSource->GetExternalSelector(I);8546 if (Sel.isNull() || SemaRef.ObjC().MethodPool.count(Sel))8547 continue;8548 8549 SemaRef.ObjC().ReadMethodPool(Sel);8550 }8551 }8552 8553 for (SemaObjC::GlobalMethodPool::iterator8554 M = SemaRef.ObjC().MethodPool.begin(),8555 MEnd = SemaRef.ObjC().MethodPool.end();8556 M != MEnd; ++M) {8557 for (ObjCMethodList *MethList = &M->second.first;8558 MethList && MethList->getMethod(); MethList = MethList->getNext()) {8559 if (!isAcceptableObjCMethod(MethList->getMethod(), MK_Any, SelIdents))8560 continue;8561 8562 if (!Selectors.insert(MethList->getMethod()->getSelector()).second)8563 continue;8564 8565 Result R(MethList->getMethod(),8566 Results.getBasePriority(MethList->getMethod()),8567 /*Qualifier=*/std::nullopt);8568 R.StartParameter = SelIdents.size();8569 R.AllParametersAreInformative = false;8570 Results.MaybeAddResult(R, SemaRef.CurContext);8571 }8572 }8573 }8574 Results.ExitScope();8575 8576 // If we're actually at the argument expression (rather than prior to the8577 // selector), we're actually performing code completion for an expression.8578 // Determine whether we have a single, best method. If so, we can8579 // code-complete the expression using the corresponding parameter type as8580 // our preferred type, improving completion results.8581 if (AtArgumentExpression) {8582 QualType PreferredType =8583 getPreferredArgumentTypeForMessageSend(Results, SelIdents.size());8584 if (PreferredType.isNull())8585 CodeCompleteOrdinaryName(S, PCC_Expression);8586 else8587 CodeCompleteExpression(S, PreferredType);8588 return;8589 }8590 8591 HandleCodeCompleteResults(&SemaRef, CodeCompleter,8592 Results.getCompletionContext(), Results.data(),8593 Results.size());8594}8595 8596void SemaCodeCompletion::CodeCompleteObjCForCollection(8597 Scope *S, DeclGroupPtrTy IterationVar) {8598 CodeCompleteExpressionData Data;8599 Data.ObjCCollection = true;8600 8601 if (IterationVar.getAsOpaquePtr()) {8602 DeclGroupRef DG = IterationVar.get();8603 for (DeclGroupRef::iterator I = DG.begin(), End = DG.end(); I != End; ++I) {8604 if (*I)8605 Data.IgnoreDecls.push_back(*I);8606 }8607 }8608 8609 CodeCompleteExpression(S, Data);8610}8611 8612void SemaCodeCompletion::CodeCompleteObjCSelector(8613 Scope *S, ArrayRef<const IdentifierInfo *> SelIdents) {8614 // If we have an external source, load the entire class method8615 // pool from the AST file.8616 if (SemaRef.ExternalSource) {8617 for (uint32_t I = 0, N = SemaRef.ExternalSource->GetNumExternalSelectors();8618 I != N; ++I) {8619 Selector Sel = SemaRef.ExternalSource->GetExternalSelector(I);8620 if (Sel.isNull() || SemaRef.ObjC().MethodPool.count(Sel))8621 continue;8622 8623 SemaRef.ObjC().ReadMethodPool(Sel);8624 }8625 }8626 8627 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),8628 CodeCompleter->getCodeCompletionTUInfo(),8629 CodeCompletionContext::CCC_SelectorName);8630 Results.EnterNewScope();8631 for (SemaObjC::GlobalMethodPool::iterator8632 M = SemaRef.ObjC().MethodPool.begin(),8633 MEnd = SemaRef.ObjC().MethodPool.end();8634 M != MEnd; ++M) {8635 8636 Selector Sel = M->first;8637 if (!isAcceptableObjCSelector(Sel, MK_Any, SelIdents))8638 continue;8639 8640 CodeCompletionBuilder Builder(Results.getAllocator(),8641 Results.getCodeCompletionTUInfo());8642 if (Sel.isUnarySelector()) {8643 Builder.AddTypedTextChunk(8644 Builder.getAllocator().CopyString(Sel.getNameForSlot(0)));8645 Results.AddResult(Builder.TakeString());8646 continue;8647 }8648 8649 std::string Accumulator;8650 for (unsigned I = 0, N = Sel.getNumArgs(); I != N; ++I) {8651 if (I == SelIdents.size()) {8652 if (!Accumulator.empty()) {8653 Builder.AddInformativeChunk(8654 Builder.getAllocator().CopyString(Accumulator));8655 Accumulator.clear();8656 }8657 }8658 8659 Accumulator += Sel.getNameForSlot(I);8660 Accumulator += ':';8661 }8662 Builder.AddTypedTextChunk(Builder.getAllocator().CopyString(Accumulator));8663 Results.AddResult(Builder.TakeString());8664 }8665 Results.ExitScope();8666 8667 HandleCodeCompleteResults(&SemaRef, CodeCompleter,8668 Results.getCompletionContext(), Results.data(),8669 Results.size());8670}8671 8672/// Add all of the protocol declarations that we find in the given8673/// (translation unit) context.8674static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext,8675 bool OnlyForwardDeclarations,8676 ResultBuilder &Results) {8677 typedef CodeCompletionResult Result;8678 8679 for (const auto *D : Ctx->decls()) {8680 // Record any protocols we find.8681 if (const auto *Proto = dyn_cast<ObjCProtocolDecl>(D))8682 if (!OnlyForwardDeclarations || !Proto->hasDefinition())8683 Results.AddResult(Result(Proto, Results.getBasePriority(Proto),8684 /*Qualifier=*/std::nullopt),8685 CurContext, nullptr, false);8686 }8687}8688 8689void SemaCodeCompletion::CodeCompleteObjCProtocolReferences(8690 ArrayRef<IdentifierLoc> Protocols) {8691 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),8692 CodeCompleter->getCodeCompletionTUInfo(),8693 CodeCompletionContext::CCC_ObjCProtocolName);8694 8695 if (CodeCompleter->includeGlobals()) {8696 Results.EnterNewScope();8697 8698 // Tell the result set to ignore all of the protocols we have8699 // already seen.8700 // FIXME: This doesn't work when caching code-completion results.8701 for (const IdentifierLoc &Pair : Protocols)8702 if (ObjCProtocolDecl *Protocol = SemaRef.ObjC().LookupProtocol(8703 Pair.getIdentifierInfo(), Pair.getLoc()))8704 Results.Ignore(Protocol);8705 8706 // Add all protocols.8707 AddProtocolResults(getASTContext().getTranslationUnitDecl(),8708 SemaRef.CurContext, false, Results);8709 8710 Results.ExitScope();8711 }8712 8713 HandleCodeCompleteResults(&SemaRef, CodeCompleter,8714 Results.getCompletionContext(), Results.data(),8715 Results.size());8716}8717 8718void SemaCodeCompletion::CodeCompleteObjCProtocolDecl(Scope *) {8719 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),8720 CodeCompleter->getCodeCompletionTUInfo(),8721 CodeCompletionContext::CCC_ObjCProtocolName);8722 8723 if (CodeCompleter->includeGlobals()) {8724 Results.EnterNewScope();8725 8726 // Add all protocols.8727 AddProtocolResults(getASTContext().getTranslationUnitDecl(),8728 SemaRef.CurContext, true, Results);8729 8730 Results.ExitScope();8731 }8732 8733 HandleCodeCompleteResults(&SemaRef, CodeCompleter,8734 Results.getCompletionContext(), Results.data(),8735 Results.size());8736}8737 8738/// Add all of the Objective-C interface declarations that we find in8739/// the given (translation unit) context.8740static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext,8741 bool OnlyForwardDeclarations,8742 bool OnlyUnimplemented,8743 ResultBuilder &Results) {8744 typedef CodeCompletionResult Result;8745 8746 for (const auto *D : Ctx->decls()) {8747 // Record any interfaces we find.8748 if (const auto *Class = dyn_cast<ObjCInterfaceDecl>(D))8749 if ((!OnlyForwardDeclarations || !Class->hasDefinition()) &&8750 (!OnlyUnimplemented || !Class->getImplementation()))8751 Results.AddResult(Result(Class, Results.getBasePriority(Class),8752 /*Qualifier=*/std::nullopt),8753 CurContext, nullptr, false);8754 }8755}8756 8757void SemaCodeCompletion::CodeCompleteObjCInterfaceDecl(Scope *S) {8758 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),8759 CodeCompleter->getCodeCompletionTUInfo(),8760 CodeCompletionContext::CCC_ObjCInterfaceName);8761 Results.EnterNewScope();8762 8763 if (CodeCompleter->includeGlobals()) {8764 // Add all classes.8765 AddInterfaceResults(getASTContext().getTranslationUnitDecl(),8766 SemaRef.CurContext, false, false, Results);8767 }8768 8769 Results.ExitScope();8770 8771 HandleCodeCompleteResults(&SemaRef, CodeCompleter,8772 Results.getCompletionContext(), Results.data(),8773 Results.size());8774}8775 8776void SemaCodeCompletion::CodeCompleteObjCClassForwardDecl(Scope *S) {8777 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),8778 CodeCompleter->getCodeCompletionTUInfo(),8779 CodeCompletionContext::CCC_ObjCClassForwardDecl);8780 Results.EnterNewScope();8781 8782 if (CodeCompleter->includeGlobals()) {8783 // Add all classes.8784 AddInterfaceResults(getASTContext().getTranslationUnitDecl(),8785 SemaRef.CurContext, false, false, Results);8786 }8787 8788 Results.ExitScope();8789 8790 HandleCodeCompleteResults(&SemaRef, CodeCompleter,8791 Results.getCompletionContext(), Results.data(),8792 Results.size());8793}8794 8795void SemaCodeCompletion::CodeCompleteObjCSuperclass(8796 Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc) {8797 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),8798 CodeCompleter->getCodeCompletionTUInfo(),8799 CodeCompletionContext::CCC_ObjCInterfaceName);8800 Results.EnterNewScope();8801 8802 // Make sure that we ignore the class we're currently defining.8803 NamedDecl *CurClass = SemaRef.LookupSingleName(8804 SemaRef.TUScope, ClassName, ClassNameLoc, Sema::LookupOrdinaryName);8805 if (CurClass && isa<ObjCInterfaceDecl>(CurClass))8806 Results.Ignore(CurClass);8807 8808 if (CodeCompleter->includeGlobals()) {8809 // Add all classes.8810 AddInterfaceResults(getASTContext().getTranslationUnitDecl(),8811 SemaRef.CurContext, false, false, Results);8812 }8813 8814 Results.ExitScope();8815 8816 HandleCodeCompleteResults(&SemaRef, CodeCompleter,8817 Results.getCompletionContext(), Results.data(),8818 Results.size());8819}8820 8821void SemaCodeCompletion::CodeCompleteObjCImplementationDecl(Scope *S) {8822 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),8823 CodeCompleter->getCodeCompletionTUInfo(),8824 CodeCompletionContext::CCC_ObjCImplementation);8825 Results.EnterNewScope();8826 8827 if (CodeCompleter->includeGlobals()) {8828 // Add all unimplemented classes.8829 AddInterfaceResults(getASTContext().getTranslationUnitDecl(),8830 SemaRef.CurContext, false, true, Results);8831 }8832 8833 Results.ExitScope();8834 8835 HandleCodeCompleteResults(&SemaRef, CodeCompleter,8836 Results.getCompletionContext(), Results.data(),8837 Results.size());8838}8839 8840void SemaCodeCompletion::CodeCompleteObjCInterfaceCategory(8841 Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc) {8842 typedef CodeCompletionResult Result;8843 8844 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),8845 CodeCompleter->getCodeCompletionTUInfo(),8846 CodeCompletionContext::CCC_ObjCCategoryName);8847 8848 // Ignore any categories we find that have already been implemented by this8849 // interface.8850 llvm::SmallPtrSet<IdentifierInfo *, 16> CategoryNames;8851 NamedDecl *CurClass = SemaRef.LookupSingleName(8852 SemaRef.TUScope, ClassName, ClassNameLoc, Sema::LookupOrdinaryName);8853 if (ObjCInterfaceDecl *Class =8854 dyn_cast_or_null<ObjCInterfaceDecl>(CurClass)) {8855 for (const auto *Cat : Class->visible_categories())8856 CategoryNames.insert(Cat->getIdentifier());8857 }8858 8859 // Add all of the categories we know about.8860 Results.EnterNewScope();8861 TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();8862 for (const auto *D : TU->decls())8863 if (const auto *Category = dyn_cast<ObjCCategoryDecl>(D))8864 if (CategoryNames.insert(Category->getIdentifier()).second)8865 Results.AddResult(Result(Category, Results.getBasePriority(Category),8866 /*Qualifier=*/std::nullopt),8867 SemaRef.CurContext, nullptr, false);8868 Results.ExitScope();8869 8870 HandleCodeCompleteResults(&SemaRef, CodeCompleter,8871 Results.getCompletionContext(), Results.data(),8872 Results.size());8873}8874 8875void SemaCodeCompletion::CodeCompleteObjCImplementationCategory(8876 Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc) {8877 typedef CodeCompletionResult Result;8878 8879 // Find the corresponding interface. If we couldn't find the interface, the8880 // program itself is ill-formed. However, we'll try to be helpful still by8881 // providing the list of all of the categories we know about.8882 NamedDecl *CurClass = SemaRef.LookupSingleName(8883 SemaRef.TUScope, ClassName, ClassNameLoc, Sema::LookupOrdinaryName);8884 ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurClass);8885 if (!Class)8886 return CodeCompleteObjCInterfaceCategory(S, ClassName, ClassNameLoc);8887 8888 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),8889 CodeCompleter->getCodeCompletionTUInfo(),8890 CodeCompletionContext::CCC_ObjCCategoryName);8891 8892 // Add all of the categories that have corresponding interface8893 // declarations in this class and any of its superclasses, except for8894 // already-implemented categories in the class itself.8895 llvm::SmallPtrSet<IdentifierInfo *, 16> CategoryNames;8896 Results.EnterNewScope();8897 bool IgnoreImplemented = true;8898 while (Class) {8899 for (const auto *Cat : Class->visible_categories()) {8900 if ((!IgnoreImplemented || !Cat->getImplementation()) &&8901 CategoryNames.insert(Cat->getIdentifier()).second)8902 Results.AddResult(Result(Cat, Results.getBasePriority(Cat),8903 /*Qualifier=*/std::nullopt),8904 SemaRef.CurContext, nullptr, false);8905 }8906 8907 Class = Class->getSuperClass();8908 IgnoreImplemented = false;8909 }8910 Results.ExitScope();8911 8912 HandleCodeCompleteResults(&SemaRef, CodeCompleter,8913 Results.getCompletionContext(), Results.data(),8914 Results.size());8915}8916 8917void SemaCodeCompletion::CodeCompleteObjCPropertyDefinition(Scope *S) {8918 CodeCompletionContext CCContext(CodeCompletionContext::CCC_Other);8919 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),8920 CodeCompleter->getCodeCompletionTUInfo(), CCContext);8921 8922 // Figure out where this @synthesize lives.8923 ObjCContainerDecl *Container =8924 dyn_cast_or_null<ObjCContainerDecl>(SemaRef.CurContext);8925 if (!Container || (!isa<ObjCImplementationDecl>(Container) &&8926 !isa<ObjCCategoryImplDecl>(Container)))8927 return;8928 8929 // Ignore any properties that have already been implemented.8930 Container = getContainerDef(Container);8931 for (const auto *D : Container->decls())8932 if (const auto *PropertyImpl = dyn_cast<ObjCPropertyImplDecl>(D))8933 Results.Ignore(PropertyImpl->getPropertyDecl());8934 8935 // Add any properties that we find.8936 AddedPropertiesSet AddedProperties;8937 Results.EnterNewScope();8938 if (ObjCImplementationDecl *ClassImpl =8939 dyn_cast<ObjCImplementationDecl>(Container))8940 AddObjCProperties(CCContext, ClassImpl->getClassInterface(), false,8941 /*AllowNullaryMethods=*/false, SemaRef.CurContext,8942 AddedProperties, Results);8943 else8944 AddObjCProperties(CCContext,8945 cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl(),8946 false, /*AllowNullaryMethods=*/false, SemaRef.CurContext,8947 AddedProperties, Results);8948 Results.ExitScope();8949 8950 HandleCodeCompleteResults(&SemaRef, CodeCompleter,8951 Results.getCompletionContext(), Results.data(),8952 Results.size());8953}8954 8955void SemaCodeCompletion::CodeCompleteObjCPropertySynthesizeIvar(8956 Scope *S, IdentifierInfo *PropertyName) {8957 typedef CodeCompletionResult Result;8958 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),8959 CodeCompleter->getCodeCompletionTUInfo(),8960 CodeCompletionContext::CCC_Other);8961 8962 // Figure out where this @synthesize lives.8963 ObjCContainerDecl *Container =8964 dyn_cast_or_null<ObjCContainerDecl>(SemaRef.CurContext);8965 if (!Container || (!isa<ObjCImplementationDecl>(Container) &&8966 !isa<ObjCCategoryImplDecl>(Container)))8967 return;8968 8969 // Figure out which interface we're looking into.8970 ObjCInterfaceDecl *Class = nullptr;8971 if (ObjCImplementationDecl *ClassImpl =8972 dyn_cast<ObjCImplementationDecl>(Container))8973 Class = ClassImpl->getClassInterface();8974 else8975 Class = cast<ObjCCategoryImplDecl>(Container)8976 ->getCategoryDecl()8977 ->getClassInterface();8978 8979 // Determine the type of the property we're synthesizing.8980 QualType PropertyType = getASTContext().getObjCIdType();8981 if (Class) {8982 if (ObjCPropertyDecl *Property = Class->FindPropertyDeclaration(8983 PropertyName, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {8984 PropertyType =8985 Property->getType().getNonReferenceType().getUnqualifiedType();8986 8987 // Give preference to ivars8988 Results.setPreferredType(PropertyType);8989 }8990 }8991 8992 // Add all of the instance variables in this class and its superclasses.8993 Results.EnterNewScope();8994 bool SawSimilarlyNamedIvar = false;8995 std::string NameWithPrefix;8996 NameWithPrefix += '_';8997 NameWithPrefix += PropertyName->getName();8998 std::string NameWithSuffix = PropertyName->getName().str();8999 NameWithSuffix += '_';9000 for (; Class; Class = Class->getSuperClass()) {9001 for (ObjCIvarDecl *Ivar = Class->all_declared_ivar_begin(); Ivar;9002 Ivar = Ivar->getNextIvar()) {9003 Results.AddResult(Result(Ivar, Results.getBasePriority(Ivar),9004 /*Qualifier=*/std::nullopt),9005 SemaRef.CurContext, nullptr, false);9006 9007 // Determine whether we've seen an ivar with a name similar to the9008 // property.9009 if ((PropertyName == Ivar->getIdentifier() ||9010 NameWithPrefix == Ivar->getName() ||9011 NameWithSuffix == Ivar->getName())) {9012 SawSimilarlyNamedIvar = true;9013 9014 // Reduce the priority of this result by one, to give it a slight9015 // advantage over other results whose names don't match so closely.9016 if (Results.size() &&9017 Results.data()[Results.size() - 1].Kind ==9018 CodeCompletionResult::RK_Declaration &&9019 Results.data()[Results.size() - 1].Declaration == Ivar)9020 Results.data()[Results.size() - 1].Priority--;9021 }9022 }9023 }9024 9025 if (!SawSimilarlyNamedIvar) {9026 // Create ivar result _propName, that the user can use to synthesize9027 // an ivar of the appropriate type.9028 unsigned Priority = CCP_MemberDeclaration + 1;9029 typedef CodeCompletionResult Result;9030 CodeCompletionAllocator &Allocator = Results.getAllocator();9031 CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo(),9032 Priority, CXAvailability_Available);9033 9034 PrintingPolicy Policy = getCompletionPrintingPolicy(SemaRef);9035 Builder.AddResultTypeChunk(GetCompletionTypeString(9036 PropertyType, getASTContext(), Policy, Allocator));9037 Builder.AddTypedTextChunk(Allocator.CopyString(NameWithPrefix));9038 Results.AddResult(9039 Result(Builder.TakeString(), Priority, CXCursor_ObjCIvarDecl));9040 }9041 9042 Results.ExitScope();9043 9044 HandleCodeCompleteResults(&SemaRef, CodeCompleter,9045 Results.getCompletionContext(), Results.data(),9046 Results.size());9047}9048 9049// Mapping from selectors to the methods that implement that selector, along9050// with the "in original class" flag.9051typedef llvm::DenseMap<Selector,9052 llvm::PointerIntPair<ObjCMethodDecl *, 1, bool>>9053 KnownMethodsMap;9054 9055/// Find all of the methods that reside in the given container9056/// (and its superclasses, protocols, etc.) that meet the given9057/// criteria. Insert those methods into the map of known methods,9058/// indexed by selector so they can be easily found.9059static void FindImplementableMethods(ASTContext &Context,9060 ObjCContainerDecl *Container,9061 std::optional<bool> WantInstanceMethods,9062 QualType ReturnType,9063 KnownMethodsMap &KnownMethods,9064 bool InOriginalClass = true) {9065 if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)) {9066 // Make sure we have a definition; that's what we'll walk.9067 if (!IFace->hasDefinition())9068 return;9069 9070 IFace = IFace->getDefinition();9071 Container = IFace;9072 9073 const ObjCList<ObjCProtocolDecl> &Protocols =9074 IFace->getReferencedProtocols();9075 for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),9076 E = Protocols.end();9077 I != E; ++I)9078 FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType,9079 KnownMethods, InOriginalClass);9080 9081 // Add methods from any class extensions and categories.9082 for (auto *Cat : IFace->visible_categories()) {9083 FindImplementableMethods(Context, Cat, WantInstanceMethods, ReturnType,9084 KnownMethods, false);9085 }9086 9087 // Visit the superclass.9088 if (IFace->getSuperClass())9089 FindImplementableMethods(Context, IFace->getSuperClass(),9090 WantInstanceMethods, ReturnType, KnownMethods,9091 false);9092 }9093 9094 if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) {9095 // Recurse into protocols.9096 const ObjCList<ObjCProtocolDecl> &Protocols =9097 Category->getReferencedProtocols();9098 for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),9099 E = Protocols.end();9100 I != E; ++I)9101 FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType,9102 KnownMethods, InOriginalClass);9103 9104 // If this category is the original class, jump to the interface.9105 if (InOriginalClass && Category->getClassInterface())9106 FindImplementableMethods(Context, Category->getClassInterface(),9107 WantInstanceMethods, ReturnType, KnownMethods,9108 false);9109 }9110 9111 if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {9112 // Make sure we have a definition; that's what we'll walk.9113 if (!Protocol->hasDefinition())9114 return;9115 Protocol = Protocol->getDefinition();9116 Container = Protocol;9117 9118 // Recurse into protocols.9119 const ObjCList<ObjCProtocolDecl> &Protocols =9120 Protocol->getReferencedProtocols();9121 for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),9122 E = Protocols.end();9123 I != E; ++I)9124 FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType,9125 KnownMethods, false);9126 }9127 9128 // Add methods in this container. This operation occurs last because9129 // we want the methods from this container to override any methods9130 // we've previously seen with the same selector.9131 for (auto *M : Container->methods()) {9132 if (!WantInstanceMethods || M->isInstanceMethod() == *WantInstanceMethods) {9133 if (!ReturnType.isNull() &&9134 !Context.hasSameUnqualifiedType(ReturnType, M->getReturnType()))9135 continue;9136 9137 KnownMethods[M->getSelector()] =9138 KnownMethodsMap::mapped_type(M, InOriginalClass);9139 }9140 }9141}9142 9143/// Add the parenthesized return or parameter type chunk to a code9144/// completion string.9145static void AddObjCPassingTypeChunk(QualType Type, unsigned ObjCDeclQuals,9146 ASTContext &Context,9147 const PrintingPolicy &Policy,9148 CodeCompletionBuilder &Builder) {9149 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9150 std::string Quals = formatObjCParamQualifiers(ObjCDeclQuals, Type);9151 if (!Quals.empty())9152 Builder.AddTextChunk(Builder.getAllocator().CopyString(Quals));9153 Builder.AddTextChunk(9154 GetCompletionTypeString(Type, Context, Policy, Builder.getAllocator()));9155 Builder.AddChunk(CodeCompletionString::CK_RightParen);9156}9157 9158/// Determine whether the given class is or inherits from a class by9159/// the given name.9160static bool InheritsFromClassNamed(ObjCInterfaceDecl *Class, StringRef Name) {9161 if (!Class)9162 return false;9163 9164 if (Class->getIdentifier() && Class->getIdentifier()->getName() == Name)9165 return true;9166 9167 return InheritsFromClassNamed(Class->getSuperClass(), Name);9168}9169 9170/// Add code completions for Objective-C Key-Value Coding (KVC) and9171/// Key-Value Observing (KVO).9172static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,9173 bool IsInstanceMethod,9174 QualType ReturnType, ASTContext &Context,9175 VisitedSelectorSet &KnownSelectors,9176 ResultBuilder &Results) {9177 IdentifierInfo *PropName = Property->getIdentifier();9178 if (!PropName || PropName->getLength() == 0)9179 return;9180 9181 PrintingPolicy Policy = getCompletionPrintingPolicy(Results.getSema());9182 9183 // Builder that will create each code completion.9184 typedef CodeCompletionResult Result;9185 CodeCompletionAllocator &Allocator = Results.getAllocator();9186 CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo());9187 9188 // The selector table.9189 SelectorTable &Selectors = Context.Selectors;9190 9191 // The property name, copied into the code completion allocation region9192 // on demand.9193 struct KeyHolder {9194 CodeCompletionAllocator &Allocator;9195 StringRef Key;9196 const char *CopiedKey;9197 9198 KeyHolder(CodeCompletionAllocator &Allocator, StringRef Key)9199 : Allocator(Allocator), Key(Key), CopiedKey(nullptr) {}9200 9201 operator const char *() {9202 if (CopiedKey)9203 return CopiedKey;9204 9205 return CopiedKey = Allocator.CopyString(Key);9206 }9207 } Key(Allocator, PropName->getName());9208 9209 // The uppercased name of the property name.9210 std::string UpperKey = std::string(PropName->getName());9211 if (!UpperKey.empty())9212 UpperKey[0] = toUppercase(UpperKey[0]);9213 9214 bool ReturnTypeMatchesProperty =9215 ReturnType.isNull() ||9216 Context.hasSameUnqualifiedType(ReturnType.getNonReferenceType(),9217 Property->getType());9218 bool ReturnTypeMatchesVoid = ReturnType.isNull() || ReturnType->isVoidType();9219 9220 // Add the normal accessor -(type)key.9221 if (IsInstanceMethod &&9222 KnownSelectors.insert(Selectors.getNullarySelector(PropName)).second &&9223 ReturnTypeMatchesProperty && !Property->getGetterMethodDecl()) {9224 if (ReturnType.isNull())9225 AddObjCPassingTypeChunk(Property->getType(), /*Quals=*/0, Context, Policy,9226 Builder);9227 9228 Builder.AddTypedTextChunk(Key);9229 Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern,9230 CXCursor_ObjCInstanceMethodDecl));9231 }9232 9233 // If we have an integral or boolean property (or the user has provided9234 // an integral or boolean return type), add the accessor -(type)isKey.9235 if (IsInstanceMethod &&9236 ((!ReturnType.isNull() &&9237 (ReturnType->isIntegerType() || ReturnType->isBooleanType())) ||9238 (ReturnType.isNull() && (Property->getType()->isIntegerType() ||9239 Property->getType()->isBooleanType())))) {9240 std::string SelectorName = (Twine("is") + UpperKey).str();9241 IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);9242 if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))9243 .second) {9244 if (ReturnType.isNull()) {9245 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9246 Builder.AddTextChunk("BOOL");9247 Builder.AddChunk(CodeCompletionString::CK_RightParen);9248 }9249 9250 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorId->getName()));9251 Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern,9252 CXCursor_ObjCInstanceMethodDecl));9253 }9254 }9255 9256 // Add the normal mutator.9257 if (IsInstanceMethod && ReturnTypeMatchesVoid &&9258 !Property->getSetterMethodDecl()) {9259 std::string SelectorName = (Twine("set") + UpperKey).str();9260 IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);9261 if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {9262 if (ReturnType.isNull()) {9263 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9264 Builder.AddTextChunk("void");9265 Builder.AddChunk(CodeCompletionString::CK_RightParen);9266 }9267 9268 Builder.AddTypedTextChunk(9269 Allocator.CopyString(SelectorId->getName() + ":"));9270 AddObjCPassingTypeChunk(Property->getType(), /*Quals=*/0, Context, Policy,9271 Builder);9272 Builder.AddTextChunk(Key);9273 Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern,9274 CXCursor_ObjCInstanceMethodDecl));9275 }9276 }9277 9278 // Indexed and unordered accessors9279 unsigned IndexedGetterPriority = CCP_CodePattern;9280 unsigned IndexedSetterPriority = CCP_CodePattern;9281 unsigned UnorderedGetterPriority = CCP_CodePattern;9282 unsigned UnorderedSetterPriority = CCP_CodePattern;9283 if (const auto *ObjCPointer =9284 Property->getType()->getAs<ObjCObjectPointerType>()) {9285 if (ObjCInterfaceDecl *IFace = ObjCPointer->getInterfaceDecl()) {9286 // If this interface type is not provably derived from a known9287 // collection, penalize the corresponding completions.9288 if (!InheritsFromClassNamed(IFace, "NSMutableArray")) {9289 IndexedSetterPriority += CCD_ProbablyNotObjCCollection;9290 if (!InheritsFromClassNamed(IFace, "NSArray"))9291 IndexedGetterPriority += CCD_ProbablyNotObjCCollection;9292 }9293 9294 if (!InheritsFromClassNamed(IFace, "NSMutableSet")) {9295 UnorderedSetterPriority += CCD_ProbablyNotObjCCollection;9296 if (!InheritsFromClassNamed(IFace, "NSSet"))9297 UnorderedGetterPriority += CCD_ProbablyNotObjCCollection;9298 }9299 }9300 } else {9301 IndexedGetterPriority += CCD_ProbablyNotObjCCollection;9302 IndexedSetterPriority += CCD_ProbablyNotObjCCollection;9303 UnorderedGetterPriority += CCD_ProbablyNotObjCCollection;9304 UnorderedSetterPriority += CCD_ProbablyNotObjCCollection;9305 }9306 9307 // Add -(NSUInteger)countOf<key>9308 if (IsInstanceMethod &&9309 (ReturnType.isNull() || ReturnType->isIntegerType())) {9310 std::string SelectorName = (Twine("countOf") + UpperKey).str();9311 IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);9312 if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))9313 .second) {9314 if (ReturnType.isNull()) {9315 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9316 Builder.AddTextChunk("NSUInteger");9317 Builder.AddChunk(CodeCompletionString::CK_RightParen);9318 }9319 9320 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorId->getName()));9321 Results.AddResult(9322 Result(Builder.TakeString(),9323 std::min(IndexedGetterPriority, UnorderedGetterPriority),9324 CXCursor_ObjCInstanceMethodDecl));9325 }9326 }9327 9328 // Indexed getters9329 // Add -(id)objectInKeyAtIndex:(NSUInteger)index9330 if (IsInstanceMethod &&9331 (ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) {9332 std::string SelectorName = (Twine("objectIn") + UpperKey + "AtIndex").str();9333 IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);9334 if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {9335 if (ReturnType.isNull()) {9336 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9337 Builder.AddTextChunk("id");9338 Builder.AddChunk(CodeCompletionString::CK_RightParen);9339 }9340 9341 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));9342 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9343 Builder.AddTextChunk("NSUInteger");9344 Builder.AddChunk(CodeCompletionString::CK_RightParen);9345 Builder.AddTextChunk("index");9346 Results.AddResult(Result(Builder.TakeString(), IndexedGetterPriority,9347 CXCursor_ObjCInstanceMethodDecl));9348 }9349 }9350 9351 // Add -(NSArray *)keyAtIndexes:(NSIndexSet *)indexes9352 if (IsInstanceMethod &&9353 (ReturnType.isNull() ||9354 (ReturnType->isObjCObjectPointerType() &&9355 ReturnType->castAs<ObjCObjectPointerType>()->getInterfaceDecl() &&9356 ReturnType->castAs<ObjCObjectPointerType>()9357 ->getInterfaceDecl()9358 ->getName() == "NSArray"))) {9359 std::string SelectorName = (Twine(Property->getName()) + "AtIndexes").str();9360 IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);9361 if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {9362 if (ReturnType.isNull()) {9363 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9364 Builder.AddTextChunk("NSArray *");9365 Builder.AddChunk(CodeCompletionString::CK_RightParen);9366 }9367 9368 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));9369 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9370 Builder.AddTextChunk("NSIndexSet *");9371 Builder.AddChunk(CodeCompletionString::CK_RightParen);9372 Builder.AddTextChunk("indexes");9373 Results.AddResult(Result(Builder.TakeString(), IndexedGetterPriority,9374 CXCursor_ObjCInstanceMethodDecl));9375 }9376 }9377 9378 // Add -(void)getKey:(type **)buffer range:(NSRange)inRange9379 if (IsInstanceMethod && ReturnTypeMatchesVoid) {9380 std::string SelectorName = (Twine("get") + UpperKey).str();9381 const IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName),9382 &Context.Idents.get("range")};9383 9384 if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) {9385 if (ReturnType.isNull()) {9386 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9387 Builder.AddTextChunk("void");9388 Builder.AddChunk(CodeCompletionString::CK_RightParen);9389 }9390 9391 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));9392 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9393 Builder.AddPlaceholderChunk("object-type");9394 Builder.AddTextChunk(" **");9395 Builder.AddChunk(CodeCompletionString::CK_RightParen);9396 Builder.AddTextChunk("buffer");9397 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);9398 Builder.AddTypedTextChunk("range:");9399 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9400 Builder.AddTextChunk("NSRange");9401 Builder.AddChunk(CodeCompletionString::CK_RightParen);9402 Builder.AddTextChunk("inRange");9403 Results.AddResult(Result(Builder.TakeString(), IndexedGetterPriority,9404 CXCursor_ObjCInstanceMethodDecl));9405 }9406 }9407 9408 // Mutable indexed accessors9409 9410 // - (void)insertObject:(type *)object inKeyAtIndex:(NSUInteger)index9411 if (IsInstanceMethod && ReturnTypeMatchesVoid) {9412 std::string SelectorName = (Twine("in") + UpperKey + "AtIndex").str();9413 const IdentifierInfo *SelectorIds[2] = {&Context.Idents.get("insertObject"),9414 &Context.Idents.get(SelectorName)};9415 9416 if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) {9417 if (ReturnType.isNull()) {9418 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9419 Builder.AddTextChunk("void");9420 Builder.AddChunk(CodeCompletionString::CK_RightParen);9421 }9422 9423 Builder.AddTypedTextChunk("insertObject:");9424 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9425 Builder.AddPlaceholderChunk("object-type");9426 Builder.AddTextChunk(" *");9427 Builder.AddChunk(CodeCompletionString::CK_RightParen);9428 Builder.AddTextChunk("object");9429 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);9430 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));9431 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9432 Builder.AddPlaceholderChunk("NSUInteger");9433 Builder.AddChunk(CodeCompletionString::CK_RightParen);9434 Builder.AddTextChunk("index");9435 Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority,9436 CXCursor_ObjCInstanceMethodDecl));9437 }9438 }9439 9440 // - (void)insertKey:(NSArray *)array atIndexes:(NSIndexSet *)indexes9441 if (IsInstanceMethod && ReturnTypeMatchesVoid) {9442 std::string SelectorName = (Twine("insert") + UpperKey).str();9443 const IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName),9444 &Context.Idents.get("atIndexes")};9445 9446 if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) {9447 if (ReturnType.isNull()) {9448 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9449 Builder.AddTextChunk("void");9450 Builder.AddChunk(CodeCompletionString::CK_RightParen);9451 }9452 9453 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));9454 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9455 Builder.AddTextChunk("NSArray *");9456 Builder.AddChunk(CodeCompletionString::CK_RightParen);9457 Builder.AddTextChunk("array");9458 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);9459 Builder.AddTypedTextChunk("atIndexes:");9460 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9461 Builder.AddPlaceholderChunk("NSIndexSet *");9462 Builder.AddChunk(CodeCompletionString::CK_RightParen);9463 Builder.AddTextChunk("indexes");9464 Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority,9465 CXCursor_ObjCInstanceMethodDecl));9466 }9467 }9468 9469 // -(void)removeObjectFromKeyAtIndex:(NSUInteger)index9470 if (IsInstanceMethod && ReturnTypeMatchesVoid) {9471 std::string SelectorName =9472 (Twine("removeObjectFrom") + UpperKey + "AtIndex").str();9473 const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);9474 if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {9475 if (ReturnType.isNull()) {9476 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9477 Builder.AddTextChunk("void");9478 Builder.AddChunk(CodeCompletionString::CK_RightParen);9479 }9480 9481 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));9482 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9483 Builder.AddTextChunk("NSUInteger");9484 Builder.AddChunk(CodeCompletionString::CK_RightParen);9485 Builder.AddTextChunk("index");9486 Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority,9487 CXCursor_ObjCInstanceMethodDecl));9488 }9489 }9490 9491 // -(void)removeKeyAtIndexes:(NSIndexSet *)indexes9492 if (IsInstanceMethod && ReturnTypeMatchesVoid) {9493 std::string SelectorName = (Twine("remove") + UpperKey + "AtIndexes").str();9494 const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);9495 if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {9496 if (ReturnType.isNull()) {9497 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9498 Builder.AddTextChunk("void");9499 Builder.AddChunk(CodeCompletionString::CK_RightParen);9500 }9501 9502 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));9503 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9504 Builder.AddTextChunk("NSIndexSet *");9505 Builder.AddChunk(CodeCompletionString::CK_RightParen);9506 Builder.AddTextChunk("indexes");9507 Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority,9508 CXCursor_ObjCInstanceMethodDecl));9509 }9510 }9511 9512 // - (void)replaceObjectInKeyAtIndex:(NSUInteger)index withObject:(id)object9513 if (IsInstanceMethod && ReturnTypeMatchesVoid) {9514 std::string SelectorName =9515 (Twine("replaceObjectIn") + UpperKey + "AtIndex").str();9516 const IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName),9517 &Context.Idents.get("withObject")};9518 9519 if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) {9520 if (ReturnType.isNull()) {9521 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9522 Builder.AddTextChunk("void");9523 Builder.AddChunk(CodeCompletionString::CK_RightParen);9524 }9525 9526 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));9527 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9528 Builder.AddPlaceholderChunk("NSUInteger");9529 Builder.AddChunk(CodeCompletionString::CK_RightParen);9530 Builder.AddTextChunk("index");9531 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);9532 Builder.AddTypedTextChunk("withObject:");9533 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9534 Builder.AddTextChunk("id");9535 Builder.AddChunk(CodeCompletionString::CK_RightParen);9536 Builder.AddTextChunk("object");9537 Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority,9538 CXCursor_ObjCInstanceMethodDecl));9539 }9540 }9541 9542 // - (void)replaceKeyAtIndexes:(NSIndexSet *)indexes withKey:(NSArray *)array9543 if (IsInstanceMethod && ReturnTypeMatchesVoid) {9544 std::string SelectorName1 =9545 (Twine("replace") + UpperKey + "AtIndexes").str();9546 std::string SelectorName2 = (Twine("with") + UpperKey).str();9547 const IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName1),9548 &Context.Idents.get(SelectorName2)};9549 9550 if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) {9551 if (ReturnType.isNull()) {9552 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9553 Builder.AddTextChunk("void");9554 Builder.AddChunk(CodeCompletionString::CK_RightParen);9555 }9556 9557 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName1 + ":"));9558 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9559 Builder.AddPlaceholderChunk("NSIndexSet *");9560 Builder.AddChunk(CodeCompletionString::CK_RightParen);9561 Builder.AddTextChunk("indexes");9562 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);9563 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName2 + ":"));9564 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9565 Builder.AddTextChunk("NSArray *");9566 Builder.AddChunk(CodeCompletionString::CK_RightParen);9567 Builder.AddTextChunk("array");9568 Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority,9569 CXCursor_ObjCInstanceMethodDecl));9570 }9571 }9572 9573 // Unordered getters9574 // - (NSEnumerator *)enumeratorOfKey9575 if (IsInstanceMethod &&9576 (ReturnType.isNull() ||9577 (ReturnType->isObjCObjectPointerType() &&9578 ReturnType->castAs<ObjCObjectPointerType>()->getInterfaceDecl() &&9579 ReturnType->castAs<ObjCObjectPointerType>()9580 ->getInterfaceDecl()9581 ->getName() == "NSEnumerator"))) {9582 std::string SelectorName = (Twine("enumeratorOf") + UpperKey).str();9583 const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);9584 if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))9585 .second) {9586 if (ReturnType.isNull()) {9587 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9588 Builder.AddTextChunk("NSEnumerator *");9589 Builder.AddChunk(CodeCompletionString::CK_RightParen);9590 }9591 9592 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName));9593 Results.AddResult(Result(Builder.TakeString(), UnorderedGetterPriority,9594 CXCursor_ObjCInstanceMethodDecl));9595 }9596 }9597 9598 // - (type *)memberOfKey:(type *)object9599 if (IsInstanceMethod &&9600 (ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) {9601 std::string SelectorName = (Twine("memberOf") + UpperKey).str();9602 const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);9603 if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {9604 if (ReturnType.isNull()) {9605 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9606 Builder.AddPlaceholderChunk("object-type");9607 Builder.AddTextChunk(" *");9608 Builder.AddChunk(CodeCompletionString::CK_RightParen);9609 }9610 9611 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));9612 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9613 if (ReturnType.isNull()) {9614 Builder.AddPlaceholderChunk("object-type");9615 Builder.AddTextChunk(" *");9616 } else {9617 Builder.AddTextChunk(GetCompletionTypeString(9618 ReturnType, Context, Policy, Builder.getAllocator()));9619 }9620 Builder.AddChunk(CodeCompletionString::CK_RightParen);9621 Builder.AddTextChunk("object");9622 Results.AddResult(Result(Builder.TakeString(), UnorderedGetterPriority,9623 CXCursor_ObjCInstanceMethodDecl));9624 }9625 }9626 9627 // Mutable unordered accessors9628 // - (void)addKeyObject:(type *)object9629 if (IsInstanceMethod && ReturnTypeMatchesVoid) {9630 std::string SelectorName =9631 (Twine("add") + UpperKey + Twine("Object")).str();9632 const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);9633 if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {9634 if (ReturnType.isNull()) {9635 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9636 Builder.AddTextChunk("void");9637 Builder.AddChunk(CodeCompletionString::CK_RightParen);9638 }9639 9640 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));9641 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9642 Builder.AddPlaceholderChunk("object-type");9643 Builder.AddTextChunk(" *");9644 Builder.AddChunk(CodeCompletionString::CK_RightParen);9645 Builder.AddTextChunk("object");9646 Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority,9647 CXCursor_ObjCInstanceMethodDecl));9648 }9649 }9650 9651 // - (void)addKey:(NSSet *)objects9652 if (IsInstanceMethod && ReturnTypeMatchesVoid) {9653 std::string SelectorName = (Twine("add") + UpperKey).str();9654 const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);9655 if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {9656 if (ReturnType.isNull()) {9657 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9658 Builder.AddTextChunk("void");9659 Builder.AddChunk(CodeCompletionString::CK_RightParen);9660 }9661 9662 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));9663 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9664 Builder.AddTextChunk("NSSet *");9665 Builder.AddChunk(CodeCompletionString::CK_RightParen);9666 Builder.AddTextChunk("objects");9667 Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority,9668 CXCursor_ObjCInstanceMethodDecl));9669 }9670 }9671 9672 // - (void)removeKeyObject:(type *)object9673 if (IsInstanceMethod && ReturnTypeMatchesVoid) {9674 std::string SelectorName =9675 (Twine("remove") + UpperKey + Twine("Object")).str();9676 const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);9677 if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {9678 if (ReturnType.isNull()) {9679 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9680 Builder.AddTextChunk("void");9681 Builder.AddChunk(CodeCompletionString::CK_RightParen);9682 }9683 9684 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));9685 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9686 Builder.AddPlaceholderChunk("object-type");9687 Builder.AddTextChunk(" *");9688 Builder.AddChunk(CodeCompletionString::CK_RightParen);9689 Builder.AddTextChunk("object");9690 Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority,9691 CXCursor_ObjCInstanceMethodDecl));9692 }9693 }9694 9695 // - (void)removeKey:(NSSet *)objects9696 if (IsInstanceMethod && ReturnTypeMatchesVoid) {9697 std::string SelectorName = (Twine("remove") + UpperKey).str();9698 const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);9699 if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {9700 if (ReturnType.isNull()) {9701 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9702 Builder.AddTextChunk("void");9703 Builder.AddChunk(CodeCompletionString::CK_RightParen);9704 }9705 9706 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));9707 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9708 Builder.AddTextChunk("NSSet *");9709 Builder.AddChunk(CodeCompletionString::CK_RightParen);9710 Builder.AddTextChunk("objects");9711 Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority,9712 CXCursor_ObjCInstanceMethodDecl));9713 }9714 }9715 9716 // - (void)intersectKey:(NSSet *)objects9717 if (IsInstanceMethod && ReturnTypeMatchesVoid) {9718 std::string SelectorName = (Twine("intersect") + UpperKey).str();9719 const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);9720 if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {9721 if (ReturnType.isNull()) {9722 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9723 Builder.AddTextChunk("void");9724 Builder.AddChunk(CodeCompletionString::CK_RightParen);9725 }9726 9727 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));9728 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9729 Builder.AddTextChunk("NSSet *");9730 Builder.AddChunk(CodeCompletionString::CK_RightParen);9731 Builder.AddTextChunk("objects");9732 Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority,9733 CXCursor_ObjCInstanceMethodDecl));9734 }9735 }9736 9737 // Key-Value Observing9738 // + (NSSet *)keyPathsForValuesAffectingKey9739 if (!IsInstanceMethod &&9740 (ReturnType.isNull() ||9741 (ReturnType->isObjCObjectPointerType() &&9742 ReturnType->castAs<ObjCObjectPointerType>()->getInterfaceDecl() &&9743 ReturnType->castAs<ObjCObjectPointerType>()9744 ->getInterfaceDecl()9745 ->getName() == "NSSet"))) {9746 std::string SelectorName =9747 (Twine("keyPathsForValuesAffecting") + UpperKey).str();9748 const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);9749 if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))9750 .second) {9751 if (ReturnType.isNull()) {9752 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9753 Builder.AddTextChunk("NSSet<NSString *> *");9754 Builder.AddChunk(CodeCompletionString::CK_RightParen);9755 }9756 9757 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName));9758 Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern,9759 CXCursor_ObjCClassMethodDecl));9760 }9761 }9762 9763 // + (BOOL)automaticallyNotifiesObserversForKey9764 if (!IsInstanceMethod &&9765 (ReturnType.isNull() || ReturnType->isIntegerType() ||9766 ReturnType->isBooleanType())) {9767 std::string SelectorName =9768 (Twine("automaticallyNotifiesObserversOf") + UpperKey).str();9769 const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);9770 if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))9771 .second) {9772 if (ReturnType.isNull()) {9773 Builder.AddChunk(CodeCompletionString::CK_LeftParen);9774 Builder.AddTextChunk("BOOL");9775 Builder.AddChunk(CodeCompletionString::CK_RightParen);9776 }9777 9778 Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName));9779 Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern,9780 CXCursor_ObjCClassMethodDecl));9781 }9782 }9783}9784 9785void SemaCodeCompletion::CodeCompleteObjCMethodDecl(9786 Scope *S, std::optional<bool> IsInstanceMethod, ParsedType ReturnTy) {9787 ASTContext &Context = getASTContext();9788 // Determine the return type of the method we're declaring, if9789 // provided.9790 QualType ReturnType = SemaRef.GetTypeFromParser(ReturnTy);9791 Decl *IDecl = nullptr;9792 if (SemaRef.CurContext->isObjCContainer()) {9793 ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(SemaRef.CurContext);9794 IDecl = OCD;9795 }9796 // Determine where we should start searching for methods.9797 ObjCContainerDecl *SearchDecl = nullptr;9798 bool IsInImplementation = false;9799 if (Decl *D = IDecl) {9800 if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(D)) {9801 SearchDecl = Impl->getClassInterface();9802 IsInImplementation = true;9803 } else if (ObjCCategoryImplDecl *CatImpl =9804 dyn_cast<ObjCCategoryImplDecl>(D)) {9805 SearchDecl = CatImpl->getCategoryDecl();9806 IsInImplementation = true;9807 } else9808 SearchDecl = dyn_cast<ObjCContainerDecl>(D);9809 }9810 9811 if (!SearchDecl && S) {9812 if (DeclContext *DC = S->getEntity())9813 SearchDecl = dyn_cast<ObjCContainerDecl>(DC);9814 }9815 9816 if (!SearchDecl) {9817 HandleCodeCompleteResults(&SemaRef, CodeCompleter,9818 CodeCompletionContext::CCC_Other, nullptr, 0);9819 return;9820 }9821 9822 // Find all of the methods that we could declare/implement here.9823 KnownMethodsMap KnownMethods;9824 FindImplementableMethods(Context, SearchDecl, IsInstanceMethod, ReturnType,9825 KnownMethods);9826 9827 // Add declarations or definitions for each of the known methods.9828 typedef CodeCompletionResult Result;9829 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),9830 CodeCompleter->getCodeCompletionTUInfo(),9831 CodeCompletionContext::CCC_Other);9832 Results.EnterNewScope();9833 PrintingPolicy Policy = getCompletionPrintingPolicy(SemaRef);9834 for (KnownMethodsMap::iterator M = KnownMethods.begin(),9835 MEnd = KnownMethods.end();9836 M != MEnd; ++M) {9837 ObjCMethodDecl *Method = M->second.getPointer();9838 CodeCompletionBuilder Builder(Results.getAllocator(),9839 Results.getCodeCompletionTUInfo());9840 9841 // Add the '-'/'+' prefix if it wasn't provided yet.9842 if (!IsInstanceMethod) {9843 Builder.AddTextChunk(Method->isInstanceMethod() ? "-" : "+");9844 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);9845 }9846 9847 // If the result type was not already provided, add it to the9848 // pattern as (type).9849 if (ReturnType.isNull()) {9850 QualType ResTy = Method->getSendResultType().stripObjCKindOfType(Context);9851 AttributedType::stripOuterNullability(ResTy);9852 AddObjCPassingTypeChunk(ResTy, Method->getObjCDeclQualifier(), Context,9853 Policy, Builder);9854 }9855 9856 Selector Sel = Method->getSelector();9857 9858 if (Sel.isUnarySelector()) {9859 // Unary selectors have no arguments.9860 Builder.AddTypedTextChunk(9861 Builder.getAllocator().CopyString(Sel.getNameForSlot(0)));9862 } else {9863 // Add all parameters to the pattern.9864 unsigned I = 0;9865 for (ObjCMethodDecl::param_iterator P = Method->param_begin(),9866 PEnd = Method->param_end();9867 P != PEnd; (void)++P, ++I) {9868 // Add the part of the selector name.9869 if (I == 0)9870 Builder.AddTypedTextChunk(9871 Builder.getAllocator().CopyString(Sel.getNameForSlot(I) + ":"));9872 else if (I < Sel.getNumArgs()) {9873 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);9874 Builder.AddTypedTextChunk(9875 Builder.getAllocator().CopyString(Sel.getNameForSlot(I) + ":"));9876 } else9877 break;9878 9879 // Add the parameter type.9880 QualType ParamType;9881 if ((*P)->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability)9882 ParamType = (*P)->getType();9883 else9884 ParamType = (*P)->getOriginalType();9885 ParamType = ParamType.substObjCTypeArgs(9886 Context, {}, ObjCSubstitutionContext::Parameter);9887 AttributedType::stripOuterNullability(ParamType);9888 AddObjCPassingTypeChunk(ParamType, (*P)->getObjCDeclQualifier(),9889 Context, Policy, Builder);9890 9891 if (IdentifierInfo *Id = (*P)->getIdentifier())9892 Builder.AddTextChunk(9893 Builder.getAllocator().CopyString(Id->getName()));9894 }9895 }9896 9897 if (Method->isVariadic()) {9898 if (Method->param_size() > 0)9899 Builder.AddChunk(CodeCompletionString::CK_Comma);9900 Builder.AddTextChunk("...");9901 }9902 9903 if (IsInImplementation && Results.includeCodePatterns()) {9904 // We will be defining the method here, so add a compound statement.9905 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);9906 Builder.AddChunk(CodeCompletionString::CK_LeftBrace);9907 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);9908 if (!Method->getReturnType()->isVoidType()) {9909 // If the result type is not void, add a return clause.9910 Builder.AddTextChunk("return");9911 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);9912 Builder.AddPlaceholderChunk("expression");9913 Builder.AddChunk(CodeCompletionString::CK_SemiColon);9914 } else9915 Builder.AddPlaceholderChunk("statements");9916 9917 Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);9918 Builder.AddChunk(CodeCompletionString::CK_RightBrace);9919 }9920 9921 unsigned Priority = CCP_CodePattern;9922 auto R = Result(Builder.TakeString(), Method, Priority);9923 if (!M->second.getInt())9924 setInBaseClass(R);9925 Results.AddResult(std::move(R));9926 }9927 9928 // Add Key-Value-Coding and Key-Value-Observing accessor methods for all of9929 // the properties in this class and its categories.9930 if (Context.getLangOpts().ObjC) {9931 SmallVector<ObjCContainerDecl *, 4> Containers;9932 Containers.push_back(SearchDecl);9933 9934 VisitedSelectorSet KnownSelectors;9935 for (KnownMethodsMap::iterator M = KnownMethods.begin(),9936 MEnd = KnownMethods.end();9937 M != MEnd; ++M)9938 KnownSelectors.insert(M->first);9939 9940 ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(SearchDecl);9941 if (!IFace)9942 if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(SearchDecl))9943 IFace = Category->getClassInterface();9944 9945 if (IFace)9946 llvm::append_range(Containers, IFace->visible_categories());9947 9948 if (IsInstanceMethod) {9949 for (unsigned I = 0, N = Containers.size(); I != N; ++I)9950 for (auto *P : Containers[I]->instance_properties())9951 AddObjCKeyValueCompletions(P, *IsInstanceMethod, ReturnType, Context,9952 KnownSelectors, Results);9953 }9954 }9955 9956 Results.ExitScope();9957 9958 HandleCodeCompleteResults(&SemaRef, CodeCompleter,9959 Results.getCompletionContext(), Results.data(),9960 Results.size());9961}9962 9963void SemaCodeCompletion::CodeCompleteObjCMethodDeclSelector(9964 Scope *S, bool IsInstanceMethod, bool AtParameterName, ParsedType ReturnTy,9965 ArrayRef<const IdentifierInfo *> SelIdents) {9966 // If we have an external source, load the entire class method9967 // pool from the AST file.9968 if (SemaRef.ExternalSource) {9969 for (uint32_t I = 0, N = SemaRef.ExternalSource->GetNumExternalSelectors();9970 I != N; ++I) {9971 Selector Sel = SemaRef.ExternalSource->GetExternalSelector(I);9972 if (Sel.isNull() || SemaRef.ObjC().MethodPool.count(Sel))9973 continue;9974 9975 SemaRef.ObjC().ReadMethodPool(Sel);9976 }9977 }9978 9979 // Build the set of methods we can see.9980 typedef CodeCompletionResult Result;9981 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),9982 CodeCompleter->getCodeCompletionTUInfo(),9983 CodeCompletionContext::CCC_Other);9984 9985 if (ReturnTy)9986 Results.setPreferredType(9987 SemaRef.GetTypeFromParser(ReturnTy).getNonReferenceType());9988 9989 Results.EnterNewScope();9990 for (SemaObjC::GlobalMethodPool::iterator9991 M = SemaRef.ObjC().MethodPool.begin(),9992 MEnd = SemaRef.ObjC().MethodPool.end();9993 M != MEnd; ++M) {9994 for (ObjCMethodList *MethList = IsInstanceMethod ? &M->second.first9995 : &M->second.second;9996 MethList && MethList->getMethod(); MethList = MethList->getNext()) {9997 if (!isAcceptableObjCMethod(MethList->getMethod(), MK_Any, SelIdents))9998 continue;9999 10000 if (AtParameterName) {10001 // Suggest parameter names we've seen before.10002 unsigned NumSelIdents = SelIdents.size();10003 if (NumSelIdents &&10004 NumSelIdents <= MethList->getMethod()->param_size()) {10005 ParmVarDecl *Param =10006 MethList->getMethod()->parameters()[NumSelIdents - 1];10007 if (Param->getIdentifier()) {10008 CodeCompletionBuilder Builder(Results.getAllocator(),10009 Results.getCodeCompletionTUInfo());10010 Builder.AddTypedTextChunk(Builder.getAllocator().CopyString(10011 Param->getIdentifier()->getName()));10012 Results.AddResult(Builder.TakeString());10013 }10014 }10015 10016 continue;10017 }10018 10019 Result R(MethList->getMethod(),10020 Results.getBasePriority(MethList->getMethod()),10021 /*Qualifier=*/std::nullopt);10022 R.StartParameter = SelIdents.size();10023 R.AllParametersAreInformative = false;10024 R.DeclaringEntity = true;10025 Results.MaybeAddResult(R, SemaRef.CurContext);10026 }10027 }10028 10029 Results.ExitScope();10030 10031 if (!AtParameterName && !SelIdents.empty() &&10032 SelIdents.front()->getName().starts_with("init")) {10033 for (const auto &M : SemaRef.PP.macros()) {10034 if (M.first->getName() != "NS_DESIGNATED_INITIALIZER")10035 continue;10036 Results.EnterNewScope();10037 CodeCompletionBuilder Builder(Results.getAllocator(),10038 Results.getCodeCompletionTUInfo());10039 Builder.AddTypedTextChunk(10040 Builder.getAllocator().CopyString(M.first->getName()));10041 Results.AddResult(CodeCompletionResult(Builder.TakeString(), CCP_Macro,10042 CXCursor_MacroDefinition));10043 Results.ExitScope();10044 }10045 }10046 10047 HandleCodeCompleteResults(&SemaRef, CodeCompleter,10048 Results.getCompletionContext(), Results.data(),10049 Results.size());10050}10051 10052void SemaCodeCompletion::CodeCompletePreprocessorDirective(bool InConditional) {10053 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),10054 CodeCompleter->getCodeCompletionTUInfo(),10055 CodeCompletionContext::CCC_PreprocessorDirective);10056 Results.EnterNewScope();10057 10058 // #if <condition>10059 CodeCompletionBuilder Builder(Results.getAllocator(),10060 Results.getCodeCompletionTUInfo());10061 Builder.AddTypedTextChunk("if");10062 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10063 Builder.AddPlaceholderChunk("condition");10064 Results.AddResult(Builder.TakeString());10065 10066 // #ifdef <macro>10067 Builder.AddTypedTextChunk("ifdef");10068 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10069 Builder.AddPlaceholderChunk("macro");10070 Results.AddResult(Builder.TakeString());10071 10072 // #ifndef <macro>10073 Builder.AddTypedTextChunk("ifndef");10074 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10075 Builder.AddPlaceholderChunk("macro");10076 Results.AddResult(Builder.TakeString());10077 10078 if (InConditional) {10079 // #elif <condition>10080 Builder.AddTypedTextChunk("elif");10081 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10082 Builder.AddPlaceholderChunk("condition");10083 Results.AddResult(Builder.TakeString());10084 10085 // #elifdef <macro>10086 Builder.AddTypedTextChunk("elifdef");10087 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10088 Builder.AddPlaceholderChunk("macro");10089 Results.AddResult(Builder.TakeString());10090 10091 // #elifndef <macro>10092 Builder.AddTypedTextChunk("elifndef");10093 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10094 Builder.AddPlaceholderChunk("macro");10095 Results.AddResult(Builder.TakeString());10096 10097 // #else10098 Builder.AddTypedTextChunk("else");10099 Results.AddResult(Builder.TakeString());10100 10101 // #endif10102 Builder.AddTypedTextChunk("endif");10103 Results.AddResult(Builder.TakeString());10104 }10105 10106 // #include "header"10107 Builder.AddTypedTextChunk("include");10108 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10109 Builder.AddTextChunk("\"");10110 Builder.AddPlaceholderChunk("header");10111 Builder.AddTextChunk("\"");10112 Results.AddResult(Builder.TakeString());10113 10114 // #include <header>10115 Builder.AddTypedTextChunk("include");10116 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10117 Builder.AddTextChunk("<");10118 Builder.AddPlaceholderChunk("header");10119 Builder.AddTextChunk(">");10120 Results.AddResult(Builder.TakeString());10121 10122 // #define <macro>10123 Builder.AddTypedTextChunk("define");10124 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10125 Builder.AddPlaceholderChunk("macro");10126 Results.AddResult(Builder.TakeString());10127 10128 // #define <macro>(<args>)10129 Builder.AddTypedTextChunk("define");10130 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10131 Builder.AddPlaceholderChunk("macro");10132 Builder.AddChunk(CodeCompletionString::CK_LeftParen);10133 Builder.AddPlaceholderChunk("args");10134 Builder.AddChunk(CodeCompletionString::CK_RightParen);10135 Results.AddResult(Builder.TakeString());10136 10137 // #undef <macro>10138 Builder.AddTypedTextChunk("undef");10139 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10140 Builder.AddPlaceholderChunk("macro");10141 Results.AddResult(Builder.TakeString());10142 10143 // #line <number>10144 Builder.AddTypedTextChunk("line");10145 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10146 Builder.AddPlaceholderChunk("number");10147 Results.AddResult(Builder.TakeString());10148 10149 // #line <number> "filename"10150 Builder.AddTypedTextChunk("line");10151 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10152 Builder.AddPlaceholderChunk("number");10153 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10154 Builder.AddTextChunk("\"");10155 Builder.AddPlaceholderChunk("filename");10156 Builder.AddTextChunk("\"");10157 Results.AddResult(Builder.TakeString());10158 10159 // #error <message>10160 Builder.AddTypedTextChunk("error");10161 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10162 Builder.AddPlaceholderChunk("message");10163 Results.AddResult(Builder.TakeString());10164 10165 // #pragma <arguments>10166 Builder.AddTypedTextChunk("pragma");10167 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10168 Builder.AddPlaceholderChunk("arguments");10169 Results.AddResult(Builder.TakeString());10170 10171 if (getLangOpts().ObjC) {10172 // #import "header"10173 Builder.AddTypedTextChunk("import");10174 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10175 Builder.AddTextChunk("\"");10176 Builder.AddPlaceholderChunk("header");10177 Builder.AddTextChunk("\"");10178 Results.AddResult(Builder.TakeString());10179 10180 // #import <header>10181 Builder.AddTypedTextChunk("import");10182 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10183 Builder.AddTextChunk("<");10184 Builder.AddPlaceholderChunk("header");10185 Builder.AddTextChunk(">");10186 Results.AddResult(Builder.TakeString());10187 }10188 10189 // #include_next "header"10190 Builder.AddTypedTextChunk("include_next");10191 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10192 Builder.AddTextChunk("\"");10193 Builder.AddPlaceholderChunk("header");10194 Builder.AddTextChunk("\"");10195 Results.AddResult(Builder.TakeString());10196 10197 // #include_next <header>10198 Builder.AddTypedTextChunk("include_next");10199 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10200 Builder.AddTextChunk("<");10201 Builder.AddPlaceholderChunk("header");10202 Builder.AddTextChunk(">");10203 Results.AddResult(Builder.TakeString());10204 10205 // #warning <message>10206 Builder.AddTypedTextChunk("warning");10207 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10208 Builder.AddPlaceholderChunk("message");10209 Results.AddResult(Builder.TakeString());10210 10211 if (getLangOpts().C23) {10212 // #embed "file"10213 Builder.AddTypedTextChunk("embed");10214 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10215 Builder.AddTextChunk("\"");10216 Builder.AddPlaceholderChunk("file");10217 Builder.AddTextChunk("\"");10218 Results.AddResult(Builder.TakeString());10219 10220 // #embed <file>10221 Builder.AddTypedTextChunk("embed");10222 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10223 Builder.AddTextChunk("<");10224 Builder.AddPlaceholderChunk("file");10225 Builder.AddTextChunk(">");10226 Results.AddResult(Builder.TakeString());10227 }10228 10229 // Note: #ident and #sccs are such crazy anachronisms that we don't provide10230 // completions for them. And __include_macros is a Clang-internal extension10231 // that we don't want to encourage anyone to use.10232 10233 // FIXME: we don't support #assert or #unassert, so don't suggest them.10234 Results.ExitScope();10235 10236 HandleCodeCompleteResults(&SemaRef, CodeCompleter,10237 Results.getCompletionContext(), Results.data(),10238 Results.size());10239}10240 10241void SemaCodeCompletion::CodeCompleteInPreprocessorConditionalExclusion(10242 Scope *S) {10243 CodeCompleteOrdinaryName(S, S->getFnParent()10244 ? SemaCodeCompletion::PCC_RecoveryInFunction10245 : SemaCodeCompletion::PCC_Namespace);10246}10247 10248void SemaCodeCompletion::CodeCompletePreprocessorMacroName(bool IsDefinition) {10249 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),10250 CodeCompleter->getCodeCompletionTUInfo(),10251 IsDefinition ? CodeCompletionContext::CCC_MacroName10252 : CodeCompletionContext::CCC_MacroNameUse);10253 if (!IsDefinition && CodeCompleter->includeMacros()) {10254 // Add just the names of macros, not their arguments.10255 CodeCompletionBuilder Builder(Results.getAllocator(),10256 Results.getCodeCompletionTUInfo());10257 Results.EnterNewScope();10258 for (Preprocessor::macro_iterator M = SemaRef.PP.macro_begin(),10259 MEnd = SemaRef.PP.macro_end();10260 M != MEnd; ++M) {10261 Builder.AddTypedTextChunk(10262 Builder.getAllocator().CopyString(M->first->getName()));10263 Results.AddResult(CodeCompletionResult(10264 Builder.TakeString(), CCP_CodePattern, CXCursor_MacroDefinition));10265 }10266 Results.ExitScope();10267 } else if (IsDefinition) {10268 // FIXME: Can we detect when the user just wrote an include guard above?10269 }10270 10271 HandleCodeCompleteResults(&SemaRef, CodeCompleter,10272 Results.getCompletionContext(), Results.data(),10273 Results.size());10274}10275 10276void SemaCodeCompletion::CodeCompletePreprocessorExpression() {10277 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),10278 CodeCompleter->getCodeCompletionTUInfo(),10279 CodeCompletionContext::CCC_PreprocessorExpression);10280 10281 if (CodeCompleter->includeMacros())10282 AddMacroResults(SemaRef.PP, Results, CodeCompleter->loadExternal(), true);10283 10284 // defined (<macro>)10285 Results.EnterNewScope();10286 CodeCompletionBuilder Builder(Results.getAllocator(),10287 Results.getCodeCompletionTUInfo());10288 Builder.AddTypedTextChunk("defined");10289 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);10290 Builder.AddChunk(CodeCompletionString::CK_LeftParen);10291 Builder.AddPlaceholderChunk("macro");10292 Builder.AddChunk(CodeCompletionString::CK_RightParen);10293 Results.AddResult(Builder.TakeString());10294 Results.ExitScope();10295 10296 HandleCodeCompleteResults(&SemaRef, CodeCompleter,10297 Results.getCompletionContext(), Results.data(),10298 Results.size());10299}10300 10301void SemaCodeCompletion::CodeCompletePreprocessorMacroArgument(10302 Scope *S, IdentifierInfo *Macro, MacroInfo *MacroInfo, unsigned Argument) {10303 // FIXME: In the future, we could provide "overload" results, much like we10304 // do for function calls.10305 10306 // Now just ignore this. There will be another code-completion callback10307 // for the expanded tokens.10308}10309 10310// This handles completion inside an #include filename, e.g. #include <foo/ba10311// We look for the directory "foo" under each directory on the include path,10312// list its files, and reassemble the appropriate #include.10313void SemaCodeCompletion::CodeCompleteIncludedFile(llvm::StringRef Dir,10314 bool Angled) {10315 // RelDir should use /, but unescaped \ is possible on windows!10316 // Our completions will normalize to / for simplicity, this case is rare.10317 std::string RelDir = llvm::sys::path::convert_to_slash(Dir);10318 // We need the native slashes for the actual file system interactions.10319 SmallString<128> NativeRelDir = StringRef(RelDir);10320 llvm::sys::path::native(NativeRelDir);10321 llvm::vfs::FileSystem &FS =10322 SemaRef.getSourceManager().getFileManager().getVirtualFileSystem();10323 10324 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),10325 CodeCompleter->getCodeCompletionTUInfo(),10326 CodeCompletionContext::CCC_IncludedFile);10327 llvm::DenseSet<StringRef> SeenResults; // To deduplicate results.10328 10329 // Helper: adds one file or directory completion result.10330 auto AddCompletion = [&](StringRef Filename, bool IsDirectory) {10331 SmallString<64> TypedChunk = Filename;10332 // Directory completion is up to the slash, e.g. <sys/10333 TypedChunk.push_back(IsDirectory ? '/' : Angled ? '>' : '"');10334 auto R = SeenResults.insert(TypedChunk);10335 if (R.second) { // New completion10336 const char *InternedTyped = Results.getAllocator().CopyString(TypedChunk);10337 *R.first = InternedTyped; // Avoid dangling StringRef.10338 CodeCompletionBuilder Builder(CodeCompleter->getAllocator(),10339 CodeCompleter->getCodeCompletionTUInfo());10340 Builder.AddTypedTextChunk(InternedTyped);10341 // The result is a "Pattern", which is pretty opaque.10342 // We may want to include the real filename to allow smart ranking.10343 Results.AddResult(CodeCompletionResult(Builder.TakeString()));10344 }10345 };10346 10347 // Helper: scans IncludeDir for nice files, and adds results for each.10348 auto AddFilesFromIncludeDir = [&](StringRef IncludeDir,10349 bool IsSystem,10350 DirectoryLookup::LookupType_t LookupType) {10351 llvm::SmallString<128> Dir = IncludeDir;10352 if (!NativeRelDir.empty()) {10353 if (LookupType == DirectoryLookup::LT_Framework) {10354 // For a framework dir, #include <Foo/Bar/> actually maps to10355 // a path of Foo.framework/Headers/Bar/.10356 auto Begin = llvm::sys::path::begin(NativeRelDir);10357 auto End = llvm::sys::path::end(NativeRelDir);10358 10359 llvm::sys::path::append(Dir, *Begin + ".framework", "Headers");10360 llvm::sys::path::append(Dir, ++Begin, End);10361 } else {10362 llvm::sys::path::append(Dir, NativeRelDir);10363 }10364 }10365 10366 const StringRef &Dirname = llvm::sys::path::filename(Dir);10367 const bool isQt = Dirname.starts_with("Qt") || Dirname == "ActiveQt";10368 const bool ExtensionlessHeaders =10369 IsSystem || isQt || Dir.ends_with(".framework/Headers");10370 std::error_code EC;10371 unsigned Count = 0;10372 for (auto It = FS.dir_begin(Dir, EC);10373 !EC && It != llvm::vfs::directory_iterator(); It.increment(EC)) {10374 if (++Count == 2500) // If we happen to hit a huge directory,10375 break; // bail out early so we're not too slow.10376 StringRef Filename = llvm::sys::path::filename(It->path());10377 10378 // To know whether a symlink should be treated as file or a directory, we10379 // have to stat it. This should be cheap enough as there shouldn't be many10380 // symlinks.10381 llvm::sys::fs::file_type Type = It->type();10382 if (Type == llvm::sys::fs::file_type::symlink_file) {10383 if (auto FileStatus = FS.status(It->path()))10384 Type = FileStatus->getType();10385 }10386 switch (Type) {10387 case llvm::sys::fs::file_type::directory_file:10388 // All entries in a framework directory must have a ".framework" suffix,10389 // but the suffix does not appear in the source code's include/import.10390 if (LookupType == DirectoryLookup::LT_Framework &&10391 NativeRelDir.empty() && !Filename.consume_back(".framework"))10392 break;10393 10394 AddCompletion(Filename, /*IsDirectory=*/true);10395 break;10396 case llvm::sys::fs::file_type::regular_file: {10397 // Only files that really look like headers. (Except in special dirs).10398 const bool IsHeader = Filename.ends_with_insensitive(".h") ||10399 Filename.ends_with_insensitive(".hh") ||10400 Filename.ends_with_insensitive(".hpp") ||10401 Filename.ends_with_insensitive(".hxx") ||10402 Filename.ends_with_insensitive(".inc") ||10403 (ExtensionlessHeaders && !Filename.contains('.'));10404 if (!IsHeader)10405 break;10406 AddCompletion(Filename, /*IsDirectory=*/false);10407 break;10408 }10409 default:10410 break;10411 }10412 }10413 };10414 10415 // Helper: adds results relative to IncludeDir, if possible.10416 auto AddFilesFromDirLookup = [&](const DirectoryLookup &IncludeDir,10417 bool IsSystem) {10418 switch (IncludeDir.getLookupType()) {10419 case DirectoryLookup::LT_HeaderMap:10420 // header maps are not (currently) enumerable.10421 break;10422 case DirectoryLookup::LT_NormalDir:10423 AddFilesFromIncludeDir(IncludeDir.getDirRef()->getName(), IsSystem,10424 DirectoryLookup::LT_NormalDir);10425 break;10426 case DirectoryLookup::LT_Framework:10427 AddFilesFromIncludeDir(IncludeDir.getFrameworkDirRef()->getName(),10428 IsSystem, DirectoryLookup::LT_Framework);10429 break;10430 }10431 };10432 10433 // Finally with all our helpers, we can scan the include path.10434 // Do this in standard order so deduplication keeps the right file.10435 // (In case we decide to add more details to the results later).10436 const auto &S = SemaRef.PP.getHeaderSearchInfo();10437 using llvm::make_range;10438 if (!Angled) {10439 // The current directory is on the include path for "quoted" includes.10440 if (auto CurFile = SemaRef.PP.getCurrentFileLexer()->getFileEntry())10441 AddFilesFromIncludeDir(CurFile->getDir().getName(), false,10442 DirectoryLookup::LT_NormalDir);10443 for (const auto &D : make_range(S.quoted_dir_begin(), S.quoted_dir_end()))10444 AddFilesFromDirLookup(D, false);10445 }10446 for (const auto &D : make_range(S.angled_dir_begin(), S.angled_dir_end()))10447 AddFilesFromDirLookup(D, false);10448 for (const auto &D : make_range(S.system_dir_begin(), S.system_dir_end()))10449 AddFilesFromDirLookup(D, true);10450 10451 HandleCodeCompleteResults(&SemaRef, CodeCompleter,10452 Results.getCompletionContext(), Results.data(),10453 Results.size());10454}10455 10456void SemaCodeCompletion::CodeCompleteNaturalLanguage() {10457 HandleCodeCompleteResults(&SemaRef, CodeCompleter,10458 CodeCompletionContext::CCC_NaturalLanguage, nullptr,10459 0);10460}10461 10462void SemaCodeCompletion::CodeCompleteAvailabilityPlatformName() {10463 ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),10464 CodeCompleter->getCodeCompletionTUInfo(),10465 CodeCompletionContext::CCC_Other);10466 Results.EnterNewScope();10467 static const char *Platforms[] = {"macOS", "iOS", "watchOS", "tvOS"};10468 for (const char *Platform : llvm::ArrayRef(Platforms)) {10469 Results.AddResult(CodeCompletionResult(Platform));10470 Results.AddResult(CodeCompletionResult(Results.getAllocator().CopyString(10471 Twine(Platform) + "ApplicationExtension")));10472 }10473 Results.ExitScope();10474 HandleCodeCompleteResults(&SemaRef, CodeCompleter,10475 Results.getCompletionContext(), Results.data(),10476 Results.size());10477}10478 10479void SemaCodeCompletion::GatherGlobalCodeCompletions(10480 CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo,10481 SmallVectorImpl<CodeCompletionResult> &Results) {10482 ResultBuilder Builder(SemaRef, Allocator, CCTUInfo,10483 CodeCompletionContext::CCC_Recovery);10484 if (!CodeCompleter || CodeCompleter->includeGlobals()) {10485 CodeCompletionDeclConsumer Consumer(10486 Builder, getASTContext().getTranslationUnitDecl());10487 SemaRef.LookupVisibleDecls(getASTContext().getTranslationUnitDecl(),10488 Sema::LookupAnyName, Consumer,10489 !CodeCompleter || CodeCompleter->loadExternal());10490 }10491 10492 if (!CodeCompleter || CodeCompleter->includeMacros())10493 AddMacroResults(SemaRef.PP, Builder,10494 !CodeCompleter || CodeCompleter->loadExternal(), true);10495 10496 Results.clear();10497 Results.insert(Results.end(), Builder.data(),10498 Builder.data() + Builder.size());10499}10500 10501SemaCodeCompletion::SemaCodeCompletion(Sema &S,10502 CodeCompleteConsumer *CompletionConsumer)10503 : SemaBase(S), CodeCompleter(CompletionConsumer),10504 Resolver(S.getASTContext()) {}10505