diff options
author | Kaelyn Takata <rikka@google.com> | 2014-11-20 22:06:30 +0000 |
---|---|---|
committer | Kaelyn Takata <rikka@google.com> | 2014-11-20 22:06:30 +0000 |
commit | 3f9794f288d89d33fe42e89cdf57371784bf0258 (patch) | |
tree | f813c8dfbd6d2cd9d0874f123f7fb7f66007b3b1 /clang/lib/Sema/SemaExprCXX.cpp | |
parent | 6fc91a9d5e7d151890c7fc344e1999b8b11f34c2 (diff) | |
download | bcm5719-llvm-3f9794f288d89d33fe42e89cdf57371784bf0258.tar.gz bcm5719-llvm-3f9794f288d89d33fe42e89cdf57371784bf0258.zip |
Factor out the default recovery handling.
The default handling is extended to properly create member expressions
and Objective-C ivar references.
Also detect and reject cases where multiple corrections have identical
correction distances and are valid, instead of suggesting the first one
that is found.
llvm-svn: 222462
Diffstat (limited to 'clang/lib/Sema/SemaExprCXX.cpp')
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 91 |
1 files changed, 77 insertions, 14 deletions
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 02a657fd257..abd5b9d471b 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -5920,6 +5920,60 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( CurrentLSI->clearPotentialCaptures(); } +static ExprResult attemptRecovery(Sema &SemaRef, + const TypoCorrectionConsumer &Consumer, + TypoCorrection TC) { + LookupResult R(SemaRef, Consumer.getLookupResult().getLookupNameInfo(), + Consumer.getLookupResult().getLookupKind()); + const CXXScopeSpec *SS = Consumer.getSS(); + CXXScopeSpec NewSS; + + // Use an approprate CXXScopeSpec for building the expr. + if (auto *NNS = TC.getCorrectionSpecifier()) + NewSS.MakeTrivial(SemaRef.Context, NNS, TC.getCorrectionRange()); + else if (SS && !TC.WillReplaceSpecifier()) + NewSS = *SS; + + if (auto *ND = TC.getCorrectionDecl()) { + R.addDecl(ND); + if (ND->isCXXClassMember()) { + // Figure out the correct naming class to ad to the LookupResult. + CXXRecordDecl *Record = nullptr; + if (auto *NNS = TC.getCorrectionSpecifier()) + Record = NNS->getAsType()->getAsCXXRecordDecl(); + if (!Record) + Record = cast<CXXRecordDecl>(ND->getDeclContext()->getRedeclContext()); + R.setNamingClass(Record); + + // Detect and handle the case where the decl might be an implicit + // member. + bool MightBeImplicitMember; + if (!Consumer.isAddressOfOperand()) + MightBeImplicitMember = true; + else if (!NewSS.isEmpty()) + MightBeImplicitMember = false; + else if (R.isOverloadedResult()) + MightBeImplicitMember = false; + else if (R.isUnresolvableResult()) + MightBeImplicitMember = true; + else + MightBeImplicitMember = isa<FieldDecl>(ND) || + isa<IndirectFieldDecl>(ND) || + isa<MSPropertyDecl>(ND); + + if (MightBeImplicitMember) + return SemaRef.BuildPossibleImplicitMemberExpr( + NewSS, /*TemplateKWLoc*/ SourceLocation(), R, + /*TemplateArgs*/ nullptr); + } else if (auto *Ivar = dyn_cast<ObjCIvarDecl>(ND)) { + return SemaRef.LookupInObjCMethod(R, Consumer.getScope(), + Ivar->getIdentifier()); + } + } + + return SemaRef.BuildDeclarationNameExpr(NewSS, R, false); +} + namespace { class TransformTypos : public TreeTransform<TransformTypos> { typedef TreeTransform<TransformTypos> BaseTransform; @@ -6049,21 +6103,30 @@ public: // For the first TypoExpr and an uncached TypoExpr, find the next likely // typo correction and return it. while (TypoCorrection TC = State.Consumer->getNextCorrection()) { - ExprResult NE; - if (State.RecoveryHandler) { - NE = State.RecoveryHandler(SemaRef, E, TC); - } else { - LookupResult R(SemaRef, - State.Consumer->getLookupResult().getLookupNameInfo(), - State.Consumer->getLookupResult().getLookupKind()); - if (!TC.isKeyword()) - R.addDecl(TC.getCorrectionDecl()); - NE = SemaRef.BuildDeclarationNameExpr(CXXScopeSpec(), R, false); - } - assert(!NE.isUnset() && - "Typo was transformed into a valid-but-null ExprResult"); - if (!NE.isInvalid()) + ExprResult NE = State.RecoveryHandler ? + State.RecoveryHandler(SemaRef, E, TC) : + attemptRecovery(SemaRef, *State.Consumer, TC); + if (!NE.isInvalid()) { + // Check whether there is a second viable correction with the same edit + // distance--in which case do not suggest anything since both are + // equally good candidates for correcting the typo. + Sema::SFINAETrap LocalTrap(SemaRef); + TypoCorrection Next; + while ((Next = State.Consumer->peekNextCorrection()) && + Next.getEditDistance(false) == TC.getEditDistance(false)) { + ExprResult Res = + State.RecoveryHandler + ? State.RecoveryHandler(SemaRef, E, Next) + : attemptRecovery(SemaRef, *State.Consumer, Next); + if (!Res.isInvalid()) { + NE = ExprError(); + State.Consumer->getNextCorrection(); + } + } + assert(!NE.isUnset() && + "Typo was transformed into a valid-but-null ExprResult"); return CacheEntry = NE; + } } return CacheEntry = ExprError(); } |