poelmanc updated this revision to Diff 225896.
poelmanc added a comment.
Rebase to latest master (tests moved into new "checkers" subdirectory.)
Repository:
rCTE Clang Tools Extra
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D67460/new/
https://reviews.llvm.org/D67460
Files:
clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp
Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp
===================================================================
--- clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp
@@ -183,3 +183,67 @@
void f() override { super::f(); }
};
}
+
+template <typename T1, typename T2>
+class TwoArgTemplate {
+ typedef TwoArgTemplate<T1, T2> self;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
+ // CHECK-FIXES: using self = TwoArgTemplate<T1, T2>;
+};
+
+template <bool B, typename T>
+struct S {};
+
+typedef S<(0 > 0), int> S_t, *S_p;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef S<(0 > 0), int> S_t, *S_p;
+
+typedef S<(0 < 0), int> S2_t, *S2_p;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef S<(0 < 0), int> S2_t, *S2_p;
+
+typedef S<(0 > 0 && (3 > 1) && (1 < 1)), int> S3_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using S3_t = S<(0 > 0 && (3 > 1) && (1 < 1)), int>;
+
+template <bool B>
+struct Q {};
+
+constexpr bool b[1] = {true};
+
+typedef Q<b[0 < 0]> Q_t, *Q_p;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef Q<b[0 < 0]> Q_t, *Q_p;
+
+typedef Q<b[0 < 0]> Q2_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Q2_t = Q<b[0 < 0]>;
+
+struct T {
+ constexpr T(bool) {}
+
+ static constexpr bool b = true;
+};
+
+typedef Q<T{0 < 0}.b> Q3_t, *Q3_p;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef Q<T{0 < 0}.b> Q3_t, *Q3_p;
+
+typedef Q<T{0 < 0}.b> Q3_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Q3_t = Q<T{0 < 0}.b>;
+
+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]> > >;
+
+template <typename... Args>
+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]> > > >
+
+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-FIXES: typedef Variadic<Variadic<int, bool, Q<T{0 < 0}.b> >, S<(0 < 0), Variadic<Q<b[0 < 0]> > > > Variadic_t, *Variadic_p;
Index: clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
@@ -39,25 +39,46 @@
File.begin(), TokenBegin, File.end());
Token Tok;
- int ParenLevel = 0;
+ int NestingLevel = 0; // Parens, braces, and square brackets
+ int AngleBracketLevel = 0;
bool FoundTypedef = false;
while (!DeclLexer.LexFromRawLexer(Tok) && !Tok.is(tok::semi)) {
switch (Tok.getKind()) {
case tok::l_brace:
- case tok::r_brace:
- // This might be the `typedef struct {...} T;` case.
- return false;
+ if (NestingLevel == 0 && AngleBracketLevel == 0) {
+ // At top level, this might be the `typedef struct {...} T;` case.
+ // Inside parens, square brackets, or angle brackets it's not.
+ return false;
+ }
+ NestingLevel++;
+ break;
case tok::l_paren:
- ParenLevel++;
+ case tok::l_square:
+ NestingLevel++;
break;
+ case tok::r_brace:
case tok::r_paren:
- ParenLevel--;
+ case tok::r_square:
+ NestingLevel--;
+ break;
+ case tok::less:
+ // If not nested in paren/brace/square bracket, treat as opening angle bracket.
+ if (NestingLevel == 0)
+ AngleBracketLevel++;
+ break;
+ case tok::greater:
+ // Per C++ 17 Draft N4659, Section 17.2/3
+ // https://timsong-cpp.github.io/cppwp/n4659/temp.names#3:
+ // "When parsing a template-argument-list, the first non-nested > is
+ // taken as the ending delimiter rather than a greater-than operator."
+ // If not nested in paren/brace/square bracket, treat as closing angle bracket.
+ if (NestingLevel == 0)
+ AngleBracketLevel--;
break;
case tok::comma:
- if (ParenLevel == 0) {
- // If there is comma and we are not between open parenthesis then it is
- // two or more declarations in this chain.
+ if (NestingLevel == 0 && AngleBracketLevel == 0) {
+ // If there is a non-nested comma we have two or more declarations in this chain.
return false;
}
break;
@@ -88,8 +109,7 @@
if (StartLoc.isMacroID() && IgnoreMacros)
return;
- auto Diag =
- diag(StartLoc, "use 'using' instead of 'typedef'");
+ auto Diag = diag(StartLoc, "use 'using' instead of 'typedef'");
// do not fix if there is macro or array
if (MatchedDecl->getUnderlyingType()->isArrayType() || StartLoc.isMacroID())
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits