-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang-tidy] Add fix-its to readability-avoid-return-with-void-value
check
#81420
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
[clang-tidy] Add fix-its to readability-avoid-return-with-void-value
check
#81420
Conversation
@llvm/pr-subscribers-clang-tools-extra Author: Danny Mösch (SimplyDanny) ChangesFull diff: https://github.com/llvm/llvm-project/pull/81420.diff 3 Files Affected:
diff --git a/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
index e3400f614fa564..1aa03fe9ba5da7 100644
--- a/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
@@ -10,6 +10,7 @@
#include "clang/AST/Stmt.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
using namespace clang::ast_matchers;
@@ -42,10 +43,28 @@ void AvoidReturnWithVoidValueCheck::check(
const auto *VoidReturn = Result.Nodes.getNodeAs<ReturnStmt>("void_return");
if (IgnoreMacros && VoidReturn->getBeginLoc().isMacroID())
return;
- if (!StrictMode && !Result.Nodes.getNodeAs<CompoundStmt>("compound_parent"))
+ const auto *SurroundingBlock =
+ Result.Nodes.getNodeAs<CompoundStmt>("compound_parent");
+ if (!StrictMode && !SurroundingBlock)
return;
+ const auto ReturnExpr =
+ Lexer::getSourceText(CharSourceRange::getTokenRange(
+ VoidReturn->getRetValue()->getSourceRange()),
+ *Result.SourceManager, getLangOpts());
+ SourceLocation SemicolonPos;
+ if (const auto NextToken =
+ Lexer::findNextToken(VoidReturn->getRetValue()->getEndLoc(),
+ *Result.SourceManager, getLangOpts()))
+ SemicolonPos = NextToken->getEndLoc();
+ auto Replacement = (ReturnExpr + "; return;").str();
+ if (!SurroundingBlock)
+ Replacement = "{" + Replacement + "}";
diag(VoidReturn->getBeginLoc(), "return statement within a void function "
- "should not have a specified return value");
+ "should not have a specified return value")
+ << FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(VoidReturn->getBeginLoc(),
+ SemicolonPos),
+ Replacement);
}
void AvoidReturnWithVoidValueCheck::storeOptions(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index ee68c8f49b3df2..bfe0e4ba2e131d 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -160,6 +160,10 @@ Changes in existing checks
`AllowStringArrays` option, enabling the exclusion of array types with deduced
length initialized from string literals.
+- Improved :doc:`readability-avoid-return-with-void-value
+ <clang-tidy/checks/readability/avoid-return-with-void-value>` check by adding
+ fix-its.
+
Removed checks
^^^^^^^^^^^^^^
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp
index f00407c99ce570..0d269ceee82bc9 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp
@@ -12,14 +12,18 @@ void f2() {
return f1();
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: f1(); return;
}
void f3(bool b) {
if (b) return f1();
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: if (b) {f1(); return;}
return f2();
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: f2(); return;
+ // CHECK-FIXES-LENIENT: f2(); return;
}
template<class T>
@@ -29,6 +33,8 @@ void f5() {
return f4<void>();
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: f4<void>(); return;
+ // CHECK-FIXES-LENIENT: f4<void>(); return;
}
void f6() { return; }
@@ -41,6 +47,8 @@ void f9() {
return (void)f7();
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: (void)f7(); return;
+ // CHECK-FIXES-LENIENT: (void)f7(); return;
}
#define RETURN_VOID return (void)1
@@ -50,12 +58,12 @@ void f10() {
// CHECK-MESSAGES-INCLUDE-MACROS: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
}
-template <typename A>
+template <typename A>
struct C {
C(A) {}
};
-template <class T>
+template <class T>
C<T> f11() { return {}; }
using VOID = void;
@@ -66,4 +74,6 @@ VOID f13() {
return f12();
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: f12(); return;
+ // CHECK-FIXES-LENIENT: f12(); return;
}
|
@llvm/pr-subscribers-clang-tidy Author: Danny Mösch (SimplyDanny) ChangesFull diff: https://github.com/llvm/llvm-project/pull/81420.diff 3 Files Affected:
diff --git a/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
index e3400f614fa564..1aa03fe9ba5da7 100644
--- a/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
@@ -10,6 +10,7 @@
#include "clang/AST/Stmt.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
using namespace clang::ast_matchers;
@@ -42,10 +43,28 @@ void AvoidReturnWithVoidValueCheck::check(
const auto *VoidReturn = Result.Nodes.getNodeAs<ReturnStmt>("void_return");
if (IgnoreMacros && VoidReturn->getBeginLoc().isMacroID())
return;
- if (!StrictMode && !Result.Nodes.getNodeAs<CompoundStmt>("compound_parent"))
+ const auto *SurroundingBlock =
+ Result.Nodes.getNodeAs<CompoundStmt>("compound_parent");
+ if (!StrictMode && !SurroundingBlock)
return;
+ const auto ReturnExpr =
+ Lexer::getSourceText(CharSourceRange::getTokenRange(
+ VoidReturn->getRetValue()->getSourceRange()),
+ *Result.SourceManager, getLangOpts());
+ SourceLocation SemicolonPos;
+ if (const auto NextToken =
+ Lexer::findNextToken(VoidReturn->getRetValue()->getEndLoc(),
+ *Result.SourceManager, getLangOpts()))
+ SemicolonPos = NextToken->getEndLoc();
+ auto Replacement = (ReturnExpr + "; return;").str();
+ if (!SurroundingBlock)
+ Replacement = "{" + Replacement + "}";
diag(VoidReturn->getBeginLoc(), "return statement within a void function "
- "should not have a specified return value");
+ "should not have a specified return value")
+ << FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(VoidReturn->getBeginLoc(),
+ SemicolonPos),
+ Replacement);
}
void AvoidReturnWithVoidValueCheck::storeOptions(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index ee68c8f49b3df2..bfe0e4ba2e131d 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -160,6 +160,10 @@ Changes in existing checks
`AllowStringArrays` option, enabling the exclusion of array types with deduced
length initialized from string literals.
+- Improved :doc:`readability-avoid-return-with-void-value
+ <clang-tidy/checks/readability/avoid-return-with-void-value>` check by adding
+ fix-its.
+
Removed checks
^^^^^^^^^^^^^^
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp
index f00407c99ce570..0d269ceee82bc9 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp
@@ -12,14 +12,18 @@ void f2() {
return f1();
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: f1(); return;
}
void f3(bool b) {
if (b) return f1();
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: if (b) {f1(); return;}
return f2();
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: f2(); return;
+ // CHECK-FIXES-LENIENT: f2(); return;
}
template<class T>
@@ -29,6 +33,8 @@ void f5() {
return f4<void>();
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: f4<void>(); return;
+ // CHECK-FIXES-LENIENT: f4<void>(); return;
}
void f6() { return; }
@@ -41,6 +47,8 @@ void f9() {
return (void)f7();
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: (void)f7(); return;
+ // CHECK-FIXES-LENIENT: (void)f7(); return;
}
#define RETURN_VOID return (void)1
@@ -50,12 +58,12 @@ void f10() {
// CHECK-MESSAGES-INCLUDE-MACROS: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
}
-template <typename A>
+template <typename A>
struct C {
C(A) {}
};
-template <class T>
+template <class T>
C<T> f11() { return {}; }
using VOID = void;
@@ -66,4 +74,6 @@ VOID f13() {
return f12();
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: f12(); return;
+ // CHECK-FIXES-LENIENT: f12(); return;
}
|
} | ||
|
||
void f3(bool b) { | ||
if (b) return f1(); | ||
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] | ||
// CHECK-FIXES: if (b) {f1(); return;} |
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.
Is it okay to assume some formatter will run afterwards to make the output readable?
@@ -12,14 +12,18 @@ void f2() { | |||
return f1(); | |||
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] | |||
// CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] | |||
// CHECK-FIXES: f1(); return; |
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.
Is an unnecessary return
okay? Otherwise, this would need an analysis that goes beyond the scope of this rule.
clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
Outdated
Show resolved
Hide resolved
clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
Outdated
Show resolved
Hide resolved
34f2445
to
b99fe4b
Compare
clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
Outdated
Show resolved
Hide resolved
b99fe4b
to
71a7da3
Compare
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.
When from functional point of view current code looks fine and could be merged, there are few improvements possible. Add also description to PR request.
Consider also ignoring return;
if this is last stmt in function.
clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
Outdated
Show resolved
Hide resolved
clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
Outdated
Show resolved
Hide resolved
clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
Outdated
Show resolved
Hide resolved
clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp
Show resolved
Hide resolved
71a7da3
to
070968b
Compare
070968b
to
91db7ba
Compare
@PiotrZSL: Friendly ping. |
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.
LGTM.
Loc = Loc.getLocWithOffset(1); | ||
|
||
for (;;) { | ||
assert(Loc.isValid()); |
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.
this probably should be an if... instead of assert
avoid-return-with-void-value
checkreadability-avoid-return-with-void-value
check
if (!SurroundingBlock) { | ||
const auto BraceInsertionHints = utils::getBraceInsertionsHints( | ||
VoidReturn, getLangOpts(), *Result.SourceManager, | ||
VoidReturn->getBeginLoc()); | ||
if (BraceInsertionHints) | ||
Diag << BraceInsertionHints.openingBraceFixIt() | ||
<< BraceInsertionHints.closingBraceFixIt(); | ||
} | ||
Diag << FixItHint::CreateRemoval(VoidReturn->getReturnLoc()); | ||
if (!Result.Nodes.getNodeAs<FunctionDecl>("function_parent") || | ||
SurroundingBlock->body_back() != VoidReturn) |
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.
Hi @SimplyDanny, we are getting a static verifier hit on this code now since there is a nullptr check of SurroundingBlock followed by a use of SurroundingBlock without a check.
It seems when there is a function parent SurroundingBlock won't be a nullptr since it will be set to the function's CompoundStmt, but that's not completely obvious to the reader of the code.
You might consider adding an assert to make it clear for anyone modifying in the future. Maybe:
const auto *FunctionParent =
Result.Nodes.getNodeAs<FunctionDecl>("function_parent");
assert((!FunctionParent || SurroundingBlock) &&
"missing surrounding block when function parent");
if (!FunctionParent || SurroundingBlock->body_back() != VoidReturn)
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.
Addressing this in #90173.
No description provided.