From 2b17b472d2f503ee61c460ca23f226c2aebcdd62 Mon Sep 17 00:00:00 2001 From: Kaelyn Uhrain Date: Fri, 27 Sep 2013 19:40:08 +0000 Subject: [PATCH] Cache the location of failed typo corrections so that typo correction isn't repeatedly attempted for the same identifier at the same location. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191543 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 22 ++++++++++++++++- lib/Sema/SemaExprObjC.cpp | 6 ++--- lib/Sema/SemaLookup.cpp | 51 ++++++++++++++++++++------------------- 3 files changed, 50 insertions(+), 29 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 56988b1d57..6ac19ae5f7 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2493,7 +2493,8 @@ public: CorrectionCandidateCallback &CCC, DeclContext *MemberContext = 0, bool EnteringContext = false, - const ObjCObjectPointerType *OPT = 0); + const ObjCObjectPointerType *OPT = 0, + bool RecordFailure = true); void diagnoseTypo(const TypoCorrection &Correction, const PartialDiagnostic &TypoDiag, @@ -2705,6 +2706,17 @@ private: bool receiverIdOrClass, bool warn, bool instance); + /// \brief Record the typo correction failure and return an empty correction. + TypoCorrection FailedCorrection(IdentifierInfo *Typo, SourceLocation TypoLoc, + bool RecordFailure = true, + bool IsUnqualifiedLookup = false) { + if (IsUnqualifiedLookup) + (void)UnqualifiedTyposCorrected[Typo]; + if (RecordFailure) + TypoCorrectionFailures[Typo].insert(TypoLoc); + return TypoCorrection(); + } + public: /// AddInstanceMethodToGlobalPool - All instance methods in a translation /// unit are added to a global pool. This allows us to efficiently associate @@ -6308,6 +6320,14 @@ public: /// string represents a keyword. UnqualifiedTyposCorrectedMap UnqualifiedTyposCorrected; + typedef llvm::SmallSet SrcLocSet; + typedef llvm::DenseMap IdentifierSourceLocations; + + /// \brief A cache containing identifiers for which typo correction failed and + /// their locations, so that repeated attempts to correct an identifier in a + /// given location are ignored if typo correction already failed for it. + IdentifierSourceLocations TypoCorrectionFailures; + /// \brief Worker object for performing CFG-based warnings. sema::AnalysisBasedWarnings AnalysisWarnings; diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 81d2a8122a..5550eb8cf9 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -1839,9 +1839,9 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, } ObjCInterfaceOrSuperCCC Validator(getCurMethodDecl()); - if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(), - Result.getLookupKind(), S, NULL, - Validator)) { + if (TypoCorrection Corrected = + CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S, + NULL, Validator, NULL, false, NULL, false)) { if (Corrected.isKeyword()) { // If we've found the keyword "super" (the only keyword that would be // returned by CorrectTypo), this is a send to super. diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 75b0f984f8..c2e23c7ede 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -4056,7 +4056,8 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, CorrectionCandidateCallback &CCC, DeclContext *MemberContext, bool EnteringContext, - const ObjCObjectPointerType *OPT) { + const ObjCObjectPointerType *OPT, + bool RecordFailure) { // Always let the ExternalSource have the first chance at correction, even // if we would otherwise have given up. if (ExternalSource) { @@ -4095,6 +4096,12 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, if (S && S->isInObjcMethodScope() && Typo == getSuperIdentifier()) return TypoCorrection(); + // Abort if typo correction already failed for this specific typo. + IdentifierSourceLocations::iterator locs = TypoCorrectionFailures.find(Typo); + if (locs != TypoCorrectionFailures.end() && + locs->second.count(TypoName.getLoc()) > 0) + return TypoCorrection(); + NamespaceSpecifierSet Namespaces(Context, CurContext, SS); TypoCorrectionConsumer Consumer(*this, Typo); @@ -4193,24 +4200,16 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, AddKeywordsToConsumer(*this, Consumer, S, CCC, SS && SS->isNotEmpty()); // If we haven't found anything, we're done. - if (Consumer.empty()) { - // If this was an unqualified lookup, note that no correction was found. - if (IsUnqualifiedLookup) - (void)UnqualifiedTyposCorrected[Typo]; - - return TypoCorrection(); - } + if (Consumer.empty()) + return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure, + IsUnqualifiedLookup); // Make sure the best edit distance (prior to adding any namespace qualifiers) // is not more that about a third of the length of the typo's identifier. unsigned ED = Consumer.getBestEditDistance(true); - if (ED > 0 && Typo->getName().size() / ED < 3) { - // If this was an unqualified lookup, note that no correction was found. - if (IsUnqualifiedLookup) - (void)UnqualifiedTyposCorrected[Typo]; - - return TypoCorrection(); - } + if (ED > 0 && Typo->getName().size() / ED < 3) + return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure, + IsUnqualifiedLookup); // Build the NestedNameSpecifiers for the KnownNamespaces, if we're going // to search those namespaces. @@ -4327,7 +4326,7 @@ retry_lookup: case LookupResult::Ambiguous: // We don't deal with ambiguities. - return TypoCorrection(); + return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); case LookupResult::FoundOverloaded: { TypoCorrectionConsumer::result_iterator Prev = I; @@ -4431,7 +4430,8 @@ retry_lookup: } // No corrections remain... - if (Consumer.empty()) return TypoCorrection(); + if (Consumer.empty()) + return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); TypoResultsMap &BestResults = Consumer.getBestResults(); ED = Consumer.getBestEditDistance(true); @@ -4440,21 +4440,21 @@ retry_lookup: // If this was an unqualified lookup and we believe the callback // object wouldn't have filtered out possible corrections, note // that no correction was found. - if (IsUnqualifiedLookup && !ValidatingCallback) - (void)UnqualifiedTyposCorrected[Typo]; - - return TypoCorrection(); + return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure, + IsUnqualifiedLookup && !ValidatingCallback); } // If only a single name remains, return that result. if (BestResults.size() == 1) { const TypoResultList &CorrectionList = BestResults.begin()->second; const TypoCorrection &Result = CorrectionList.front(); - if (CorrectionList.size() != 1) return TypoCorrection(); + if (CorrectionList.size() != 1) + return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); // Don't correct to a keyword that's the same as the typo; the keyword // wasn't actually in scope. - if (ED == 0 && Result.isKeyword()) return TypoCorrection(); + if (ED == 0 && Result.isKeyword()) + return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); // Record the correction for unqualified lookup. if (IsUnqualifiedLookup) @@ -4477,7 +4477,8 @@ retry_lookup: // Don't correct to a keyword that's the same as the typo; the keyword // wasn't actually in scope. - if (ED == 0) return TypoCorrection(); + if (ED == 0) + return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); // Record the correction for unqualified lookup. if (IsUnqualifiedLookup) @@ -4493,7 +4494,7 @@ retry_lookup: if (IsUnqualifiedLookup && !ValidatingCallback) (void)UnqualifiedTyposCorrected[Typo]; - return TypoCorrection(); + return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); } void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) { -- 2.40.0