-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Sema] Fix fixit cast printing inside macros #66853
Conversation
@llvm/pr-subscribers-clang Changes
Fixes #63462 Full diff: https://github.com/llvm/llvm-project/pull/66853.diff 2 Files Affected:
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index fad70223362eddd..4fbdb315ddc87b4 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -11470,7 +11470,10 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
Hints.push_back(
FixItHint::CreateInsertion(E->getBeginLoc(), CastFix.str()));
- SourceLocation After = S.getLocForEndOfToken(E->getEndLoc());
+ // We don't use getLocForEndOfToken because it returns invalid source
+ // locations for macro expansions (by design).
+ SourceLocation After = E->getEndLoc().getLocWithOffset(
+ Lexer::MeasureTokenLength(E->getEndLoc(), S.SourceMgr, S.LangOpts));
Hints.push_back(FixItHint::CreateInsertion(After, ")"));
}
diff --git a/clang/test/FixIt/format.cpp b/clang/test/FixIt/format.cpp
index 9cc4c2600eb6670..46a0a0a11cc850a 100644
--- a/clang/test/FixIt/format.cpp
+++ b/clang/test/FixIt/format.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -Wformat %s 2>&1 | FileCheck %s
extern "C" int printf(const char *, ...);
+#define LOG(...) printf(__VA_ARGS__)
namespace N {
enum class E { One };
@@ -16,4 +17,8 @@ void a() {
printf("%hu", N::E::One);
// CHECK: "static_cast<unsigned short>("
+
+ LOG("%d", N::E::One); // expected-warning{{format specifies type 'int' but the argument has type 'N::E'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:13}:"static_cast<int>("
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:22-[[@LINE-2]]:22}:")"
}
|
Since this is a diagnostic improvement, can you post the before and after output of an example? |
I updated the PR description with an example. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome! I couldn't figure this out when I looked :)
`Lexer::getLocForEndOfToken` is documented as returning an invalid source location when the end of the token is inside a macro expansion. We don't want that for this particular application, so just calculate the end location directly instead. Before this, format fix-its would omit the closing parenthesis (thus producing invalid code) for macros, e.g.: ``` $ cat format.cpp extern "C" int printf(const char *, ...); enum class Foo { Bar }; void f(Foo foo) { LOG("%d\n", foo); } $ clang -fsyntax-only format.cpp format.cpp:4:29: warning: format specifies type 'int' but the argument has type 'Foo' [-Wformat] 4 | void f(Foo f) { LOG("%d\n", f); } | ~~ ^ | static_cast<int>( format.cpp:3:25: note: expanded from macro 'LOG' 3 | #define LOG(...) printf(__VA_ARGS__) | ^~~~~~~~~~~ 1 warning generated. ``` We now emit a valid fix-it: ``` $ clang -fsyntax-only format.cpp format.cpp:4:31: warning: format specifies type 'int' but the argument has type 'Foo' [-Wformat] 4 | void f(Foo foo) { LOG("%d\n", foo); } | ~~ ^~~ | static_cast<int>( ) format.cpp:3:25: note: expanded from macro 'LOG' 3 | #define LOG(...) printf(__VA_ARGS__) | ^~~~~~~~~~~ 1 warning generated. ``` Fixes llvm#63462
`Lexer::getLocForEndOfToken` is documented as returning an invalid source location when the end of the token is inside a macro expansion. We don't want that for this particular application, so just calculate the end location directly instead. Before this, format fix-its would omit the closing parenthesis (thus producing invalid code) for macros, e.g.: ``` $ cat format.cpp extern "C" int printf(const char *, ...); enum class Foo { Bar }; #define LOG(...) printf(__VA_ARGS__) void f(Foo foo) { LOG("%d\n", foo); } $ clang -fsyntax-only format.cpp format.cpp:4:29: warning: format specifies type 'int' but the argument has type 'Foo' [-Wformat] 4 | void f(Foo f) { LOG("%d\n", f); } | ~~ ^ | static_cast<int>( format.cpp:3:25: note: expanded from macro 'LOG' 3 | #define LOG(...) printf(__VA_ARGS__) | ^~~~~~~~~~~ 1 warning generated. ``` We now emit a valid fix-it: ``` $ clang -fsyntax-only format.cpp format.cpp:4:31: warning: format specifies type 'int' but the argument has type 'Foo' [-Wformat] 4 | void f(Foo foo) { LOG("%d\n", foo); } | ~~ ^~~ | static_cast<int>( ) format.cpp:3:25: note: expanded from macro 'LOG' 3 | #define LOG(...) printf(__VA_ARGS__) | ^~~~~~~~~~~ 1 warning generated. ``` Fixes #63462 (cherry picked from commit 61c5ad8)
Set the correct end for the CastOperation.OpRange in CXXFunctionalCastExpr. Now it is the closing bracket's location instead of the parameter's location. This can lead to better highlight in the diagnostics. Similar to #66853 Before: warning: cast from 'long (*)(const int &)' to 'decltype(fun_ptr)' (aka 'long (*)(int &)') converts to incompatible function type [-Wcast-function-type-strict] 24 | return decltype(fun_ptr)( f_ptr /*comment*/); | ^~~~~~~~~~~~~~~~~~~~~~~~ After: warning: cast from 'long (*)(const int &)' to 'decltype(fun_ptr)' (aka 'long (*)(int &)') converts to incompatible function type [-Wcast-function-type-strict] 24 | return decltype(fun_ptr)( f_ptr /*comment*/); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Reviewed By: AaronBallman, tbaederr GitHub PR: #69480
Lexer::getLocForEndOfToken
is documented as returning an invalidsource location when the end of the token is inside a macro expansion.
We don't want that for this particular application, so just calculate
the end location directly instead.
Before this, format fix-its would omit the closing parenthesis (thus
producing invalid code) for macros, e.g.:
We now emit a valid fix-it:
Fixes #63462