From: Kaelyn Takata Date: Fri, 21 Nov 2014 18:48:00 +0000 (+0000) Subject: Properly correct initializer expressions based on whether they would be valid. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b108f094f02cca962eb0bdfafc9fdd7f86ae3b93;p=clang Properly correct initializer expressions based on whether they would be valid. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@222550 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index d44f141776..08f5c3c8b8 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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()) { diff --git a/test/SemaCXX/typo-correction-delayed.cpp b/test/SemaCXX/typo-correction-delayed.cpp index c82f865a86..124f0ec2a1 100644 --- a/test/SemaCXX/typo-correction-delayed.cpp +++ b/test/SemaCXX/typo-correction-delayed.cpp @@ -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'{{$}}}} +} +}