From: Douglas Gregor Date: Fri, 1 Jan 2010 00:03:05 +0000 (+0000) Subject: Typo correction for C99 designated field initializers, e.g., X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c171e3b192a372669cf622ff0b6a847f8e5b4220;p=clang Typo correction for C99 designated field initializers, e.g., test/FixIt/typo.c:19:4: error: field designator 'bunds' does not refer to any field in type 'struct Window'; did you mean 'bounds'? .bunds. ^~~~~ bounds git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@92376 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 41f8c4c356..155633b08f 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2566,6 +2566,9 @@ def err_no_member_template_suggest : Error< def err_mem_init_not_member_or_class_suggest : Error< "initializer %0 does not name a non-static data member or base " "class; did you mean the %select{base class|member}1 %2?">; +def err_field_designator_unknown_suggest : Error< + "field designator %0 does not refer to any field in type %1; did you mean " + "%2?">; } diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 9c85ceca74..3ef51561ff 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -16,6 +16,7 @@ //===----------------------------------------------------------------------===// #include "SemaInit.h" +#include "Lookup.h" #include "Sema.h" #include "clang/Parse/Designator.h" #include "clang/AST/ASTContext.h" @@ -1286,22 +1287,33 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, // may find nothing, or may find a member of an anonymous // struct/union. DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName); + FieldDecl *ReplacementField = 0; if (Lookup.first == Lookup.second) { - // Name lookup didn't find anything. - SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown) - << FieldName << CurrentObjectType; - ++Index; - return true; - } else if (!KnownField && isa(*Lookup.first) && - cast((*Lookup.first)->getDeclContext()) - ->isAnonymousStructOrUnion()) { - // Handle an field designator that refers to a member of an - // anonymous struct or union. - ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, - cast(*Lookup.first), - Field, FieldIndex); - D = DIE->getDesignator(DesigIdx); - } else { + // Name lookup didn't find anything. Determine whether this + // was a typo for another field name. + LookupResult R(SemaRef, FieldName, D->getFieldLoc(), + Sema::LookupMemberName); + if (SemaRef.CorrectTypo(R, /*Scope=*/0, /*SS=*/0, RT->getDecl()) && + (ReplacementField = R.getAsSingle()) && + ReplacementField->getDeclContext()->getLookupContext() + ->Equals(RT->getDecl())) { + SemaRef.Diag(D->getFieldLoc(), + diag::err_field_designator_unknown_suggest) + << FieldName << CurrentObjectType << R.getLookupName() + << CodeModificationHint::CreateReplacement(D->getFieldLoc(), + R.getLookupName().getAsString()); + } else { + SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown) + << FieldName << CurrentObjectType; + ++Index; + return true; + } + } else if (!KnownField) { + // Determine whether we found a field at all. + ReplacementField = dyn_cast(*Lookup.first); + } + + if (!ReplacementField) { // Name lookup found something, but it wasn't a field. SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield) << FieldName; @@ -1310,6 +1322,32 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, ++Index; return true; } + + if (!KnownField && + cast((ReplacementField)->getDeclContext()) + ->isAnonymousStructOrUnion()) { + // Handle an field designator that refers to a member of an + // anonymous struct or union. + ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, + ReplacementField, + Field, FieldIndex); + D = DIE->getDesignator(DesigIdx); + } else if (!KnownField) { + // The replacement field comes from typo correction; find it + // in the list of fields. + FieldIndex = 0; + Field = RT->getDecl()->field_begin(); + for (; Field != FieldEnd; ++Field) { + if (Field->isUnnamedBitfield()) + continue; + + if (ReplacementField == *Field || + Field->getIdentifier() == ReplacementField->getIdentifier()) + break; + + ++FieldIndex; + } + } } else if (!KnownField && cast((*Field)->getDeclContext()) ->isAnonymousStructOrUnion()) { diff --git a/test/FixIt/typo.c b/test/FixIt/typo.c new file mode 100644 index 0000000000..0777551780 --- /dev/null +++ b/test/FixIt/typo.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -fixit -o - | %clang_cc1 -fsyntax-only -pedantic -Werror -x c - +struct Point { + float x, y; +}; + +struct Rectangle { + struct Point top_left, bottom_right; +}; + +enum Color { Red, Green, Blue }; + +struct Window { + struct Rectangle bounds; + enum Color color; +}; + +struct Window window = { + .bunds. // expected-error{{field designator 'bunds' does not refer to any field in type 'struct Window'; did you mean 'bounds'?}} + topleft.x = 3.14, // expected-error{{field designator 'topleft' does not refer to any field in type 'struct Rectangle'; did you mean 'top_left'?}} + 2.71818, 5.0, 6.0, Red +};