]> granicus.if.org Git - clang/commitdiff
Properly correct initializer expressions based on whether they would be valid.
authorKaelyn Takata <rikka@google.com>
Fri, 21 Nov 2014 18:48:00 +0000 (18:48 +0000)
committerKaelyn Takata <rikka@google.com>
Fri, 21 Nov 2014 18:48:00 +0000 (18:48 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@222550 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaDecl.cpp
test/SemaCXX/typo-correction-delayed.cpp

index d44f14177624b257782db2b5e3fe095449e8e9e1..08f5c3c8b8a7084447f78ce2334e7d07693ce351 100644 (file)
@@ -8799,6 +8799,23 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
       Args = MultiExprArg(CXXDirectInit->getExprs(),
                           CXXDirectInit->getNumExprs());
 
+    // Try to correct any TypoExprs if there might be some in the initialization
+    // arguments (TypoExprs are marked as type-dependent).
+    // TODO: Handle typo correction when there's more than one argument?
+    if (Args.size() == 1 && Expr::hasAnyTypeDependentArguments(Args)) {
+      ExprResult Res =
+          CorrectDelayedTyposInExpr(Args[0], [this, Entity, Kind](Expr *E) {
+            InitializationSequence Init(*this, Entity, Kind, MultiExprArg(E));
+            return Init.Failed() ? ExprError() : E;
+          });
+      if (Res.isInvalid()) {
+        VDecl->setInvalidDecl();
+        return;
+      }
+      if (Res.get() != Args[0])
+        Args[0] = Res.get();
+    }
+
     InitializationSequence InitSeq(*this, Entity, Kind, Args);
     ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT);
     if (Result.isInvalid()) {
index c82f865a863e6f7f3f9b97eb3c7fed39f539df60..124f0ec2a1ca202f5771c057ab337cb2acd1f88f 100644 (file)
@@ -59,3 +59,37 @@ void testExprFilter(Item *i) {
   Item *j;
   j = i->Next();  // expected-error {{no member named 'Next' in 'Item'; did you mean 'next'?}}
 }
+
+// Test that initializer expressions are handled correctly and that the type
+// being initialized is taken into account when choosing a correction.
+namespace initializerCorrections {
+struct Node {
+  string text() const;
+  // Node* Next() is not implemented yet
+};
+void f(Node *node) {
+  // text is only an edit distance of 1 from Next, but would trigger type
+  // conversion errors if used in this initialization expression.
+  Node *next = node->Next();  // expected-error-re {{no member named 'Next' in 'initializerCorrections::Node'{{$}}}}
+}
+
+struct LinkedNode {
+  LinkedNode* next();  // expected-note {{'next' declared here}}
+  string text() const;
+};
+void f(LinkedNode *node) {
+  // text and next are equidistant from Next, but only one results in a valid
+  // initialization expression.
+  LinkedNode *next = node->Next();  // expected-error {{no member named 'Next' in 'initializerCorrections::LinkedNode'; did you mean 'next'?}}
+}
+
+struct NestedNode {
+  NestedNode* Nest();
+  NestedNode* next();
+  string text() const;
+};
+void f(NestedNode *node) {
+  // There are two equidistant, usable corrections for Next: next and Nest
+  NestedNode *next = node->Next();  // expected-error-re {{no member named 'Next' in 'initializerCorrections::NestedNode'{{$}}}}
+}
+}