[clang-tools-extra] [clang-tidy] Make `modernize-use-using`'s fixits more robust (PR #149694)

via cfe-commits cfe-commits at lists.llvm.org
Sun Jul 20 00:10:30 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

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

Author: Victor Chernyakin (localspook)

<details>
<summary>Changes</summary>

Fixes #<!-- -->105503.
Fixes #<!-- -->31141 (the new fixit is not the one the author suggests, but now it's at least *correct*).

First, let's look at `typedef`s that only introduce one name. Currently, this fails in several cases:

```cpp
typedef const int i;
// becomes
using i = int; // The const is gone!

typedef struct foo_s { int i; } * foo_t;
// becomes
using foo_t = struct foo_s { int i; }; // The pointer is gone!

typedef float vec3[3];
// Warns, but provides no fixit.
```

With this PR, all `typedef`s that only introduce one name are handled correctly, with a fixit.

Now let's look at `typedef`s that introduce multiple names. Here's the current situation:

```cpp
// & and * are handled correctly.
typedef int i, &lval, *ptr;
// becomes
using i = int;
using lval = i&;
using ptr = i*;

// Anything else is not.
typedef int i, &&rval, vec3[3], *const const_ptr, (*fn)();
// becomes
using i = int;
using rval = int;
using const_ptr = i*;
using fn = int i, &&rval, vec3[3], *const const_ptr, (*)();
```

With this PR, all these cases are handled correctly. 

There is a preexisting issue that this PR does not fix though:

https://github.com/llvm/llvm-project/blob/e7ac49977a3e8ee8f9716ffa43619ff41af7dfb2/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using.cpp#L388-L392

 This test asserts incorrect behaviour: with the `typedef`, both `int_ptr` and `int_ptr_ptr` are `int *`; the name `int_ptr_ptr` is wrong. The fixit transforms them into `int *` and `int **` respectively. The fundamental problem is that we have no way to understand that, given `int* int_ptr`, the `int` applies to all the introduced names, while the `*` only applies to the first name.



This PR does come with some regressions:

Currently, we offer fixits when the `typedef` is not the first thing in the *`decl-specifier-seq`*. This sometimes works, sometimes doesn't:

```cpp
int typedef i;
// becomes
using i = int; // ✅

int typedef * ptr;
// becomes
using ptr = int typedef *; // 💥
```

With this PR, we mishandle these cases. We also now mishandle cases where the introduced name is a macro:

```cpp
#define Macro foo
typedef int Macro;
```

So, what do you think? I hope you'll agree that it's a net improvement: many common cases are handled better, and it's only weird cases that are handled worse.

---

Patch is 22.63 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/149694.diff


5 Files Affected:

- (modified) clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp (+36-158) 
- (modified) clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h (+3-7) 
- (modified) clang-tools-extra/docs/ReleaseNotes.rst (+4) 
- (modified) clang-tools-extra/test/clang-tidy/checkers/modernize/use-using-macros.cpp (-5) 
- (modified) clang-tools-extra/test/clang-tidy/checkers/modernize/use-using.cpp (+39-53) 


``````````diff
diff --git a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
index 936a906651f16..fc49d7b820109 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
@@ -7,14 +7,12 @@
 //===----------------------------------------------------------------------===//
 
 #include "UseUsingCheck.h"
-#include "../utils/LexerUtils.h"
-#include "clang/AST/DeclGroup.h"
+#include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TokenKinds.h"
 #include "clang/Lex/Lexer.h"
-#include <string>
 
 using namespace clang::ast_matchers;
 namespace {
@@ -22,15 +20,13 @@ namespace {
 AST_MATCHER(clang::LinkageSpecDecl, isExternCLinkage) {
   return Node.getLanguage() == clang::LinkageSpecLanguageIDs::C;
 }
+
 } // namespace
 
 namespace clang::tidy::modernize {
 
 static constexpr llvm::StringLiteral ExternCDeclName = "extern-c-decl";
-static constexpr llvm::StringLiteral ParentDeclName = "parent-decl";
-static constexpr llvm::StringLiteral TagDeclName = "tag-decl";
 static constexpr llvm::StringLiteral TypedefName = "typedef";
-static constexpr llvm::StringLiteral DeclStmtName = "decl-stmt";
 
 UseUsingCheck::UseUsingCheck(StringRef Name, ClangTidyContext *Context)
     : ClangTidyCheck(Name, Context),
@@ -47,66 +43,14 @@ void UseUsingCheck::registerMatchers(MatchFinder *Finder) {
       typedefDecl(
           unless(isInstantiated()),
           optionally(hasAncestor(
-              linkageSpecDecl(isExternCLinkage()).bind(ExternCDeclName))),
-          anyOf(hasParent(decl().bind(ParentDeclName)),
-                hasParent(declStmt().bind(DeclStmtName))))
+              linkageSpecDecl(isExternCLinkage()).bind(ExternCDeclName))))
           .bind(TypedefName),
       this);
