diff options
author | Matt Beaumont-Gay <matthewbg@google.com> | 2011-05-04 22:10:40 +0000 |
---|---|---|
committer | Matt Beaumont-Gay <matthewbg@google.com> | 2011-05-04 22:10:40 +0000 |
commit | c9366ba8fff6461a5b7f0fd2626d1bce3e98e629 (patch) | |
tree | 93b5a087931afb71c2f9c9526ab950db1e78e244 /lib/Sema/SemaExpr.cpp | |
parent | c7469374548b06e50aa8b4d41bf1a35338e9b358 (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.cpp | 146 |
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(); |