diff options
-rw-r--r-- | include/clang/Sema/Sema.h | 11 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 96 | ||||
-rw-r--r-- | test/SemaObjC/super.m | 4 |
3 files changed, 83 insertions, 28 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index c0def12156..5e6497fe1b 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3518,6 +3518,17 @@ public: /// \brief The number of typos corrected by CorrectTypo. unsigned TyposCorrected; + typedef llvm::DenseMap<IdentifierInfo *, std::pair<llvm::StringRef, bool> > + UnqualifiedTyposCorrectedMap; + + /// \brief A cache containing the results of typo correction for unqualified + /// name lookup. + /// + /// The string is the string that we corrected to (which may be empty, if + /// there was no correction), while the boolean will be true when the + /// string represents a keyword. + UnqualifiedTyposCorrectedMap UnqualifiedTyposCorrected; + /// \brief Worker object for performing CFG-based warnings. sema::AnalysisBasedWarnings AnalysisWarnings; diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index ab810a4682..1294f4f013 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -2822,14 +2822,6 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, const ObjCObjectPointerType *OPT) { if (Diags.hasFatalErrorOccurred() || !getLangOptions().SpellChecking) return DeclarationName(); - - // Provide a stop gap for files that are just seriously broken. Trying - // to correct all typos can turn into a HUGE performance penalty, causing - // some files to take minutes to get rejected by the parser. - // FIXME: Is this the right solution? - if (TyposCorrected == 20) - return DeclarationName(); - ++TyposCorrected; // We only attempt to correct typos for identifiers. IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo(); @@ -2849,6 +2841,7 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, TypoCorrectionConsumer Consumer(Typo); // Perform name lookup to find visible, similarly-named entities. + bool IsUnqualifiedLookup = false; if (MemberContext) { LookupVisibleDecls(MemberContext, Res.getLookupKind(), Consumer); @@ -2864,26 +2857,52 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, if (!DC) return DeclarationName(); + // Provide a stop gap for files that are just seriously broken. Trying + // to correct all typos can turn into a HUGE performance penalty, causing + // some files to take minutes to get rejected by the parser. + if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20) + return DeclarationName(); + ++TyposCorrected; + LookupVisibleDecls(DC, Res.getLookupKind(), Consumer); } else { - // For unqualified lookup, look through all of the names that we have - // seen in this translation unit. - for (IdentifierTable::iterator I = Context.Idents.begin(), - IEnd = Context.Idents.end(); - I != IEnd; ++I) - Consumer.FoundName(I->getKey()); - - // Walk through identifiers in external identifier sources. - if (IdentifierInfoLookup *External + IsUnqualifiedLookup = true; + UnqualifiedTyposCorrectedMap::iterator Cached + = UnqualifiedTyposCorrected.find(Typo); + if (Cached == UnqualifiedTyposCorrected.end()) { + // Provide a stop gap for files that are just seriously broken. Trying + // to correct all typos can turn into a HUGE performance penalty, causing + // some files to take minutes to get rejected by the parser. + if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20) + return DeclarationName(); + + // For unqualified lookup, look through all of the names that we have + // seen in this translation unit. + for (IdentifierTable::iterator I = Context.Idents.begin(), + IEnd = Context.Idents.end(); + I != IEnd; ++I) + Consumer.FoundName(I->getKey()); + + // Walk through identifiers in external identifier sources. + if (IdentifierInfoLookup *External = Context.Idents.getExternalIdentifierLookup()) { - IdentifierIterator *Iter = External->getIdentifiers(); - do { - llvm::StringRef Name = Iter->Next(); - if (Name.empty()) - break; + IdentifierIterator *Iter = External->getIdentifiers(); + do { + llvm::StringRef Name = Iter->Next(); + if (Name.empty()) + break; - Consumer.FoundName(Name); - } while (true); + Consumer.FoundName(Name); + } while (true); + } + } else { + // Use the cached value, unless it's a keyword. In the keyword case, we'll + // end up adding the keyword below. + if (Cached->second.first.empty()) + return DeclarationName(); + + if (!Cached->second.second) + Consumer.FoundName(Cached->second.first); } } @@ -3053,14 +3072,24 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, } // If we haven't found anything, we're done. - if (Consumer.empty()) + if (Consumer.empty()) { + // If this was an unqualified lookup, note that no correction was found. + if (IsUnqualifiedLookup) + (void)UnqualifiedTyposCorrected[Typo]; + return DeclarationName(); + } // Make sure that the user typed at least 3 characters for each correction // made. Otherwise, we don't even both looking at the results. unsigned ED = Consumer.getBestEditDistance(); - if (ED > 0 && Typo->getName().size() / ED < 3) + 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 DeclarationName(); + } // Weed out any names that could not be found by name lookup. bool LastLookupWasAccepted = false; @@ -3172,6 +3201,11 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, } } + // Record the correction for unqualified lookup. + if (IsUnqualifiedLookup) + UnqualifiedTyposCorrected[Typo] + = std::make_pair(Consumer.begin()->getKey(), Consumer.begin()->second); + return &Context.Idents.get(Consumer.begin()->getKey()); } else if (Consumer.size() > 1 && CTC == CTC_ObjCMessageReceiver @@ -3180,11 +3214,21 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, // context. Res.suppressDiagnostics(); Res.clear(); + + // Record the correction for unqualified lookup. + if (IsUnqualifiedLookup) + UnqualifiedTyposCorrected[Typo] + = std::make_pair(Consumer.begin()->getKey(), Consumer.begin()->second); + return &Context.Idents.get("super"); } Res.suppressDiagnostics(); Res.setLookupName(Typo); Res.clear(); + // Record the correction for unqualified lookup. + if (IsUnqualifiedLookup) + (void)UnqualifiedTyposCorrected[Typo]; + return DeclarationName(); } diff --git a/test/SemaObjC/super.m b/test/SemaObjC/super.m index 31d8db1702..c15df26f34 100644 --- a/test/SemaObjC/super.m +++ b/test/SemaObjC/super.m @@ -54,8 +54,8 @@ void f0(int super) { [super m]; // expected-warning{{receiver type 'int' is not 'id'}} \ expected-warning {{method '-m' not found (return type defaults to 'id')}} } -void f1(id puper) { // expected-note {{'puper' declared here}} - [super m]; // expected-error{{use of undeclared identifier 'super'; did you mean 'puper'?}} +void f1(id puper) { + [super m]; // expected-error{{use of undeclared identifier 'super'}} } // radar 7400691 |