[clang-tools-extra] [clang-tidy] Providing correct fixes for modernize-use-using (PR #174104)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Dec 31 08:17:13 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-tidy
Author: mitchell (zeyi2)
<details>
<summary>Changes</summary>
Closes [#<!-- -->173830](https://github.com/llvm/llvm-project/issues/173830)
---
Full diff: https://github.com/llvm/llvm-project/pull/174104.diff
3 Files Affected:
- (modified) clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp (+33-11)
- (modified) clang-tools-extra/docs/ReleaseNotes.rst (+7-6)
- (modified) clang-tools-extra/test/clang-tidy/checkers/modernize/use-using.cpp (+60-25)
``````````diff
diff --git a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
index 085dbde60db61..b38bc63a9bb57 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
@@ -129,17 +129,26 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
}
const TypeLoc TL = MatchedDecl->getTypeSourceInfo()->getTypeLoc();
+ const bool InvolvesMacro =
+ TL.getBeginLoc().isMacroID() || TL.getEndLoc().isMacroID();
+ const bool FunctionPointerCase =
+ TL.getSourceRange().fullyContains(MatchedDecl->getLocation());
+
+ auto [Type, QualifierStr] =
+ [MatchedDecl, this, &TL, &SM, &LO, InvolvesMacro,
+ FunctionPointerCase]() -> std::pair<std::string, std::string> {
+ if (!InvolvesMacro) {
+ PrintingPolicy Policy(LO);
+ Policy.SuppressScope = false;
+ Policy.SuppressUnwrittenScope = true;
+ return {MatchedDecl->getUnderlyingType().getAsString(Policy), ""};
+ }
- bool FunctionPointerCase = false;
- auto [Type, QualifierStr] = [MatchedDecl, this, &TL, &FunctionPointerCase,
- &SM,
- &LO]() -> std::pair<std::string, std::string> {
SourceRange TypeRange = TL.getSourceRange();
// Function pointer case, get the left and right side of the identifier
// without the identifier.
- if (TypeRange.fullyContains(MatchedDecl->getLocation())) {
- FunctionPointerCase = true;
+ if (FunctionPointerCase) {
const auto RangeLeftOfIdentifier = CharSourceRange::getCharRange(
TypeRange.getBegin(), MatchedDecl->getLocation());
const auto RangeRightOfIdentifier = CharSourceRange::getCharRange(
@@ -175,6 +184,7 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
.str(),
ExtraReference.str()};
}();
+
const StringRef Name = MatchedDecl->getName();
SourceRange ReplaceRange = MatchedDecl->getSourceRange();
@@ -197,9 +207,22 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
} else {
// This is additional TypedefDecl in a comma-separated typedef declaration.
// Start replacement *after* prior replacement and separate with semicolon.
- ReplaceRange.setBegin(LastReplacementEnd);
Using = ";\nusing ";
+ // Find the comma that precedes this declarator
+ SourceLocation CommaLoc = utils::lexer::findPreviousAnyTokenKind(
+ MatchedDecl->getLocation(), SM, LO, tok::TokenKind::comma);
+ if (CommaLoc.isValid() && !CommaLoc.isMacroID())
+ ReplaceRange.setBegin(CommaLoc);
+ else
+ ReplaceRange.setBegin(LastReplacementEnd);
+
+ if (FunctionPointerCase) {
+ SourceLocation DeclaratorEnd = TL.getEndLoc();
+ if (DeclaratorEnd.isValid() && !DeclaratorEnd.isMacroID())
+ ReplaceRange.setEnd(DeclaratorEnd);
+ }
+
// If this additional TypedefDecl's Type starts with the first TypedefDecl's
// type, make this using statement refer back to the first type, e.g. make
// "typedef int Foo, *Foo_p;" -> "using Foo = int;\nusing Foo_p = Foo*;"
@@ -207,10 +230,9 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
Type = FirstTypedefName;
}
- if (!ReplaceRange.getEnd().isMacroID()) {
- const SourceLocation::IntTy Offset = FunctionPointerCase ? 0 : Name.size();
- LastReplacementEnd = ReplaceRange.getEnd().getLocWithOffset(Offset);
- }
+ if (!ReplaceRange.getEnd().isMacroID())
+ LastReplacementEnd =
+ Lexer::getLocForEndOfToken(ReplaceRange.getEnd(), 0, SM, LO);
auto Diag = diag(ReplaceRange.getBegin(), UseUsingWarning);
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 7d878f7d28386..b685dc494c7ee 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -111,10 +111,10 @@ Hover
Code completion
^^^^^^^^^^^^^^^
-- Added a new ``MacroFilter`` configuration option to ``Completion`` to
- allow fuzzy-matching with the ``FuzzyMatch`` option when suggesting
- macros. ``ExactPrefix`` is the default, which retains previous
- behavior of suggesting macros which match the prefix exactly.
+- Added a new ``MacroFilter`` configuration option to ``Completion`` to
+ allow fuzzy-matching with the ``FuzzyMatch`` option when suggesting
+ macros. ``ExactPrefix`` is the default, which retains previous
+ behavior of suggesting macros which match the prefix exactly.
Code actions
^^^^^^^^^^^^
@@ -205,7 +205,7 @@ Improvements to clang-tidy
- Improved :program:`clang-tidy` by adding the `--removed-arg` option to remove
arguments sent to the compiler when invoking Clang-Tidy. This option was also
- added to :program:`run-clang-tidy.py` and :program:`clang-tidy-diff.py` and
+ added to :program:`run-clang-tidy.py` and :program:`clang-tidy-diff.py` and
can be configured in the config file through the `RemovedArgs` option.
- Deprecated the :program:`clang-tidy` ``zircon`` module. All checks have been
@@ -585,7 +585,8 @@ Changes in existing checks
- Improved :doc:`modernize-use-using
<clang-tidy/checks/modernize/use-using>` check to correctly provide fix-its
- for typedefs of pointers or references to array types.
+ for typedefs of pointers, references to array types and cases with
+ comma-separated multiple declarations and complex declarators.
- Improved :doc:`performance-unnecessary-copy-initialization
<clang-tidy/checks/performance/unnecessary-copy-initialization>` by printing
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using.cpp
index a1f32b06df091..c9d3d585f7138 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using.cpp
@@ -32,7 +32,7 @@ class Class {
typedef void (Class::*MyPtrType)(Bla) const;
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
-// CHECK-FIXES: using MyPtrType = void (Class::*)(Bla)[[ATTR:( __attribute__\(\(thiscall\)\))?]] const;
+// CHECK-FIXES: using MyPtrType = void (Class::*)(Bla) const;
class Iterable {
public:
@@ -52,7 +52,7 @@ union A {};
typedef void (A::*PtrType)(int, int) const;
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
-// CHECK-FIXES: using PtrType = void (A::*)(int, int)[[ATTR]] const;
+// CHECK-FIXES: using PtrType = void (A::*)(int, int) const;
typedef Class some_class;
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
@@ -70,7 +70,7 @@ class cclass {};
typedef void (cclass::*MyPtrType3)(Bla);
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
-// CHECK-FIXES: using MyPtrType3 = void (cclass::*)(Bla)[[ATTR]];
+// CHECK-FIXES: using MyPtrType3 = void (cclass::*)(Bla);
using my_class = int;
@@ -80,7 +80,7 @@ typedef Test<my_class *> another;
typedef int* PInt;
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
-// CHECK-FIXES: using PInt = int*;
+// CHECK-FIXES: using PInt = int *;
typedef int bla1, bla2, bla3;
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
@@ -202,13 +202,13 @@ typedef S<(0 > 0), int> S_t, *S_p;
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
// CHECK-MESSAGES: :[[@LINE-2]]:28: warning: use 'using' instead of 'typedef'
// CHECK-FIXES: using S_t = S<(0 > 0), int>;
-// CHECK-FIXES-NEXT: using S_p = S_t*;
+// CHECK-FIXES-NEXT: using S_p = S<(0 > 0), int> *;
typedef S<(0 < 0), int> S2_t, *S2_p;
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
// CHECK-MESSAGES: :[[@LINE-2]]:29: warning: use 'using' instead of 'typedef'
// CHECK-FIXES: using S2_t = S<(0 < 0), int>;
-// CHECK-FIXES-NEXT: using S2_p = S2_t*;
+// CHECK-FIXES-NEXT: using S2_p = S<(0 < 0), int> *;
typedef S<(0 > 0 && (3 > 1) && (1 < 1)), int> S3_t;
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
@@ -223,7 +223,7 @@ typedef Q<b[0 < 0]> Q_t, *Q_p;
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
// CHECK-MESSAGES: :[[@LINE-2]]:24: warning: use 'using' instead of 'typedef'
// CHECK-FIXES: using Q_t = Q<b[0 < 0]>;
-// CHECK-FIXES-NEXT: using Q_p = Q_t*;
+// CHECK-FIXES-NEXT: using Q_p = Q<b[0 < 0]> *;
typedef Q<b[0 < 0]> Q2_t;
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
@@ -239,7 +239,7 @@ typedef Q<T{0 < 0}.b> Q3_t, *Q3_p;
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
// CHECK-MESSAGES: :[[@LINE-2]]:27: warning: use 'using' instead of 'typedef'
// CHECK-FIXES: using Q3_t = Q<T{0 < 0}.b>;
-// CHECK-FIXES-NEXT: using Q3_p = Q3_t*;
+// CHECK-FIXES-NEXT: using Q3_p = Q<T{0 < 0}.b> *;
typedef Q<T{0 < 0}.b> Q3_t;
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
@@ -247,7 +247,7 @@ typedef Q<T{0 < 0}.b> Q3_t;
typedef TwoArgTemplate<TwoArgTemplate<int, Q<T{0 < 0}.b> >, S<(0 < 0), Q<b[0 < 0]> > > Nested_t;
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
-// CHECK-FIXES: using Nested_t = TwoArgTemplate<TwoArgTemplate<int, Q<T{0 < 0}.b> >, S<(0 < 0), Q<b[0 < 0]> > >;
+// CHECK-FIXES: using Nested_t = TwoArgTemplate<TwoArgTemplate<int, Q<T{0 < 0}.b>>, S<(0 < 0), Q<b[0 < 0]>>>;
template <typename a>
class TemplateKeyword {
@@ -265,19 +265,19 @@ class Variadic {};
typedef Variadic<Variadic<int, bool, Q<T{0 < 0}.b> >, S<(0 < 0), Variadic<Q<b[0 < 0]> > > > Variadic_t;
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
-// CHECK-FIXES: using Variadic_t = Variadic<Variadic<int, bool, Q<T{0 < 0}.b> >, S<(0 < 0), Variadic<Q<b[0 < 0]> > > >;
+// CHECK-FIXES: using Variadic_t = Variadic<Variadic<int, bool, Q<T{0 < 0}.b>>, S<(0 < 0), Variadic<Q<b[0 < 0]>>>>;
typedef Variadic<Variadic<int, bool, Q<T{0 < 0}.b> >, S<(0 < 0), Variadic<Q<b[0 < 0]> > > > Variadic_t, *Variadic_p;
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
// CHECK-MESSAGES: :[[@LINE-2]]:103: warning: use 'using' instead of 'typedef'
-// CHECK-FIXES: using Variadic_t = Variadic<Variadic<int, bool, Q<T{0 < 0}.b> >, S<(0 < 0), Variadic<Q<b[0 < 0]> > > >;
-// CHECK-FIXES-NEXT: using Variadic_p = Variadic_t*;
+// CHECK-FIXES: using Variadic_t = Variadic<Variadic<int, bool, Q<T{0 < 0}.b>>, S<(0 < 0), Variadic<Q<b[0 < 0]>>>>;
+// CHECK-FIXES-NEXT: using Variadic_p = Variadic<Variadic<int, bool, Q<T{0 < 0}.b>>, S<(0 < 0), Variadic<Q<b[0 < 0]>>>> *;
typedef struct { int a; } R_t, *R_p;
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
// CHECK-MESSAGES: :[[@LINE-2]]:30: warning: use 'using' instead of 'typedef'
// CHECK-FIXES: using R_t = struct { int a; };
-// CHECK-FIXES-NEXT: using R_p = R_t*;
+// CHECK-FIXES-NEXT: using R_p = struct R_t *;
typedef enum { ea1, eb1 } EnumT1;
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
@@ -293,14 +293,14 @@ template <int A>
struct InjectedClassName {
typedef InjectedClassName b;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
- // CHECK-FIXES: using b = InjectedClassName;
+ // CHECK-FIXES: using b = InjectedClassName<A>;
};
template <int>
struct InjectedClassNameWithUnnamedArgument {
typedef InjectedClassNameWithUnnamedArgument b;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
- // CHECK-FIXES: using b = InjectedClassNameWithUnnamedArgument;
+ // CHECK-FIXES: using b = InjectedClassNameWithUnnamedArgument<value-parameter-0-0>;
};
typedef struct { int a; union { int b; }; } PR50990;
@@ -344,7 +344,7 @@ typedef int InExternCPP;
}
namespace ISSUE_72179
-{
+{
void foo()
{
typedef int a;
@@ -375,7 +375,7 @@ namespace ISSUE_72179
{
typedef MyClass c;
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use 'using' instead of 'typedef' [modernize-use-using]
- // CHECK-FIXES: using c = MyClass;
+ // CHECK-FIXES: using c = MyClass<T>;
}
};
@@ -388,8 +388,8 @@ namespace ISSUE_72179
typedef int* int_ptr, *int_ptr_ptr;
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' [modernize-use-using]
// CHECK-MESSAGES: :[[@LINE-2]]:21: warning: use 'using' instead of 'typedef' [modernize-use-using]
-// CHECK-FIXES: using int_ptr = int*;
-// CHECK-FIXES-NEXT: using int_ptr_ptr = int_ptr*;
+// CHECK-FIXES: using int_ptr = int *;
+// CHECK-FIXES-NEXT: using int_ptr_ptr = int *;
#ifndef SpecialMode
#define SomeMacro(x) x
@@ -401,23 +401,23 @@ class SomeMacro(GH33760) { };
typedef void(SomeMacro(GH33760)::* FunctionType)(float, int);
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' [modernize-use-using]
-// CHECK-FIXES: using FunctionType = void(SomeMacro(GH33760)::* )(float, int);
+// CHECK-FIXES: using FunctionType = void (GH33760::*)(float, int);
#define CDECL __attribute((cdecl))
// GH37846 & GH41685
typedef void (CDECL *GH37846)(int);
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' [modernize-use-using]
-// CHECK-FIXES: using GH37846 = void (CDECL *)(int);
+// CHECK-FIXES: using GH37846 = CDECL void (*)(int))(int);
typedef void (__attribute((cdecl)) *GH41685)(int);
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' [modernize-use-using]
-// CHECK-FIXES: using GH41685 = void (__attribute((cdecl)) *)(int);
+// CHECK-FIXES: using GH41685 = void (*)(int) __attribute__((cdecl)))(int);
namespace GH83568 {
typedef int(*name)(int arg1, int arg2);
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' [modernize-use-using]
-// CHECK-FIXES: using name = int(*)(int arg1, int arg2);
+// CHECK-FIXES: using name = int (*)(int, int);
}
#ifdef FOO
@@ -435,7 +435,7 @@ namespace GH97009 {
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' [modernize-use-using]
typedef bool (*Function)(PointType, PointType);
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' [modernize-use-using]
-// CHECK-FIXES: using Function = bool (*)(PointType, PointType);
+// CHECK-FIXES: using Function = bool (*)(double *, double *);
}
namespace GH173732 {
@@ -459,5 +459,40 @@ namespace GH173732 {
// multiple in one typedef
typedef char (&refArray)[2], (*ptrArray)[2];
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' [modernize-use-using]
- // CHECK-MESSAGES: :[[@LINE-2]]:29: warning: use 'using' instead of 'typedef' [modernize-use-using]
+ // CHECK-MESSAGES: :[[@LINE-2]]:30: warning: use 'using' instead of 'typedef' [modernize-use-using]
+ // CHECK-FIXES: using refArray = char (&)[2];
+ // CHECK-FIXES-NEXT: using ptrArray = char (*)[2];
+}
+
+namespace GHReportedIssue {
+ typedef char x1, (&refArray)();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' [modernize-use-using]
+ // CHECK-MESSAGES: :[[@LINE-2]]:18: warning: use 'using' instead of 'typedef' [modernize-use-using]
+ // CHECK-FIXES: using x1 = char;
+ // CHECK-FIXES-NEXT: using refArray = char (&)();
+
+ typedef void (*FuncPtr)(), (*FuncPtr2)(int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' [modernize-use-using]
+ // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: use 'using' instead of 'typedef' [modernize-use-using]
+ // CHECK-FIXES: using FuncPtr = void (*)();
+ // CHECK-FIXES-NEXT: using FuncPtr2 = void (*)(int);
+
+ typedef int Integer, (*FuncPtr3)();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' [modernize-use-using]
+ // CHECK-MESSAGES: :[[@LINE-2]]:22: warning: use 'using' instead of 'typedef' [modernize-use-using]
+ // CHECK-FIXES: using Integer = int;
+ // CHECK-FIXES-NEXT: using FuncPtr3 = int (*)();
+
+ typedef int **PtrPtr, (&RefArr)[5];
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' [modernize-use-using]
+ // CHECK-MESSAGES: :[[@LINE-2]]:23: warning: use 'using' instead of 'typedef' [modernize-use-using]
+ // CHECK-FIXES: using PtrPtr = int **;
+ // CHECK-FIXES-NEXT: using RefArr = int (&)[5];
+
+ // 4. Qualifiers
+ typedef const int CInt, (*PCInt);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
+ // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use 'using' instead of 'typedef'
+ // CHECK-FIXES: using CInt = const int;
+ // CHECK-FIXES-NEXT: using PCInt = const int (*);
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/174104
More information about the cfe-commits
mailing list