Skip to content

[clang-tidy] modernize-use-trailing-return-type: add an option to apply to void-returning functions as well #129406

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

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

khuldraeseth
Copy link

@khuldraeseth khuldraeseth commented Mar 1, 2025

Adds an option modernize-use-trailing-return-type.WarnOnNontrailingVoid that when true enforces this check for declarations like void foo();. Default is false to preserve existing behavior.

Copy link

github-actions bot commented Mar 1, 2025

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot
Copy link
Member

llvmbot commented Mar 1, 2025

@llvm/pr-subscribers-clang-tools-extra

@llvm/pr-subscribers-clang-tidy

Author: None (khuldraeseth)

Changes

Adds an option modernize-use-trailing-return-type.EvenWhenVoid that when true enforces this check for declarations like void foo();. Default is false to preserve existing behavior.


Full diff: https://github.com/llvm/llvm-project/pull/129406.diff

5 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp (+11-5)
  • (modified) clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.h (+7-1)
  • (modified) clang-tools-extra/docs/ReleaseNotes.rst (+5)
  • (modified) clang-tools-extra/docs/clang-tidy/checks/modernize/use-trailing-return-type.rst (+8)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/modernize/use-trailing-return-type.cpp (+27-5)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp
index 9774e988d71e2..12448303fdcd8 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp
@@ -8,8 +8,10 @@
 
 #include "UseTrailingReturnTypeCheck.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Tooling/FixIt.h"
 #include "llvm/ADT/StringExtras.h"
@@ -287,7 +289,6 @@ SourceRange UseTrailingReturnTypeCheck::findReturnTypeAndCVSourceRange(
     return {};
   }
 
-
   // If the return type has no local qualifiers, it's source range is accurate.
   if (!hasAnyNestedLocalQualifiers(F.getReturnType()))
     return ReturnTypeRange;