-
-  // This matcher is used to find tag declarations in source code within
-  // typedefs. They appear in the AST just *prior* to the typedefs.
-  Finder->addMatcher(
-      tagDecl(
-          anyOf(allOf(unless(anyOf(isImplicit(),
-                                   classTemplateSpecializationDecl())),
-                      anyOf(hasParent(decl().bind(ParentDeclName)),
-                            hasParent(declStmt().bind(DeclStmtName)))),
-                // We want the parent of the ClassTemplateDecl, not the parent
-                // of the specialization.
-                classTemplateSpecializationDecl(hasAncestor(classTemplateDecl(
-                    anyOf(hasParent(decl().bind(ParentDeclName)),
-                          hasParent(declStmt().bind(DeclStmtName))))))))
-          .bind(TagDeclName),
-      this);
 }
 
 void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
-  const auto *ParentDecl = Result.Nodes.getNodeAs<Decl>(ParentDeclName);
-
-  if (!ParentDecl) {
-    const auto *ParentDeclStmt = Result.Nodes.getNodeAs<DeclStmt>(DeclStmtName);
-    if (ParentDeclStmt) {
-      if (ParentDeclStmt->isSingleDecl())
-        ParentDecl = ParentDeclStmt->getSingleDecl();
-      else
-        ParentDecl =
-            ParentDeclStmt->getDeclGroup().getDeclGroup()
-                [ParentDeclStmt->getDeclGroup().getDeclGroup().size() - 1];
-    }
-  }
-
-  if (!ParentDecl)
-    return;
-
-  const SourceManager &SM = *Result.SourceManager;
-  const LangOptions &LO = getLangOpts();
-
-  // Match CXXRecordDecl only to store the range of the last non-implicit full
-  // declaration, to later check whether it's within the typdef itself.
-  const auto *MatchedTagDecl = Result.Nodes.getNodeAs<TagDecl>(TagDeclName);
-  if (MatchedTagDecl) {
-    // It is not sufficient to just track the last TagDecl that we've seen,
-    // because if one struct or union is nested inside another, the last TagDecl
-    // before the typedef will be the nested one (PR#50990). Therefore, we also
-    // keep track of the parent declaration, so that we can look up the last
-    // TagDecl that is a sibling of the typedef in the AST.
-    if (MatchedTagDecl->isThisDeclarationADefinition())
-      LastTagDeclRanges[ParentDecl] = MatchedTagDecl->getSourceRange();
-    return;
-  }
-
-  const auto *MatchedDecl = Result.Nodes.getNodeAs<TypedefDecl>(TypedefName);
-  if (MatchedDecl->getLocation().isInvalid())
+  const auto &MatchedDecl = *Result.Nodes.getNodeAs<TypedefDecl>(TypedefName);
+  if (MatchedDecl.getLocation().isInvalid())
     return;
 
   const auto *ExternCDecl =
@@ -114,116 +58,50 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
   if (ExternCDecl && IgnoreExternC)
     return;
 
-  SourceLocation StartLoc = MatchedDecl->getBeginLoc();
-
-  if (StartLoc.isMacroID() && IgnoreMacros)
-    return;
-
   static constexpr llvm::StringLiteral UseUsingWarning =
       "use 'using' instead of 'typedef'";
 
