aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaExpr.cpp
diff options
context:
space:
mode:
authorMatt Beaumont-Gay <matthewbg@google.com>2011-05-04 22:10:40 +0000
committerMatt Beaumont-Gay <matthewbg@google.com>2011-05-04 22:10:40 +0000
commitc9366ba8fff6461a5b7f0fd2626d1bce3e98e629 (patch)
tree93b5a087931afb71c2f9c9526ab950db1e78e244 /lib/Sema/SemaExpr.cpp
parentc7469374548b06e50aa8b4d41bf1a35338e9b358 (diff)
Implement Sema::isExprCallable.
We can use this to produce nice diagnostics (and try to fixit-and-recover) in various cases where we might see "MyFunction" instead of "MyFunction()". The changes in SemaExpr are an example of how to use isExprCallable. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130878 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaExpr.cpp')
-rw-r--r--lib/Sema/SemaExpr.cpp146
1 files changed, 39 insertions, 107 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index afcde44814..56abdfbcd3 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -4377,120 +4377,52 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
// If the user is trying to apply -> or . to a function name, it's probably
// because they forgot parentheses to call that function.
- bool TryCall = false;
- bool Overloaded = false;
- UnresolvedSet<8> AllOverloads;
- if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(BaseExpr.get())) {
- AllOverloads.append(Overloads->decls_begin(), Overloads->decls_end());
- TryCall = true;
- Overloaded = true;
- } else if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(BaseExpr.get())) {
- if (FunctionDecl* Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) {
- AllOverloads.addDecl(Fun);
- TryCall = true;
- }
- }
-
- if (TryCall) {
- // Plunder the overload set for something that would make the member
- // expression valid.
- UnresolvedSet<4> ViableOverloads;
- bool HasViableZeroArgOverload = false;
- for (OverloadExpr::decls_iterator it = AllOverloads.begin(),
- DeclsEnd = AllOverloads.end(); it != DeclsEnd; ++it) {
- // Our overload set may include TemplateDecls, which we'll ignore for the
- // purposes of determining whether we can issue a '()' fixit.
- if (const FunctionDecl *OverloadDecl = dyn_cast<FunctionDecl>(*it)) {
- QualType ResultTy = OverloadDecl->getResultType();
- if ((!IsArrow && ResultTy->isRecordType()) ||
- (IsArrow && ResultTy->isPointerType() &&
- ResultTy->getPointeeType()->isRecordType())) {
- ViableOverloads.addDecl(*it);
- if (OverloadDecl->getMinRequiredArguments() == 0) {
- HasViableZeroArgOverload = true;
- }
- }
- }
- }
-
- if (!HasViableZeroArgOverload || ViableOverloads.size() != 1) {
+ QualType ZeroArgCallTy;
+ UnresolvedSet<4> Overloads;
+ if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) {
+ if (ZeroArgCallTy.isNull()) {
Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
- << (AllOverloads.size() > 1) << 0
- << BaseExpr.get()->getSourceRange();
- int ViableOverloadCount = ViableOverloads.size();
- int I;
- for (I = 0; I < ViableOverloadCount; ++I) {
- // FIXME: Magic number for max shown overloads stolen from
- // OverloadCandidateSet::NoteCandidates.
- if (I >= 4 && Diags.getShowOverloads() == Diagnostic::Ovl_Best) {
- break;
- }
- Diag(ViableOverloads[I].getDecl()->getSourceRange().getBegin(),
- diag::note_member_ref_possible_intended_overload);
- }
- if (I != ViableOverloadCount) {
- Diag(BaseExpr.get()->getExprLoc(), diag::note_ovl_too_many_candidates)
- << int(ViableOverloadCount - I);
+ << (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange();
+ UnresolvedSet<2> PlausibleOverloads;
+ for (OverloadExpr::decls_iterator It = Overloads.begin(),
+ DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
+ const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It);
+ QualType OverloadResultTy = OverloadDecl->getResultType();
+ if ((!IsArrow && OverloadResultTy->isRecordType()) ||
+ (IsArrow && OverloadResultTy->isPointerType() &&
+ OverloadResultTy->getPointeeType()->isRecordType()))
+ PlausibleOverloads.addDecl(It.getDecl());
}
+ NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc());
return ExprError();
}
- } else {
- // We don't have an expression that's convenient to get a Decl from, but we
- // can at least check if the type is "function of 0 arguments which returns
- // an acceptable type".
- const FunctionType *Fun = NULL;
- if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
- if ((Fun = Ptr->getPointeeType()->getAs<FunctionType>())) {
- TryCall = true;
- }
- } else if ((Fun = BaseType->getAs<FunctionType>())) {
- TryCall = true;
- } else if (BaseType == Context.BoundMemberTy) {
- // Look for the bound-member type. If it's still overloaded,
- // give up, although we probably should have fallen into the
- // OverloadExpr case above if we actually have an overloaded
- // bound member.
- QualType fnType = Expr::findBoundMemberType(BaseExpr.get());
- if (!fnType.isNull()) {
- TryCall = true;
- Fun = fnType->castAs<FunctionType>();
- }
- }
-
- if (TryCall) {
- if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Fun)) {
- if (FPT->getNumArgs() == 0) {
- QualType ResultTy = Fun->getResultType();
- TryCall = (!IsArrow && ResultTy->isRecordType()) ||
- (IsArrow && ResultTy->isPointerType() &&
- ResultTy->getPointeeType()->isRecordType());
- }
- }
+ if ((!IsArrow && ZeroArgCallTy->isRecordType()) ||
+ (IsArrow && ZeroArgCallTy->isPointerType() &&
+ ZeroArgCallTy->getPointeeType()->isRecordType())) {
+ // At this point, we know BaseExpr looks like it's potentially callable
+ // with 0 arguments, and that it returns something of a reasonable type,
+ // so we can emit a fixit and carry on pretending that BaseExpr was
+ // actually a CallExpr.
+ SourceLocation ParenInsertionLoc =
+ PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd());
+ Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
+ << (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange()
+ << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
+ // FIXME: Try this before emitting the fixit, and suppress diagnostics
+ // while doing so.
+ ExprResult NewBase =
+ ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc,
+ MultiExprArg(*this, 0, 0),
+ ParenInsertionLoc.getFileLocWithOffset(1));
+ if (NewBase.isInvalid())
+ return ExprError();
+ BaseExpr = NewBase;
+ BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
}
}
- if (TryCall) {
- // At this point, we know BaseExpr looks like it's potentially callable with
- // 0 arguments, and that it returns something of a reasonable type, so we
- // can emit a fixit and carry on pretending that BaseExpr was actually a
- // CallExpr.
- SourceLocation ParenInsertionLoc =
- PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd());
- Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
- << int(Overloaded) << 1
- << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
- ExprResult NewBase = ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc,
- MultiExprArg(*this, 0, 0),
- ParenInsertionLoc);
- if (NewBase.isInvalid())
- return ExprError();
- BaseExpr = NewBase;
- BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- }
-
Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
<< BaseType << BaseExpr.get()->getSourceRange();