summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorKaelyn Uhrain <rikka@google.com>2013-09-26 19:10:29 +0000
committerKaelyn Uhrain <rikka@google.com>2013-09-26 19:10:29 +0000
commit95995be7a35167e404a844b7156448814c33d7ea (patch)
tree6cd450caf17e6d84ecc1248aa8e3cb4326b2f9bb /clang/lib
parente228d1070909d55a253640a0c50046a969f0bff2 (diff)
downloadbcm5719-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.cpp2
-rw-r--r--clang/lib/Sema/SemaLookup.cpp107
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:
OpenPOWER on IntegriCloud