@@ -384,10 +385,15 @@ void UseTrailingReturnTypeCheck::keepSpecifiers(
 }
 
 void UseTrailingReturnTypeCheck::registerMatchers(MatchFinder *Finder) {
-  auto F = functionDecl(
-               unless(anyOf(hasTrailingReturn(), returns(voidType()),
-                            cxxConversionDecl(), cxxMethodDecl(isImplicit()))))
-               .bind("Func");
+  const auto hasNoWrittenReturnType =
+      anyOf(cxxConversionDecl(), cxxConstructorDecl(), cxxDestructorDecl(),
+            cxxMethodDecl(isImplicit()));
+
+  const auto where = functionDecl(
+      unless(anyOf(hasTrailingReturn(), hasNoWrittenReturnType,
+                   EvenWhenVoid ? unless(anything()) : returns(voidType()))));
+
+  auto F = where.bind("Func");
 
   Finder->addMatcher(F, this);
   Finder->addMatcher(friendDecl(hasDescendant(F)).bind("Friend"), this);
diff --git a/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.h b/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.h
index 5fb6ae945f466..fdd8be285c03b 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.h
@@ -28,7 +28,8 @@ struct ClassifiedToken {
 class UseTrailingReturnTypeCheck : public ClangTidyCheck {
 public:
   UseTrailingReturnTypeCheck(StringRef Name, ClangTidyContext *Context)
-      : ClangTidyCheck(Name, Context) {}
+      : ClangTidyCheck(Name, Context),
+        EvenWhenVoid(Options.get("EvenWhenVoid", false)) {}
   bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
     return LangOpts.CPlusPlus11;
   }
@@ -39,6 +40,7 @@ class UseTrailingReturnTypeCheck : public ClangTidyCheck {
 
 private:
   Preprocessor *PP = nullptr;
+  bool const EvenWhenVoid;
 
   SourceLocation findTrailingReturnTypeSourceLocation(
       const FunctionDecl &F, const FunctionTypeLoc &FTL, const ASTContext &Ctx,
@@ -56,6 +58,10 @@ class UseTrailingReturnTypeCheck : public ClangTidyCheck {
                       SourceRange ReturnTypeCVRange, const FunctionDecl &F,
                       const FriendDecl *Fr, const ASTContext &Ctx,
                       const SourceManager &SM, const LangOptions &LangOpts);
+
+  auto storeOptions(ClangTidyOptions::OptionMap &Opts) -> void override {
+    Options.store(Opts, "EvenWhenVoid", EvenWhenVoid);
+  }
 };
 
 } // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 2dcefa2ddec83..93b2202ce8635 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -120,6 +120,11 @@ Changes in existing checks
   tolerating fix-it breaking compilation when functions is used as pointers 
   to avoid matching usage of functions within the current compilation unit.
 
+- Improved :doc:`modernize/use-trailing-return-type
+  <clang-tidy/checks/modernize/use-trailing-return-type>` check by adding the
+  option ``EvenWhenVoid`` that applies the check to ``void``-returning functions
+  that by default are excluded from this check.
+
 Removed checks
 ^^^^^^^^^^^^^^
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-trailing-return-type.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-trailing-return-type.rst
index 0593a35326aaa..1187c931fca43 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-trailing-return-type.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-trailing-return-type.rst
@@ -25,6 +25,14 @@ transforms to:
   inline auto f2(int arg) -> int noexcept;
   virtual auto f3() const && -> float = delete;
 
+Options
+-------
+
+.. option:: EvenWhenVoid
+
+  If the option is set to `true`, the check will apply even to function signatures
+  with return type `void`. Default is `false`.
+
 Known Limitations
 -----------------
 
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-trailing-return-type.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-trailing-return-type.cpp
index e1f36c52a7c01..d8bef1b64f217 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-trailing-return-type.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-trailing-return-type.cpp
@@ -1,4 +1,12 @@
-// RUN: %check_clang_tidy -std=c++14-or-later %s modernize-use-trailing-return-type %t -- -- -fdeclspec -fexceptions -DCOMMAND_LINE_INT=int
+// RUN: %check_clang_tidy                                                   \
+// RUN:   -std=c++14-or-later %s modernize-use-trailing-return-type %t --   \
+// RUN:   -- -fdeclspec -fexceptions -DCOMMAND_LINE_INT=int
+// RUN: %check_clang_tidy -check-suffixes=,EVEN-WHEN-VOID                   \
+// RUN:   -std=c++14-or-later %s modernize-use-trailing-return-type %t --   \
+// RUN:   -config="{CheckOptions: {                                         \
+// RUN:              modernize-use-trailing-return-type.EvenWhenVoid: true, \
+// RUN:            }}"                                                      \
+// RUN:   -- -fdeclspec -fexceptions -DCOMMAND_LINE_INT=int
 
 namespace std {
     template <typename T>
@@ -566,6 +574,24 @@ ostream& operator<<(ostream& ostream, int i);
 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
 // CHECK-FIXES: {{^}}ostream& operator<<(ostream& ostream, int i);{{$}}
 
+//
+// EvenWhenVoid option
+//
+
+void leadingVoid();
+// CHECK-MESSAGES-EVEN-WHEN-VOID: :[[@LINE-1]]:6: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
+// CHECK-FIXES-EVEN-WHEN-VOID: {{^}}auto leadingVoid() -> void;{{$}}
+void leadingVoid(int arg);
+// CHECK-MESSAGES-EVEN-WHEN-VOID: :[[@LINE-1]]:6: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
+// CHECK-FIXES-EVEN-WHEN-VOID: {{^}}auto leadingVoid(int arg) -> void;{{$}}
+void leadingVoid(int arg) { return; }
+// CHECK-MESSAGES-EVEN-WHEN-VOID: :[[@LINE-1]]:6: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
+// CHECK-FIXES-EVEN-WHEN-VOID: {{^}}auto leadingVoid(int arg) -> void { return; }{{$}}
+
+auto trailingVoid() -> void;
+auto trailingVoid(int arg) -> void;
+auto trailingVoid(int arg) -> void { return; }
+
 //
 // Samples which do not trigger the check
 //
@@ -579,10 +605,6 @@ template <typename T> auto f(T t) -> int;
 
 auto ff();
 
-void c();
-void c(int arg);
-void c(int arg) { return; }
-
 struct D2 : B {
     D2();
     virtual ~D2();

@vbvictor
Copy link
Contributor

vbvictor commented Mar 2, 2025

Consider renaming your option EvenOnVoid to a name that has WarnOn prefix, that is more or less
established approach for naming (see other option names) . In your case I think it's better to name WarnOnVoidFunctions.

@khuldraeseth
Copy link
Author

Consider renaming your option EvenOnVoid to a name that has WarnOn prefix, that is more or less established approach for naming (see other option names) . In your case I think it's better to name WarnOnVoidFunctions.

How's WarnOnLeadingVoid or WarnOnNontrailingVoid? WarnOnVoidFunctions suggests different behavior to me.

@vbvictor
Copy link
Contributor

vbvictor commented Mar 2, 2025

Consider renaming your option EvenOnVoid to a name that has WarnOn prefix, that is more or less established approach for naming (see other option names) . In your case I think it's better to name WarnOnVoidFunctions.

How's WarnOnLeadingVoid or WarnOnNontrailingVoid? WarnOnVoidFunctions suggests different behavior to me.

WarnOnNontrailingVoid is also good in my opinion

Copy link
Contributor

@HerrCai0907 HerrCai0907 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Contributor

@vbvictor vbvictor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, few nits


.. option:: WarnOnNontrailingVoid

If the option is set to `true`, the check will apply even to function signatures
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, make lines no more than 80 characters long.

// RUN: %check_clang_tidy \
// RUN: -std=c++14-or-later %s modernize-use-trailing-return-type %t -- \
// RUN: -- -fdeclspec -fexceptions -DCOMMAND_LINE_INT=int
// RUN: %check_clang_tidy -check-suffixes=,EVEN-WHEN-VOID \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, use new suffix, not EVEN-WHEN-VOID

Copy link
Member

@PiotrZSL PiotrZSL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except current comments, looks fine.

@@ -28,7 +28,8 @@ struct ClassifiedToken {
class UseTrailingReturnTypeCheck : public ClangTidyCheck {
public:
UseTrailingReturnTypeCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
: ClangTidyCheck(Name, Context),
WarnOnNontrailingVoid(Options.get("WarnOnNontrailingVoid", false)) {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shoudn't be WarnOnNonTrailingVoid ?

@@ -494,4 +500,9 @@ void UseTrailingReturnTypeCheck::check(const MatchFinder::MatchResult &Result) {
<< FixItHint::CreateInsertion(InsertionLoc, " -> " + ReturnType);
}

auto UseTrailingReturnTypeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts)
-> void {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

follow exist style = no trailing return types.

.bind("Func");
const auto HasNoWrittenReturnType =
anyOf(cxxConversionDecl(), cxxConstructorDecl(), cxxDestructorDecl(),
cxxMethodDecl(isImplicit()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This check is missing TK_IgnoreUnlessSpelledInSource, in such case those isImplicit woudn't be needed, and check could be faster.

@@ -56,6 +58,8 @@ class UseTrailingReturnTypeCheck : public ClangTidyCheck {
SourceRange ReturnTypeCVRange, const FunctionDecl &F,
const FriendDecl *Fr, const ASTContext &Ctx,
const SourceManager &SM, const LangOptions &LangOpts);

auto storeOptions(ClangTidyOptions::OptionMap &Opts) -> void override;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

follow exist style = no trailing return types.

@vbvictor
Copy link
Contributor

vbvictor commented Jun 4, 2025

@khuldraeseth, gentle ping, do you still wish to work on this PR? 21th LLVM release will be soon, If you wish to have your changes in the upcoming release please rebase on main and fix suggested issues

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants