Skip to content

Commit c57f635

Browse files
xedinrudkx
authored andcommitted
[Diagnostics] Refactor argument matching when dealing with a single candidate
(cherry picked from commit f0078d6)
1 parent a7988a1 commit c57f635

File tree

1 file changed

+134
-131
lines changed

1 file changed

+134
-131
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 134 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -4657,152 +4657,155 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI,
46574657
CCI.closeness != CC_ArgumentCountMismatch)
46584658
return false;
46594659

4660-
SmallVector<Identifier, 4> correctNames;
4661-
unsigned OOOArgIdx = ~0U, OOOPrevArgIdx = ~0U;
4662-
unsigned extraArgIdx = ~0U, missingParamIdx = ~0U;
4663-
46644660
// If we have a single candidate that failed to match the argument list,
46654661
// attempt to use matchCallArguments to diagnose the problem.
4666-
struct OurListener : public MatchCallArgumentListener {
4667-
SmallVectorImpl<Identifier> &correctNames;
4668-
unsigned &OOOArgIdx, &OOOPrevArgIdx;
4669-
unsigned &extraArgIdx, &missingParamIdx;
4662+
class ArgumentDiagnostic : public MatchCallArgumentListener {
4663+
TypeChecker &TC;
4664+
Expr *ArgExpr;
4665+
llvm::SmallVectorImpl<CallArgParam> &Parameters;
4666+
llvm::SmallVectorImpl<CallArgParam> &Arguments;
4667+
4668+
CalleeCandidateInfo CandidateInfo;
4669+
4670+
// Indicates if problem was been found and diagnostic was emitted.
4671+
bool Diagnosed = false;
4672+
// Indicates if functions we are trying to call is a subscript.
4673+
bool IsSubscript;
4674+
4675+
// Stores parameter bindings determined by call to matchCallArguments.
4676+
SmallVector<ParamBinding, 4> Bindings;
46704677

46714678
public:
4672-
OurListener(SmallVectorImpl<Identifier> &correctNames,
4673-
unsigned &OOOArgIdx, unsigned &OOOPrevArgIdx,
4674-
unsigned &extraArgIdx, unsigned &missingParamIdx)
4675-
: correctNames(correctNames),
4676-
OOOArgIdx(OOOArgIdx), OOOPrevArgIdx(OOOPrevArgIdx),
4677-
extraArgIdx(extraArgIdx), missingParamIdx(missingParamIdx) {}
4678-
void extraArgument(unsigned argIdx) override {
4679-
extraArgIdx = argIdx;
4680-
}
4681-
void missingArgument(unsigned paramIdx) override {
4682-
missingParamIdx = paramIdx;
4683-
}
4684-
void outOfOrderArgument(unsigned argIdx, unsigned prevArgIdx) override{
4685-
OOOArgIdx = argIdx;
4686-
OOOPrevArgIdx = prevArgIdx;
4679+
ArgumentDiagnostic(Expr *argExpr,
4680+
llvm::SmallVectorImpl<CallArgParam> &params,
4681+
llvm::SmallVectorImpl<CallArgParam> &args,
4682+
CalleeCandidateInfo &CCI, bool isSubscript)
4683+
: TC(CCI.CS->TC), ArgExpr(argExpr), Parameters(params), Arguments(args),
4684+
CandidateInfo(CCI), IsSubscript(isSubscript) {}
4685+
4686+
void extraArgument(unsigned extraArgIdx) override {
4687+
auto name = Arguments[extraArgIdx].Label;
4688+
Expr *arg = ArgExpr;
4689+
4690+
auto tuple = dyn_cast<TupleExpr>(ArgExpr);
4691+
if (tuple)
4692+
arg = tuple->getElement(extraArgIdx);
4693+
4694+
auto loc = arg->getLoc();
4695+
if (tuple && extraArgIdx == tuple->getNumElements() - 1 &&
4696+
tuple->hasTrailingClosure())
4697+
TC.diagnose(loc, diag::extra_trailing_closure_in_call)
4698+
.highlight(arg->getSourceRange());
4699+
else if (Parameters.empty())
4700+
TC.diagnose(loc, diag::extra_argument_to_nullary_call)
4701+
.highlight(ArgExpr->getSourceRange());
4702+
else if (name.empty())
4703+
TC.diagnose(loc, diag::extra_argument_positional)
4704+
.highlight(arg->getSourceRange());
4705+
else
4706+
TC.diagnose(loc, diag::extra_argument_named, name)
4707+
.highlight(arg->getSourceRange());
4708+
4709+
Diagnosed = true;
46874710
}
4688-
bool relabelArguments(ArrayRef<Identifier> newNames) override {
4689-
correctNames.append(newNames.begin(), newNames.end());
4690-
return true;
4711+
4712+
void missingArgument(unsigned missingParamIdx) override {
4713+
Identifier name = Parameters[missingParamIdx].Label;
4714+
auto loc = ArgExpr->getStartLoc();
4715+
if (name.empty())
4716+
TC.diagnose(loc, diag::missing_argument_positional,
4717+
missingParamIdx + 1);
4718+
else
4719+
TC.diagnose(loc, diag::missing_argument_named, name);
4720+
4721+
auto candidate = CandidateInfo[0];
4722+
if (candidate.getDecl())
4723+
TC.diagnose(candidate.getDecl(), diag::decl_declared_here,
4724+
candidate.getDecl()->getFullName());
4725+
4726+
Diagnosed = true;
46914727
}
4692-
} listener(correctNames, OOOArgIdx, OOOPrevArgIdx,
4693-
extraArgIdx, missingParamIdx);
46944728

4695-
// Use matchCallArguments to determine how close the argument list is (in
4696-
// shape) to the specified candidates parameters. This ignores the
4697-
// concrete types of the arguments, looking only at the argument labels.
4698-
SmallVector<ParamBinding, 4> paramBindings;
4699-
if (!matchCallArguments(args, params, CCI.hasTrailingClosure,
4700-
/*allowFixes:*/true, listener, paramBindings))
4701-
return false;
4729+
void outOfOrderArgument(unsigned argIdx, unsigned prevArgIdx) override {
4730+
auto tuple = cast<TupleExpr>(ArgExpr);
4731+
Identifier first = tuple->getElementName(argIdx);
4732+
Identifier second = tuple->getElementName(prevArgIdx);
4733+
4734+
// Build a mapping from arguments to parameters.
4735+
SmallVector<unsigned, 4> argBindings(tuple->getNumElements());
4736+
for (unsigned paramIdx = 0; paramIdx != Bindings.size(); ++paramIdx) {
4737+
for (auto argIdx : Bindings[paramIdx])
4738+
argBindings[argIdx] = paramIdx;
4739+
}
4740+
4741+
auto firstRange = tuple->getElement(argIdx)->getSourceRange();
4742+
if (!first.empty()) {
4743+
firstRange.Start = tuple->getElementNameLoc(argIdx);
4744+
}
4745+
unsigned OOOParamIdx = argBindings[argIdx];
4746+
if (Bindings[OOOParamIdx].size() > 1) {
4747+
firstRange.End =
4748+
tuple->getElement(Bindings[OOOParamIdx].back())->getEndLoc();
4749+
}
47024750

4751+
auto secondRange = tuple->getElement(prevArgIdx)->getSourceRange();
4752+
if (!second.empty()) {
4753+
secondRange.Start = tuple->getElementNameLoc(prevArgIdx);
4754+
}
4755+
unsigned OOOPrevParamIdx = argBindings[prevArgIdx];
4756+
if (Bindings[OOOPrevParamIdx].size() > 1) {
4757+
secondRange.End =
4758+
tuple->getElement(Bindings[OOOPrevParamIdx].back())->getEndLoc();
4759+
}
47034760

4704-
// If we are missing a parameter, diagnose that.
4705-
if (missingParamIdx != ~0U) {
4706-
Identifier name = params[missingParamIdx].Label;
4707-
auto loc = argExpr->getStartLoc();
4708-
if (name.empty())
4709-
TC.diagnose(loc, diag::missing_argument_positional,
4710-
missingParamIdx+1);
4711-
else
4712-
TC.diagnose(loc, diag::missing_argument_named, name);
4713-
4714-
if (candidate.getDecl())
4715-
TC.diagnose(candidate.getDecl(), diag::decl_declared_here,
4716-
candidate.getDecl()->getFullName());
4717-
return true;
4718-
}
4761+
SourceLoc diagLoc = firstRange.Start;
4762+
4763+
if (first.empty() && second.empty()) {
4764+
TC.diagnose(diagLoc, diag::argument_out_of_order_unnamed_unnamed,
4765+
argIdx + 1, prevArgIdx + 1)
4766+
.fixItExchange(firstRange, secondRange);
4767+
} else if (first.empty() && !second.empty()) {
4768+
TC.diagnose(diagLoc, diag::argument_out_of_order_unnamed_named,
4769+
argIdx + 1, second)
4770+
.fixItExchange(firstRange, secondRange);
4771+
} else if (!first.empty() && second.empty()) {
4772+
TC.diagnose(diagLoc, diag::argument_out_of_order_named_unnamed, first,
4773+
prevArgIdx + 1)
4774+
.fixItExchange(firstRange, secondRange);
4775+
} else {
4776+
TC.diagnose(diagLoc, diag::argument_out_of_order_named_named, first,
4777+
second)
4778+
.fixItExchange(firstRange, secondRange);
4779+
}
47194780

4720-
if (extraArgIdx != ~0U) {
4721-
auto name = args[extraArgIdx].Label;
4722-
Expr *arg = argExpr;
4723-
auto tuple = dyn_cast<TupleExpr>(argExpr);
4724-
if (tuple)
4725-
arg = tuple->getElement(extraArgIdx);
4726-
auto loc = arg->getLoc();
4727-
if (tuple && extraArgIdx == tuple->getNumElements()-1 &&
4728-
tuple->hasTrailingClosure())
4729-
TC.diagnose(loc, diag::extra_trailing_closure_in_call)
4730-
.highlight(arg->getSourceRange());
4731-
else if (params.empty())
4732-
TC.diagnose(loc, diag::extra_argument_to_nullary_call)
4733-
.highlight(argExpr->getSourceRange());
4734-
else if (name.empty())
4735-
TC.diagnose(loc, diag::extra_argument_positional)
4736-
.highlight(arg->getSourceRange());
4737-
else
4738-
TC.diagnose(loc, diag::extra_argument_named, name)
4739-
.highlight(arg->getSourceRange());
4740-
return true;
4741-
}
4781+
Diagnosed = true;
4782+
}
47424783

4743-
// If this is an argument label mismatch, then diagnose that error now.
4744-
if (!correctNames.empty() &&
4745-
diagnoseArgumentLabelError(TC, argExpr, correctNames,
4746-
isa<SubscriptExpr>(fnExpr)))
4747-
return true;
4784+
bool relabelArguments(ArrayRef<Identifier> newNames) override {
4785+
assert (!newNames.empty() && "No arguments were re-labeled");
47484786

4749-
// If we have an out-of-order argument, diagnose it as such.
4750-
if (OOOArgIdx != ~0U && isa<TupleExpr>(argExpr)) {
4751-
auto tuple = cast<TupleExpr>(argExpr);
4752-
Identifier first = tuple->getElementName(OOOArgIdx);
4753-
Identifier second = tuple->getElementName(OOOPrevArgIdx);
4754-
4755-
// Build a mapping from arguments to parameters.
4756-
SmallVector<unsigned, 4> argBindings(tuple->getNumElements());
4757-
for (unsigned paramIdx = 0; paramIdx != paramBindings.size(); ++paramIdx) {
4758-
for (auto argIdx : paramBindings[paramIdx])
4759-
argBindings[argIdx] = paramIdx;
4760-
}
4761-
4762-
auto firstRange = tuple->getElement(OOOArgIdx)->getSourceRange();
4763-
if (!first.empty()) {
4764-
firstRange.Start = tuple->getElementNameLoc(OOOArgIdx);
4765-
}
4766-
unsigned OOOParamIdx = argBindings[OOOArgIdx];
4767-
if (paramBindings[OOOParamIdx].size() > 1) {
4768-
firstRange.End =
4769-
tuple->getElement(paramBindings[OOOParamIdx].back())->getEndLoc();
4770-
}
4771-
4772-
auto secondRange = tuple->getElement(OOOPrevArgIdx)->getSourceRange();
4773-
if (!second.empty()) {
4774-
secondRange.Start = tuple->getElementNameLoc(OOOPrevArgIdx);
4775-
}
4776-
unsigned OOOPrevParamIdx = argBindings[OOOPrevArgIdx];
4777-
if (paramBindings[OOOPrevParamIdx].size() > 1) {
4778-
secondRange.End =
4779-
tuple->getElement(paramBindings[OOOPrevParamIdx].back())->getEndLoc();
4780-
}
4781-
4782-
SourceLoc diagLoc = firstRange.Start;
4783-
4784-
if (first.empty() && second.empty()) {
4785-
TC.diagnose(diagLoc, diag::argument_out_of_order_unnamed_unnamed,
4786-
OOOArgIdx + 1, OOOPrevArgIdx + 1)
4787-
.fixItExchange(firstRange, secondRange);
4788-
} else if (first.empty() && !second.empty()) {
4789-
TC.diagnose(diagLoc, diag::argument_out_of_order_unnamed_named,
4790-
OOOArgIdx + 1, second)
4791-
.fixItExchange(firstRange, secondRange);
4792-
} else if (!first.empty() && second.empty()) {
4793-
TC.diagnose(diagLoc, diag::argument_out_of_order_named_unnamed,
4794-
first, OOOPrevArgIdx + 1)
4795-
.fixItExchange(firstRange, secondRange);
4796-
} else {
4797-
TC.diagnose(diagLoc, diag::argument_out_of_order_named_named,
4798-
first, second)
4799-
.fixItExchange(firstRange, secondRange);
4787+
// Let's diagnose labeling problem but only related to corrected ones.
4788+
if (diagnoseArgumentLabelError(TC, ArgExpr, newNames, IsSubscript))
4789+
Diagnosed = true;
4790+
4791+
return true;
48004792
}
48014793

4802-
return true;
4803-
}
4794+
bool diagnose() {
4795+
// Use matchCallArguments to determine how close the argument list is (in
4796+
// shape) to the specified candidates parameters. This ignores the
4797+
// concrete types of the arguments, looking only at the argument labels.
4798+
matchCallArguments(Arguments, Parameters,
4799+
CandidateInfo.hasTrailingClosure,
4800+
/*allowFixes:*/ true, *this, Bindings);
48044801

4805-
return false;
4802+
return Diagnosed;
4803+
}
4804+
};
4805+
4806+
return ArgumentDiagnostic(argExpr, params, args, CCI,
4807+
isa<SubscriptExpr>(fnExpr))
4808+
.diagnose();
48064809
}
48074810

48084811
/// If the candidate set has been narrowed down to a specific structural

0 commit comments

Comments
 (0)