[cfe-commits] [Patch] Suggest typo corrections for implicit function decls
David Blaikie
dblaikie at gmail.com
Fri Dec 2 15:56:05 PST 2011
On Fri, Dec 2, 2011 at 3:09 PM, Richard Smith <richard at metafoo.co.uk> wrote:
> Hi Hans,
>
> On Sat, November 26, 2011 19:29, Hans Wennborg wrote:
>> I noticed that C programmers don't get to enjoy all of Clang's typo
>> corrections: a mistyped function call becomes an implicit function
>> declaration (with a warning). The attached patch adds typo correction to the
>> already existing warnings.
>>
>> Please take a look and let me know if it's okay for me to land this.
>
> Sorry for the delay. Some comments below.
>
> diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
> index cd2f071..4d45e32 100644
> --- a/lib/Sema/SemaDecl.cpp
> +++ b/lib/Sema/SemaDecl.cpp
> @@ -7262,13 +7262,49 @@ NamedDecl
> *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
> return Pos->second;
> }
>
> + // See if we can find a typo correction.
> + TypoCorrection Corrected;
> + FunctionDecl* Func = NULL;
>
> Please put the space to the right of the *, not to the left. Also, the null
> pointer constant is written as 0 more frequently than as NULL in Sema.
>
> + std::string CorrectedStr;
> + std::string CorrectedQuotedStr;
> + if (S && (Corrected = CorrectTypo(DeclarationNameInfo(&II, Loc),
> + LookupOrdinaryName, S, 0))) {
> + // Since this is an implicit function declaration, we are only
> + // interested in a potential typo for a function name.
> + if ((Func = dyn_cast_or_null<FunctionDecl>(
> + Corrected.getCorrectionDecl()))) {
> + CorrectedStr = Corrected.getAsString(getLangOptions());
> + CorrectedQuotedStr = Corrected.getQuoted(getLangOptions());
> + }
> + }
> +
> // Extension in C99. Legal in C90, but warn about it.
> - if (II.getName().startswith("__builtin_"))
> - Diag(Loc, diag::warn_builtin_unknown) << &II;
> - else if (getLangOptions().C99)
> - Diag(Loc, diag::ext_implicit_function_decl) << &II;
> - else
> - Diag(Loc, diag::warn_implicit_function_decl) << &II;
> + // If we found a typo correction, then suggest that.
> + if (Func) {
> + unsigned diagnostic_kind;
> + if (II.getName().startswith("__builtin_"))
> + diagnostic_kind = diag::warn_builtin_unknown_suggest;
> + else if (getLangOptions().C99)
> + diagnostic_kind = diag::ext_implicit_function_decl_suggest;
> + else
> + diagnostic_kind = diag::warn_implicit_function_decl_suggest;
> +
> + Diag(Loc, diagnostic_kind) << &II << CorrectedQuotedStr
> + << FixItHint::CreateReplacement(Loc, CorrectedStr);
>
> Please move this fix-it to a separate note (at least for the implicit function
> declaration case -- see below). When a fix-it is issued on a warning or an
> error, we must recover as if the fixed code had been parsed (and for a
> warning, this essentially means the fix-it must not change the semantics).
I don't believe this can be/is a requirement for warnings, is it?
Otherwise most fixits on warnings wouldn't be applicable (unless they
were just fixits to suppress the warning but not change the
semantics). I believe that "recover exactly as typed" requirement only
exists for fixits on errors.
> +
> + if (Func->getLocation().isValid())
> + Diag(Func->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr;
> + } else {
> + unsigned diagnostic_kind;
> + if (II.getName().startswith("__builtin_"))
> + diagnostic_kind = diag::warn_builtin_unknown;
> + else if (getLangOptions().C99)
> + diagnostic_kind = diag::ext_implicit_function_decl;
> + else
> + diagnostic_kind = diag::warn_implicit_function_decl;
> +
> + Diag(Loc, diagnostic_kind) << &II;
> + }
>
> // Set a Declarator for the implicit definition: int foo();
> const char *Dummy;
> diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c
> index 5fc48cd..87a982f 100644
> --- a/test/Misc/warning-flags.c
> +++ b/test/Misc/warning-flags.c
> @@ -17,7 +17,7 @@ This test serves two purposes:
>
> The list of warnings below should NEVER grow. It should gradually shrink to 0.
>
> -CHECK: Warnings without flags (274):
> +CHECK: Warnings without flags (275):
>
> New warnings without flags should not be added (not even if you're just
> splitting a warning in two -- please add a flag; we all have taxes to pay).
> However, it strikes me that a Warning, DefaultError message with no -W flag,
> like this one, is a strange construct indeed, and it should probably simply be
> changed into an Error. With that done, you can keep the fix-it on the error
> for the __builtin_ case, if you also recover as if the user had typed the
> correct builtin name.
>
> CHECK-NEXT: ext_anon_param_requires_type_specifier
> CHECK-NEXT: ext_anonymous_struct_union_qualified
> CHECK-NEXT: ext_array_init_copy
> @@ -129,6 +129,7 @@ CHECK-NEXT: warn_bitfield_width_exceeds_type_size
> CHECK-NEXT: warn_bool_switch_condition
> CHECK-NEXT: warn_braces_around_scalar_init
> CHECK-NEXT: warn_builtin_unknown
> +CHECK-NEXT: warn_builtin_unknown_suggest
> CHECK-NEXT: warn_c_kext
> CHECK-NEXT: warn_call_to_pure_virtual_member_function_from_ctor_dtor
> CHECK-NEXT: warn_call_wrong_number_of_arguments
> diff --git a/test/Sema/builtins.c b/test/Sema/builtins.c
> index 64efefc..92a49bd 100644
> --- a/test/Sema/builtins.c
> +++ b/test/Sema/builtins.c
> @@ -1,4 +1,4 @@
> -// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -triple=i686-apple-darwin9
> +// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -fno-spell-checking
> -triple=i686-apple-darwin9
>
> Rather than turning off spell-checking, it'd be better to update the test to
> expect the new output (and add more cases here if we've lost some coverage).
>
> // This test needs to set the target because it uses __builtin_ia32_vec_ext_v4si
>
> int test1(float a, int b) {
> diff --git a/test/Sema/implicit-decl.c b/test/Sema/implicit-decl.c
> index f455977..f4b9016 100644
> --- a/test/Sema/implicit-decl.c
> +++ b/test/Sema/implicit-decl.c
> @@ -3,6 +3,8 @@
> typedef int int32_t;
> typedef unsigned char Boolean;
>
> +extern int printf(__const char *__restrict __format, ...); //
> expected-note{{'printf' declared here}}
> +
> void func() {
> int32_t *vector[16];
> const char compDesc[16 + 1];
> @@ -10,6 +12,10 @@ void func() {
> if (_CFCalendarDecomposeAbsoluteTimeV(compDesc, vector, compCount)) { //
> expected-note {{previous implicit declaration is here}} \
> expected-warning {{implicit declaration of function
> '_CFCalendarDecomposeAbsoluteTimeV' is invalid in C99}}
> }
> +
> + printg("Hello, World!\n"); // expected-warning{{implicit declaration of
> function
> 'printg' is invalid in C99; did you mean 'printf'?}}
> +
> + __builtin_is_les(1, 3); // expected-error{{use of unknown builtin
> '__builtin_is_les'; did you mean '__builtin_is_less'?}}
> }
> Boolean _CFCalendarDecomposeAbsoluteTimeV(const char *componentDesc, int32_t
> **vector, int32_t count) { // expected-error{{conflicting types for
> '_CFCalendarDecomposeAbsoluteTimeV'}}
> return 0;
>
> Could you add a test for the C89 case, please?
>
> Thanks,
> Richard
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list