Index: clang-tidy/misc/StaticAssertCheck.cpp =================================================================== --- clang-tidy/misc/StaticAssertCheck.cpp +++ clang-tidy/misc/StaticAssertCheck.cpp @@ -27,10 +27,9 @@ : ClangTidyCheck(Name, Context) {} void StaticAssertCheck::registerMatchers(MatchFinder *Finder) { - // FIXME: I don't see why this checker couldn't also be interesting for - // _Static_assert in C11, or static_assert if has been included, - // but it is currently only enabled for C++11. Investigate. - if (getLangOpts().CPlusPlus11) { + // This checker only makes sense for languages that have static assertion + // capabilities: C++11 and C11. + if (getLangOpts().CPlusPlus11 || getLangOpts().C11) { auto IsAlwaysFalse = expr(ignoringParenImpCasts( expr(anyOf(boolLiteral(equals(false)), integerLiteral(equals(0)), nullPtrLiteralExpr(), gnuNullExpr())) @@ -108,6 +107,14 @@ return; } + // FIXME: static_assert is fine in C11 if the macro is defined, otherwise we + // should suggest _Static_assert. However, there is no way to determine + // whether the macro is defined at the location of the assert without access + // to the Preprocessor instance. For right now, always suggest _Static_assert + // in C11 mode. + StringRef Replacement = + getLangOpts().C11 ? "_Static_assert" : "static_assert"; + SourceLocation AssertLoc = SM.getImmediateMacroCallerLoc(AssertExpansionLoc); SmallVector FixItHints; @@ -115,7 +122,7 @@ if (AssertLoc.isValid() && !AssertLoc.isMacroID() && (LastParenLoc = getLastParenLoc(ASTCtx, AssertLoc)).isValid()) { FixItHints.push_back( - FixItHint::CreateReplacement(SourceRange(AssertLoc), "static_assert")); + FixItHint::CreateReplacement(SourceRange(AssertLoc), Replacement)); std::string StaticAssertMSG = ", \"\""; if (AssertExprRoot) { @@ -130,8 +137,8 @@ FixItHint::CreateInsertion(LastParenLoc, StaticAssertMSG)); } - diag(AssertLoc, "found assert() that could be replaced by static_assert()") - << FixItHints; + diag(AssertLoc, "found assert() that could be replaced by %0()") + << Replacement << FixItHints; } SourceLocation StaticAssertCheck::getLastParenLoc(const ASTContext *ASTCtx, Index: test/clang-tidy/check_clang_tidy.py =================================================================== --- test/clang-tidy/check_clang_tidy.py +++ test/clang-tidy/check_clang_tidy.py @@ -38,12 +38,16 @@ sys.exit('Not enough arguments.') input_file_name = sys.argv[1] + extension = '.cpp' + if (input_file_name.endswith('.c')): + extension = '.c' + check_name = sys.argv[2] - temp_file_name = sys.argv[3] + '.cpp' + temp_file_name = sys.argv[3] + extension clang_tidy_extra_args = sys.argv[4:] if len(clang_tidy_extra_args) == 0: - clang_tidy_extra_args = ['--', '--std=c++11'] + clang_tidy_extra_args = ['--', '--std=c++11' if extension == '.cpp' else '-std=c99'] with open(input_file_name, 'r') as input_file: input_text = input_file.read() Index: test/clang-tidy/misc-static-assert-c11.c =================================================================== --- test/clang-tidy/misc-static-assert-c11.c +++ test/clang-tidy/misc-static-assert-c11.c @@ -0,0 +1,26 @@ +// RUN: %python %S/check_clang_tidy.py %s misc-static-assert %t -- -std=c11 + +void abort() {} +#ifdef NDEBUG +#define assert(x) 1 +#else +#define assert(x) \ + if (!(x)) \ + abort() +#endif + +void f(void) { + int x = 1; + assert(x == 0); + // CHECK-FIXES: {{^ }}assert(x == 0); + + #define static_assert(x, msg) _Static_assert(x, msg) + assert(11 == 5 + 6); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be + // CHECK-FIXES: {{^ }}_Static_assert(11 == 5 + 6, ""); + #undef static_assert + + assert(10 == 5 + 5); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be + // CHECK-FIXES: {{^ }}_Static_assert(10 == 5 + 5, ""); +} Index: test/clang-tidy/misc-static-assert-c99.c =================================================================== --- test/clang-tidy/misc-static-assert-c99.c +++ test/clang-tidy/misc-static-assert-c99.c @@ -0,0 +1,24 @@ +// RUN: %python %S/check_clang_tidy.py %s misc-static-assert %t -- -std=c99 + +void abort() {} +#ifdef NDEBUG +#define assert(x) 1 +#else +#define assert(x) \ + if (!(x)) \ + abort() +#endif + +void f(void) { + int x = 1; + assert(x == 0); + // CHECK-FIXES: {{^ }}assert(x == 0); + + #define static_assert(x, msg) _Static_assert(x, msg) + assert(11 == 5 + 6); + // CHECK-FIXES: {{^ }}assert(11 == 5 + 6); + #undef static_assert + + assert(10 == 5 + 5); + // CHECK-FIXES: {{^ }}assert(10 == 5 + 5); +}