diff options
author | Kaelyn Uhrain <rikka@google.com> | 2013-09-26 19:10:29 +0000 |
---|---|---|
committer | Kaelyn Uhrain <rikka@google.com> | 2013-09-26 19:10:29 +0000 |
commit | 95995be7a35167e404a844b7156448814c33d7ea (patch) | |
tree | 6cd450caf17e6d84ecc1248aa8e3cb4326b2f9bb /clang/lib | |
parent | e228d1070909d55a253640a0c50046a969f0bff2 (diff) | |
download | bcm5719-llvm-95995be7a35167e404a844b7156448814c33d7ea.tar.gz bcm5719-llvm-95995be7a35167e404a844b7156448814c33d7ea.zip |
Teach typo correction to look inside of classes like it does namespaces.
Unlike with namespaces, searching inside of classes requires also
checking the access to correction candidates (i.e. don't suggest a
correction to a private class member for a correction occurring outside
that class and its methods or friends).
Included is a small (one line) fix for a bug, that was uncovered while
cleaning up the unit tests, where the decls from a TypoCorrection candidate
were preserved in new TypoCorrection candidates that are derived (copied)
from the old TypoCorrection--notably when creating a new candidate by
changing the NestedNameSpecifier associated with the base idenitifer.
llvm-svn: 191449
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Sema/SemaAccess.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 107 |
2 files changed, 104 insertions, 5 deletions
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp index 4ecbf0ba776..6dbfad4e18d 100644 --- a/clang/lib/Sema/SemaAccess.cpp +++ b/clang/lib/Sema/SemaAccess.cpp @@ -1390,6 +1390,8 @@ static AccessResult IsAccessible(Sema &S, CXXBasePath *Path = FindBestPath(S, EC, Entity, FinalAccess, Paths); if (!Path) return AR_dependent; + if (Path->Access == AS_none) // This can happen during typo correction. + return AR_inaccessible; assert(Path->Access <= UnprivilegedAccess && "access along best path worse than direct?"); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index a645986ac31..75b0f984f8c 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -3601,6 +3601,10 @@ class NamespaceSpecifierSet { /// NestedNameSpecifier and its distance in the process. void AddNamespace(NamespaceDecl *ND); + /// \brief Add the record to the set, computing the corresponding + /// NestedNameSpecifier and its distance in the process. + void AddRecord(RecordDecl *RD); + typedef SpecifierInfoList::iterator iterator; iterator begin() { if (!isSorted) SortNamespaces(); @@ -3702,6 +3706,72 @@ void NamespaceSpecifierSet::AddNamespace(NamespaceDecl *ND) { DistanceMap[NumSpecifiers].push_back(SpecifierInfo(Ctx, NNS, NumSpecifiers)); } +void NamespaceSpecifierSet::AddRecord(RecordDecl *RD) { + if (!RD->isBeingDefined() && !RD->isCompleteDefinition()) + return; + + DeclContext *Ctx = cast<DeclContext>(RD); + NestedNameSpecifier *NNS = NULL; + unsigned NumSpecifiers = 0; + DeclContextList NamespaceDeclChain(BuildContextChain(Ctx)); + DeclContextList FullNamespaceDeclChain(NamespaceDeclChain); + + // Eliminate common elements from the two DeclContext chains. + for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(), + CEnd = CurContextChain.rend(); + C != CEnd && !NamespaceDeclChain.empty() && + NamespaceDeclChain.back() == *C; ++C) { + NamespaceDeclChain.pop_back(); + } + + // Add an explicit leading '::' specifier if needed. + if (NamespaceDeclChain.empty()) { + NamespaceDeclChain = FullNamespaceDeclChain; + NNS = NestedNameSpecifier::GlobalSpecifier(Context); + } else if (NamespaceDecl *ND = + dyn_cast_or_null<NamespaceDecl>(NamespaceDeclChain.back())) { + IdentifierInfo *Name = ND->getIdentifier(); + if (std::find(CurContextIdentifiers.begin(), CurContextIdentifiers.end(), + Name) != CurContextIdentifiers.end() || + std::find(CurNameSpecifierIdentifiers.begin(), + CurNameSpecifierIdentifiers.end(), + Name) != CurNameSpecifierIdentifiers.end()) { + NamespaceDeclChain = FullNamespaceDeclChain; + NNS = NestedNameSpecifier::GlobalSpecifier(Context); + } + } + + // Build the NestedNameSpecifier from what is left of the NamespaceDeclChain + for (DeclContextList::reverse_iterator C = NamespaceDeclChain.rbegin(), + CEnd = NamespaceDeclChain.rend(); + C != CEnd; ++C) { + if (NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C)) { + NNS = NestedNameSpecifier::Create(Context, NNS, ND); + ++NumSpecifiers; + } else if (RecordDecl *RD = dyn_cast_or_null<RecordDecl>(*C)) { + NNS = NestedNameSpecifier::Create(Context, NNS, RD->isTemplateDecl(), + RD->getTypeForDecl()); + ++NumSpecifiers; + } + } + + // If the built NestedNameSpecifier would be replacing an existing + // NestedNameSpecifier, use the number of component identifiers that + // would need to be changed as the edit distance instead of the number + // of components in the built NestedNameSpecifier. + if (NNS && !CurNameSpecifierIdentifiers.empty()) { + SmallVector<const IdentifierInfo*, 4> NewNameSpecifierIdentifiers; + getNestedNameSpecifierIdentifiers(NNS, NewNameSpecifierIdentifiers); + NumSpecifiers = llvm::ComputeEditDistance( + ArrayRef<const IdentifierInfo *>(CurNameSpecifierIdentifiers), + ArrayRef<const IdentifierInfo *>(NewNameSpecifierIdentifiers)); + } + + isSorted = false; + Distances.insert(NumSpecifiers); + DistanceMap[NumSpecifiers].push_back(SpecifierInfo(Ctx, NNS, NumSpecifiers)); +} + /// \brief Perform name lookup for a possible result for typo correction. static void LookupPotentialTypoResult(Sema &SemaRef, LookupResult &Res, @@ -4153,12 +4223,22 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, for (unsigned I = 0, N = ExternalKnownNamespaces.size(); I != N; ++I) KnownNamespaces[ExternalKnownNamespaces[I]] = true; } - - for (llvm::MapVector<NamespaceDecl*, bool>::iterator + + for (llvm::MapVector<NamespaceDecl*, bool>::iterator KNI = KnownNamespaces.begin(), KNIEnd = KnownNamespaces.end(); KNI != KNIEnd; ++KNI) Namespaces.AddNamespace(KNI->first); + + for (ASTContext::type_iterator TI = Context.types_begin(), + TIEnd = Context.types_end(); + TI != TIEnd; ++TI) { + if (CXXRecordDecl *CD = (*TI)->getAsCXXRecordDecl()) { + if (!CD->isDependentType() && !CD->isAnonymousStructOrUnion() && + !CD->isUnion()) + Namespaces.AddRecord(CD); + } + } } // Weed out any names that could not be found by name lookup or, if a @@ -4295,6 +4375,17 @@ retry_lookup: NIEnd = Namespaces.end(); NI != NIEnd; ++NI) { DeclContext *Ctx = NI->DeclCtx; + const Type *NSType = NI->NameSpecifier->getAsType(); + + // If the current NestedNameSpecifier refers to a class and the + // current correction candidate is the name of that class, then skip + // it as it is unlikely a qualified version of the class' constructor + // is an appropriate correction. + if (CXXRecordDecl *NSDecl = + NSType ? NSType->getAsCXXRecordDecl() : 0) { + if (NSDecl->getIdentifier() == QRI->getCorrectionAsIdentifierInfo()) + continue; + } // FIXME: Stop searching once the namespaces are too far away to create // acceptable corrections for this identifier (since the namespaces @@ -4310,14 +4401,20 @@ retry_lookup: case LookupResult::Found: case LookupResult::FoundOverloaded: { TypoCorrection TC(*QRI); + TC.ClearCorrectionDecls(); TC.setCorrectionSpecifier(NI->NameSpecifier); TC.setQualifierDistance(NI->EditDistance); TC.setCallbackDistance(0); // Reset the callback distance for (LookupResult::iterator TRD = TmpRes.begin(), TRDEnd = TmpRes.end(); - TRD != TRDEnd; ++TRD) - TC.addCorrectionDecl(*TRD); - Consumer.addCorrection(TC); + TRD != TRDEnd; ++TRD) { + if (CheckMemberAccess(TC.getCorrectionRange().getBegin(), + NSType ? NSType->getAsCXXRecordDecl() : 0, + *TRD) == AR_accessible) + TC.addCorrectionDecl(*TRD); + } + if (TC.isResolved()) + Consumer.addCorrection(TC); break; } case LookupResult::NotFound: |