summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaExprCXX.cpp
diff options
context:
space:
mode:
authorKaelyn Takata <rikka@google.com>2014-10-27 18:07:37 +0000
committerKaelyn Takata <rikka@google.com>2014-10-27 18:07:37 +0000
commit4a3c68bb85aa70525f30ad2970272b908bf8359d (patch)
tree813c088326d0369934ea9820ea43beae671ce44a /lib/Sema/SemaExprCXX.cpp
parentcd318ced609f3e2e2aab80a1904d59df32a97271 (diff)
Start adding the infrastructure for handling TypoExprs.
Part of the infrastructure is a map from a TypoExpr to the Sema-specific state needed to correct it, along with helpers to ease dealing with the state. The the typo count is propagated up the stack of ExpressionEvaluationContextRecords when one is popped off of to avoid accidentally dropping TypoExprs on the floor. For example, the attempted correction of g() in test/CXX/class/class.mem/p5-0x.cpp happens with an ExpressionEvaluationContextRecord that is popped off the stack prior to ActOnFinishFullExpr being called and the tree transform for TypoExprs being run. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@220695 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaExprCXX.cpp')
-rw-r--r--lib/Sema/SemaExprCXX.cpp114
1 files changed, 114 insertions, 0 deletions
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index d79dcca1e9..861fb068e7 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
+#include "TreeTransform.h"
#include "TypeLocBuilder.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTLambda.h"
@@ -5914,6 +5915,103 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
CurrentLSI->clearPotentialCaptures();
}
+namespace {
+class TransformTypos : public TreeTransform<TransformTypos> {
+ typedef TreeTransform<TransformTypos> BaseTransform;
+
+ llvm::SmallSetVector<TypoExpr *, 2> TypoExprs;
+ llvm::SmallDenseMap<TypoExpr *, ExprResult, 2> TransformCache;
+
+ /// \brief Emit diagnostics for all of the TypoExprs encountered.
+ /// If the TypoExprs were successfully corrected, then the diagnostics should
+ /// suggest the corrections. Otherwise the diagnostics will not suggest
+ /// anything (having been passed an empty TypoCorrection).
+ void EmitAllDiagnostics() {
+ for (auto E : TypoExprs) {
+ TypoExpr *TE = cast<TypoExpr>(E);
+ auto &State = SemaRef.getTypoExprState(TE);
+ if (State.DiagHandler)
+ State.DiagHandler(State.Consumer->getCurrentCorrection());
+ SemaRef.clearDelayedTypo(TE);
+ }
+ }
+
+ /// \brief If corrections for the first TypoExpr have been exhausted for a
+ /// given combination of the other TypoExprs, retry those corrections against
+ /// the next combination of substitutions for the other TypoExprs by advancing
+ /// to the next potential correction of the second TypoExpr. For the second
+ /// and subsequent TypoExprs, if its stream of corrections has been exhausted,
+ /// the stream is reset and the next TypoExpr's stream is advanced by one (a
+ /// TypoExpr's correction stream is advanced by removing the TypoExpr from the
+ /// TransformCache). Returns true if there is still any untried combinations
+ /// of corrections.
+ bool CheckAndAdvanceTypoExprCorrectionStreams() {
+ for (auto TE : TypoExprs) {
+ auto &State = SemaRef.getTypoExprState(TE);
+ TransformCache.erase(TE);
+ if (!State.Consumer->finished())
+ return true;
+ State.Consumer->resetCorrectionStream();
+ }
+ return false;
+ }
+
+public:
+ TransformTypos(Sema &SemaRef) : BaseTransform(SemaRef) {}
+
+ ExprResult TransformLambdaExpr(LambdaExpr *E) { return Owned(E); }
+
+ ExprResult Transform(Expr *E) {
+ ExprResult res;
+ bool error = false;
+ while (true) {
+ Sema::SFINAETrap Trap(SemaRef);
+ res = TransformExpr(E);
+ error = Trap.hasErrorOccurred();
+
+ // Exit if either the transform was valid or if there were no TypoExprs
+ // to transform that still have any untried correction candidates..
+ if (!(error || res.isInvalid()) ||
+ !CheckAndAdvanceTypoExprCorrectionStreams())
+ break;
+ }
+
+ EmitAllDiagnostics();
+
+ return res;
+ }
+
+ ExprResult TransformTypoExpr(TypoExpr *E) {
+ // If the TypoExpr hasn't been seen before, record it. Otherwise, return the
+ // cached transformation result if there is one and the TypoExpr isn't the
+ // first one that was encountered.
+ auto &CacheEntry = TransformCache[E];
+ if (!TypoExprs.insert(E) && !CacheEntry.isUnset()) {
+ return CacheEntry;
+ }
+
+ auto &State = SemaRef.getTypoExprState(E);
+ assert(State.Consumer && "Cannot transform a cleared TypoExpr");
+
+ // For the first TypoExpr and an uncached TypoExpr, find the next likely
+ // typo correction and return it.
+ while (TypoCorrection TC = State.Consumer->getNextCorrection()) {
+ LookupResult R(SemaRef,
+ State.Consumer->getLookupResult().getLookupNameInfo(),
+ State.Consumer->getLookupResult().getLookupKind());
+ if (!TC.isKeyword())
+ R.addDecl(TC.getCorrectionDecl());
+ ExprResult NE =
+ SemaRef.BuildDeclarationNameExpr(CXXScopeSpec(), R, false);
+ assert(!NE.isUnset() &&
+ "Typo was transformed into a valid-but-null ExprResult");
+ if (!NE.isInvalid())
+ return CacheEntry = NE;
+ }
+ return CacheEntry = ExprError();
+ }
+};
+}
ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
bool DiscardedValue,
@@ -5961,6 +6059,22 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
return ExprError();
}
+ // If the current evaluation context indicates there are uncorrected typos
+ // and the current expression isn't guaranteed to not have typos, try to
+ // resolve any TypoExpr nodes that might be in the expression.
+ if (ExprEvalContexts.back().NumTypos &&
+ (FullExpr.get()->isTypeDependent() ||
+ FullExpr.get()->isValueDependent() ||
+ FullExpr.get()->isInstantiationDependent())) {
+ auto TyposResolved = DelayedTypos.size();
+ FullExpr = TransformTypos(*this).Transform(FullExpr.get());
+ TyposResolved -= DelayedTypos.size();
+ if (TyposResolved)
+ ExprEvalContexts.back().NumTypos -= TyposResolved;
+ if (FullExpr.isInvalid())
+ return ExprError();
+ }
+
CheckCompletedExpr(FullExpr.get(), CC, IsConstexpr);
// At the end of this full expression (which could be a deeply nested