-  // Warn at StartLoc but do not fix if there is macro or array.
-  if (MatchedDecl->getUnderlyingType()->isArrayType() || StartLoc.isMacroID()) {
-    diag(StartLoc, UseUsingWarning);
+  if (MatchedDecl.getBeginLoc().isMacroID()) {
+    // Warn but do not fix if there is a macro.
+    if (!IgnoreMacros)
+      diag(MatchedDecl.getBeginLoc(), UseUsingWarning);
     return;
   }
 
-  const TypeLoc TL = MatchedDecl->getTypeSourceInfo()->getTypeLoc();
-
-  auto [Type, QualifierStr] = [MatchedDecl, this, &TL, &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())) {
-      const auto RangeLeftOfIdentifier = CharSourceRange::getCharRange(
-          TypeRange.getBegin(), MatchedDecl->getLocation());
-      const auto RangeRightOfIdentifier = CharSourceRange::getCharRange(
-          Lexer::getLocForEndOfToken(MatchedDecl->getLocation(), 0, SM, LO),
-          Lexer::getLocForEndOfToken(TypeRange.getEnd(), 0, SM, LO));
-      const std::string VerbatimType =
-          (Lexer::getSourceText(RangeLeftOfIdentifier, SM, LO) +
-           Lexer::getSourceText(RangeRightOfIdentifier, SM, LO))
-              .str();
-      return {VerbatimType, ""};
-    }
-
-    StringRef ExtraReference = "";
-    if (MainTypeEndLoc.isValid() && TypeRange.fullyContains(MainTypeEndLoc)) {
-      // Each type introduced in a typedef can specify being a reference or
-      // pointer type seperately, so we need to sigure out if the new using-decl
-      // needs to be to a reference or pointer as well.
-      const SourceLocation Tok = utils::lexer::findPreviousAnyTokenKind(
-          MatchedDecl->getLocation(), SM, LO, tok::TokenKind::star,
-          tok::TokenKind::amp, tok::TokenKind::comma,
-          tok::TokenKind::kw_typedef);
-
-      ExtraReference = Lexer::getSourceText(
-          CharSourceRange::getCharRange(Tok, Tok.getLocWithOffset(1)), SM, LO);
-
-      if (ExtraReference != "*" && ExtraReference != "&")
-        ExtraReference = "";
-
-      TypeRange.setEnd(MainTypeEndLoc);
-    }
-    return {
-        Lexer::getSourceText(CharSourceRange::getTokenRange(TypeRange), SM, LO)
-            .str(),
-        ExtraReference.str()};
-  }();
-  StringRef Name = MatchedDecl->getName();
-  SourceRange ReplaceRange = MatchedDecl->getSourceRange();
+  const SourceManager &SM = *Result.SourceManager;
+  const LangOptions &LO = getLangOpts();
 
   // typedefs with multiple comma-separated definitions produce multiple
   // consecutive TypedefDecl nodes whose SourceRanges overlap. Each range starts
   // at the "typedef" and then continues *across* previous definitions through
   // the end of the current TypedefDecl definition.
-  // But also we need to check that the ranges belong to the same file because
-  // different files may contain overlapping ranges.
-  std::string Using = "using ";
-  if (ReplaceRange.getBegin().isMacroID() ||
-      (Result.SourceManager->getFileID(ReplaceRange.getBegin()) !=
-       Result.SourceManager->getFileID(LastReplacementEnd)) ||
-      (ReplaceRange.getBegin() >= LastReplacementEnd)) {
-    // This is the first (and possibly the only) TypedefDecl in a typedef. Save
-    // Type and Name in case we find subsequent TypedefDecl's in this typedef.
-    FirstTypedefType = Type;
-    FirstTypedefName = Name.str();
-    MainTypeEndLoc = TL.getEndLoc();
+  const SourceRange RemovalRange = {
+      Lexer::findPreviousToken(MatchedDecl.getLocation(), SM, LO,
+                               /*IncludeComments=*/true)
+          ->getEndLoc(),
+      Lexer::getLocForEndOfToken(MatchedDecl.getLocation(), 1, SM, LO)};
+  if (NextTypedefStartsANewSequence) {
+    diag(MatchedDecl.getBeginLoc(), UseUsingWarning)
+        << FixItHint::CreateReplacement(
+               {MatchedDecl.getBeginLoc(),
+                Lexer::getLocForEndOfToken(MatchedDecl.getBeginLoc(), 0, SM,
+                                           LO)},
+               ("using " + MatchedDecl.getName() + " =").str())
+        << FixItHint::CreateRemoval(RemovalRange);
+    FirstTypedefName = MatchedDecl.getName();
   } 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 ";
-
-    // 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*;"
-    if (Type == FirstTypedefType && !QualifierStr.empty())
-      Type = FirstTypedefName;
-  }
-
-  if (!ReplaceRange.getEnd().isMacroID()) {
-    const SourceLocation::IntTy Offset =
-        MatchedDecl->getFunctionType() ? 0 : Name.size();
-    LastReplacementEnd = ReplaceRange.getEnd().getLocWithOffset(Offset);
+    diag(LastCommaOrSemi, UseUsingWarning)
+        << FixItHint::CreateReplacement(
+               LastCommaOrSemi,
+               (";\nusing " + MatchedDecl.getName() + " = " + FirstTypedefName)
+                   .str())
+        << FixItHint::CreateRemoval(RemovalRange);
   }
 
