summaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaCodeComplete.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2022-01-27 22:06:42 +0000
committerDimitry Andric <dim@FreeBSD.org>2022-01-27 22:06:42 +0000
commit6f8fc217eaa12bf657be1c6468ed9938d10168b3 (patch)
treea1fd89b864d9b93e2ad68fe1dcf7afee2e3c8d76 /clang/lib/Sema/SemaCodeComplete.cpp
parent77fc4c146f0870ffb09c1afb823ccbe742c5e6ff (diff)
Vendor import of llvm-project main llvmorg-14-init-17616-g024a1fab5c35.vendor/llvm-project/llvmorg-14-init-17616-g024a1fab5c35
Diffstat (limited to 'clang/lib/Sema/SemaCodeComplete.cpp')
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp453
1 files changed, 370 insertions, 83 deletions
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 93c07ccc891f..01fdf51c60c3 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -36,6 +36,7 @@
#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"
@@ -98,7 +99,7 @@ private:
unsigned SingleDeclIndex;
public:
- ShadowMapEntry() : DeclOrVector(), SingleDeclIndex(0) {}
+ ShadowMapEntry() : SingleDeclIndex(0) {}
ShadowMapEntry(const ShadowMapEntry &) = delete;
ShadowMapEntry(ShadowMapEntry &&Move) { *this = std::move(Move); }
ShadowMapEntry &operator=(const ShadowMapEntry &) = delete;
@@ -1437,7 +1438,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())
@@ -1895,6 +1896,7 @@ static PrintingPolicy getCompletionPrintingPolicy(const ASTContext &Context,
Policy.SuppressStrongLifetime = true;
Policy.SuppressUnwrittenScope = true;
Policy.SuppressScope = true;
+ Policy.CleanUglifiedParameters = true;
return Policy;
}
@@ -2816,14 +2818,18 @@ formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl,
Optional<ArrayRef<QualType>> ObjCSubsts = None);
static std::string
-FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param,
- bool SuppressName = false, bool SuppressBlock = false,
+FormatFunctionParameter(const PrintingPolicy &Policy,
+ const DeclaratorDecl *Param, bool SuppressName = false,
+ bool SuppressBlock = false,
Optional<ArrayRef<QualType>> ObjCSubsts = None) {
// Params are unavailable in FunctionTypeLoc if the FunctionType is invalid.
// 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()) {
@@ -2832,18 +2838,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);
}
@@ -2871,20 +2876,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);
}
@@ -3079,14 +3083,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 {
@@ -3098,7 +3102,7 @@ static void AddTemplateParameterChunks(
PlaceholderStr = "template<...> class";
if (TTP->getIdentifier()) {
PlaceholderStr += ' ';
- PlaceholderStr += TTP->getIdentifier()->getName();
+ PlaceholderStr += TTP->getIdentifier()->deuglifiedName();
}
HasDefaultArg = TTP->hasDefaultArgument();
@@ -3688,6 +3692,31 @@ const RawComment *clang::getParameterComment(
return nullptr;
}
+static void AddOverloadAggregateChunks(const RecordDecl *RD,
+ const PrintingPolicy &Policy,
+ CodeCompletionBuilder &Result,
+ 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,
@@ -3697,6 +3726,11 @@ static void AddOverloadParameterChunks(ASTContext &Context,
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();
@@ -3757,10 +3791,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)
@@ -3770,22 +3877,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()));
@@ -3797,14 +3902,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, Result,
+ CurrentArg);
+ Result.AddChunk(Braced ? CodeCompletionString::CK_RightBrace
+ : CodeCompletionString::CK_RightParen);
return Result.TakeString();
}
@@ -5408,11 +5520,18 @@ 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();
+ }
}
}
return Unresolved;
@@ -5843,36 +5962,37 @@ 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,
+QualType Sema::ProduceCallSignatureHelp(Expr *Fn, ArrayRef<Expr *> Args,
SourceLocation OpenParLoc) {
Fn = unwrapParenList(Fn);
if (!CodeCompleter || !Fn)
@@ -5969,53 +6089,158 @@ QualType Sema::ProduceCallSignatureHelp(Scope *S, Expr *Fn,
}
}
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 None.
+static llvm::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.
+ 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 llvm::None;
+
+ // 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();
@@ -6026,12 +6251,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())
@@ -6073,7 +6352,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));