diff options
Diffstat (limited to 'clang/lib/Sema/SemaLookup.cpp')
-rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 107 |
1 files changed, 102 insertions, 5 deletions
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: |