-  auto Diag = diag(ReplaceRange.getBegin(), UseUsingWarning);
-
-  // If typedef contains a full tag declaration, extract its full text.
-  auto LastTagDeclRange = LastTagDeclRanges.find(ParentDecl);
-  if (LastTagDeclRange != LastTagDeclRanges.end() &&
-      LastTagDeclRange->second.isValid() &&
-      ReplaceRange.fullyContains(LastTagDeclRange->second)) {
-    Type = std::string(Lexer::getSourceText(
-        CharSourceRange::getTokenRange(LastTagDeclRange->second), SM, LO));
-    if (Type.empty())
-      return;
-  }
-
-  std::string Replacement = (Using + Name + " = " + Type + QualifierStr).str();
-  Diag << FixItHint::CreateReplacement(ReplaceRange, Replacement);
+  const Token CommaOrSemi = *Lexer::findNextToken(
+      MatchedDecl.getEndLoc(), SM, LO, /*IncludeComments=*/false);
+  NextTypedefStartsANewSequence = CommaOrSemi.isNot(tok::TokenKind::comma);
+  LastCommaOrSemi = CommaOrSemi.getLocation();
 }
+
 } // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
index 1e54bbf23c984..2f113e3d9e076 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
@@ -18,15 +18,11 @@ namespace clang::tidy::modernize {
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-using.html
 class UseUsingCheck : public ClangTidyCheck {
-
   const bool IgnoreMacros;
   const bool IgnoreExternC;
-  SourceLocation LastReplacementEnd;
-  llvm::DenseMap<const Decl *, SourceRange> LastTagDeclRanges;
-
-  std::string FirstTypedefType;
-  std::string FirstTypedefName;
-  SourceLocation MainTypeEndLoc;
+  bool NextTypedefStartsANewSequence = true;
+  StringRef FirstTypedefName;
+  SourceLocation LastCommaOrSemi;
 
 public:
   UseUsingCheck(StringRef Name, ClangTidyContext *Context);
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 9eb3835fe8340..91899f88491b9 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -346,6 +346,10 @@ Changes in existing checks
   whether function declarations and lambdas should be transformed by the check.
   Fixed false positives when lambda was matched as a function in C++11 mode.
 
+- Improved :doc:`modernize-use-using
+  <clang-tidy/checks/modernize/use-using>` check by removing many incorrect 
+  fixits and providing fixits where before there was only a warning.
+
 - Improved :doc:`performance-move-const-arg
   <clang-tidy/checks/performance/move-const-arg>` check by fixing false
   negatives on ternary operators calling ``std::move``.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using-macros.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using-macros.cpp
index 092bc6666bb1c..c03cbc4d557fc 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using-macros.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using-macros.cpp
@@ -9,11 +9,6 @@ CODE;
 // CHECK-FIXES: CODE;
 
 struct Foo;
-#define Bar Baz
-typedef Foo Bar;
-// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
-// CHECK-FIXES: #define Bar Baz
-// CHECK-FIXES: using Baz = Foo;
 
 #define TYPEDEF typedef
 TYPEDEF Foo Bak;
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 8288f39126a11..b32a7b5722c52 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
@@ -1,9 +1,5 @@
 // RUN: %check_clang_tidy %s modernize-use-using %t -- -- -fno-delayed-template-parsing -I %S/Inputs/use-using/
 
-typedef int Type;
-// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' [modernize-use-using]
-// CHECK-FIXES: using Type = int;
-
 typedef long LL;
 // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
 // CHECK-FIXES: using LL = long;
@@ -16,6 +12,18 @@ typedef Bla Bla2;
 // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
 // CHECK-FIXES: using Bla2 = Bla;
 
+typedef const int ConstInt;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using ConstInt = const int;
+
+typedef const int *const ConstPtrToConstInt;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using ConstPtrToConstInt = const int *const;
+
+typedef struct foo_s {} * foo_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using foo_t = struct foo_s {} *;
+
 typedef void (*type)(int, int);
 // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
 // CHECK-FIXES: using type = void (*)(int, int);
@@ -87,8 +95,24 @@ typedef int bla1, bla2, bla3;
 // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: use 'using' instead of 'typedef'
 // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use 'using' instead of 'typedef'
 // CHECK-FIXES: using bla1 = int;
-// CHECK-FIXES-NEXT: using bla2 = int;
-// CHECK-FIXES-NEXT: using bla3 = int;
+// CHECK-FIXES-NEXT: using bla2 = bla1;
+// CHECK-FIXES-NEXT: using bla3 = bla1;
+
+typedef int I, &LVal, &&RVal, *Ptr, *const ConstPtr, Vec3[3], (*Fn)();
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-MESSAGES: :[[@LINE-2]]:14: warning: use 'using' instead of 'typedef'
+// CHECK-MESSAGES: :[[@LINE-3]]:21: warning: use 'using' instead of 'typedef'
+// CHECK-MESSAGES: :[[@LINE-4]]:29: warning: use 'using' instead of 'typedef'
+// CHECK-MESSAGES: :[[@LINE-5]]:35: warning: use 'using' instead of 'typedef'
+// CHECK-MESSAGES: :[[@LINE-6]]:52: warning: use 'using' instead of 'typedef'
+// CHECK-MESSAGES: :[[@LINE-7]]:61: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using I = int;
+// CHECK-FIXES-NEXT: using LVal = I &;
+// CHECK-FIXES-NEXT: using RVal = I &&;
+// CHECK-FIXES-NEXT: using Ptr = I *;
+// CHECK-FIXES-NEXT: using ConstPtr = I *const;
+// CHECK-FIXES-NEXT: using Vec3 = I[3];
+// CHECK-FIXES-NEXT: using Fn = I (*)();
 
 #define CODE typedef int INT
 
@@ -97,11 +121,6 @@ CODE;
 // CHECK-FIXES: CODE;
 
 struct Foo;
-#define Bar Baz
-typedef Foo Bar;
-// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
-// CHECK-FIXES: #define Bar Baz
-// CHECK-FIXES: using Baz = Foo;
 
 #define TYPEDEF typedef
 TYPEDEF Foo Bak;
@@ -118,38 +137,16 @@ typedef struct Foo Bap;
 // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
 // CHECK-FIXES: using Bap = struct Foo;
 
-struct Foo typedef Bap2;
-// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
-// CHECK-FIXES: using Bap2 = struct Foo;
-
-Foo typedef Bap3;
-// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
-// CHECK-FIXES: using Bap3 = Foo;
-
 typedef struct Unknown Baq;
 // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
 // CHECK-FIXES: using Baq = struct Unknown;
 
-struct Unknown2 typedef Baw;
-// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
-// CHECK-FIXES: using Baw = struct Unknown2;
-
-int typedef Bax;
-// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
-// CHECK-FIXES: using Bax = int;
-
 typedef struct Q1 { int a; } S1;
 // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
 // CHECK-FIXES: using S1 = struct Q1 { int a; };
 typedef struct { int b; } S2;
 // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
 // CHECK-FIXES: using S2 = struct { int b; };
-struct Q2 { int c; } typedef S3;
-// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
-// CHECK-FIXES: using S3 = struct Q2 { int c; };
-struct { int d; } typedef S4;
-// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
-// CHECK-FIXES: using S4 = struct { int d; };
 
 namespace my_space {
   class my_cclass {};
@@ -161,11 +158,7 @@ namespace my_space {
 #define lol 4
 typedef unsigned Map[lol];
 // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
-// CHECK-FIXES: typedef unsigned Map[lol];
-
-typedef void (*fun_type)();
-// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
-// CHECK-FIXES: using fun_type = void (*)();
+// CHECK-FIXES: using Map = unsigned[lol];
 
 namespace template_instantiations {
 template <typename T>
@@ -202,13 +195,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_t *;
 
 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 = S2_t *;
 
 typedef S<(0 > 0 && (3 > 1) && (1 < 1)), int> S3_t;
 // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
@@ -223,7 +216,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_t *;
 
 typedef Q<b[0 < 0]> Q2_t;
 // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
@@ -239,7 +232,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...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/149694


More information about the cfe-commits mailing list