[clang-tools-extra] [clang-tidy] Add fix-its to `avoid-return-with-void-value` check (PR #81420)

Danny Mösch via cfe-commits cfe-commits at lists.llvm.org
Mon Feb 19 10:08:12 PST 2024


https://github.com/SimplyDanny updated https://github.com/llvm/llvm-project/pull/81420

>From 71a7da3cd7035452685ce926b49d8329fbd183fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sun, 11 Feb 2024 17:04:12 +0100
Subject: [PATCH] [clang-tidy] Add fix-its to `avoid-return-with-void-value`
 check

---
 .../AvoidReturnWithVoidValueCheck.cpp         | 41 +++++++++++++++----
 clang-tools-extra/docs/ReleaseNotes.rst       |  4 ++
 .../avoid-return-with-void-value.cpp          | 14 ++++++-
 3 files changed, 49 insertions(+), 10 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
index e3400f614fa564..1202eeebd06674 100644
--- a/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
@@ -10,16 +10,18 @@
 #include "clang/AST/Stmt.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Lex/Lexer.h"
 
 using namespace clang::ast_matchers;
 
 namespace clang::tidy::readability {
 
-static constexpr auto IgnoreMacrosName = "IgnoreMacros";
-static constexpr auto IgnoreMacrosDefault = true;
+static constexpr char IgnoreMacrosName[] = "IgnoreMacros";
+static const bool IgnoreMacrosDefault = true;
 
-static constexpr auto StrictModeName = "StrictMode";
-static constexpr auto StrictModeDefault = true;
+static constexpr char StrictModeName[] = "StrictMode";
+static const bool StrictModeDefault = true;
 
 AvoidReturnWithVoidValueCheck::AvoidReturnWithVoidValueCheck(
     StringRef Name, ClangTidyContext *Context)
@@ -40,12 +42,35 @@ void AvoidReturnWithVoidValueCheck::registerMatchers(MatchFinder *Finder) {
 void AvoidReturnWithVoidValueCheck::check(
     const MatchFinder::MatchResult &Result) {
   const auto *VoidReturn = Result.Nodes.getNodeAs<ReturnStmt>("void_return");
-  if (IgnoreMacros && VoidReturn->getBeginLoc().isMacroID())
+  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;
-  diag(VoidReturn->getBeginLoc(), "return statement within a void function "
-                                  "should not have a specified return value");
+  }
+  DiagnosticBuilder Diag = diag(VoidReturn->getBeginLoc(),
+                                "return statement within a void function "
+                                "should not have a specified return value");
+  std::optional<Token> SemicolonPos =
+      Lexer::findNextToken(VoidReturn->getRetValue()->getEndLoc(),
+                           *Result.SourceManager, getLangOpts());
+  if (!SemicolonPos) {
+    return;
+  }
+  const StringRef ReturnExpr =
+      Lexer::getSourceText(CharSourceRange::getTokenRange(
+                               VoidReturn->getRetValue()->getSourceRange()),
+                           *Result.SourceManager, getLangOpts());
+  std::string Replacement = (ReturnExpr + "; return;").str();
+  if (!SurroundingBlock) {
+    Replacement = "{" + Replacement + "}";
+  }
+  Diag << FixItHint::CreateReplacement(
+      CharSourceRange::getTokenRange(VoidReturn->getBeginLoc(),
+                                     SemicolonPos->getEndLoc()),
+      Replacement);
 }
 
 void AvoidReturnWithVoidValueCheck::storeOptions(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index a0b9fcfe0d7774..5e614ad3483828 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -179,6 +179,10 @@ Changes in existing checks
   <clang-tidy/checks/modernize/use-override>` check to also remove any trailing
   whitespace when deleting the ``virtual`` keyword.
 
+- Improved :doc:`readability-avoid-return-with-void-value
+  <clang-tidy/checks/readability/avoid-return-with-void-value>` check by adding
+  fix-its.
+
 - Improved :doc:`readability-implicit-bool-conversion
   <clang-tidy/checks/readability/implicit-bool-conversion>` check to provide
   valid fix suggestions for ``static_cast`` without a preceding space and
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;
 }



More information about the cfe-commits mailing list