aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaLookup.cpp
diff options
context:
space:
mode:
authorKaelyn Uhrain <rikka@google.com>2012-06-01 18:11:16 +0000
committerKaelyn Uhrain <rikka@google.com>2012-06-01 18:11:16 +0000
commit784ae8e5c6b557e2395991c6008293660f5afe66 (patch)
tree8d44a9ac9af17e9f9894ce814f146af3b7c38ded /lib/Sema/SemaLookup.cpp
parent29fbfc21924a692155ac8e4e281f17438fe27d63 (diff)
Don't allow multiple correction candidates that have the same identifier
but different nested name specifiers to quietly clobber each other so only one remains if they do not refer to the same NamedDecl. Fixes PR12951. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@157823 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaLookup.cpp')
-rw-r--r--lib/Sema/SemaLookup.cpp78
1 files changed, 53 insertions, 25 deletions
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index fb7e463ad9..5af95d8168 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -3147,7 +3147,8 @@ LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc,
namespace {
-typedef llvm::StringMap<TypoCorrection, llvm::BumpPtrAllocator> TypoResultsMap;
+typedef llvm::SmallVector<TypoCorrection, 1> TypoResultList;
+typedef llvm::StringMap<TypoResultList, llvm::BumpPtrAllocator> TypoResultsMap;
typedef std::map<unsigned, TypoResultsMap> TypoEditDistanceMap;
static const unsigned MaxTypoDistanceResultSets = 5;
@@ -3186,7 +3187,7 @@ public:
unsigned size() const { return CorrectionResults.size(); }
bool empty() const { return CorrectionResults.empty(); }
- TypoCorrection &operator[](StringRef Name) {
+ TypoResultList &operator[](StringRef Name) {
return CorrectionResults.begin()->second[Name];
}
@@ -3256,16 +3257,28 @@ void TypoCorrectionConsumer::addName(StringRef Name,
void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) {
StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName();
- TypoResultsMap &Map = CorrectionResults[Correction.getEditDistance(false)];
-
- TypoCorrection &CurrentCorrection = Map[Name];
- if (!CurrentCorrection ||
- // FIXME: The following should be rolled up into an operator< on
- // TypoCorrection with a more principled definition.
- CurrentCorrection.isKeyword() < Correction.isKeyword() ||
- Correction.getAsString(SemaRef.getLangOpts()) <
- CurrentCorrection.getAsString(SemaRef.getLangOpts()))
- CurrentCorrection = Correction;
+ TypoResultList &CList =
+ CorrectionResults[Correction.getEditDistance(false)][Name];
+
+ if (!CList.empty() && !CList.back().isResolved())
+ CList.pop_back();
+ if (NamedDecl *NewND = Correction.getCorrectionDecl()) {
+ std::string CorrectionStr = Correction.getAsString(SemaRef.getLangOpts());
+ for (TypoResultList::iterator RI = CList.begin(), RIEnd = CList.end();
+ RI != RIEnd; ++RI) {
+ // If the Correction refers to a decl already in the result list,
+ // replace the existing result if the string representation of Correction
+ // comes before the current result alphabetically, then stop as there is
+ // nothing more to be done to add Correction to the candidate set.
+ if (RI->getCorrectionDecl() == NewND) {
+ if (CorrectionStr < RI->getAsString(SemaRef.getLangOpts()))
+ *RI = Correction;
+ return;
+ }
+ }
+ }
+ if (CList.empty() || Correction.isResolved())
+ CList.push_back(Correction);
while (CorrectionResults.size() > MaxTypoDistanceResultSets)
erase(llvm::prior(CorrectionResults.end()));
@@ -3862,16 +3875,30 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// If the item already has been looked up or is a keyword, keep it.
// If a validator callback object was given, drop the correction
// unless it passes validation.
- if (I->second.isResolved()) {
+ bool Viable = false;
+ for (TypoResultList::iterator RI = I->second.begin(), RIEnd = I->second.end();
+ RI != RIEnd; /* Increment in loop. */) {
+ TypoResultList::iterator Prev = RI;
+ ++RI;
+ if (Prev->isResolved()) {
+ if (!isCandidateViable(CCC, *Prev))
+ I->second.erase(Prev);
+ else
+ Viable = true;
+ }
+ }
+ if (Viable || I->second.empty()) {
TypoCorrectionConsumer::result_iterator Prev = I;
++I;
- if (!isCandidateViable(CCC, Prev->second))
+ if (!Viable)
DI->second.erase(Prev);
continue;
}
+ assert(I->second.size() == 1 && "Expected a single unresolved candidate");
// Perform name lookup on this name.
- IdentifierInfo *Name = I->second.getCorrectionAsIdentifierInfo();
+ TypoCorrection &Candidate = I->second.front();
+ IdentifierInfo *Name = Candidate.getCorrectionAsIdentifierInfo();
LookupPotentialTypoResult(*this, TmpRes, Name, S, SS, MemberContext,
EnteringContext, CCC.IsObjCIvarLookup);
@@ -3879,7 +3906,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
case LookupResult::FoundUnresolvedValue:
- QualifiedResults.push_back(I->second);
+ QualifiedResults.push_back(Candidate);
// We didn't find this name in our scope, or didn't like what we found;
// ignore it.
{
@@ -3900,18 +3927,18 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
for (LookupResult::iterator TRD = TmpRes.begin(),
TRDEnd = TmpRes.end();
TRD != TRDEnd; ++TRD)
- I->second.addCorrectionDecl(*TRD);
+ Candidate.addCorrectionDecl(*TRD);
++I;
- if (!isCandidateViable(CCC, Prev->second))
+ if (!isCandidateViable(CCC, Candidate))
DI->second.erase(Prev);
break;
}
case LookupResult::Found: {
TypoCorrectionConsumer::result_iterator Prev = I;
- I->second.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>());
+ Candidate.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>());
++I;
- if (!isCandidateViable(CCC, Prev->second))
+ if (!isCandidateViable(CCC, Candidate))
DI->second.erase(Prev);
break;
}
@@ -3998,8 +4025,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// If only a single name remains, return that result.
if (BestResults.size() == 1) {
- const llvm::StringMapEntry<TypoCorrection> &Correction = *(BestResults.begin());
- const TypoCorrection &Result = Correction.second;
+ const TypoResultList &CorrectionList = BestResults.begin()->second;
+ const TypoCorrection &Result = CorrectionList.front();
+ if (CorrectionList.size() != 1) return TypoCorrection();
// Don't correct to a keyword that's the same as the typo; the keyword
// wasn't actually in scope.
@@ -4017,7 +4045,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// some instances of CTC_Unknown, while WantRemainingKeywords is true
// for CTC_Unknown but not for CTC_ObjCMessageReceiver.
&& CCC.WantObjCSuper && !CCC.WantRemainingKeywords
- && BestResults["super"].isKeyword()) {
+ && BestResults["super"].front().isKeyword()) {
// Prefer 'super' when we're completing in a message-receiver
// context.
@@ -4027,9 +4055,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// Record the correction for unqualified lookup.
if (IsUnqualifiedLookup)
- UnqualifiedTyposCorrected[Typo] = BestResults["super"];
+ UnqualifiedTyposCorrected[Typo] = BestResults["super"].front();
- return BestResults["super"];
+ return BestResults["super"].front();
}
// If this was an unqualified lookup and we believe the callback object did