diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/SemaCodeComplete.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Sema/SemaCodeComplete.cpp | 1074 |
1 files changed, 863 insertions, 211 deletions
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaCodeComplete.cpp b/contrib/llvm-project/clang/lib/Sema/SemaCodeComplete.cpp index e03b671ae61e..c44be0df9b0a 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaCodeComplete.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaCodeComplete.cpp @@ -23,6 +23,7 @@ #include "clang/AST/QualTypeNames.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Type.h" +#include "clang/Basic/AttributeCommonInfo.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/Specifiers.h" @@ -34,6 +35,8 @@ #include "clang/Sema/Designator.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" +#include "clang/Sema/ParsedAttr.h" +#include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Sema.h" @@ -50,8 +53,10 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" + #include <list> #include <map> +#include <optional> #include <string> #include <vector> @@ -93,10 +98,10 @@ private: /// When the entry contains a single declaration, this is /// the index associated with that entry. - unsigned SingleDeclIndex; + unsigned SingleDeclIndex = 0; public: - ShadowMapEntry() : DeclOrVector(), SingleDeclIndex(0) {} + ShadowMapEntry() = default; ShadowMapEntry(const ShadowMapEntry &) = delete; ShadowMapEntry(ShadowMapEntry &&Move) { *this = std::move(Move); } ShadowMapEntry &operator=(const ShadowMapEntry &) = delete; @@ -220,6 +225,7 @@ public: case CodeCompletionContext::CCC_ObjCMessageReceiver: case CodeCompletionContext::CCC_ParenthesizedExpression: case CodeCompletionContext::CCC_Statement: + case CodeCompletionContext::CCC_TopLevelOrExpression: case CodeCompletionContext::CCC_Recovery: if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl()) if (Method->isInstanceMethod()) @@ -304,6 +310,23 @@ public: bool isInterestingDecl(const NamedDecl *ND, bool &AsNestedNameSpecifier) const; + /// Decide whether or not a use of function Decl can be a call. + /// + /// \param ND the function declaration. + /// + /// \param BaseExprType the object type in a member access expression, + /// if any. + bool canFunctionBeCalled(const NamedDecl *ND, QualType BaseExprType) const; + + /// Decide whether or not a use of member function Decl can be a call. + /// + /// \param Method the function declaration. + /// + /// \param BaseExprType the object type in a member access expression, + /// if any. + bool canCxxMethodBeCalled(const CXXMethodDecl *Method, + QualType BaseExprType) const; + /// Check whether the result is hidden by the Hiding declaration. /// /// \returns true if the result is hidden and cannot be found, false if @@ -333,8 +356,11 @@ public: /// /// \param InBaseClass whether the result was found in a base /// class of the searched context. + /// + /// \param BaseExprType the type of expression that precedes the "." or "->" + /// in a member access expression. void AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding, - bool InBaseClass); + bool InBaseClass, QualType BaseExprType); /// Add a new non-declaration result to this result set. void AddResult(Result R); @@ -567,7 +593,6 @@ void PreferredTypeBuilder::enterMemAccess(Sema &S, SourceLocation Tok, return; // Keep the expected type, only update the location. ExpectedLoc = Tok; - return; } void PreferredTypeBuilder::enterUnary(Sema &S, SourceLocation Tok, @@ -741,9 +766,7 @@ getRequiredQualification(ASTContext &Context, const DeclContext *CurContext, static bool shouldIgnoreDueToReservedName(const NamedDecl *ND, Sema &SemaRef) { ReservedIdentifierStatus Status = ND->isReserved(SemaRef.getLangOpts()); // Ignore reserved names for compiler provided decls. - if ((Status != ReservedIdentifierStatus::NotReserved) && - (Status != ReservedIdentifierStatus::StartsWithUnderscoreAtGlobalScope) && - ND->getLocation().isInvalid()) + if (isReservedInAllContexts(Status) && ND->getLocation().isInvalid()) return true; // For system headers ignore only double-underscore names. @@ -1095,7 +1118,10 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { if (const UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) { CodeCompletionResult Result(Using->getTargetDecl(), getBasePriority(Using->getTargetDecl()), - R.Qualifier); + R.Qualifier, false, + (R.Availability == CXAvailability_Available || + R.Availability == CXAvailability_Deprecated), + std::move(R.FixIts)); Result.ShadowDecl = Using; MaybeAddResult(Result, CurContext); return; @@ -1209,7 +1235,7 @@ static void setInBaseClass(ResultBuilder::Result &R) { enum class OverloadCompare { BothViable, Dominates, Dominated }; // Will Candidate ever be called on the object, when overloaded with Incumbent? // Returns Dominates if Candidate is always called, Dominated if Incumbent is -// always called, BothViable if either may be called dependending on arguments. +// always called, BothViable if either may be called depending on arguments. // Precondition: must actually be overloads! static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate, const CXXMethodDecl &Incumbent, @@ -1227,8 +1253,8 @@ static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate, if (Candidate.parameters()[I]->getType().getCanonicalType() != Incumbent.parameters()[I]->getType().getCanonicalType()) return OverloadCompare::BothViable; - if (!llvm::empty(Candidate.specific_attrs<EnableIfAttr>()) || - !llvm::empty(Incumbent.specific_attrs<EnableIfAttr>())) + if (!Candidate.specific_attrs<EnableIfAttr>().empty() || + !Incumbent.specific_attrs<EnableIfAttr>().empty()) return OverloadCompare::BothViable; // At this point, we know calls can't pick one or the other based on // arguments, so one of the two must win. (Or both fail, handled elsewhere). @@ -1256,8 +1282,69 @@ static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate, : OverloadCompare::Dominated; } +bool ResultBuilder::canCxxMethodBeCalled(const CXXMethodDecl *Method, + QualType BaseExprType) const { + // Find the class scope that we're currently in. + // We could e.g. be inside a lambda, so walk up the DeclContext until we + // find a CXXMethodDecl. + DeclContext *CurContext = SemaRef.CurContext; + const auto *CurrentClassScope = [&]() -> const CXXRecordDecl * { + for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getParent()) { + const auto *CtxMethod = llvm::dyn_cast<CXXMethodDecl>(Ctx); + if (CtxMethod && !CtxMethod->getParent()->isLambda()) { + return CtxMethod->getParent(); + } + } + return nullptr; + }(); + + // If we're not inside the scope of the method's class, it can't be a call. + bool FunctionCanBeCall = + CurrentClassScope && + (CurrentClassScope == Method->getParent() || + CurrentClassScope->isDerivedFrom(Method->getParent())); + + // We skip the following calculation for exceptions if it's already true. + if (FunctionCanBeCall) + return true; + + // Exception: foo->FooBase::bar() or foo->Foo::bar() *is* a call. + if (const CXXRecordDecl *MaybeDerived = + BaseExprType.isNull() ? nullptr + : BaseExprType->getAsCXXRecordDecl()) { + auto *MaybeBase = Method->getParent(); + FunctionCanBeCall = + MaybeDerived == MaybeBase || MaybeDerived->isDerivedFrom(MaybeBase); + } + + return FunctionCanBeCall; +} + +bool ResultBuilder::canFunctionBeCalled(const NamedDecl *ND, + QualType BaseExprType) const { + // We apply heuristics only to CCC_Symbol: + // * CCC_{Arrow,Dot}MemberAccess reflect member access expressions: + // f.method() and f->method(). These are always calls. + // * A qualified name to a member function may *not* be a call. We have to + // subdivide the cases: For example, f.Base::method(), which is regarded as + // CCC_Symbol, should be a call. + // * Non-member functions and static member functions are always considered + // calls. + if (CompletionContext.getKind() == clang::CodeCompletionContext::CCC_Symbol) { + if (const auto *FuncTmpl = dyn_cast<FunctionTemplateDecl>(ND)) { + ND = FuncTmpl->getTemplatedDecl(); + } + const auto *Method = dyn_cast<CXXMethodDecl>(ND); + if (Method && !Method->isStatic()) { + return canCxxMethodBeCalled(Method, BaseExprType); + } + } + return true; +} + void ResultBuilder::AddResult(Result R, DeclContext *CurContext, - NamedDecl *Hiding, bool InBaseClass = false) { + NamedDecl *Hiding, bool InBaseClass = false, + QualType BaseExprType = QualType()) { if (R.Kind != Result::RK_Declaration) { // For non-declaration results, just add the result. Results.push_back(R); @@ -1268,9 +1355,13 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, if (const auto *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) { CodeCompletionResult Result(Using->getTargetDecl(), getBasePriority(Using->getTargetDecl()), - R.Qualifier); + R.Qualifier, false, + (R.Availability == CXAvailability_Available || + R.Availability == CXAvailability_Deprecated), + std::move(R.FixIts)); Result.ShadowDecl = Using; - AddResult(Result, CurContext, Hiding); + AddResult(Result, CurContext, Hiding, /*InBaseClass=*/false, + /*BaseExprType=*/BaseExprType); return; } @@ -1372,6 +1463,8 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, OverloadSet.Add(Method, Results.size()); } + R.FunctionCanBeCall = canFunctionBeCalled(R.getDeclaration(), BaseExprType); + // Insert this result into the set of results. Results.push_back(R); @@ -1438,7 +1531,7 @@ bool ResultBuilder::IsOrdinaryNonTypeName(const NamedDecl *ND) const { bool ResultBuilder::IsIntegralConstantValue(const NamedDecl *ND) const { if (!IsOrdinaryNonTypeName(ND)) - return 0; + return false; if (const auto *VD = dyn_cast<ValueDecl>(ND->getUnderlyingDecl())) if (VD->getType()->isIntegralOrEnumerationType()) @@ -1483,8 +1576,9 @@ bool ResultBuilder::IsClassOrStruct(const NamedDecl *ND) const { // For purposes of this check, interfaces match too. if (const auto *RD = dyn_cast<RecordDecl>(ND)) - return RD->getTagKind() == TTK_Class || RD->getTagKind() == TTK_Struct || - RD->getTagKind() == TTK_Interface; + return RD->getTagKind() == TagTypeKind::Class || + RD->getTagKind() == TagTypeKind::Struct || + RD->getTagKind() == TagTypeKind::Interface; return false; } @@ -1496,7 +1590,7 @@ bool ResultBuilder::IsUnion(const NamedDecl *ND) const { ND = ClassTemplate->getTemplatedDecl(); if (const auto *RD = dyn_cast<RecordDecl>(ND)) - return RD->getTagKind() == TTK_Union; + return RD->getTagKind() == TagTypeKind::Union; return false; } @@ -1644,7 +1738,7 @@ public: bool InBaseClass) override { ResultBuilder::Result Result(ND, Results.getBasePriority(ND), nullptr, false, IsAccessible(ND, Ctx), FixIts); - Results.AddResult(Result, InitialLookupCtx, Hiding, InBaseClass); + Results.AddResult(Result, InitialLookupCtx, Hiding, InBaseClass, BaseType); } void EnteredContext(DeclContext *Ctx) override { @@ -1802,7 +1896,7 @@ static void AddFunctionSpecifiers(Sema::ParserCompletionContext CCC, Results.AddResult(Result("mutable")); Results.AddResult(Result("virtual")); } - LLVM_FALLTHROUGH; + [[fallthrough]]; case Sema::PCC_ObjCInterface: case Sema::PCC_ObjCImplementation: @@ -1815,6 +1909,7 @@ static void AddFunctionSpecifiers(Sema::ParserCompletionContext CCC, case Sema::PCC_ObjCInstanceVariableList: case Sema::PCC_Expression: case Sema::PCC_Statement: + case Sema::PCC_TopLevelOrExpression: case Sema::PCC_ForInit: case Sema::PCC_Condition: case Sema::PCC_RecoveryInFunction: @@ -1872,6 +1967,7 @@ static bool WantTypesInContext(Sema::ParserCompletionContext CCC, case Sema::PCC_Type: case Sema::PCC_ParenthesizedExpression: case Sema::PCC_LocalDeclarationSpecifiers: + case Sema::PCC_TopLevelOrExpression: return true; case Sema::PCC_Expression: @@ -1896,6 +1992,7 @@ static PrintingPolicy getCompletionPrintingPolicy(const ASTContext &Context, Policy.SuppressStrongLifetime = true; Policy.SuppressUnwrittenScope = true; Policy.SuppressScope = true; + Policy.CleanUglifiedParameters = true; return Policy; } @@ -1922,15 +2019,15 @@ static const char *GetCompletionTypeString(QualType T, ASTContext &Context, if (TagDecl *Tag = TagT->getDecl()) if (!Tag->hasNameForLinkage()) { switch (Tag->getTagKind()) { - case TTK_Struct: + case TagTypeKind::Struct: return "struct <anonymous>"; - case TTK_Interface: + case TagTypeKind::Interface: return "__interface <anonymous>"; - case TTK_Class: + case TagTypeKind::Class: return "class <anonymous>"; - case TTK_Union: + case TagTypeKind::Union: return "union <anonymous>"; - case TTK_Enum: + case TagTypeKind::Enum: return "enum <anonymous>"; } } @@ -2089,7 +2186,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, AddObjCTopLevelResults(Results, true); AddTypedefResult(Results); - LLVM_FALLTHROUGH; + [[fallthrough]]; case Sema::PCC_Class: if (SemaRef.getLangOpts().CPlusPlus) { @@ -2121,8 +2218,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, if (CCC == Sema::PCC_Class) { AddTypedefResult(Results); - bool IsNotInheritanceScope = - !(S->getFlags() & Scope::ClassInheritanceScope); + bool IsNotInheritanceScope = !S->isClassInheritanceScope(); // public: Builder.AddTypedTextChunk("public"); if (IsNotInheritanceScope && Results.includeCodePatterns()) @@ -2148,7 +2244,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, Builder); } } - LLVM_FALLTHROUGH; + [[fallthrough]]; case Sema::PCC_Template: case Sema::PCC_MemberTemplate: @@ -2184,6 +2280,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, break; case Sema::PCC_RecoveryInFunction: + case Sema::PCC_TopLevelOrExpression: case Sema::PCC_Statement: { if (SemaRef.getLangOpts().CPlusPlus11) AddUsingAliasResult(Builder, Results); @@ -2418,14 +2515,14 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, AddStaticAssertResult(Builder, Results, SemaRef.getLangOpts()); } - LLVM_FALLTHROUGH; + [[fallthrough]]; // Fall through (for statement expressions). case Sema::PCC_ForInit: case Sema::PCC_Condition: AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results); // Fall through: conditions and statements can have expressions. - LLVM_FALLTHROUGH; + [[fallthrough]]; case Sema::PCC_ParenthesizedExpression: if (SemaRef.getLangOpts().ObjCAutoRefCount && @@ -2455,7 +2552,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, Results.AddResult(Result(Builder.TakeString())); } // Fall through - LLVM_FALLTHROUGH; + [[fallthrough]]; case Sema::PCC_Expression: { if (SemaRef.getLangOpts().CPlusPlus) { @@ -2638,6 +2735,13 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, Results.AddResult(Result(Builder.TakeString())); } + if (SemaRef.getLangOpts().C23) { + // nullptr + Builder.AddResultTypeChunk("nullptr_t"); + Builder.AddTypedTextChunk("nullptr"); + Results.AddResult(Result(Builder.TakeString())); + } + // sizeof expression Builder.AddResultTypeChunk("size_t"); Builder.AddTypedTextChunk("sizeof"); @@ -2778,7 +2882,7 @@ static void findTypeLocationForBlockDecl(const TypeSourceInfo *TSInfo, while (true) { // Look through typedefs. if (!SuppressBlock) { - if (TypedefTypeLoc TypedefTL = TL.getAs<TypedefTypeLoc>()) { + if (TypedefTypeLoc TypedefTL = TL.getAsAdjusted<TypedefTypeLoc>()) { if (TypeSourceInfo *InnerTSInfo = TypedefTL.getTypedefNameDecl()->getTypeSourceInfo()) { TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc(); @@ -2809,22 +2913,24 @@ static void findTypeLocationForBlockDecl(const TypeSourceInfo *TSInfo, } } -static std::string -formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl, - FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto, - bool SuppressBlockName = false, - bool SuppressBlock = false, - Optional<ArrayRef<QualType>> ObjCSubsts = None); +static std::string formatBlockPlaceholder( + const PrintingPolicy &Policy, const NamedDecl *BlockDecl, + FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto, + bool SuppressBlockName = false, bool SuppressBlock = false, + std::optional<ArrayRef<QualType>> ObjCSubsts = std::nullopt); -static std::string -FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param, - bool SuppressName = false, bool SuppressBlock = false, - Optional<ArrayRef<QualType>> ObjCSubsts = None) { +static std::string FormatFunctionParameter( + const PrintingPolicy &Policy, const DeclaratorDecl *Param, + bool SuppressName = false, bool SuppressBlock = false, + std::optional<ArrayRef<QualType>> ObjCSubsts = std::nullopt) { // Params are unavailable in FunctionTypeLoc if the FunctionType is invalid. - // It would be better to pass in the param Type, which is usually avaliable. + // It would be better to pass in the param Type, which is usually available. // But this case is rare, so just pretend we fell back to int as elsewhere. if (!Param) return "int"; + Decl::ObjCDeclQualifier ObjCQual = Decl::OBJC_TQ_None; + if (const auto *PVD = dyn_cast<ParmVarDecl>(Param)) + ObjCQual = PVD->getObjCDeclQualifier(); bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext()); if (Param->getType()->isDependentType() || !Param->getType()->isBlockPointerType()) { @@ -2833,18 +2939,17 @@ FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param, std::string Result; if (Param->getIdentifier() && !ObjCMethodParam && !SuppressName) - Result = std::string(Param->getIdentifier()->getName()); + Result = std::string(Param->getIdentifier()->deuglifiedName()); QualType Type = Param->getType(); if (ObjCSubsts) Type = Type.substObjCTypeArgs(Param->getASTContext(), *ObjCSubsts, ObjCSubstitutionContext::Parameter); if (ObjCMethodParam) { - Result = - "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier(), Type); + Result = "(" + formatObjCParamQualifiers(ObjCQual, Type); Result += Type.getAsString(Policy) + ")"; if (Param->getIdentifier() && !SuppressName) - Result += Param->getIdentifier()->getName(); + Result += Param->getIdentifier()->deuglifiedName(); } else { Type.getAsStringInternal(Result, Policy); } @@ -2872,20 +2977,19 @@ FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param, // for the block; just use the parameter type as a placeholder. std::string Result; if (!ObjCMethodParam && Param->getIdentifier()) - Result = std::string(Param->getIdentifier()->getName()); + Result = std::string(Param->getIdentifier()->deuglifiedName()); QualType Type = Param->getType().getUnqualifiedType(); if (ObjCMethodParam) { Result = Type.getAsString(Policy); - std::string Quals = - formatObjCParamQualifiers(Param->getObjCDeclQualifier(), Type); + std::string Quals = formatObjCParamQualifiers(ObjCQual, Type); if (!Quals.empty()) Result = "(" + Quals + " " + Result + ")"; if (Result.back() != ')') Result += " "; if (Param->getIdentifier()) - Result += Param->getIdentifier()->getName(); + Result += Param->getIdentifier()->deuglifiedName(); } else { Type.getAsStringInternal(Result, Policy); } @@ -2913,7 +3017,7 @@ static std::string formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl, FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto, bool SuppressBlockName, bool SuppressBlock, - Optional<ArrayRef<QualType>> ObjCSubsts) { + std::optional<ArrayRef<QualType>> ObjCSubsts) { std::string Result; QualType ResultType = Block.getTypePtr()->getReturnType(); if (ObjCSubsts) @@ -3080,14 +3184,14 @@ static void AddTemplateParameterChunks( if (TTP->getIdentifier()) { PlaceholderStr += ' '; - PlaceholderStr += TTP->getIdentifier()->getName(); + PlaceholderStr += TTP->getIdentifier()->deuglifiedName(); } HasDefaultArg = TTP->hasDefaultArgument(); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { if (NTTP->getIdentifier()) - PlaceholderStr = std::string(NTTP->getIdentifier()->getName()); + PlaceholderStr = std::string(NTTP->getIdentifier()->deuglifiedName()); NTTP->getType().getAsStringInternal(PlaceholderStr, Policy); HasDefaultArg = NTTP->hasDefaultArgument(); } else { @@ -3099,7 +3203,7 @@ static void AddTemplateParameterChunks( PlaceholderStr = "template<...> class"; if (TTP->getIdentifier()) { PlaceholderStr += ' '; - PlaceholderStr += TTP->getIdentifier()->getName(); + PlaceholderStr += TTP->getIdentifier()->deuglifiedName(); } HasDefaultArg = TTP->hasDefaultArgument(); @@ -3480,8 +3584,14 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl( // Figure out which template parameters are deduced (or have default // arguments). - llvm::SmallBitVector Deduced; - Sema::MarkDeducedTemplateParameters(Ctx, FunTmpl, Deduced); + // Note that we're creating a non-empty bit vector so that we can go + // through the loop below to omit default template parameters for non-call + // cases. + llvm::SmallBitVector Deduced(FunTmpl->getTemplateParameters()->size()); + // Avoid running it if this is not a call: We should emit *all* template + // parameters. + if (FunctionCanBeCall) + Sema::MarkDeducedTemplateParameters(Ctx, FunTmpl, Deduced); unsigned LastDeducibleArgument; for (LastDeducibleArgument = Deduced.size(); LastDeducibleArgument > 0; --LastDeducibleArgument) { @@ -3508,10 +3618,19 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl( } } - if (LastDeducibleArgument) { + if (LastDeducibleArgument || !FunctionCanBeCall) { // Some of the function template arguments cannot be deduced from a // function call, so we introduce an explicit template argument list // containing all of the arguments up to the first deducible argument. + // + // Or, if this isn't a call, emit all the template arguments + // to disambiguate the (potential) overloads. + // + // FIXME: Detect cases where the function parameters can be deduced from + // the surrounding context, as per [temp.deduct.funcaddr]. + // e.g., + // template <class T> void foo(T); + // void (*f)(int) = foo; Result.AddChunk(CodeCompletionString::CK_LeftAngle); AddTemplateParameterChunks(Ctx, Policy, FunTmpl, Result, LastDeducibleArgument); @@ -3582,7 +3701,7 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl( std::string Arg; QualType ParamType = (*P)->getType(); - Optional<ArrayRef<QualType>> ObjCSubsts; + std::optional<ArrayRef<QualType>> ObjCSubsts; if (!CCContext.getBaseType().isNull()) ObjCSubsts = CCContext.getBaseType()->getObjCSubstitutions(Method); @@ -3689,15 +3808,43 @@ const RawComment *clang::getParameterComment( return nullptr; } -/// Add function overload parameter chunks to the given code completion -/// string. -static void AddOverloadParameterChunks(ASTContext &Context, +static void AddOverloadAggregateChunks(const RecordDecl *RD, const PrintingPolicy &Policy, - const FunctionDecl *Function, - const FunctionProtoType *Prototype, CodeCompletionBuilder &Result, - unsigned CurrentArg, unsigned Start = 0, - bool InOptional = false) { + unsigned CurrentArg) { + unsigned ChunkIndex = 0; + auto AddChunk = [&](llvm::StringRef Placeholder) { + if (ChunkIndex > 0) + Result.AddChunk(CodeCompletionString::CK_Comma); + const char *Copy = Result.getAllocator().CopyString(Placeholder); + if (ChunkIndex == CurrentArg) + Result.AddCurrentParameterChunk(Copy); + else + Result.AddPlaceholderChunk(Copy); + ++ChunkIndex; + }; + // Aggregate initialization has all bases followed by all fields. + // (Bases are not legal in C++11 but in that case we never get here). + if (auto *CRD = llvm::dyn_cast<CXXRecordDecl>(RD)) { + for (const auto &Base : CRD->bases()) + AddChunk(Base.getType().getAsString(Policy)); + } + for (const auto &Field : RD->fields()) + AddChunk(FormatFunctionParameter(Policy, Field)); +} + +/// Add function overload parameter chunks to the given code completion +/// string. +static void AddOverloadParameterChunks( + ASTContext &Context, const PrintingPolicy &Policy, + const FunctionDecl *Function, const FunctionProtoType *Prototype, + FunctionProtoTypeLoc PrototypeLoc, CodeCompletionBuilder &Result, + unsigned CurrentArg, unsigned Start = 0, bool InOptional = false) { + if (!Function && !Prototype) { + Result.AddChunk(CodeCompletionString::CK_CurrentParameter, "..."); + return; + } + bool FirstParameter = true; unsigned NumParams = Function ? Function->getNumParams() : Prototype->getNumParams(); @@ -3711,8 +3858,9 @@ static void AddOverloadParameterChunks(ASTContext &Context, if (!FirstParameter) Opt.AddChunk(CodeCompletionString::CK_Comma); // Optional sections are nested. - AddOverloadParameterChunks(Context, Policy, Function, Prototype, Opt, - CurrentArg, P, /*InOptional=*/true); + AddOverloadParameterChunks(Context, Policy, Function, Prototype, + PrototypeLoc, Opt, CurrentArg, P, + /*InOptional=*/true); Result.AddOptionalChunk(Opt.TakeString()); return; } @@ -3726,8 +3874,10 @@ static void AddOverloadParameterChunks(ASTContext &Context, // Format the placeholder string. std::string Placeholder; - if (Function) { - const ParmVarDecl *Param = Function->getParamDecl(P); + assert(P < Prototype->getNumParams()); + if (Function || PrototypeLoc) { + const ParmVarDecl *Param = + Function ? Function->getParamDecl(P) : PrototypeLoc.getParam(P); Placeholder = FormatFunctionParameter(Policy, Param); if (Param->hasDefaultArg()) Placeholder += GetDefaultValueString(Param, Context.getSourceManager(), @@ -3758,10 +3908,83 @@ static void AddOverloadParameterChunks(ASTContext &Context, } } +static std::string +formatTemplateParameterPlaceholder(const NamedDecl *Param, bool &Optional, + const PrintingPolicy &Policy) { + if (const auto *Type = dyn_cast<TemplateTypeParmDecl>(Param)) { + Optional = Type->hasDefaultArgument(); + } else if (const auto *NonType = dyn_cast<NonTypeTemplateParmDecl>(Param)) { + Optional = NonType->hasDefaultArgument(); + } else if (const auto *Template = dyn_cast<TemplateTemplateParmDecl>(Param)) { + Optional = Template->hasDefaultArgument(); + } + std::string Result; + llvm::raw_string_ostream OS(Result); + Param->print(OS, Policy); + return Result; +} + +static std::string templateResultType(const TemplateDecl *TD, + const PrintingPolicy &Policy) { + if (const auto *CTD = dyn_cast<ClassTemplateDecl>(TD)) + return CTD->getTemplatedDecl()->getKindName().str(); + if (const auto *VTD = dyn_cast<VarTemplateDecl>(TD)) + return VTD->getTemplatedDecl()->getType().getAsString(Policy); + if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(TD)) + return FTD->getTemplatedDecl()->getReturnType().getAsString(Policy); + if (isa<TypeAliasTemplateDecl>(TD)) + return "type"; + if (isa<TemplateTemplateParmDecl>(TD)) + return "class"; + if (isa<ConceptDecl>(TD)) + return "concept"; + return ""; +} + +static CodeCompletionString *createTemplateSignatureString( + const TemplateDecl *TD, CodeCompletionBuilder &Builder, unsigned CurrentArg, + const PrintingPolicy &Policy) { + llvm::ArrayRef<NamedDecl *> Params = TD->getTemplateParameters()->asArray(); + CodeCompletionBuilder OptionalBuilder(Builder.getAllocator(), + Builder.getCodeCompletionTUInfo()); + std::string ResultType = templateResultType(TD, Policy); + if (!ResultType.empty()) + Builder.AddResultTypeChunk(Builder.getAllocator().CopyString(ResultType)); + Builder.AddTextChunk( + Builder.getAllocator().CopyString(TD->getNameAsString())); + Builder.AddChunk(CodeCompletionString::CK_LeftAngle); + // Initially we're writing into the main string. Once we see an optional arg + // (with default), we're writing into the nested optional chunk. + CodeCompletionBuilder *Current = &Builder; + for (unsigned I = 0; I < Params.size(); ++I) { + bool Optional = false; + std::string Placeholder = + formatTemplateParameterPlaceholder(Params[I], Optional, Policy); + if (Optional) + Current = &OptionalBuilder; + if (I > 0) + Current->AddChunk(CodeCompletionString::CK_Comma); + Current->AddChunk(I == CurrentArg + ? CodeCompletionString::CK_CurrentParameter + : CodeCompletionString::CK_Placeholder, + Current->getAllocator().CopyString(Placeholder)); + } + // Add the optional chunk to the main string if we ever used it. + if (Current == &OptionalBuilder) + Builder.AddOptionalChunk(OptionalBuilder.TakeString()); + Builder.AddChunk(CodeCompletionString::CK_RightAngle); + // For function templates, ResultType was the function's return type. + // Give some clue this is a function. (Don't show the possibly-bulky params). + if (isa<FunctionTemplateDecl>(TD)) + Builder.AddInformativeChunk("()"); + return Builder.TakeString(); +} + CodeCompletionString * CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( unsigned CurrentArg, Sema &S, CodeCompletionAllocator &Allocator, - CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments) const { + CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments, + bool Braced) const { PrintingPolicy Policy = getCompletionPrintingPolicy(S); // Show signatures of constructors as they are declared: // vector(int n) rather than vector<string>(int n) @@ -3771,22 +3994,20 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( // FIXME: Set priority, availability appropriately. CodeCompletionBuilder Result(Allocator, CCTUInfo, 1, CXAvailability_Available); + + if (getKind() == CK_Template) + return createTemplateSignatureString(getTemplate(), Result, CurrentArg, + Policy); + FunctionDecl *FDecl = getFunction(); const FunctionProtoType *Proto = - dyn_cast<FunctionProtoType>(getFunctionType()); - if (!FDecl && !Proto) { - // Function without a prototype. Just give the return type and a - // highlighted ellipsis. - const FunctionType *FT = getFunctionType(); - Result.AddResultTypeChunk(Result.getAllocator().CopyString( - FT->getReturnType().getAsString(Policy))); - Result.AddChunk(CodeCompletionString::CK_LeftParen); - Result.AddChunk(CodeCompletionString::CK_CurrentParameter, "..."); - Result.AddChunk(CodeCompletionString::CK_RightParen); - return Result.TakeString(); - } + dyn_cast_or_null<FunctionProtoType>(getFunctionType()); - if (FDecl) { + // First, the name/type of the callee. + if (getKind() == CK_Aggregate) { + Result.AddTextChunk( + Result.getAllocator().CopyString(getAggregate()->getName())); + } else if (FDecl) { if (IncludeBriefComments) { if (auto RC = getParameterComment(S.getASTContext(), *this, CurrentArg)) Result.addBriefComment(RC->getBriefText(S.getASTContext())); @@ -3798,14 +4019,21 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( FDecl->getDeclName().print(OS, Policy); Result.AddTextChunk(Result.getAllocator().CopyString(OS.str())); } else { + // Function without a declaration. Just give the return type. Result.AddResultTypeChunk(Result.getAllocator().CopyString( - Proto->getReturnType().getAsString(Policy))); + getFunctionType()->getReturnType().getAsString(Policy))); } - Result.AddChunk(CodeCompletionString::CK_LeftParen); - AddOverloadParameterChunks(S.getASTContext(), Policy, FDecl, Proto, Result, - CurrentArg); - Result.AddChunk(CodeCompletionString::CK_RightParen); + // Next, the brackets and parameters. + Result.AddChunk(Braced ? CodeCompletionString::CK_LeftBrace + : CodeCompletionString::CK_LeftParen); + if (getKind() == CK_Aggregate) + AddOverloadAggregateChunks(getAggregate(), Policy, Result, CurrentArg); + else + AddOverloadParameterChunks(S.getASTContext(), Policy, FDecl, Proto, + getFunctionProtoTypeLoc(), Result, CurrentArg); + Result.AddChunk(Braced ? CodeCompletionString::CK_RightBrace + : CodeCompletionString::CK_RightParen); return Result.TakeString(); } @@ -3934,17 +4162,23 @@ CXCursorKind clang::getCursorKindForDecl(const Decl *D) { case Decl::ObjCTypeParam: return CXCursor_TemplateTypeParameter; + case Decl::Concept: + return CXCursor_ConceptDecl; + + case Decl::LinkageSpec: + return CXCursor_LinkageSpec; + default: if (const auto *TD = dyn_cast<TagDecl>(D)) { switch (TD->getTagKind()) { - case TTK_Interface: // fall through - case TTK_Struct: + case TagTypeKind::Interface: // fall through + case TagTypeKind::Struct: return CXCursor_StructDecl; - case TTK_Class: + case TagTypeKind::Class: return CXCursor_ClassDecl; - case TTK_Union: + case TagTypeKind::Union: return CXCursor_UnionDecl; - case TTK_Enum: + case TagTypeKind::Enum: return CXCursor_EnumDecl; } } @@ -3994,7 +4228,7 @@ static void AddPrettyFunctionResults(const LangOptions &LangOpts, static void HandleCodeCompleteResults(Sema *S, CodeCompleteConsumer *CodeCompleter, - CodeCompletionContext Context, + const CodeCompletionContext &Context, CodeCompletionResult *Results, unsigned NumResults) { if (CodeCompleter) @@ -4054,6 +4288,8 @@ mapCodeCompletionContext(Sema &S, Sema::ParserCompletionContext PCC) { case Sema::PCC_LocalDeclarationSpecifiers: return CodeCompletionContext::CCC_Type; + case Sema::PCC_TopLevelOrExpression: + return CodeCompletionContext::CCC_TopLevelOrExpression; } llvm_unreachable("Invalid ParserCompletionContext!"); @@ -4080,7 +4316,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, // We need to have names for all of the parameters, if we're going to // generate a forwarding call. - for (auto P : Method->parameters()) + for (auto *P : Method->parameters()) if (!P->getDeclName()) return; @@ -4108,7 +4344,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, Results.getAllocator().CopyString(Overridden->getNameAsString())); Builder.AddChunk(CodeCompletionString::CK_LeftParen); bool FirstParam = true; - for (auto P : Method->parameters()) { + for (auto *P : Method->parameters()) { if (FirstParam) FirstParam = false; else @@ -4155,16 +4391,13 @@ void Sema::CodeCompleteModuleImport(SourceLocation ImportLoc, /*IsInclusionDirective=*/false); // Enumerate submodules. if (Mod) { - for (Module::submodule_iterator Sub = Mod->submodule_begin(), - SubEnd = Mod->submodule_end(); - Sub != SubEnd; ++Sub) { - + for (auto *Submodule : Mod->submodules()) { Builder.AddTypedTextChunk( - Builder.getAllocator().CopyString((*Sub)->Name)); + Builder.getAllocator().CopyString(Submodule->Name)); Results.AddResult(Result( Builder.TakeString(), CCP_Declaration, CXCursor_ModuleImportDecl, - (*Sub)->isAvailable() ? CXAvailability_Available - : CXAvailability_NotAvailable)); + Submodule->isAvailable() ? CXAvailability_Available + : CXAvailability_NotAvailable)); } } } @@ -4197,6 +4430,7 @@ void Sema::CodeCompleteOrdinaryName(Scope *S, break; case PCC_Statement: + case PCC_TopLevelOrExpression: case PCC_ParenthesizedExpression: case PCC_Expression: case PCC_ForInit: @@ -4234,6 +4468,7 @@ void Sema::CodeCompleteOrdinaryName(Scope *S, case PCC_ParenthesizedExpression: case PCC_Expression: case PCC_Statement: + case PCC_TopLevelOrExpression: case PCC_RecoveryInFunction: if (S->getFnParent()) AddPrettyFunctionResults(getLangOpts(), Results); @@ -4325,7 +4560,8 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, 0) { ParsedType T = DS.getRepAsType(); if (!T.get().isNull() && T.get()->isObjCObjectOrInterfaceType()) - AddClassMessageCompletions(*this, S, T, None, false, false, Results); + AddClassMessageCompletions(*this, S, T, std::nullopt, false, false, + Results); } // Note that we intentionally suppress macro results here, since we do not @@ -4335,6 +4571,158 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, Results.data(), Results.size()); } +static const char *underscoreAttrScope(llvm::StringRef Scope) { + if (Scope == "clang") + return "_Clang"; + if (Scope == "gnu") + return "__gnu__"; + return nullptr; +} + +static const char *noUnderscoreAttrScope(llvm::StringRef Scope) { + if (Scope == "_Clang") + return "clang"; + if (Scope == "__gnu__") + return "gnu"; + return nullptr; +} + +void Sema::CodeCompleteAttribute(AttributeCommonInfo::Syntax Syntax, + AttributeCompletion Completion, + const IdentifierInfo *InScope) { + if (Completion == AttributeCompletion::None) + return; + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompleter->getCodeCompletionTUInfo(), + CodeCompletionContext::CCC_Attribute); + + // We're going to iterate over the normalized spellings of the attribute. + // These don't include "underscore guarding": the normalized spelling is + // clang::foo but you can also write _Clang::__foo__. + // + // (Clang supports a mix like clang::__foo__ but we won't suggest it: either + // you care about clashing with macros or you don't). + // + // So if we're already in a scope, we determine its canonical spellings + // (for comparison with normalized attr spelling) and remember whether it was + // underscore-guarded (so we know how to spell contained attributes). + llvm::StringRef InScopeName; + bool InScopeUnderscore = false; + if (InScope) { + InScopeName = InScope->getName(); + if (const char *NoUnderscore = noUnderscoreAttrScope(InScopeName)) { + InScopeName = NoUnderscore; + InScopeUnderscore = true; + } + } + bool SyntaxSupportsGuards = Syntax == AttributeCommonInfo::AS_GNU || + Syntax == AttributeCommonInfo::AS_CXX11 || + Syntax == AttributeCommonInfo::AS_C23; + + llvm::DenseSet<llvm::StringRef> FoundScopes; + auto AddCompletions = [&](const ParsedAttrInfo &A) { + if (A.IsTargetSpecific && !A.existsInTarget(Context.getTargetInfo())) + return; + if (!A.acceptsLangOpts(getLangOpts())) + return; + for (const auto &S : A.Spellings) { + if (S.Syntax != Syntax) + continue; + llvm::StringRef Name = S.NormalizedFullName; + llvm::StringRef Scope; + if ((Syntax == AttributeCommonInfo::AS_CXX11 || + Syntax == AttributeCommonInfo::AS_C23)) { + std::tie(Scope, Name) = Name.split("::"); + if (Name.empty()) // oops, unscoped + std::swap(Name, Scope); + } + + // Do we just want a list of scopes rather than attributes? + if (Completion == AttributeCompletion::Scope) { + // Make sure to emit each scope only once. + if (!Scope.empty() && FoundScopes.insert(Scope).second) { + Results.AddResult( + CodeCompletionResult(Results.getAllocator().CopyString(Scope))); + // Include alternate form (__gnu__ instead of gnu). + if (const char *Scope2 = underscoreAttrScope(Scope)) + Results.AddResult(CodeCompletionResult(Scope2)); + } + continue; + } + + // If a scope was specified, it must match but we don't need to print it. + if (!InScopeName.empty()) { + if (Scope != InScopeName) + continue; + Scope = ""; + } + + auto Add = [&](llvm::StringRef Scope, llvm::StringRef Name, + bool Underscores) { + CodeCompletionBuilder Builder(Results.getAllocator(), + Results.getCodeCompletionTUInfo()); + llvm::SmallString<32> Text; + if (!Scope.empty()) { + Text.append(Scope); + Text.append("::"); + } + if (Underscores) + Text.append("__"); + Text.append(Name); + if (Underscores) + Text.append("__"); + Builder.AddTypedTextChunk(Results.getAllocator().CopyString(Text)); + + if (!A.ArgNames.empty()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen, "("); + bool First = true; + for (const char *Arg : A.ArgNames) { + if (!First) + Builder.AddChunk(CodeCompletionString::CK_Comma, ", "); + First = false; + Builder.AddPlaceholderChunk(Arg); + } + Builder.AddChunk(CodeCompletionString::CK_RightParen, ")"); + } + + Results.AddResult(Builder.TakeString()); + }; + + // Generate the non-underscore-guarded result. + // Note this is (a suffix of) the NormalizedFullName, no need to copy. + // If an underscore-guarded scope was specified, only the + // underscore-guarded attribute name is relevant. + if (!InScopeUnderscore) + Add(Scope, Name, /*Underscores=*/false); + + // Generate the underscore-guarded version, for syntaxes that support it. + // We skip this if the scope was already spelled and not guarded, or + // we must spell it and can't guard it. + if (!(InScope && !InScopeUnderscore) && SyntaxSupportsGuards) { + llvm::SmallString<32> Guarded; + if (Scope.empty()) { + Add(Scope, Name, /*Underscores=*/true); + } else { + const char *GuardedScope = underscoreAttrScope(Scope); + if (!GuardedScope) + continue; + Add(GuardedScope, Name, /*Underscores=*/true); + } + } + + // It may be nice to include the Kind so we can look up the docs later. + } + }; + + for (const auto *A : ParsedAttrInfo::getAllBuiltin()) + AddCompletions(*A); + for (const auto &Entry : ParsedAttrInfoRegistry::entries()) + AddCompletions(*Entry.instantiate()); + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); +} + struct Sema::CodeCompleteExpressionData { CodeCompleteExpressionData(QualType PreferredType = QualType(), bool IsParenthesized = false) @@ -4386,9 +4774,9 @@ static const FunctionProtoType *TryDeconstructFunctionLike(QualType T) { // Note we only handle the sugared types, they closely match what users wrote. // We explicitly choose to not handle ClassTemplateSpecializationDecl. if (auto *Specialization = T->getAs<TemplateSpecializationType>()) { - if (Specialization->getNumArgs() != 1) + if (Specialization->template_arguments().size() != 1) return nullptr; - const TemplateArgument &Argument = Specialization->getArg(0); + const TemplateArgument &Argument = Specialization->template_arguments()[0]; if (Argument.getKind() != TemplateArgument::Type) return nullptr; return Argument.getAsType()->getAs<FunctionProtoType>(); @@ -4530,7 +4918,7 @@ void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E, if (E.isInvalid()) CodeCompleteExpression(S, PreferredType); else if (getLangOpts().ObjC) - CodeCompleteObjCInstanceMessage(S, E.get(), None, false); + CodeCompleteObjCInstanceMessage(S, E.get(), std::nullopt, false); } /// The set of properties that have already been added, referenced by @@ -4774,9 +5162,11 @@ AddObjCProperties(const CodeCompletionContext &CCContext, } } -static void AddRecordMembersCompletionResults( - Sema &SemaRef, ResultBuilder &Results, Scope *S, QualType BaseType, - ExprValueKind BaseKind, RecordDecl *RD, Optional<FixItHint> AccessOpFixIt) { +static void +AddRecordMembersCompletionResults(Sema &SemaRef, ResultBuilder &Results, + Scope *S, QualType BaseType, + ExprValueKind BaseKind, RecordDecl *RD, + std::optional<FixItHint> AccessOpFixIt) { // Indicate that we are performing a member access, and the cv-qualifiers // for the base object type. Results.setObjectTypeQualifiers(BaseType.getQualifiers(), BaseKind); @@ -4785,7 +5175,7 @@ static void AddRecordMembersCompletionResults( Results.allowNestedNameSpecifiers(); std::vector<FixItHint> FixIts; if (AccessOpFixIt) - FixIts.emplace_back(AccessOpFixIt.getValue()); + FixIts.emplace_back(*AccessOpFixIt); CodeCompletionDeclConsumer Consumer(Results, RD, BaseType, std::move(FixIts)); SemaRef.LookupVisibleDecls(RD, Sema::LookupMemberName, Consumer, SemaRef.CodeCompleter->includeGlobals(), @@ -4815,7 +5205,8 @@ static void AddRecordMembersCompletionResults( // Returns the RecordDecl inside the BaseType, falling back to primary template // in case of specializations. Since we might not have a decl for the // instantiation/specialization yet, e.g. dependent code. -static RecordDecl *getAsRecordDecl(const QualType BaseType) { +static RecordDecl *getAsRecordDecl(QualType BaseType) { + BaseType = BaseType.getNonReferenceType(); if (auto *RD = BaseType->getAsRecordDecl()) { if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(RD)) { @@ -4874,7 +5265,7 @@ public: // We don't have the declared parameter types, only the actual types of // arguments we've seen. These are still valuable, as it's hard to render // a useful function completion with neither parameter types nor names! - llvm::Optional<SmallVector<QualType, 1>> ArgTypes; + std::optional<SmallVector<QualType, 1>> ArgTypes; // Whether this is accessed as T.member, T->member, or T::member. enum AccessOperator { Colons, @@ -5093,8 +5484,8 @@ private: // Overwrite existing if the new member has more info. // The preference of . vs :: vs -> is fairly arbitrary. if (/*Inserted*/ R.second || - std::make_tuple(M.ArgTypes.hasValue(), M.ResultType != nullptr, - M.Operator) > std::make_tuple(O.ArgTypes.hasValue(), + std::make_tuple(M.ArgTypes.has_value(), M.ResultType != nullptr, + M.Operator) > std::make_tuple(O.ArgTypes.has_value(), O.ResultType != nullptr, O.Operator)) O = std::move(M); @@ -5204,11 +5595,16 @@ private: // We accept some lossiness (like dropping parameters). // We only try to handle common expressions on the LHS of MemberExpr. QualType getApproximateType(const Expr *E) { + if (E->getType().isNull()) + return QualType(); + E = E->IgnoreParenImpCasts(); QualType Unresolved = E->getType(); - if (Unresolved.isNull() || - !Unresolved->isSpecificBuiltinType(BuiltinType::Dependent)) - return Unresolved; - E = E->IgnoreParens(); + // We only resolve DependentTy, or undeduced autos (including auto* etc). + if (!Unresolved->isSpecificBuiltinType(BuiltinType::Dependent)) { + AutoType *Auto = Unresolved->getContainedAutoType(); + if (!Auto || !Auto->isUndeducedAutoType()) + return Unresolved; + } // A call: approximate-resolve callee to a function type, get its return type if (const CallExpr *CE = llvm::dyn_cast<CallExpr>(E)) { QualType Callee = getApproximateType(CE->getCallee()); @@ -5257,11 +5653,25 @@ QualType getApproximateType(const Expr *E) { : getApproximateType(CDSME->getBase()); if (CDSME->isArrow() && !Base.isNull()) Base = Base->getPointeeType(); // could handle unique_ptr etc here? - RecordDecl *RD = Base.isNull() ? nullptr : getAsRecordDecl(Base); + auto *RD = + Base.isNull() + ? nullptr + : llvm::dyn_cast_or_null<CXXRecordDecl>(getAsRecordDecl(Base)); if (RD && RD->isCompleteDefinition()) { - for (const auto *Member : RD->lookup(CDSME->getMember())) - if (const ValueDecl *VD = llvm::dyn_cast<ValueDecl>(Member)) - return VD->getType().getNonReferenceType(); + // Look up member heuristically, including in bases. + for (const auto *Member : RD->lookupDependentName( + CDSME->getMember(), [](const NamedDecl *Member) { + return llvm::isa<ValueDecl>(Member); + })) { + return llvm::cast<ValueDecl>(Member)->getType().getNonReferenceType(); + } + } + } + // A reference to an `auto` variable: approximate-resolve its initializer. + if (const auto *DRE = llvm::dyn_cast<DeclRefExpr>(E)) { + if (const auto *VD = llvm::dyn_cast<VarDecl>(DRE->getDecl())) { + if (VD->hasInit()) + return getApproximateType(VD->getInit()); } } return Unresolved; @@ -5322,7 +5732,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, &ResultBuilder::IsMember); auto DoCompletion = [&](Expr *Base, bool IsArrow, - Optional<FixItHint> AccessOpFixIt) -> bool { + std::optional<FixItHint> AccessOpFixIt) -> bool { if (!Base) return false; @@ -5369,7 +5779,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, // Objective-C property reference. Bail if we're performing fix-it code // completion since Objective-C properties are normally backed by ivars, // most Objective-C fix-its here would have little value. - if (AccessOpFixIt.hasValue()) { + if (AccessOpFixIt) { return false; } AddedPropertiesSet AddedProperties; @@ -5394,7 +5804,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, // Objective-C instance variable access. Bail if we're performing fix-it // code completion since Objective-C properties are normally backed by // ivars, most Objective-C fix-its here would have little value. - if (AccessOpFixIt.hasValue()) { + if (AccessOpFixIt) { return false; } ObjCInterfaceDecl *Class = nullptr; @@ -5420,7 +5830,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, Results.EnterNewScope(); - bool CompletionSucceded = DoCompletion(Base, IsArrow, None); + bool CompletionSucceded = DoCompletion(Base, IsArrow, std::nullopt); if (CodeCompleter->includeFixIts()) { const CharSourceRange OpRange = CharSourceRange::getTokenRange(OpLoc, OpLoc); @@ -5666,7 +6076,8 @@ static void mergeCandidatesWithResults( if (Candidate.Function) { if (Candidate.Function->isDeleted()) continue; - if (!Candidate.Function->isVariadic() && + if (shouldEnforceArgLimit(/*PartialOverloading=*/true, + Candidate.Function) && Candidate.Function->getNumParams() <= ArgSize && // Having zero args is annoying, normally we don't surface a function // with 2 params, if you already have 2 params, because you are @@ -5691,36 +6102,79 @@ static QualType getParamType(Sema &SemaRef, // overload candidates. QualType ParamType; for (auto &Candidate : Candidates) { - if (const auto *FType = Candidate.getFunctionType()) - if (const auto *Proto = dyn_cast<FunctionProtoType>(FType)) - if (N < Proto->getNumParams()) { - if (ParamType.isNull()) - ParamType = Proto->getParamType(N); - else if (!SemaRef.Context.hasSameUnqualifiedType( - ParamType.getNonReferenceType(), - Proto->getParamType(N).getNonReferenceType())) - // Otherwise return a default-constructed QualType. - return QualType(); - } + QualType CandidateParamType = Candidate.getParamType(N); + if (CandidateParamType.isNull()) + continue; + if (ParamType.isNull()) { + ParamType = CandidateParamType; + continue; + } + if (!SemaRef.Context.hasSameUnqualifiedType( + ParamType.getNonReferenceType(), + CandidateParamType.getNonReferenceType())) + // Two conflicting types, give up. + return QualType(); } return ParamType; } static QualType -ProduceSignatureHelp(Sema &SemaRef, Scope *S, - MutableArrayRef<ResultCandidate> Candidates, - unsigned CurrentArg, SourceLocation OpenParLoc) { +ProduceSignatureHelp(Sema &SemaRef, MutableArrayRef<ResultCandidate> Candidates, + unsigned CurrentArg, SourceLocation OpenParLoc, + bool Braced) { if (Candidates.empty()) return QualType(); if (SemaRef.getPreprocessor().isCodeCompletionReached()) SemaRef.CodeCompleter->ProcessOverloadCandidates( - SemaRef, CurrentArg, Candidates.data(), Candidates.size(), OpenParLoc); + SemaRef, CurrentArg, Candidates.data(), Candidates.size(), OpenParLoc, + Braced); return getParamType(SemaRef, Candidates, CurrentArg); } -QualType Sema::ProduceCallSignatureHelp(Scope *S, Expr *Fn, - ArrayRef<Expr *> Args, +// Given a callee expression `Fn`, if the call is through a function pointer, +// try to find the declaration of the corresponding function pointer type, +// so that we can recover argument names from it. +static FunctionProtoTypeLoc GetPrototypeLoc(Expr *Fn) { + TypeLoc Target; + if (const auto *T = Fn->getType().getTypePtr()->getAs<TypedefType>()) { + Target = T->getDecl()->getTypeSourceInfo()->getTypeLoc(); + + } else if (const auto *DR = dyn_cast<DeclRefExpr>(Fn)) { + const auto *D = DR->getDecl(); + if (const auto *const VD = dyn_cast<VarDecl>(D)) { + Target = VD->getTypeSourceInfo()->getTypeLoc(); + } + } + + if (!Target) + return {}; + + // Unwrap types that may be wrapping the function type + while (true) { + if (auto P = Target.getAs<PointerTypeLoc>()) { + Target = P.getPointeeLoc(); + continue; + } + if (auto A = Target.getAs<AttributedTypeLoc>()) { + Target = A.getModifiedLoc(); + continue; + } + if (auto P = Target.getAs<ParenTypeLoc>()) { + Target = P.getInnerLoc(); + continue; + } + break; + } + + if (auto F = Target.getAs<FunctionProtoTypeLoc>()) { + return F; + } + + return {}; +} + +QualType Sema::ProduceCallSignatureHelp(Expr *Fn, ArrayRef<Expr *> Args, SourceLocation OpenParLoc) { Fn = unwrapParenList(Fn); if (!CodeCompleter || !Fn) @@ -5801,6 +6255,8 @@ QualType Sema::ProduceCallSignatureHelp(Scope *S, Expr *Fn, } else { // Lastly we check whether expression's type is function pointer or // function. + + FunctionProtoTypeLoc P = GetPrototypeLoc(NakedFn); QualType T = NakedFn->getType(); if (!T->getPointeeType().isNull()) T = T->getPointeeType(); @@ -5809,61 +6265,171 @@ QualType Sema::ProduceCallSignatureHelp(Scope *S, Expr *Fn, if (!TooManyArguments(FP->getNumParams(), ArgsWithoutDependentTypes.size(), /*PartialOverloading=*/true) || - FP->isVariadic()) - Results.push_back(ResultCandidate(FP)); + FP->isVariadic()) { + if (P) { + Results.push_back(ResultCandidate(P)); + } else { + Results.push_back(ResultCandidate(FP)); + } + } } else if (auto FT = T->getAs<FunctionType>()) // No prototype and declaration, it may be a K & R style function. Results.push_back(ResultCandidate(FT)); } } mergeCandidatesWithResults(*this, Results, CandidateSet, Loc, Args.size()); - QualType ParamType = - ProduceSignatureHelp(*this, S, Results, Args.size(), OpenParLoc); + QualType ParamType = ProduceSignatureHelp(*this, Results, Args.size(), + OpenParLoc, /*Braced=*/false); return !CandidateSet.empty() ? ParamType : QualType(); } -QualType Sema::ProduceConstructorSignatureHelp(Scope *S, QualType Type, +// Determine which param to continue aggregate initialization from after +// a designated initializer. +// +// Given struct S { int a,b,c,d,e; }: +// after `S{.b=1,` we want to suggest c to continue +// after `S{.b=1, 2,` we continue with d (this is legal C and ext in C++) +// after `S{.b=1, .a=2,` we continue with b (this is legal C and ext in C++) +// +// Possible outcomes: +// - we saw a designator for a field, and continue from the returned index. +// Only aggregate initialization is allowed. +// - we saw a designator, but it was complex or we couldn't find the field. +// Only aggregate initialization is possible, but we can't assist with it. +// Returns an out-of-range index. +// - we saw no designators, just positional arguments. +// Returns std::nullopt. +static std::optional<unsigned> +getNextAggregateIndexAfterDesignatedInit(const ResultCandidate &Aggregate, + ArrayRef<Expr *> Args) { + static constexpr unsigned Invalid = std::numeric_limits<unsigned>::max(); + assert(Aggregate.getKind() == ResultCandidate::CK_Aggregate); + + // Look for designated initializers. + // They're in their syntactic form, not yet resolved to fields. + const IdentifierInfo *DesignatedFieldName = nullptr; + unsigned ArgsAfterDesignator = 0; + for (const Expr *Arg : Args) { + if (const auto *DIE = dyn_cast<DesignatedInitExpr>(Arg)) { + if (DIE->size() == 1 && DIE->getDesignator(0)->isFieldDesignator()) { + DesignatedFieldName = DIE->getDesignator(0)->getFieldName(); + ArgsAfterDesignator = 0; + } else { + return Invalid; // Complicated designator. + } + } else if (isa<DesignatedInitUpdateExpr>(Arg)) { + return Invalid; // Unsupported. + } else { + ++ArgsAfterDesignator; + } + } + if (!DesignatedFieldName) + return std::nullopt; + + // Find the index within the class's fields. + // (Probing getParamDecl() directly would be quadratic in number of fields). + unsigned DesignatedIndex = 0; + const FieldDecl *DesignatedField = nullptr; + for (const auto *Field : Aggregate.getAggregate()->fields()) { + if (Field->getIdentifier() == DesignatedFieldName) { + DesignatedField = Field; + break; + } + ++DesignatedIndex; + } + if (!DesignatedField) + return Invalid; // Designator referred to a missing field, give up. + + // Find the index within the aggregate (which may have leading bases). + unsigned AggregateSize = Aggregate.getNumParams(); + while (DesignatedIndex < AggregateSize && + Aggregate.getParamDecl(DesignatedIndex) != DesignatedField) + ++DesignatedIndex; + + // Continue from the index after the last named field. + return DesignatedIndex + ArgsAfterDesignator + 1; +} + +QualType Sema::ProduceConstructorSignatureHelp(QualType Type, SourceLocation Loc, ArrayRef<Expr *> Args, - SourceLocation OpenParLoc) { + SourceLocation OpenParLoc, + bool Braced) { if (!CodeCompleter) return QualType(); + SmallVector<ResultCandidate, 8> Results; // A complete type is needed to lookup for constructors. - CXXRecordDecl *RD = - isCompleteType(Loc, Type) ? Type->getAsCXXRecordDecl() : nullptr; + RecordDecl *RD = + isCompleteType(Loc, Type) ? Type->getAsRecordDecl() : nullptr; if (!RD) return Type; + CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD); + + // Consider aggregate initialization. + // We don't check that types so far are correct. + // We also don't handle C99/C++17 brace-elision, we assume init-list elements + // are 1:1 with fields. + // FIXME: it would be nice to support "unwrapping" aggregates that contain + // a single subaggregate, like std::array<T, N> -> T __elements[N]. + if (Braced && !RD->isUnion() && + (!LangOpts.CPlusPlus || (CRD && CRD->isAggregate()))) { + ResultCandidate AggregateSig(RD); + unsigned AggregateSize = AggregateSig.getNumParams(); + + if (auto NextIndex = + getNextAggregateIndexAfterDesignatedInit(AggregateSig, Args)) { + // A designator was used, only aggregate init is possible. + if (*NextIndex >= AggregateSize) + return Type; + Results.push_back(AggregateSig); + return ProduceSignatureHelp(*this, Results, *NextIndex, OpenParLoc, + Braced); + } + + // Describe aggregate initialization, but also constructors below. + if (Args.size() < AggregateSize) + Results.push_back(AggregateSig); + } // FIXME: Provide support for member initializers. // FIXME: Provide support for variadic template constructors. - OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal); + if (CRD) { + OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal); + for (NamedDecl *C : LookupConstructors(CRD)) { + if (auto *FD = dyn_cast<FunctionDecl>(C)) { + // FIXME: we can't yet provide correct signature help for initializer + // list constructors, so skip them entirely. + if (Braced && LangOpts.CPlusPlus && isInitListConstructor(FD)) + continue; + AddOverloadCandidate(FD, DeclAccessPair::make(FD, C->getAccess()), Args, + CandidateSet, + /*SuppressUserConversions=*/false, + /*PartialOverloading=*/true, + /*AllowExplicit*/ true); + } else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(C)) { + if (Braced && LangOpts.CPlusPlus && + isInitListConstructor(FTD->getTemplatedDecl())) + continue; - for (NamedDecl *C : LookupConstructors(RD)) { - if (auto *FD = dyn_cast<FunctionDecl>(C)) { - AddOverloadCandidate(FD, DeclAccessPair::make(FD, C->getAccess()), Args, - CandidateSet, - /*SuppressUserConversions=*/false, - /*PartialOverloading=*/true, - /*AllowExplicit*/ true); - } else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(C)) { - AddTemplateOverloadCandidate( - FTD, DeclAccessPair::make(FTD, C->getAccess()), - /*ExplicitTemplateArgs=*/nullptr, Args, CandidateSet, - /*SuppressUserConversions=*/false, - /*PartialOverloading=*/true); + AddTemplateOverloadCandidate( + FTD, DeclAccessPair::make(FTD, C->getAccess()), + /*ExplicitTemplateArgs=*/nullptr, Args, CandidateSet, + /*SuppressUserConversions=*/false, + /*PartialOverloading=*/true); + } } + mergeCandidatesWithResults(*this, Results, CandidateSet, Loc, Args.size()); } - SmallVector<ResultCandidate, 8> Results; - mergeCandidatesWithResults(*this, Results, CandidateSet, Loc, Args.size()); - return ProduceSignatureHelp(*this, S, Results, Args.size(), OpenParLoc); + return ProduceSignatureHelp(*this, Results, Args.size(), OpenParLoc, Braced); } QualType Sema::ProduceCtorInitMemberSignatureHelp( - Scope *S, Decl *ConstructorDecl, CXXScopeSpec SS, ParsedType TemplateTypeTy, - ArrayRef<Expr *> ArgExprs, IdentifierInfo *II, SourceLocation OpenParLoc) { + Decl *ConstructorDecl, CXXScopeSpec SS, ParsedType TemplateTypeTy, + ArrayRef<Expr *> ArgExprs, IdentifierInfo *II, SourceLocation OpenParLoc, + bool Braced) { if (!CodeCompleter) return QualType(); @@ -5874,12 +6440,66 @@ QualType Sema::ProduceCtorInitMemberSignatureHelp( // FIXME: Add support for Base class constructors as well. if (ValueDecl *MemberDecl = tryLookupCtorInitMemberDecl( Constructor->getParent(), SS, TemplateTypeTy, II)) - return ProduceConstructorSignatureHelp(getCurScope(), MemberDecl->getType(), + return ProduceConstructorSignatureHelp(MemberDecl->getType(), MemberDecl->getLocation(), ArgExprs, - OpenParLoc); + OpenParLoc, Braced); return QualType(); } +static bool argMatchesTemplateParams(const ParsedTemplateArgument &Arg, + unsigned Index, + const TemplateParameterList &Params) { + const NamedDecl *Param; + if (Index < Params.size()) + Param = Params.getParam(Index); + else if (Params.hasParameterPack()) + Param = Params.asArray().back(); + else + return false; // too many args + + switch (Arg.getKind()) { + case ParsedTemplateArgument::Type: + return llvm::isa<TemplateTypeParmDecl>(Param); // constraints not checked + case ParsedTemplateArgument::NonType: + return llvm::isa<NonTypeTemplateParmDecl>(Param); // type not checked + case ParsedTemplateArgument::Template: + return llvm::isa<TemplateTemplateParmDecl>(Param); // signature not checked + } + llvm_unreachable("Unhandled switch case"); +} + +QualType Sema::ProduceTemplateArgumentSignatureHelp( + TemplateTy ParsedTemplate, ArrayRef<ParsedTemplateArgument> Args, + SourceLocation LAngleLoc) { + if (!CodeCompleter || !ParsedTemplate) + return QualType(); + + SmallVector<ResultCandidate, 8> Results; + auto Consider = [&](const TemplateDecl *TD) { + // Only add if the existing args are compatible with the template. + bool Matches = true; + for (unsigned I = 0; I < Args.size(); ++I) { + if (!argMatchesTemplateParams(Args[I], I, *TD->getTemplateParameters())) { + Matches = false; + break; + } + } + if (Matches) + Results.emplace_back(TD); + }; + + TemplateName Template = ParsedTemplate.get(); + if (const auto *TD = Template.getAsTemplateDecl()) { + Consider(TD); + } else if (const auto *OTS = Template.getAsOverloadedTemplate()) { + for (const NamedDecl *ND : *OTS) + if (const auto *TD = llvm::dyn_cast<TemplateDecl>(ND)) + Consider(TD); + } + return ProduceSignatureHelp(*this, Results, Args.size(), LAngleLoc, + /*Braced=*/false); +} + static QualType getDesignatedType(QualType BaseType, const Designation &Desig) { for (unsigned I = 0; I < Desig.getNumDesignators(); ++I) { if (BaseType.isNull()) @@ -5893,7 +6513,7 @@ static QualType getDesignatedType(QualType BaseType, const Designation &Desig) { assert(D.isFieldDesignator()); auto *RD = getAsRecordDecl(BaseType); if (RD && RD->isCompleteDefinition()) { - for (const auto *Member : RD->lookup(D.getField())) + for (const auto *Member : RD->lookup(D.getFieldDecl())) if (const FieldDecl *FD = llvm::dyn_cast<FieldDecl>(Member)) { NextType = FD->getType(); break; @@ -5921,7 +6541,15 @@ void Sema::CodeCompleteDesignator(QualType BaseType, CodeCompleter->getCodeCompletionTUInfo(), CCC); Results.EnterNewScope(); - for (const auto *FD : RD->fields()) { + for (const Decl *D : RD->decls()) { + const FieldDecl *FD; + if (auto *IFD = dyn_cast<IndirectFieldDecl>(D)) + FD = IFD->getAnonField(); + else if (auto *DFD = dyn_cast<FieldDecl>(D)) + FD = DFD; + else + continue; + // FIXME: Make use of previous designators to mark any fields before those // inaccessible, and also compute the next initializer priority. ResultBuilder::Result Result(FD, Results.getBasePriority(FD)); @@ -6066,7 +6694,7 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, // The "template" keyword can follow "::" in the grammar, but only // put it into the grammar if the nested-name-specifier is dependent. // FIXME: results is always empty, this appears to be dead. - if (!Results.empty() && NNS->isDependent()) + if (!Results.empty() && NNS && NNS->isDependent()) Results.AddResult("template"); // If the scope is a concept-constrained type parameter, infer nested @@ -7050,7 +7678,8 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S) { Results.EnterNewScope(); VisitedSelectorSet Selectors; - AddObjCMethods(Class, true, MK_ZeroArgSelector, None, CurContext, Selectors, + AddObjCMethods(Class, true, MK_ZeroArgSelector, std::nullopt, CurContext, + Selectors, /*AllowSameLength=*/true, Results); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), @@ -7076,7 +7705,8 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S) { Results.EnterNewScope(); VisitedSelectorSet Selectors; - AddObjCMethods(Class, true, MK_OneArgSelector, None, CurContext, Selectors, + AddObjCMethods(Class, true, MK_OneArgSelector, std::nullopt, CurContext, + Selectors, /*AllowSameLength=*/true, Results); Results.ExitScope(); @@ -7372,7 +8002,8 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) { if (Iface->getSuperClass()) { Results.AddResult(Result("super")); - AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, None, Results); + AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, std::nullopt, + Results); } if (getLangOpts().CPlusPlus11) @@ -7922,6 +8553,24 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) { Results.data(), Results.size()); } +void Sema::CodeCompleteObjCClassForwardDecl(Scope *S) { + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompleter->getCodeCompletionTUInfo(), + CodeCompletionContext::CCC_ObjCClassForwardDecl); + Results.EnterNewScope(); + + if (CodeCompleter->includeGlobals()) { + // Add all classes. + AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, + false, Results); + } + + Results.ExitScope(); + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); +} + void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), @@ -8018,7 +8667,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S, CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_ObjCCategoryName); - // Add all of the categories that have have corresponding interface + // Add all of the categories that have corresponding interface // declarations in this class and any of its superclasses, except for // already-implemented categories in the class itself. llvm::SmallPtrSet<IdentifierInfo *, 16> CategoryNames; @@ -8182,7 +8831,7 @@ typedef llvm::DenseMap<Selector, /// indexed by selector so they can be easily found. static void FindImplementableMethods(ASTContext &Context, ObjCContainerDecl *Container, - Optional<bool> WantInstanceMethods, + std::optional<bool> WantInstanceMethods, QualType ReturnType, KnownMethodsMap &KnownMethods, bool InOriginalClass = true) { @@ -8699,8 +9348,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && (ReturnType.isNull() || (ReturnType->isObjCObjectPointerType() && - ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() && - ReturnType->getAs<ObjCObjectPointerType>() + ReturnType->castAs<ObjCObjectPointerType>()->getInterfaceDecl() && + ReturnType->castAs<ObjCObjectPointerType>() ->getInterfaceDecl() ->getName() == "NSEnumerator"))) { std::string SelectorName = (Twine("enumeratorOf") + UpperKey).str(); @@ -8906,7 +9555,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, } } -void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod, +void Sema::CodeCompleteObjCMethodDecl(Scope *S, + std::optional<bool> IsInstanceMethod, ParsedType ReturnTy) { // Determine the return type of the method we're declaring, if // provided. @@ -9066,8 +9716,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod, IFace = Category->getClassInterface(); if (IFace) - for (auto *Cat : IFace->visible_categories()) - Containers.push_back(Cat); + llvm::append_range(Containers, IFace->visible_categories()); if (IsInstanceMethod) { for (unsigned I = 0, N = Containers.size(); I != N; ++I) @@ -9149,7 +9798,7 @@ void Sema::CodeCompleteObjCMethodDeclSelector( Results.ExitScope(); if (!AtParameterName && !SelIdents.empty() && - SelIdents.front()->getName().startswith("init")) { + SelIdents.front()->getName().starts_with("init")) { for (const auto &M : PP.macros()) { if (M.first->getName() != "NS_DESIGNATED_INITIALIZER") continue; @@ -9348,7 +9997,7 @@ void Sema::CodeCompletePreprocessorMacroName(bool IsDefinition) { CodeCompleter->getCodeCompletionTUInfo(), IsDefinition ? CodeCompletionContext::CCC_MacroName : CodeCompletionContext::CCC_MacroNameUse); - if (!IsDefinition && (!CodeCompleter || CodeCompleter->includeMacros())) { + if (!IsDefinition && CodeCompleter->includeMacros()) { // Add just the names of macros, not their arguments. CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); @@ -9375,9 +10024,8 @@ void Sema::CodeCompletePreprocessorExpression() { CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_PreprocessorExpression); - if (!CodeCompleter || CodeCompleter->includeMacros()) - AddMacroResults(PP, Results, - !CodeCompleter || CodeCompleter->loadExternal(), true); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, Results, CodeCompleter->loadExternal(), true); // defined (<macro>) Results.EnterNewScope(); @@ -9461,6 +10109,10 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) { } } + const StringRef &Dirname = llvm::sys::path::filename(Dir); + const bool isQt = Dirname.starts_with("Qt") || Dirname == "ActiveQt"; + const bool ExtensionlessHeaders = + IsSystem || isQt || Dir.ends_with(".framework/Headers"); std::error_code EC; unsigned Count = 0; for (auto It = FS.dir_begin(Dir, EC); @@ -9487,18 +10139,19 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) { AddCompletion(Filename, /*IsDirectory=*/true); break; - case llvm::sys::fs::file_type::regular_file: - // Only files that really look like headers. (Except in system dirs). - if (!IsSystem) { - // Header extensions from Types.def, which we can't depend on here. - if (!(Filename.endswith_insensitive(".h") || - Filename.endswith_insensitive(".hh") || - Filename.endswith_insensitive(".hpp") || - Filename.endswith_insensitive(".inc"))) - break; - } + case llvm::sys::fs::file_type::regular_file: { + // Only files that really look like headers. (Except in special dirs). + const bool IsHeader = Filename.ends_with_insensitive(".h") || + Filename.ends_with_insensitive(".hh") || + Filename.ends_with_insensitive(".hpp") || + Filename.ends_with_insensitive(".hxx") || + Filename.ends_with_insensitive(".inc") || + (ExtensionlessHeaders && !Filename.contains('.')); + if (!IsHeader) + break; AddCompletion(Filename, /*IsDirectory=*/false); break; + } default: break; } @@ -9513,12 +10166,12 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) { // header maps are not (currently) enumerable. break; case DirectoryLookup::LT_NormalDir: - AddFilesFromIncludeDir(IncludeDir.getDir()->getName(), IsSystem, + AddFilesFromIncludeDir(IncludeDir.getDirRef()->getName(), IsSystem, DirectoryLookup::LT_NormalDir); break; case DirectoryLookup::LT_Framework: - AddFilesFromIncludeDir(IncludeDir.getFrameworkDir()->getName(), IsSystem, - DirectoryLookup::LT_Framework); + AddFilesFromIncludeDir(IncludeDir.getFrameworkDirRef()->getName(), + IsSystem, DirectoryLookup::LT_Framework); break; } }; @@ -9530,9 +10183,8 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) { using llvm::make_range; if (!Angled) { // The current directory is on the include path for "quoted" includes. - auto *CurFile = PP.getCurrentFileLexer()->getFileEntry(); - if (CurFile && CurFile->getDir()) - AddFilesFromIncludeDir(CurFile->getDir()->getName(), false, + if (auto CurFile = PP.getCurrentFileLexer()->getFileEntry()) + AddFilesFromIncludeDir(CurFile->getDir().getName(), false, DirectoryLookup::LT_NormalDir); for (const auto &D : make_range(S.quoted_dir_begin(), S.quoted_dir_end())) AddFilesFromDirLookup(D, false); @@ -9558,7 +10210,7 @@ void Sema::CodeCompleteAvailabilityPlatformName() { CodeCompletionContext::CCC_Other); Results.EnterNewScope(); static const char *Platforms[] = {"macOS", "iOS", "watchOS", "tvOS"}; - for (const char *Platform : llvm::makeArrayRef(Platforms)) { + for (const char *Platform : llvm::ArrayRef(Platforms)) { Results.AddResult(CodeCompletionResult(Platform)); Results.AddResult(CodeCompletionResult(Results.getAllocator().CopyString( Twine(Platform) + "ApplicationExtension"))); |