From 67d8fe3f69bfb586f3cda59659337caf90e00756 Mon Sep 17 00:00:00 2001 From: Kaelyn Takata Date: Fri, 4 Apr 2014 22:16:30 +0000 Subject: [PATCH] Try harder about not suggesting methods as corrections when they obviously won't work. Specifically, don't suggest methods (static or not) from unrelated classes when the expression is a method call through a specific object. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@205653 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/TypoCorrection.h | 4 +-- lib/Sema/SemaExpr.cpp | 39 ++++++++++++---------------- lib/Sema/SemaLookup.cpp | 20 +++++++------- lib/Sema/SemaOverload.cpp | 3 ++- test/SemaCXX/typo-correction-pt2.cpp | 22 ++++++++++++++++ 5 files changed, 53 insertions(+), 35 deletions(-) diff --git a/include/clang/Sema/TypoCorrection.h b/include/clang/Sema/TypoCorrection.h index 16d732831a..2ef8d84fad 100644 --- a/include/clang/Sema/TypoCorrection.h +++ b/include/clang/Sema/TypoCorrection.h @@ -306,15 +306,15 @@ class FunctionCallFilterCCC : public CorrectionCandidateCallback { public: FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs, bool HasExplicitTemplateArgs, - bool AllowNonStaticMethods = true); + MemberExpr *ME = 0); bool ValidateCandidate(const TypoCorrection &candidate) override; private: unsigned NumArgs; bool HasExplicitTemplateArgs; - bool AllowNonStaticMethods; DeclContext *CurContext; + MemberExpr *MemberFn; }; // @brief Callback class that effectively disabled typo correction diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 7894682efc..c6e3e23fdd 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -3974,8 +3974,8 @@ namespace { class FunctionCallCCC : public FunctionCallFilterCCC { public: FunctionCallCCC(Sema &SemaRef, const IdentifierInfo *FuncName, - unsigned NumArgs, bool HasExplicitTemplateArgs) - : FunctionCallFilterCCC(SemaRef, NumArgs, HasExplicitTemplateArgs), + unsigned NumArgs, MemberExpr *ME) + : FunctionCallFilterCCC(SemaRef, NumArgs, false, ME), FunctionName(FuncName) {} bool ValidateCandidate(const TypoCorrection &candidate) override { @@ -3992,17 +3992,20 @@ private: }; } -static TypoCorrection TryTypoCorrectionForCall(Sema &S, - DeclarationNameInfo FuncName, +static TypoCorrection TryTypoCorrectionForCall(Sema &S, Expr *Fn, + FunctionDecl *FDecl, ArrayRef Args) { - FunctionCallCCC CCC(S, FuncName.getName().getAsIdentifierInfo(), - Args.size(), false); - if (TypoCorrection Corrected = - S.CorrectTypo(FuncName, Sema::LookupOrdinaryName, - S.getScopeForContext(S.CurContext), NULL, CCC)) { + MemberExpr *ME = dyn_cast(Fn); + DeclarationName FuncName = FDecl->getDeclName(); + SourceLocation NameLoc = ME ? ME->getMemberLoc() : Fn->getLocStart(); + FunctionCallCCC CCC(S, FuncName.getAsIdentifierInfo(), Args.size(), ME); + + if (TypoCorrection Corrected = S.CorrectTypo( + DeclarationNameInfo(FuncName, NameLoc), Sema::LookupOrdinaryName, + S.getScopeForContext(S.CurContext), NULL, CCC)) { if (NamedDecl *ND = Corrected.getCorrectionDecl()) { if (Corrected.isOverloaded()) { - OverloadCandidateSet OCS(FuncName.getLoc()); + OverloadCandidateSet OCS(NameLoc); OverloadCandidateSet::iterator Best; for (TypoCorrection::decl_iterator CD = Corrected.begin(), CDEnd = Corrected.end(); @@ -4011,7 +4014,7 @@ static TypoCorrection TryTypoCorrectionForCall(Sema &S, S.AddOverloadCandidate(FD, DeclAccessPair::make(FD, AS_none), Args, OCS); } - switch (OCS.BestViableFunction(S, FuncName.getLoc(), Best)) { + switch (OCS.BestViableFunction(S, NameLoc, Best)) { case OR_Success: ND = Best->Function; Corrected.setCorrectionDecl(ND); @@ -4062,13 +4065,8 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, // arguments for the remaining parameters), don't make the call. if (Args.size() < NumParams) { if (Args.size() < MinArgs) { - MemberExpr *ME = dyn_cast(Fn); TypoCorrection TC; - if (FDecl && (TC = TryTypoCorrectionForCall( - *this, DeclarationNameInfo(FDecl->getDeclName(), - (ME ? ME->getMemberLoc() - : Fn->getLocStart())), - Args))) { + if (FDecl && (TC = TryTypoCorrectionForCall(*this, Fn, FDecl, Args))) { unsigned diag_id = MinArgs == NumParams && !Proto->isVariadic() ? diag::err_typecheck_call_too_few_args_suggest @@ -4103,13 +4101,8 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, // them. if (Args.size() > NumParams) { if (!Proto->isVariadic()) { - MemberExpr *ME = dyn_cast(Fn); TypoCorrection TC; - if (FDecl && (TC = TryTypoCorrectionForCall( - *this, DeclarationNameInfo(FDecl->getDeclName(), - (ME ? ME->getMemberLoc() - : Fn->getLocStart())), - Args))) { + if (FDecl && (TC = TryTypoCorrectionForCall(*this, Fn, FDecl, Args))) { unsigned diag_id = MinArgs == NumParams && !Proto->isVariadic() ? diag::err_typecheck_call_too_many_args_suggest diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index ac6fb25cae..39a1ceaa57 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -4511,10 +4511,9 @@ bool CorrectionCandidateCallback::ValidateCandidate(const TypoCorrection &candid FunctionCallFilterCCC::FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs, bool HasExplicitTemplateArgs, - bool AllowNonStaticMethods) + MemberExpr *ME) : NumArgs(NumArgs), HasExplicitTemplateArgs(HasExplicitTemplateArgs), - AllowNonStaticMethods(AllowNonStaticMethods), - CurContext(SemaRef.CurContext) { + CurContext(SemaRef.CurContext), MemberFn(ME) { WantTypeSpecifiers = SemaRef.getLangOpts().CPlusPlus; WantRemainingKeywords = false; } @@ -4550,13 +4549,16 @@ bool FunctionCallFilterCCC::ValidateCandidate(const TypoCorrection &candidate) { FD->getMinRequiredArguments() <= NumArgs)) continue; - // If the current candidate is a non-static C++ method and non-static - // methods are being excluded, then skip the candidate unless the current - // DeclContext is a method in the same class or a descendent class of the - // candidate's parent class. + // If the current candidate is a non-static C++ method, skip the candidate + // unless the method being corrected--or the current DeclContext, if the + // function being corrected is not a method--is a method in the same class + // or a descendent class of the candidate's parent class. if (CXXMethodDecl *MD = dyn_cast(FD)) { - if (!AllowNonStaticMethods && !MD->isStatic()) { - CXXMethodDecl *CurMD = dyn_cast_or_null(CurContext); + if (MemberFn || !MD->isStatic()) { + CXXMethodDecl *CurMD = + MemberFn + ? dyn_cast_or_null(MemberFn->getMemberDecl()) + : dyn_cast_or_null(CurContext); CXXRecordDecl *CurRD = CurMD ? CurMD->getParent()->getCanonicalDecl() : 0; CXXRecordDecl *RD = MD->getParent()->getCanonicalDecl(); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index ee1feb5c82..90710205db 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -10383,7 +10383,8 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(), Sema::LookupOrdinaryName); FunctionCallFilterCCC Validator(SemaRef, Args.size(), - ExplicitTemplateArgs != 0, false); + ExplicitTemplateArgs != 0, + dyn_cast(Fn)); NoTypoCorrectionCCC RejectAll; CorrectionCandidateCallback *CCC = AllowTypoCorrection ? (CorrectionCandidateCallback*)&Validator : diff --git a/test/SemaCXX/typo-correction-pt2.cpp b/test/SemaCXX/typo-correction-pt2.cpp index 9943dd21f5..2fab22a204 100644 --- a/test/SemaCXX/typo-correction-pt2.cpp +++ b/test/SemaCXX/typo-correction-pt2.cpp @@ -242,6 +242,28 @@ void func() { }; bar(); // expected-error-re {{use of undeclared identifier 'bar'{{$}}}} } + +class Thread { + public: + void Start(); + static void Stop(); // expected-note {{'Thread::Stop' declared here}} +}; + +class Manager { + public: + void Start(int); // expected-note {{'Start' declared here}} + void Stop(int); // expected-note {{'Stop' declared here}} +}; + +void test(Manager *m) { + // Don't suggest Thread::Start as a correction just because it has the same + // (unqualified) name and accepts the right number of args; this is a method + // call on an object in an unrelated class. + m->Start(); // expected-error-re {{too few arguments to function call, expected 1, have 0{{$}}}} + m->Stop(); // expected-error-re {{too few arguments to function call, expected 1, have 0{{$}}}} + Stop(); // expected-error {{use of undeclared identifier 'Stop'; did you mean 'Thread::Stop'?}} +} + } namespace std { -- 2.40.0