[PATCH] D67460: clang-tidy: modernize-use-using work with multi-argument templates

2019-09-11 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc created this revision.
poelmanc added reviewers: alexfh, alexfh_.
poelmanc added a project: clang-tools-extra.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

clang-tidy's modernize-use-using feature is great! But if it finds any commas 
that are not within parentheses, it won't create a fix. That means it won't 
change lines like:
`  typedef std::pair Point;`
to
`  using Point = std::pair;`
or even:
`  typedef std::map MyMap;`
`  typedef std::vector> MyVector;`

This patch allows the fix to apply to lines with commas if they are within 
parentheses //or// angle brackets.

One test is include


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D67460

Files:
  clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
  clang-tools-extra/test/clang-tidy/modernize-use-using.cpp


Index: clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
===
--- clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
+++ clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
@@ -182,4 +182,11 @@
 class E : public C {
   void f() override { super::f(); }
 };
+
+template 
+class TwoArgTemplate {
+  typedef TwoArgTemplate self;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
+  // CHECK-FIXES: using self = TwoArgTemplate;
+};
 }
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
@@ -40,6 +40,7 @@
 
   Token Tok;
   int ParenLevel = 0;
+  int AngleBracketLevel = 0;
   bool FoundTypedef = false;
 
   while (!DeclLexer.LexFromRawLexer(Tok) && !Tok.is(tok::semi)) {
@@ -54,10 +55,16 @@
 case tok::r_paren:
   ParenLevel--;
   break;
+case tok::less: // '<', start template
+  AngleBracketLevel++;
+  break;
+case tok::greater: // '>', end template
+  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 (ParenLevel == 0 && AngleBracketLevel == 0) {
+// If there is comma and we are not between open parenthesis or between
+// open angle brackets then it is two or more declarations in this 
chain.
 return false;
   }
   break;
@@ -88,8 +95,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())


Index: clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
===
--- clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
+++ clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
@@ -182,4 +182,11 @@
 class E : public C {
   void f() override { super::f(); }
 };
+
+template 
+class TwoArgTemplate {
+  typedef TwoArgTemplate self;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
+  // CHECK-FIXES: using self = TwoArgTemplate;
+};
 }
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
@@ -40,6 +40,7 @@
 
   Token Tok;
   int ParenLevel = 0;
+  int AngleBracketLevel = 0;
   bool FoundTypedef = false;
 
   while (!DeclLexer.LexFromRawLexer(Tok) && !Tok.is(tok::semi)) {
@@ -54,10 +55,16 @@
 case tok::r_paren:
   ParenLevel--;
   break;
+case tok::less: // '<', start template
+  AngleBracketLevel++;
+  break;
+case tok::greater: // '>', end template
+  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 (ParenLevel == 0 && AngleBracketLevel == 0) {
+// If there is comma and we are not between open parenthesis or between
+// open angle brackets then it is two or more declarations in this chain.
 return false;
   }
   break;
@@ -88,8 +95,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
cfe-commits@lists.llvm.

[PATCH] D67460: clang-tidy: modernize-use-using work with multi-argument templates

2019-09-11 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 219834.
poelmanc edited the summary of this revision.

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/modernize-use-using.cpp


Index: clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
===
--- clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
+++ clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
@@ -182,4 +182,22 @@
 class E : public C {
   void f() override { super::f(); }
 };
+
+template 
+class TwoArgTemplate {
+  typedef TwoArgTemplate self;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
+  // CHECK-FIXES: using self = TwoArgTemplate;
+};
 }
+
+template 
+struct S {};
+
+typedef S<(0 > 0 && (3 < 1)), int> S_t, *S_p;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef S<(0 > 0 && (3 < 1)), int> S_t, *S_p;
+
+typedef S<(0 > 0 && (3 < 1)), int> S2_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using S2_t = S<(0 > 0 && (3 < 1)), int>;
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
@@ -40,6 +40,7 @@
 
   Token Tok;
   int ParenLevel = 0;
+  int AngleBracketLevel = 0;
   bool FoundTypedef = false;
 
   while (!DeclLexer.LexFromRawLexer(Tok) && !Tok.is(tok::semi)) {
@@ -54,10 +55,20 @@
 case tok::r_paren:
   ParenLevel--;
   break;
+case tok::less:
+  // '<' starts a template if not within parentheses like (0 < 1)
+  if (ParenLevel == 0)
+AngleBracketLevel++;
+  break;
+case tok::greater:
+  // '>' ends a template if not within parentheses like (0 > 1)
+  if (ParenLevel == 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 (ParenLevel == 0 && AngleBracketLevel == 0) {
+// If there is comma and we are not between open parenthesis or between
+// open angle brackets then it is two or more declarations in this 
chain.
 return false;
   }
   break;
@@ -88,8 +99,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())


Index: clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
===
--- clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
+++ clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
@@ -182,4 +182,22 @@
 class E : public C {
   void f() override { super::f(); }
 };
+
+template 
+class TwoArgTemplate {
+  typedef TwoArgTemplate self;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
+  // CHECK-FIXES: using self = TwoArgTemplate;
+};
 }
+
+template 
+struct S {};
+
+typedef S<(0 > 0 && (3 < 1)), int> S_t, *S_p;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef S<(0 > 0 && (3 < 1)), int> S_t, *S_p;
+
+typedef S<(0 > 0 && (3 < 1)), int> S2_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using S2_t = S<(0 > 0 && (3 < 1)), int>;
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
@@ -40,6 +40,7 @@
 
   Token Tok;
   int ParenLevel = 0;
+  int AngleBracketLevel = 0;
   bool FoundTypedef = false;
 
   while (!DeclLexer.LexFromRawLexer(Tok) && !Tok.is(tok::semi)) {
@@ -54,10 +55,20 @@
 case tok::r_paren:
   ParenLevel--;
   break;
+case tok::less:
+  // '<' starts a template if not within parentheses like (0 < 1)
+  if (ParenLevel == 0)
+AngleBracketLevel++;
+  break;
+case tok::greater:
+  // '>' ends a template if not within parentheses like (0 > 1)
+  if (ParenLevel == 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 (ParenLevel == 0 && AngleBracketLevel == 0) {
+// If there

[PATCH] D67460: clang-tidy: modernize-use-using work with multi-argument templates

2019-09-11 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

Wow, thanks for the super-quick testing, feedback and a new test case! I added 
a slightly enhanced version of your test case to the modernize-use-using.cpp 
test file and got it passing by treating tok::less and tok::right as 
AngleBrackets //only when ParenLevel == 0//. See updated patch above. Holler if 
you think of any other stressing cases!

P.S. What do we think of actually handling the comma cases? (A) that's probably 
hard, and (B) as a C++ programmer I don't use them myself, so would we expand:

  typedef S<(0 < 0)> S_t, *S_p;

to:

  using S_t = S<(0 < 0)>;
  using S_p = S_t*;

?


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D67460/new/

https://reviews.llvm.org/D67460



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D67460: clang-tidy: modernize-use-using work with multi-argument templates

2019-09-12 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 219957.
poelmanc added a comment.

Thanks for the stressing test cases. I reverted to your original test case with 
a single >, added a separate one with a single <, and expanded the final case 
to have a non-balanced number of > and <. I added all your new cases, with 
variations for non-fixed (multiple typedef) and fixed (single typedef) examples.

To make the braces example pass, we now only abandon the fix when encountering 
a non-nested open brace.


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/modernize-use-using.cpp

Index: clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
===
--- clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
+++ clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
@@ -182,4 +182,53 @@
 class E : public C {
   void f() override { super::f(); }
 };
+
+template 
+class TwoArgTemplate {
+  typedef TwoArgTemplate self;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
+  // CHECK-FIXES: using self = TwoArgTemplate;
+};
 }
+
+template 
+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 
+struct Q {};
+
+constexpr bool b[1] = {true};
+
+typedef Q Q_t, *Q_p;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef Q Q_t, *Q_p;
+
+typedef Q Q2_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Q2_t = Q;
+
+struct T {
+  constexpr T(bool) {}
+
+  static constexpr bool b = true;
+};
+
+typedef Q Q3_t, *Q3_p;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef Q Q3_t, *Q3_p;
+
+typedef Q Q3_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Q3_t = Q;
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
@@ -40,24 +40,54 @@
 
   Token Tok;
   int ParenLevel = 0;
+  int BraceLevel = 0;
+  int AngleBracketLevel = 0;
+  int SquareBracketLevel = 0;
   bool FoundTypedef = false;
 
   while (!DeclLexer.LexFromRawLexer(Tok) && !Tok.is(tok::semi)) {
 switch (Tok.getKind()) {
 case tok::l_brace:
+  if (ParenLevel == 0 && SquareBracketLevel == 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;
+  }
+  BraceLevel++;
+  break;
 case tok::r_brace:
-  // This might be the `typedef struct {...} T;` case.
-  return false;
+  BraceLevel--;
+  break;
 case tok::l_paren:
   ParenLevel++;
   break;
 case tok::r_paren:
   ParenLevel--;
   break;
+case tok::l_square:
+  SquareBracketLevel++;
+  break;
+case tok::r_square:
+  SquareBracketLevel--;
+  break;
+case tok::less:
+  // If not nested, treat as opening angle bracket.
+  if (ParenLevel == 0 && SquareBracketLevel == 0 && BraceLevel == 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, treat as closing angle bracket.
+  if (ParenLevel == 0 && SquareBracketLevel == 0 && BraceLevel == 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 (ParenLevel == 0 && SquareBracketLevel == 0 && BraceLevel == 0 &&
+  AngleBracketLevel == 0) {
+// If there is comma not nested then it is two or more declarations in this chain.
 return false;
   }
   break;
@@ -88,8 +118,7 @@
   if (StartLoc.isMacroID() && IgnoreMacros)
 return;
 
-  auto Diag =
-

[PATCH] D67460: clang-tidy: modernize-use-using work with multi-argument templates

2019-09-12 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 220002.
poelmanc added a comment.

Nice catch, that simplifies the code quite a bit! I added two more nested, 
complex multiple-template-argument tests and am happy to add more.

(We could do a case fallthrough after tok::l_brace, though some linters warn 
about them.)


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/modernize-use-using.cpp

Index: clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
===
--- clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
+++ clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
@@ -183,3 +183,63 @@
   void f() override { super::f(); }
 };
 }
+
+template 
+class TwoArgTemplate {
+  typedef TwoArgTemplate self;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
+  // CHECK-FIXES: using self = TwoArgTemplate;
+};
+
+template 
+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 
+struct Q {};
+
+constexpr bool b[1] = {true};
+
+typedef Q Q_t, *Q_p;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef Q Q_t, *Q_p;
+
+typedef Q Q2_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Q2_t = Q;
+
+struct T {
+  constexpr T(bool) {}
+
+  static constexpr bool b = true;
+};
+
+typedef Q Q3_t, *Q3_p;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef Q Q3_t, *Q3_p;
+
+typedef Q Q3_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Q3_t = Q;
+
+typedef TwoArgTemplate >, S<(0 < 0), Q > > Nested_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Nested_t = TwoArgTemplate >, S<(0 < 0), Q > >;
+
+template 
+class Variadic {};
+
+typedef Variadic >, S<(0 < 0), Variadic > > > Variadic_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Variadic_t = Variadic >, S<(0 < 0), Variadic > > >
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 thi

[PATCH] D67460: clang-tidy: modernize-use-using work with multi-argument templates

2019-09-12 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 220007.
poelmanc added a comment.

Sorry one more test at the end to make sure a multi-typedef with all that 
Variadic stuff still doesn't get changed to using.


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/modernize-use-using.cpp

Index: clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
===
--- clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
+++ clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
@@ -183,3 +183,67 @@
   void f() override { super::f(); }
 };
 }
+
+template 
+class TwoArgTemplate {
+  typedef TwoArgTemplate self;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
+  // CHECK-FIXES: using self = TwoArgTemplate;
+};
+
+template 
+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 
+struct Q {};
+
+constexpr bool b[1] = {true};
+
+typedef Q Q_t, *Q_p;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef Q Q_t, *Q_p;
+
+typedef Q Q2_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Q2_t = Q;
+
+struct T {
+  constexpr T(bool) {}
+
+  static constexpr bool b = true;
+};
+
+typedef Q Q3_t, *Q3_p;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef Q Q3_t, *Q3_p;
+
+typedef Q Q3_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Q3_t = Q;
+
+typedef TwoArgTemplate >, S<(0 < 0), Q > > Nested_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Nested_t = TwoArgTemplate >, S<(0 < 0), Q > >;
+
+template 
+class Variadic {};
+
+typedef Variadic >, S<(0 < 0), Variadic > > > Variadic_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Variadic_t = Variadic >, S<(0 < 0), Variadic > > >
+
+typedef Variadic >, S<(0 < 0), Variadic > > > Variadic_t, *Variadic_p;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef Variadic >, S<(0 < 0), Variadic > > > 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

[PATCH] D67460: clang-tidy: modernize-use-using work with multi-argument templates

2019-10-04 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.
Herald added a subscriber: mgehre.

Hi @alexfh, @jonathanmeier has reviewed my pull request but lacks commit 
access. It changes ~30 lines of code isolated to modernize-use-using.cpp and 
adds ~60 lines of tests. If you have time I'd greatly appreciate it if you 
could provide any feedback or commit it. Alternatively can you suggest someone 
else who can review it? Thanks!


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D67460/new/

https://reviews.llvm.org/D67460



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D68682: Clang-tidy fixes should avoid creating new blank lines

2019-10-08 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc created this revision.
poelmanc added reviewers: jonathanmeier, alexfh.
poelmanc added a project: clang-tools-extra.
Herald added subscribers: cfe-commits, mgehre, ormris.
Herald added a project: clang.

Clang-tidy can ignore most formatting concerns as formatting is clang-format's 
job. However, clang-format treats blank lines as intentional separators, so 
clang-tidy fixes that accidentally insert blank lines can prevent clang-format 
from properly fixing formatting. For example, applying 
readability-redundant-member-init to:

  struct F10 {
F10() :
  f(),
  g()
{}
S f, g;
  };

results in:

  struct F10 {
F10()
  
  
{}
S f, g;
  };

which may get converted to:

  struct F10 {
F10()
  
  
  = default;
S f, g;
  };

The newly blank lines prevent clang-format from fixing this to the desired:

  struct F10 {
F10() = default;
S f, g;
  };

A few individual fixes take steps to reduce some newly blank lines, e.g. 
RedundantControlFlowCheck.cpp calls 
`Lexer::findLocationAfterToken(.../*SkipTrailingWhitespaceAndNewLine=*/true )` 
to chomp trailing newlines after redundant `continue;` or `break;` statements. 
But this approach is insufficient when multiple rules combine to generate a 
blank line and forces more work onto each fix writer.

This patch adds a function `removeNewlyBlankLinesFromReplacements` to 
ClangTidy.cpp that looks for sequences of Replacements that will result in 
making a previously non-blank line blank. When found a Replacement is added 
that removes the entire line, including newlines.

The patch adds the above and other tests to 
readability-redundant-member-init.cpp, and adds tests to 
readability-redundant-control-flow.cpp and 
readability-redundant-declaration.cpp to demonstrate its effectiveness in 
avoiding newly blank lines anywhere.

Two previously private/static helper functions are exposed to assist in the 
implementation: AST/CommentLexer's `skipNewline` and AST/CommentParser's 
`isWhitespace(StringRef)`.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D68682

Files:
  clang-tools-extra/clang-tidy/ClangTidy.cpp
  clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
  clang-tools-extra/test/clang-tidy/readability-redundant-control-flow.cpp
  clang-tools-extra/test/clang-tidy/readability-redundant-declaration.cpp
  clang-tools-extra/test/clang-tidy/readability-redundant-member-init.cpp
  clang/include/clang/AST/CommentLexer.h
  clang/include/clang/AST/CommentParser.h
  clang/lib/AST/CommentLexer.cpp
  clang/lib/AST/CommentParser.cpp

Index: clang/lib/AST/CommentParser.cpp
===
--- clang/lib/AST/CommentParser.cpp
+++ clang/lib/AST/CommentParser.cpp
@@ -16,7 +16,8 @@
 
 namespace clang {
 
-static inline bool isWhitespace(llvm::StringRef S) {
+// Consider moving this useful function to a more general utility location.
+bool isWhitespace(llvm::StringRef S) {
   for (StringRef::const_iterator I = S.begin(), E = S.end(); I != E; ++I) {
 if (!isWhitespace(*I))
   return false;
Index: clang/lib/AST/CommentLexer.cpp
===
--- clang/lib/AST/CommentLexer.cpp
+++ clang/lib/AST/CommentLexer.cpp
@@ -16,6 +16,23 @@
 #include "llvm/Support/ErrorHandling.h"
 
 namespace clang {
+
+// Consider moving this useful function to a more general utility location.
+const char *skipNewline(const char *BufferPtr, const char *BufferEnd) {
+  if (BufferPtr == BufferEnd)
+return BufferPtr;
+
+  if (*BufferPtr == '\n')
+BufferPtr++;
+  else {
+assert(*BufferPtr == '\r');
+BufferPtr++;
+if (BufferPtr != BufferEnd && *BufferPtr == '\n')
+  BufferPtr++;
+  }
+  return BufferPtr;
+}
+
 namespace comments {
 
 void Token::dump(const Lexer &L, const SourceManager &SM) const {
@@ -131,21 +148,6 @@
   return BufferEnd;
 }
 
-const char *skipNewline(const char *BufferPtr, const char *BufferEnd) {
-  if (BufferPtr == BufferEnd)
-return BufferPtr;
-
-  if (*BufferPtr == '\n')
-BufferPtr++;
-  else {
-assert(*BufferPtr == '\r');
-BufferPtr++;
-if (BufferPtr != BufferEnd && *BufferPtr == '\n')
-  BufferPtr++;
-  }
-  return BufferPtr;
-}
-
 const char *skipNamedCharacterReference(const char *BufferPtr,
 const char *BufferEnd) {
   for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
Index: clang/include/clang/AST/CommentParser.h
===
--- clang/include/clang/AST/CommentParser.h
+++ clang/include/clang/AST/CommentParser.h
@@ -22,6 +22,10 @@
 namespace clang {
 class SourceManager;
 
+/// Returns true if and only if S consists entirely of whitespace.
+/// Consider moving this useful function to a more general utility location.
+bool isWhitespace(llvm::StringRef S);
+
 namespace comments {
 class CommandTraits;
 
Index: clang/include/clang/AST/CommentLexer.h
=

[PATCH] D68682: Clang-tidy fix removals removing all non-blank text from a line should remove the line

2019-10-09 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 224089.
poelmanc retitled this revision from "Clang-tidy fixes should avoid creating 
new blank lines" to "Clang-tidy fix removals removing all non-blank text from a 
line should remove the line".
poelmanc edited the summary of this revision.
poelmanc added a comment.

Thanks for the prompt review and feedback! MyDeveloperDay, your "drive-by" 
comments are quite welcome as the goal is to make clang-tidy and clang-format 
work better in tandem. You are correct that my prior version could have 
thwarted someone's chang-tidy checker that adds whitespace, which was an 
oversight on my part. I've updated the patch to change `isWhitespace( 
RemovalText )` to `RemovalText.isBlank()`. Now this only applies to 
//Removals// that remove all non-blank text from a line. I also updated the 
Title and Summary accordingly, adding the example that most confounded me of ": 
a()\n", which readability-redundant-member-init makes blank with a combination 
of two separate removals: one for the ":" and one for the "a()".

I understand and appreciate the feedback:

- //this removal of extra white space needs to be handled at the point the 
replacement is created and not on all the final replacements where the context 
is lost//
- //Checks that edit the source code should be improved to delete newlines 
where they become unnecessary//

Indeed I first tried fixing this entirely within 
readability-redundant-member-init. One problem was that when a line becomes 
blank due to two separate removals, code that peeks ahead or backwards to see 
if the line is blank doesn't know about other removals that will occur. Perhaps 
this can be fixed if the check() function has access to other removals that 
have already been created? (See also //Note 1//.) As I broadened my search I 
found code in readability-redundant-control-flow that heuristically tried to 
remove blank lines, but it failed to examine the entire line and thus removed 
newlines from the ends of lines that were not actually blank. (See the test 
case I added to readability-redundant-control-flow.cpp, where `  /* NOTE */ 
continue;\n` had the newline following `continue;` removed, leaving the comment 
attached to the next line.) And I found that readability-redundant-declaration 
did not attempt to remove blank lines, and its test cases specifically added 
comments to all removed declarations so that in its test cases, none of the 
resulting lines were blank. (See the test case I added to 
readability-redundant-declaration.cpp.)

Digging into these examples led me to the exact opposite conclusion: that the 
"newly blank line" problem needs to be solved consistently at a higher-level 
where all removals can be examined jointly, rather than trying to address it 
within each check.

I guess here's the high-level question: //should all removals that remove all 
non-blank text from a line also delete the line//?

- If //yes//: consider reviewing the patch
- If //mostly//: consider adding this as a top-level clang-tidy option that's 
off by default
- //Otherwise//: if it's possible to address this solely within each of 
readability-redundant-member-init, readability-redundant-control-flow, 
readability-redundant-declaration, etc., I can revisit that original approach. 
I'd appreciate pointers on how to access prior Removals on the same line from 
within check(), and any guesses regarding the Windows line-ending issue of 
//Note 1//.

Thanks!

//Note 1:// When applied to a file with Windows-style 2-character line endings, 
adding a Removal to readability-redundant-member-init whose Length was set to 
include the two-character newline would delete only the first character of the 
newline, leaving a \r. Then when I increased the removal length by 1, it would 
delete both newline characters //and// the first character of the line 
//after// the newline, which would be extremely undesirable. Updating removals 
at the top-level of ClangTidy.cpp did not have this problem. I was never able 
to track down where/why this error occurred, though it's surely fixable.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68682/new/

https://reviews.llvm.org/D68682

Files:
  clang-tools-extra/clang-tidy/ClangTidy.cpp
  clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
  clang-tools-extra/test/clang-tidy/readability-redundant-control-flow.cpp
  clang-tools-extra/test/clang-tidy/readability-redundant-declaration.cpp
  clang-tools-extra/test/clang-tidy/readability-redundant-member-init.cpp
  clang/include/clang/AST/CommentLexer.h
  clang/include/clang/AST/CommentParser.h
  clang/lib/AST/CommentLexer.cpp
  clang/lib/AST/CommentParser.cpp

Index: clang/lib/AST/CommentParser.cpp
===
--- clang/lib/AST/CommentParser.cpp
+++ clang/lib/AST/CommentParser.cpp
@@ -16,7 +16,8 @@
 
 namespace clang {
 
-static inline bool isWhitespace(llvm::StringRef S

[PATCH] D68682: Clang-tidy fix removals removing all non-blank text from a line should remove the line

2019-10-09 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

In D68682#1700908 , @Eugene.Zelenko 
wrote:

> You may be interested to also look on PR43583 related to 
> readability-redundant-member-init.


Thanks Eugene, I'm having trouble finding that. https://reviews.llvm.org/D43583 
seems related to MIPS instructions rather than 
readability-redundant-member-init. Could you please post a link? Thanks.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68682/new/

https://reviews.llvm.org/D68682



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D68682: Clang-tidy fix removals removing all non-blank text from a line should remove the line

2019-10-09 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc marked an inline comment as done.
poelmanc added inline comments.



Comment at: clang-tools-extra/clang-tidy/ClangTidy.cpp:27
 #include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/CharInfo.h" // for isWhiteSpace(char), 
isVerticalWhitespace(char)
 #include "clang/Config/config.h"

MyDeveloperDay wrote:
> Nit: I'm guessing you'd drop these comments later
Thanks, will do!



Comment at: clang-tools-extra/clang-tidy/ClangTidy.cpp:143
+ ReplacementText.empty();
+LineCheckedThroughPos = R.getOffset() + R.getLength();
+  }

MyDeveloperDay wrote:
> so If I understand correctly, if the ReplcementText is empty we are assuming 
> we've removed it, as opposed to if someone was adding a blank line the 
> ReplacementText would be all whitespace as we might remove it by mistake.. 
> sound reasonable
Exactly. A check's check() function can create a clang::FixItHint as an 
Insertion, Removal, or Replacement. Later FixItHints get processed, sorted, and 
merged into an ordered set of clang::tooling::Replacement. Each Replacement has 
a file Offset, Length, and ReplacementText. So a Removal FixItHint generally 
ends up as a Replacement whose ReplacementText is the empty string.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68682/new/

https://reviews.llvm.org/D68682



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D68682: Clang-tidy fix removals removing all non-blank text from a line should remove the line

2019-10-11 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

In D68682#1705865 , @Eugene.Zelenko 
wrote:

> In D68682#1705505 , @jonathanmeier 
> wrote:
>
> > In D68682#1702025 , @poelmanc 
> > wrote:
> >
> > > In D68682#1700908 , 
> > > @Eugene.Zelenko wrote:
> > >
> > > > You may be interested to also look on PR43583 related to 
> > > > readability-redundant-member-init.
> > >
> > >
> > > Thanks Eugene, I'm having trouble finding that. 
> > > https://reviews.llvm.org/D43583 seems related to MIPS instructions rather 
> > > than readability-redundant-member-init. Could you please post a link? 
> > > Thanks.
> >
> >
> > PRs are bug reports. You can access them like this: https://llvm.org/PR43583
>
>
> Or direct link to LLVM Bugzilla 
> (https://bugs.llvm.org/show_bug.cgi?id=). Ideally Phabricator should 
> recognize PR prefixes in same way as it recognize D.


Thanks @Eugene.Zelenko and @jonathanmeier. https://llvm.org/PR43583 now 
explains to me perfectly why my initial attempts to remove blank lines solely 
within readability-redundant-member-init failed: the final removal of ":" that 
in some cases left the line blank was not made in 
readability-redundant-member-init but higher up in the cleanup stage.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68682/new/

https://reviews.llvm.org/D68682



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D68682: Clang-tidy fix removals removing all non-blank text from a line should remove the line

2019-10-11 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

In D68682#1705866 , @gribozavr wrote:

> > I guess here's the high-level question: should all removals that remove all 
> > non-blank text from a line also delete the line?
>
> I see your point, but as https://llvm.org/PR43583 shows, we have a much 
> larger problem: textual replacements don't compose. So, whatever we do, it 
> will only be hacky workarounds for specific high-value cases.
>
> About how exactly to do it. It would be preferred if checkers that already 
> know that they are deleting a full line, just deleted the newline characters. 
> However, for other cases, I feel like the place where this patch implements 
> newline deletion is not ideal. It implements newline deletion while applying 
> all fixes. Applying fixes is not the only client of fixit information. 
> Probably it is one of the least-important ones, to be honest. I don't know 
> who will run clang-tidy and just trust it to apply whatever fixes it wants. 
> More likely, the user will want to see a preview of findings and fixes, and 
> fixit application will be done by some other tool. Therefore, implementing 
> newline deletion in the code that applies all fixes is not going to be 
> helpful for most workflows.
>
> Therefore, I think the most appropriate place to do this cleanup is 
> `cleanupAroundReplacements`. What do you think?


Thanks, from the name that sounds like the perfect place to do it. If 
`cleanupAroundReplacements` also is used by clang-format, would we want to make 
the functionality optional, e.g. via a new bool parameter to 
`cleanupAroundReplacements`, a new option in FormatStyle, etc.?


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68682/new/

https://reviews.llvm.org/D68682



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D68682: Clang-tidy fix removals removing all non-blank text from a line should remove the line

2019-10-17 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 225523.
poelmanc edited the summary of this revision.
poelmanc added a comment.

In D68682#1707764 , @alexfh wrote:

> cleanupAroundReplacements is not used by clang-format itself. I believe, it's 
> a part of clang-format only because it was easier to implement it on top of 
> some infrastructure clang-format provides.


Thanks for the correction @alexfh. I've updated the patch to call the line 
removal from cleanupAroundReplacements().


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68682/new/

https://reviews.llvm.org/D68682

Files:
  clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
  clang-tools-extra/test/clang-tidy/readability-redundant-control-flow.cpp
  clang-tools-extra/test/clang-tidy/readability-redundant-declaration.cpp
  clang-tools-extra/test/clang-tidy/readability-redundant-member-init.cpp
  clang/include/clang/AST/CommentLexer.h
  clang/include/clang/AST/CommentParser.h
  clang/include/clang/Format/Format.h
  clang/lib/AST/CommentLexer.cpp
  clang/lib/AST/CommentParser.cpp
  clang/lib/Format/Format.cpp

Index: clang/lib/Format/Format.cpp
===
--- clang/lib/Format/Format.cpp
+++ clang/lib/Format/Format.cpp
@@ -25,6 +25,9 @@
 #include "UnwrappedLineParser.h"
 #include "UsingDeclarationsSorter.h"
 #include "WhitespaceManager.h"
+#include "clang/AST/CommentLexer.h"
+#include "clang/AST/CommentParser.h"
+#include "clang/Basic/CharInfo.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/DiagnosticOptions.h"
 #include "clang/Basic/SourceManager.h"
@@ -2266,6 +2269,85 @@
 
 } // anonymous namespace
 
+llvm::Expected
+removeNewlyBlankLines(StringRef Code, const tooling::Replacements &Replaces) {
+  tooling::Replacements NewReplaces(Replaces);
+  // pair< LineStartPos, CheckedThroughPos > of lines that have been checked
+  // and confirmed that the replacement result so far will be entirely blank.
+  std::list> PotentialWholeLineCuts;
+  int LineStartPos = -1;
+  int LineCheckedThroughPos = -1;
+  bool LineBlankSoFar = true;
+  const char *FileText = Code.data();
+  StringRef FilePath; // Must be the same for every Replacement
+  for (const auto &R : Replaces) {
+assert(FilePath.empty() || FilePath == R.getFilePath());
+FilePath = R.getFilePath();
+const int RStartPos = R.getOffset();
+
+int CurrentRLineStartPos = RStartPos;
+while (CurrentRLineStartPos > 0 &&
+   !isVerticalWhitespace(FileText[CurrentRLineStartPos - 1])) {
+  --CurrentRLineStartPos;
+}
+
+assert(CurrentRLineStartPos >= LineStartPos);
+if (CurrentRLineStartPos != LineStartPos) {
+  // We've moved on to a new line. Wrap up the old one before moving on.
+  if (LineBlankSoFar) {
+PotentialWholeLineCuts.push_back(
+std::make_pair(LineStartPos, LineCheckedThroughPos));
+  }
+  LineCheckedThroughPos = CurrentRLineStartPos;
+  LineStartPos = CurrentRLineStartPos;
+  LineBlankSoFar = true;
+}
+
+// Check to see if line from LineCheckedThroughPos to here is blank.
+assert(RStartPos >= LineCheckedThroughPos);
+StringRef PriorTextToCheck(FileText + LineCheckedThroughPos,
+   RStartPos - LineCheckedThroughPos);
+StringRef ReplacementText = R.getReplacementText();
+LineBlankSoFar = LineBlankSoFar && isWhitespace(PriorTextToCheck) &&
+ ReplacementText.empty();
+LineCheckedThroughPos = R.getOffset() + R.getLength();
+  }
+
+  if (LineBlankSoFar) {
+PotentialWholeLineCuts.push_back(
+std::make_pair(LineStartPos, LineCheckedThroughPos));
+  }
+
+  // Now remove whole line if and only if (a) rest of line is blank, and
+  // (b) the original line was *not* blank.
+  for (const auto &LineCheckedThrough : PotentialWholeLineCuts) {
+const int LineStartPos = LineCheckedThrough.first;
+const int CheckedThroughPos = LineCheckedThrough.second;
+
+int LineEndPos = CheckedThroughPos;
+while (LineEndPos < Code.size() &&
+   !isVerticalWhitespace(FileText[LineEndPos])) {
+  ++LineEndPos;
+}
+
+assert(LineEndPos >= CheckedThroughPos);
+StringRef TrailingText(FileText + CheckedThroughPos,
+   LineEndPos - CheckedThroughPos);
+assert(LineEndPos >= LineStartPos);
+StringRef OriginalLine(FileText + LineStartPos, LineEndPos - LineStartPos);
+if (isWhitespace(TrailingText) && !isWhitespace(OriginalLine)) {
+  const char *CutTo = skipNewline(FileText + LineEndPos, Code.end());
+  int CutCount = CutTo - FileText - LineStartPos;
+  llvm::Error Err = NewReplaces.add(
+  tooling::Replacement(FilePath, LineStartPos, CutCount, ""));
+  if (Err) {
+return llvm::Expected(std::move(Err));
+  }
+}
+  }
+  return NewReplaces;
+}
+
 llvm::Expected
 cleanupAroundReplacements(Stri

[PATCH] D69145: Give readability-redundant-member-init an option IgnoreBaseInCopyConstructors to avoid breaking code with gcc -Werror=extra

2019-10-17 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc created this revision.
poelmanc added reviewers: malcolm.parsons, alexfh, hokein, aaron.ballman.
poelmanc added a project: clang-tools-extra.
Herald added subscribers: cfe-commits, mgehre.
Herald added a project: clang.

readability-redundant-member-init removes redundant / unnecessary member and 
base class initialization. Unfortunately for the specific case of a copy 
constructor's initialization of a base class, gcc at strict warning levels 
warns if "base class is not initialized in the copy constructor of a derived 
class ".

This patch adds an option `IgnoreBaseInCopyConstructors` defaulting to false 
(thus maintaining current behavior by default) to skip the specific case of 
removal of redundant base class initialization in the copy constructor. 
Enabling this option enables the resulting code to continue to compile 
successfully under `gcc -Werror=extra`. New test cases `WithCopyConstructor1` 
and `WithCopyConstructor2` in 
clang-tools-extra/test/clang-tidy/readability-redundant-member-init.cpp show 
that it removes redundant members even from copy constructors.

I blindly followed examples for adding a new option and would greatly 
appreciate any review/suggestions/feedback. Thank you.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D69145

Files:
  clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp
  clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h
  clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst
  clang-tools-extra/test/clang-tidy/readability-redundant-member-init.cpp

Index: clang-tools-extra/test/clang-tidy/readability-redundant-member-init.cpp
===
--- clang-tools-extra/test/clang-tidy/readability-redundant-member-init.cpp
+++ clang-tools-extra/test/clang-tidy/readability-redundant-member-init.cpp
@@ -1,4 +1,8 @@
 // RUN: %check_clang_tidy %s readability-redundant-member-init %t
+// RUN:   -config="{CheckOptions: \
+// RUN: [{key: readability-redundant-member-init.IgnoreBaseInCopyConstructors, \
+// RUN:   value: 1}] \
+// RUN: }"
 
 struct S {
   S() = default;
@@ -116,6 +120,35 @@
   };
 };
 
+// struct whose inline copy constructor default-initializes its base class
+struct WithCopyConstructor1 : public T {
+  WithCopyConstructor1(const WithCopyConstructor1& other) : T(),
+f(),
+g()
+  {}
+  S f, g;
+};
+// No warning in copy constructor about T since IgnoreBaseInCopyConstructors=1
+// CHECK-MESSAGES: :[[@LINE-6]]:5: warning: initializer for member 'f' is redundant
+// CHECK-MESSAGES: :[[@LINE-6]]:5: warning: initializer for member 'g' is redundant
+// CHECK-FIXES: WithCopyConstructor1(const WithCopyConstructor1& other) : T()
+// CHECK-NEXT: 
+// CHECK-NEXT: 
+// CHECK-NEXT: {}
+
+// struct whose copy constructor default-initializes its base class
+struct WithCopyConstructor2 : public T {
+  WithCopyConstructor2(const WithCopyConstructor2& other);
+  S a;
+};
+WithCopyConstructor2::WithCopyConstructor2(const WithCopyConstructor2& other)
+  : T(), a()
+{}
+// No warning in copy constructor about T since IgnoreBaseInCopyConstructors=1
+// CHECK-MESSAGES: :[[@LINE-3]]:10: warning: initializer for member 'a' is redundant
+// CHECK-FIXES: {{^}}  : T() {{$}}
+// CHECK-NEXT: {}
+
 // Initializer not written
 struct NF1 {
   NF1() {}
Index: clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst
===
--- clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst
+++ clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst
@@ -6,7 +6,8 @@
 Finds member initializations that are unnecessary because the same default
 constructor would be called if they were not present.
 
-Example:
+Example
+---
 
 .. code-block:: c++
 
@@ -18,3 +19,14 @@
   private:
 std::string s;
   };
+
+Options
+---
+
+.. option:: IgnoreBaseInCopyConstructors
+
+When non-zero, the check will ignore unnecessary base class initializations
+within copy constructors. Some compilers issue warnings requiring copy
+constructors to explicitly initialize their base classes.
+
+Default is ``0``.  
Index: clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h
===
--- clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h
+++ clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h
@@ -23,9 +23,14 @@
 class RedundantMemberInitCheck : public ClangTidyCheck {
 public:
   RedundantMemberInitCheck(StringRef Name, ClangTidyContext *Context)
-  : ClangTidyCheck(Name, Context) {}
+  : ClangTidyCheck(Name, Context),
+IgnoreBaseInCopyConstructors(Options.get("IgnoreBaseInCopyConstructors", 0))
+  {}
+  void storeO

[PATCH] D69145: Give readability-redundant-member-init an option IgnoreBaseInCopyConstructors to avoid breaking code with gcc -Werror=extra

2019-10-19 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

In D69145#1715611 , @mgehre wrote:

> Exactly due to the issue you are fixing here, we ended up disabling the 
> complete check because we didn't want to live with the warnings it produced 
> on -Wextra.
>  Therefore, I'm actually strongly in favor to enable the option by default.
>
> When others see that clang-tidy fixits introduce warnings (with -Wextra) or 
> even break their build (with -Werror), they might not look into check 
> options, but just disable the check directly.


Thank you for the feedback! I certainly like your suggestion to enable this by 
default but will await a collective conclusion before changing that.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69145/new/

https://reviews.llvm.org/D69145



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69145: Give readability-redundant-member-init an option IgnoreBaseInCopyConstructors to avoid breaking code with gcc -Werror=extra

2019-10-19 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 225764.
poelmanc added a comment.

Addressed @mgehre's feedback:

- Ran clang-format
- Included gcc, -Wextra, -Werror=extra, and the full text of the warning/error 
message to aid in searchability, so people can find this option when they 
encounter the problem. Also added example code to the documentation.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69145/new/

https://reviews.llvm.org/D69145

Files:
  clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp
  clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h
  clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst
  clang-tools-extra/test/clang-tidy/readability-redundant-member-init.cpp

Index: clang-tools-extra/test/clang-tidy/readability-redundant-member-init.cpp
===
--- clang-tools-extra/test/clang-tidy/readability-redundant-member-init.cpp
+++ clang-tools-extra/test/clang-tidy/readability-redundant-member-init.cpp
@@ -1,4 +1,8 @@
 // RUN: %check_clang_tidy %s readability-redundant-member-init %t
+// RUN:   -config="{CheckOptions: \
+// RUN: [{key: readability-redundant-member-init.IgnoreBaseInCopyConstructors, \
+// RUN:   value: 1}] \
+// RUN: }"
 
 struct S {
   S() = default;
@@ -116,6 +120,35 @@
   };
 };
 
+// struct whose inline copy constructor default-initializes its base class
+struct WithCopyConstructor1 : public T {
+  WithCopyConstructor1(const WithCopyConstructor1& other) : T(),
+f(),
+g()
+  {}
+  S f, g;
+};
+// No warning in copy constructor about T since IgnoreBaseInCopyConstructors=1
+// CHECK-MESSAGES: :[[@LINE-6]]:5: warning: initializer for member 'f' is redundant
+// CHECK-MESSAGES: :[[@LINE-6]]:5: warning: initializer for member 'g' is redundant
+// CHECK-FIXES: WithCopyConstructor1(const WithCopyConstructor1& other) : T()
+// CHECK-NEXT: 
+// CHECK-NEXT: 
+// CHECK-NEXT: {}
+
+// struct whose copy constructor default-initializes its base class
+struct WithCopyConstructor2 : public T {
+  WithCopyConstructor2(const WithCopyConstructor2& other);
+  S a;
+};
+WithCopyConstructor2::WithCopyConstructor2(const WithCopyConstructor2& other)
+  : T(), a()
+{}
+// No warning in copy constructor about T since IgnoreBaseInCopyConstructors=1
+// CHECK-MESSAGES: :[[@LINE-3]]:10: warning: initializer for member 'a' is redundant
+// CHECK-FIXES: {{^}}  : T() {{$}}
+// CHECK-NEXT: {}
+
 // Initializer not written
 struct NF1 {
   NF1() {}
Index: clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst
===
--- clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst
+++ clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst
@@ -6,7 +6,8 @@
 Finds member initializations that are unnecessary because the same default
 constructor would be called if they were not present.
 
-Example:
+Example
+---
 
 .. code-block:: c++
 
@@ -18,3 +19,27 @@
   private:
 std::string s;
   };
+
+Options
+---
+
+.. option:: IgnoreBaseInCopyConstructors
+
+Default is ``0``.
+
+When non-zero, the check will ignore unnecessary base class initializations
+within copy constructors, since some compilers issue warnings/errors when
+base classes are not explicitly intialized in copy constructors. For example,
+``gcc`` with ``-Wextra`` or ``-Werror=extra`` issues warning or error
+``base class ‘Bar’ should be explicitly initialized in the copy constructor``
+if ``Bar()`` were removed in the following example:
+
+.. code-block:: c++
+
+  // Explicitly initializing member s and base class Bar is unnecessary.
+  struct Foo : public Bar {
+// Remove s() below. If IgnoreBaseInCopyConstructors!=0, keep Bar().
+Foo(const Foo& foo) : Bar(), s() {}
+std::string s;
+  };
+
Index: clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h
===
--- clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h
+++ clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h
@@ -23,9 +23,15 @@
 class RedundantMemberInitCheck : public ClangTidyCheck {
 public:
   RedundantMemberInitCheck(StringRef Name, ClangTidyContext *Context)
-  : ClangTidyCheck(Name, Context) {}
+  : ClangTidyCheck(Name, Context),
+IgnoreBaseInCopyConstructors(
+Options.get("IgnoreBaseInCopyConstructors", 0)) {}
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  bool IgnoreBaseInCopyConstructors;
 };
 
 } // namespace readability
Index: clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp
=

[PATCH] D69145: Give readability-redundant-member-init an option IgnoreBaseInCopyConstructors to avoid breaking code with gcc -Werror=extra

2019-10-19 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

In D69145#1715614 , @lebedev.ri wrote:

> So https://godbolt.org/z/qzjU-C
>  This feels like gcc being overly zealous, i'm not sure what it says with 
> that warning.


I'd agree, while copy constructors //usually// need to copy base class 
information as well, and forgetting to do so //may// indicate a programming 
error, this warning may be more appropriate as a linter suggestion than a 
compiler warning. (Usually you'd want `: BaseClass(other)`; `: BaseClass()` is 
really just silencing the warning so you can handle `BaseClass` in the body of 
the copy constructor.)

That said, the warning appears to have been introduced in gcc 4.0 

 in 2005  so every modern version of gcc will 
produce this warning. So in practical terms the concerns raised by @mgehre are 
why I feel this option is needed.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69145/new/

https://reviews.llvm.org/D69145



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69238: Fix clang-tidy readability-redundant-string-init for c++17/c++2a

2019-10-21 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc created this revision.
poelmanc added reviewers: gribozavr, etienneb, alexfh.
Herald added subscribers: cfe-commits, mgehre, dylanmckay.
Herald added a project: clang.

`readability-redundant-string-init` was one of several clang-tidy checks 
documented as failing for C++17 by @gribozavr's extensive testing on 
2019-05-20. (The failure mode in C++17 is that it changes `std::string Name = 
"";` to `std::string Name = Name;`, which actually compiles.)

I found that the `CtorExpr->getSourceRange()` for `string Name = ""` changed 
from spanning the `Name = ""` in C++11/14 to only spanning the `""` in 
C++17/2a. My fix was to add a `CtorSourceRange` function that, if CtorExpr does 
not already start with `Name`, searches backwards for `Name = ` and extends the 
SourceRange to include it. The readability-redundant-string-init.cpp and 
readability-redundant-string-init-msvc.cpp tests now pass for C++11/14/17/2a. 
(The warning for `DECL_STRING(e, "");` is reported at different character 
positions in 11/14 versus 17/2a, so I updated that test to accept either 
position.)

As always I welcome any feedback or suggestions for improvement. In particular, 
the fix would be far simpler if there's some other expression matcher that 
captures the whole `Name = ""` expression. Or, is it possible that this change 
in SourceRange is an unintentional difference in the parsing code? If so fixing 
that might make more sense.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D69238

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init-msvc.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
@@ -1,5 +1,4 @@
-// RUN: %check_clang_tidy -std=c++11,c++14 %s readability-redundant-string-init %t
-// FIXME: Fix the checker to work in C++17 mode.
+// RUN: %check_clang_tidy %s readability-redundant-string-init %t
 
 namespace std {
 template 
@@ -104,7 +103,7 @@
   // CHECK-MESSAGES: [[@LINE-1]]:10: warning: redundant string initialization
   // CHECK-FIXES: STRING d;
   DECL_STRING(e, "");
-  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+  // CHECK-MESSAGES: [[@LINE-1]]:1{{[58]}}: warning: redundant string initialization
 
   MyString f = "u";
   STRING g = "u";
Index: clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init-msvc.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init-msvc.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init-msvc.cpp
@@ -1,5 +1,4 @@
-// RUN: %check_clang_tidy -std=c++11,c++14 %s readability-redundant-string-init %t
-// FIXME: Fix the checker to work in C++17 mode.
+// RUN: %check_clang_tidy %s readability-redundant-string-init %t
 
 namespace std {
 template 
Index: clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
@@ -57,12 +57,76 @@
   this);
 }
 
+// Returns the SourceRange for the string constructor expression and a bool
+// indicating whether to fix it (by replacing it with just the variable name)
+// or just issue a diagnostic warning. CtorExpr's SourceRange includes:
+//   foo = ""
+//   bar("")
+//   ""(only in C++17 and later)
+//
+// With -std c++14 or earlier (!LangOps.CPlusPlus17), it was sufficient to
+// return CtorExpr->getSourceRange(). However, starting with c++17, parsing
+// the expression 'std::string Name = ""' results in a CtorExpr whose
+// SourceRange includes just '""' rather than the previous 'Name = ""'.
+//
+// So if the CtorExpr's SourceRange doesn't already start with 'Name', we
+// search leftward for 'Name\b*=\b*' (where \b* represents optional whitespace)
+// and if found, extend the SourceRange to start at 'Name'.
+std::pair
+CtorSourceRange(const MatchFinder::MatchResult &Result,
+const clang::NamedDecl *Decl, const clang::Expr *CtorExpr) {
+  const auto &SM = *Result.SourceManager;
+  const StringRef Name = Decl->getName();
+  const int NameLength = Name.size();
+  const SourceLocation CtorStartLoc(CtorExpr->getSourceRange().getBegin());
+  const std::pair CtorLocInfo = SM.getDecomposedLoc(
+  CtorStartLoc.isMacroID() ? SM.getImmediateMacroCallerLoc(CtorStartLoc)
+   : CtorStartLoc);
+  const int CtorStartPos = CtorLocInfo

[PATCH] D69238: Fix clang-tidy readability-redundant-string-init for c++17/c++2a

2019-10-21 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 225894.
poelmanc added a comment.

Removed the two uses of auto where the type was not an iterator or clear from 
the right-hand-side.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69238/new/

https://reviews.llvm.org/D69238

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init-msvc.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
@@ -1,5 +1,4 @@
-// RUN: %check_clang_tidy -std=c++11,c++14 %s readability-redundant-string-init %t
-// FIXME: Fix the checker to work in C++17 mode.
+// RUN: %check_clang_tidy %s readability-redundant-string-init %t
 
 namespace std {
 template 
@@ -104,7 +103,7 @@
   // CHECK-MESSAGES: [[@LINE-1]]:10: warning: redundant string initialization
   // CHECK-FIXES: STRING d;
   DECL_STRING(e, "");
-  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+  // CHECK-MESSAGES: [[@LINE-1]]:1{{[58]}}: warning: redundant string initialization
 
   MyString f = "u";
   STRING g = "u";
Index: clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init-msvc.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init-msvc.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init-msvc.cpp
@@ -1,5 +1,4 @@
-// RUN: %check_clang_tidy -std=c++11,c++14 %s readability-redundant-string-init %t
-// FIXME: Fix the checker to work in C++17 mode.
+// RUN: %check_clang_tidy %s readability-redundant-string-init %t
 
 namespace std {
 template 
Index: clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
@@ -57,12 +57,77 @@
   this);
 }
 
+// Returns the SourceRange for the string constructor expression and a bool
+// indicating whether to fix it (by replacing it with just the variable name)
+// or just issue a diagnostic warning. CtorExpr's SourceRange includes:
+//   foo = ""
+//   bar("")
+//   ""(only in C++17 and later)
+//
+// With -std c++14 or earlier (!LangOps.CPlusPlus17), it was sufficient to
+// return CtorExpr->getSourceRange(). However, starting with c++17, parsing
+// the expression 'std::string Name = ""' results in a CtorExpr whose
+// SourceRange includes just '""' rather than the previous 'Name = ""'.
+//
+// So if the CtorExpr's SourceRange doesn't already start with 'Name', we
+// search leftward for 'Name\b*=\b*' (where \b* represents optional whitespace)
+// and if found, extend the SourceRange to start at 'Name'.
+std::pair
+CtorSourceRange(const MatchFinder::MatchResult &Result,
+const clang::NamedDecl *Decl, const clang::Expr *CtorExpr) {
+  const SourceManager &SM = *Result.SourceManager;
+  const StringRef Name = Decl->getName();
+  const int NameLength = Name.size();
+  const SourceLocation CtorStartLoc(CtorExpr->getSourceRange().getBegin());
+  const std::pair CtorLocInfo = SM.getDecomposedLoc(
+  CtorStartLoc.isMacroID() ? SM.getImmediateMacroCallerLoc(CtorStartLoc)
+   : CtorStartLoc);
+  const int CtorStartPos = CtorLocInfo.second;
+  const StringRef File = SM.getBufferData(CtorLocInfo.first);
+  const StringRef CtorCheckName = File.substr(CtorStartPos, NameLength);
+  if (CtorCheckName == Name) {
+// For 'std::string foo("");', CtorExpr is 'foo("")'
+return std::make_pair(CtorExpr->getSourceRange(), true);
+  }
+  // Scan backwards from CtorStartPos.
+  // If find "Name\b*=\b*", extend CtorExpr SourceRange leftwards to include it.
+  bool FoundEquals = false;
+  for (int Pos = CtorStartPos - 1; Pos >= 0; Pos--) {
+const char Char = File.data()[Pos];
+if (Char == '=') {
+  if (FoundEquals) {
+break; // Only allow one equals sign
+  }
+  FoundEquals = true;
+} else if (!isWhitespace(Char)) {
+  // First non-whitespace/non-equals char. Check for Name ending with it.
+  const int CheckNameStart = Pos - NameLength + 1;
+  const StringRef CheckName(File.data() + CheckNameStart, NameLength);
+  if (FoundEquals && Name == CheckName) {
+return std::make_pair(
+clang::SourceRange(
+CtorStartLoc.getLocWithOffset(CheckNameStart - CtorStartPos),
+CtorExpr->getSourceRange().getEnd()),
+

[PATCH] D69238: Fix clang-tidy readability-redundant-string-init for c++17/c++2a

2019-10-21 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc marked 2 inline comments as done.
poelmanc added a comment.

Thanks for the quick feedback, fixed.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69238/new/

https://reviews.llvm.org/D69238



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D67460: clang-tidy: modernize-use-using work with multi-argument templates

2019-10-21 Thread Conrad Poelman via Phabricator via cfe-commits
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 
+class TwoArgTemplate {
+  typedef TwoArgTemplate self;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
+  // CHECK-FIXES: using self = TwoArgTemplate;
+};
+
+template 
+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 
+struct Q {};
+
+constexpr bool b[1] = {true};
+
+typedef Q Q_t, *Q_p;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef Q Q_t, *Q_p;
+
+typedef Q Q2_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Q2_t = Q;
+
+struct T {
+  constexpr T(bool) {}
+
+  static constexpr bool b = true;
+};
+
+typedef Q Q3_t, *Q3_p;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef Q Q3_t, *Q3_p;
+
+typedef Q Q3_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Q3_t = Q;
+
+typedef TwoArgTemplate >, S<(0 < 0), Q > > Nested_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Nested_t = TwoArgTemplate >, S<(0 < 0), Q > >;
+
+template 
+class Variadic {};
+
+typedef Variadic >, S<(0 < 0), Variadic > > > Variadic_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Variadic_t = Variadic >, S<(0 < 0), Variadic > > >
+
+typedef Variadic >, S<(0 < 0), Variadic > > > Variadic_t, *Variadic_p;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef Variadic >, S<(0 < 0), Variadic > > > 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 == 

[PATCH] D67460: clang-tidy: modernize-use-using work with multi-argument templates

2019-10-21 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc marked an inline comment as done.
poelmanc added a comment.

Checked "Done". (I addressed @jonathanmeier's comment feedback with a previous 
update but forgot to check the box!)

I welcome any more feedback. Thanks.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D67460/new/

https://reviews.llvm.org/D67460



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69145: Give readability-redundant-member-init an option IgnoreBaseInCopyConstructors to avoid breaking code with gcc -Werror=extra

2019-10-21 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc marked 2 inline comments as done.
poelmanc added a comment.

Addressed these the other day but failed to check the "Done" boxes. Done!


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69145/new/

https://reviews.llvm.org/D69145



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69145: Give readability-redundant-member-init an option IgnoreBaseInCopyConstructors to avoid breaking code with gcc -Werror=extra

2019-10-21 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 225897.
poelmanc added a comment.

Rebase to latest master (tests moved into new "checkers" directory.)


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69145/new/

https://reviews.llvm.org/D69145

Files:
  clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp
  clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h
  clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp
@@ -1,4 +1,8 @@
 // RUN: %check_clang_tidy %s readability-redundant-member-init %t
+// RUN:   -config="{CheckOptions: \
+// RUN: [{key: readability-redundant-member-init.IgnoreBaseInCopyConstructors, \
+// RUN:   value: 1}] \
+// RUN: }"
 
 struct S {
   S() = default;
@@ -116,6 +120,35 @@
   };
 };
 
+// struct whose inline copy constructor default-initializes its base class
+struct WithCopyConstructor1 : public T {
+  WithCopyConstructor1(const WithCopyConstructor1& other) : T(),
+f(),
+g()
+  {}
+  S f, g;
+};
+// No warning in copy constructor about T since IgnoreBaseInCopyConstructors=1
+// CHECK-MESSAGES: :[[@LINE-6]]:5: warning: initializer for member 'f' is redundant
+// CHECK-MESSAGES: :[[@LINE-6]]:5: warning: initializer for member 'g' is redundant
+// CHECK-FIXES: WithCopyConstructor1(const WithCopyConstructor1& other) : T()
+// CHECK-NEXT: 
+// CHECK-NEXT: 
+// CHECK-NEXT: {}
+
+// struct whose copy constructor default-initializes its base class
+struct WithCopyConstructor2 : public T {
+  WithCopyConstructor2(const WithCopyConstructor2& other);
+  S a;
+};
+WithCopyConstructor2::WithCopyConstructor2(const WithCopyConstructor2& other)
+  : T(), a()
+{}
+// No warning in copy constructor about T since IgnoreBaseInCopyConstructors=1
+// CHECK-MESSAGES: :[[@LINE-3]]:10: warning: initializer for member 'a' is redundant
+// CHECK-FIXES: {{^}}  : T() {{$}}
+// CHECK-NEXT: {}
+
 // Initializer not written
 struct NF1 {
   NF1() {}
Index: clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst
===
--- clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst
+++ clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst
@@ -6,7 +6,8 @@
 Finds member initializations that are unnecessary because the same default
 constructor would be called if they were not present.
 
-Example:
+Example
+---
 
 .. code-block:: c++
 
@@ -18,3 +19,27 @@
   private:
 std::string s;
   };
+
+Options
+---
+
+.. option:: IgnoreBaseInCopyConstructors
+
+Default is ``0``.
+
+When non-zero, the check will ignore unnecessary base class initializations
+within copy constructors, since some compilers issue warnings/errors when
+base classes are not explicitly intialized in copy constructors. For example,
+``gcc`` with ``-Wextra`` or ``-Werror=extra`` issues warning or error
+``base class ‘Bar’ should be explicitly initialized in the copy constructor``
+if ``Bar()`` were removed in the following example:
+
+.. code-block:: c++
+
+  // Explicitly initializing member s and base class Bar is unnecessary.
+  struct Foo : public Bar {
+// Remove s() below. If IgnoreBaseInCopyConstructors!=0, keep Bar().
+Foo(const Foo& foo) : Bar(), s() {}
+std::string s;
+  };
+
Index: clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h
===
--- clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h
+++ clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h
@@ -23,9 +23,15 @@
 class RedundantMemberInitCheck : public ClangTidyCheck {
 public:
   RedundantMemberInitCheck(StringRef Name, ClangTidyContext *Context)
-  : ClangTidyCheck(Name, Context) {}
+  : ClangTidyCheck(Name, Context),
+IgnoreBaseInCopyConstructors(
+Options.get("IgnoreBaseInCopyConstructors", 0)) {}
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  bool IgnoreBaseInCopyConstructors;
 };
 
 } // namespace readability
Index: clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp
+++ clang-tools-extra/clang

[PATCH] D69145: Give readability-redundant-member-init an option IgnoreBaseInCopyConstructors to avoid breaking code with gcc -Werror=extra

2019-10-24 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

What do @malcolm.parsons, @alexfh, @hokein, @aaron.ballman, @lebedev.ri think 
of @mgehre's suggestion to enable `IgnoreBaseInCopyConstructors` as the default 
setting, so gcc users won't experience build errors and think "clang-tidy broke 
my code!"

I could go either way and appreciate any input.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69145/new/

https://reviews.llvm.org/D69145



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69238: Fix clang-tidy readability-redundant-string-init for c++17/c++2a

2019-10-28 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 226695.
poelmanc added a comment.

Remove extra `const`, braces for one-line `if` statements, and `clang::`. Added 
a comment explaining the need for a regex on a warning test line.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69238/new/

https://reviews.llvm.org/D69238

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init-msvc.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
@@ -1,5 +1,4 @@
-// RUN: %check_clang_tidy -std=c++11,c++14 %s readability-redundant-string-init %t
-// FIXME: Fix the checker to work in C++17 mode.
+// RUN: %check_clang_tidy %s readability-redundant-string-init %t
 
 namespace std {
 template 
@@ -104,7 +103,8 @@
   // CHECK-MESSAGES: [[@LINE-1]]:10: warning: redundant string initialization
   // CHECK-FIXES: STRING d;
   DECL_STRING(e, "");
-  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+  // Warning at position :15 with -std=c++11/14, position :18 for -std=c++17/2x
+  // CHECK-MESSAGES: [[@LINE-2]]:1{{[58]}}: warning: redundant string initialization
 
   MyString f = "u";
   STRING g = "u";
Index: clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init-msvc.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init-msvc.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init-msvc.cpp
@@ -1,5 +1,4 @@
-// RUN: %check_clang_tidy -std=c++11,c++14 %s readability-redundant-string-init %t
-// FIXME: Fix the checker to work in C++17 mode.
+// RUN: %check_clang_tidy %s readability-redundant-string-init %t
 
 namespace std {
 template 
Index: clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
@@ -57,12 +57,73 @@
   this);
 }
 
+// Returns the SourceRange for the string constructor expression and a bool
+// indicating whether to fix it (by replacing it with just the variable name)
+// or just issue a diagnostic warning. CtorExpr's SourceRange includes:
+//   foo = ""
+//   bar("")
+//   ""(only in C++17 and later)
+//
+// With -std c++14 or earlier (!LangOps.CPlusPlus17), it was sufficient to
+// return CtorExpr->getSourceRange(). However, starting with c++17, parsing
+// the expression 'std::string Name = ""' results in a CtorExpr whose
+// SourceRange includes just '""' rather than the previous 'Name = ""'.
+//
+// So if the CtorExpr's SourceRange doesn't already start with 'Name', we
+// search leftward for 'Name\b*=\b*' (where \b* represents optional whitespace)
+// and if found, extend the SourceRange to start at 'Name'.
+std::pair
+CtorSourceRange(const MatchFinder::MatchResult &Result, const NamedDecl *Decl,
+const Expr *CtorExpr) {
+  const SourceManager &SM = *Result.SourceManager;
+  StringRef Name = Decl->getName();
+  int NameLength = Name.size();
+  SourceLocation CtorStartLoc(CtorExpr->getSourceRange().getBegin());
+  std::pair CtorLocInfo = SM.getDecomposedLoc(
+  CtorStartLoc.isMacroID() ? SM.getImmediateMacroCallerLoc(CtorStartLoc)
+   : CtorStartLoc);
+  int CtorStartPos = CtorLocInfo.second;
+  StringRef File = SM.getBufferData(CtorLocInfo.first);
+  StringRef CtorCheckName = File.substr(CtorStartPos, NameLength);
+  if (CtorCheckName == Name)
+// For 'std::string foo("");', CtorExpr is 'foo("")'
+return std::make_pair(CtorExpr->getSourceRange(), true);
+  // Scan backwards from CtorStartPos.
+  // If find "Name\b*=\b*", extend CtorExpr SourceRange leftwards to include it.
+  bool FoundEquals = false;
+  for (int Pos = CtorStartPos - 1; Pos >= 0; Pos--) {
+char Char = File.data()[Pos];
+if (Char == '=') {
+  if (FoundEquals)
+break; // Only allow one equals sign
+  FoundEquals = true;
+} else if (!isWhitespace(Char)) {
+  // First non-whitespace/non-equals char. Check for Name ending with it.
+  int CheckNameStart = Pos - NameLength + 1;
+  StringRef CheckName(File.data() + CheckNameStart, NameLength);
+  if (FoundEquals && Name == CheckName) {
+return std::make_pair(SourceRange(CtorStartLoc.getLocWithOffset(
+  CheckNameStart - CtorStartPos),
+  

[PATCH] D69238: Fix clang-tidy readability-redundant-string-init for c++17/c++2a

2019-10-28 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc marked 5 inline comments as done.
poelmanc added a comment.

Thanks for the feedback, the new patch removes the extra `const`, `clang::`, 
and braces on one-line `if` statements, and now explains the regex in 
readability-redundant-string-init.cpp.




Comment at: 
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp:106
   DECL_STRING(e, "");
-  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+  // CHECK-MESSAGES: [[@LINE-1]]:1{{[58]}}: warning: redundant string 
initialization
 

aaron.ballman wrote:
> Why does this need a regex?
Thanks, I added a comment explaining that the character position of the warning 
differs slightly between C++11/14 (reports at the 'e') and C++17/2x (reports at 
the '"'), since the underlying parsing code has changed.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69238/new/

https://reviews.llvm.org/D69238



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69548: Give clang-tidy readability-redundant-string-init a customizable list of string types to fix

2019-10-28 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc created this revision.
poelmanc added a reviewer: MyDeveloperDay.
poelmanc added a project: clang-tools-extra.
Herald added subscribers: cfe-commits, mgehre.
Herald added a project: clang.

This patch adds a feature requested by @MyDeveloperDay at 
https://reviews.llvm.org/D69238, @MyDeveloperDay to enable 
`readability-redundant-string-init` to take a list of strings to apply the fix 
to rather than hard-coding `basic_string`. It adds a `StringNames` option of 
semicolon-delimited names of string classes to which to apply this fix. Tests 
ensure this works with test class OurTestString as well as std::string and 
std::wstring as before. It should be applicable to llvm::StringRef, QString, 
etc.

This diff is currently based on https://reviews.llvm.org/D69238. Both make 
changes to the top of readability-redundant-string-init.cpp. I'm happy to 
rebase it on any version desired.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D69548

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
  clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.h
  clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
  clang/include/clang/ASTMatchers/ASTMatchers.h

Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -2551,6 +2551,19 @@
 internal::hasAnyNameFunc>
 hasAnyName;
 
+/// Matches NamedDecl nodes that have any of the specified names.
+///
+/// \code
+/// hasListedName({a, b, c,...})
+/// \endcode
+///  is equivalent to
+/// \code
+/// anyOf(hasName(a), hasName(b), hasName(c),...)
+/// \endcode
+inline internal::Matcher hasListedName(const std::vector &Names) {
+  return internal::Matcher(new internal::HasNameMatcher(Names));
+}
+
 /// Matches NamedDecl nodes whose fully qualified names contain
 /// a substring matched by the given RegExp.
 ///
Index: clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
@@ -1,4 +1,8 @@
 // RUN: %check_clang_tidy %s readability-redundant-string-init %t
+// RUN:   -config="{CheckOptions: \
+// RUN: [{key: readability-redundant-string-init.StringNames, \
+// RUN:   value: "basic_string;OurTestString"}] \
+// RUN: }"
 
 namespace std {
 template 
@@ -139,3 +143,31 @@
 void Param3(std::string param = "") {}
 void Param4(STRING param = "") {}
 
+struct OurTestString {
+  OurTestString();
+  OurTestString(const OurTestString &);
+  // MSVC headers define two constructors instead of using optional arguments.
+  OurTestString(const char *);
+  ~OurTestString();
+};
+
+void OurTestStringTests() {
+  OurTestString a = "";
+  // CHECK-MESSAGES: [[@LINE-1]]:17: warning: redundant string initialization
+  // CHECK-FIXES: OurTestString a;
+  OurTestString b("");
+  // CHECK-MESSAGES: [[@LINE-1]]:17: warning: redundant string initialization
+  // CHECK-FIXES: OurTestString b;
+  OurTestString c = R"()";
+  // CHECK-MESSAGES: [[@LINE-1]]:17: warning: redundant string initialization
+  // CHECK-FIXES: OurTestString c;
+  OurTestString d(R"()");
+  // CHECK-MESSAGES: [[@LINE-1]]:17: warning: redundant string initialization
+  // CHECK-FIXES: OurTestString d;
+
+  OurTestString u = "u";
+  OurTestString w("w");
+  OurTestString x = R"(x)";
+  OurTestString y(R"(y)");
+  OurTestString z;
+}
Index: clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
===
--- clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
+++ clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
@@ -5,7 +5,8 @@
 
 Finds unnecessary string initializations.
 
-Examples:
+Examples
+
 
 .. code-block:: c++
 
@@ -17,3 +18,16 @@
 
   std::string a;
   std::string b;
+
+Options
+---
+
+.. option:: StringNames
+
+Default is ``basic_string``.
+
+Semicolon-delimited list of base class names to apply this check to.
+By default ``basic_string`` applies to std::string and std::wstring.
+Set to e.g. ``basic_string;StringRef;QString`` to perform this check on
+custom classes as well.
+
Index: clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.h
===
--- clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.h
+++ clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.h
@@ -11,6 +11,9 @@
 
 #includ

[PATCH] D69238: Fix clang-tidy readability-redundant-string-init for c++17/c++2a

2019-10-28 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc marked 3 inline comments as done.
poelmanc added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp:50
   varDecl(hasType(hasUnqualifiedDesugaredType(recordType(
   
hasDeclaration(cxxRecordDecl(hasName("basic_string")),
   hasInitializer(expr(ignoringImplicit(anyOf(

MyDeveloperDay wrote:
> driveby aside comment (feel free to ignore): wouldn't it be good if 
> "basic_string" here was configurable, this would allow anyone who defines a 
> string class (say like StringRef) which could have this kind of redundant 
> string initialization be able to catch them.
> 
> Couldn't this be then used to find code like `StringRef EnabledPrefixOut = 
> "";`
> 
> ```
> static void ParseMRecip(const Driver &D, const ArgList &Args,
> ArgStringList &OutStrings) {
>   StringRef DisabledPrefixIn = "!";
>   StringRef DisabledPrefixOut = "!";
>   StringRef EnabledPrefixOut = "";
>   StringRef Out = "-mrecip=";
> ```
> 
Great suggestion, done. See https://reviews.llvm.org/D69548. (I figured it 
should be a separate topic from this one, but holler if you prefer I add it to 
this patch.)


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69238/new/

https://reviews.llvm.org/D69238



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69145: Give readability-redundant-member-init an option IgnoreBaseInCopyConstructors to avoid breaking code with gcc -Werror=extra

2019-10-29 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 226847.
poelmanc added a comment.

Changed default to 1, updated help accordingly, and removed an extraneous set 
of braces around a one-line statement.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69145/new/

https://reviews.llvm.org/D69145

Files:
  clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp
  clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h
  clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp
@@ -1,4 +1,8 @@
 // RUN: %check_clang_tidy %s readability-redundant-member-init %t
+// RUN:   -config="{CheckOptions: \
+// RUN: [{key: readability-redundant-member-init.IgnoreBaseInCopyConstructors, \
+// RUN:   value: 1}] \
+// RUN: }"
 
 struct S {
   S() = default;
@@ -116,6 +120,35 @@
   };
 };
 
+// struct whose inline copy constructor default-initializes its base class
+struct WithCopyConstructor1 : public T {
+  WithCopyConstructor1(const WithCopyConstructor1& other) : T(),
+f(),
+g()
+  {}
+  S f, g;
+};
+// No warning in copy constructor about T since IgnoreBaseInCopyConstructors=1
+// CHECK-MESSAGES: :[[@LINE-6]]:5: warning: initializer for member 'f' is redundant
+// CHECK-MESSAGES: :[[@LINE-6]]:5: warning: initializer for member 'g' is redundant
+// CHECK-FIXES: WithCopyConstructor1(const WithCopyConstructor1& other) : T()
+// CHECK-NEXT: 
+// CHECK-NEXT: 
+// CHECK-NEXT: {}
+
+// struct whose copy constructor default-initializes its base class
+struct WithCopyConstructor2 : public T {
+  WithCopyConstructor2(const WithCopyConstructor2& other);
+  S a;
+};
+WithCopyConstructor2::WithCopyConstructor2(const WithCopyConstructor2& other)
+  : T(), a()
+{}
+// No warning in copy constructor about T since IgnoreBaseInCopyConstructors=1
+// CHECK-MESSAGES: :[[@LINE-3]]:10: warning: initializer for member 'a' is redundant
+// CHECK-FIXES: {{^}}  : T() {{$}}
+// CHECK-NEXT: {}
+
 // Initializer not written
 struct NF1 {
   NF1() {}
Index: clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst
===
--- clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst
+++ clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst
@@ -6,7 +6,8 @@
 Finds member initializations that are unnecessary because the same default
 constructor would be called if they were not present.
 
-Example:
+Example
+---
 
 .. code-block:: c++
 
@@ -18,3 +19,27 @@
   private:
 std::string s;
   };
+
+Options
+---
+
+.. option:: IgnoreBaseInCopyConstructors
+
+Default is ``1``.
+
+When non-zero, the check will ignore unnecessary base class initializations
+within copy constructors, since some compilers issue warnings/errors when
+base classes are not explicitly intialized in copy constructors. For example,
+``gcc`` with ``-Wextra`` or ``-Werror=extra`` issues warning or error
+``base class ‘Bar’ should be explicitly initialized in the copy constructor``
+if ``Bar()`` were removed in the following example:
+
+.. code-block:: c++
+
+  // Explicitly initializing member s and base class Bar is unnecessary.
+  struct Foo : public Bar {
+// Remove s() below. If IgnoreBaseInCopyConstructors!=0, keep Bar().
+Foo(const Foo& foo) : Bar(), s() {}
+std::string s;
+  };
+
Index: clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h
===
--- clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h
+++ clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h
@@ -23,9 +23,15 @@
 class RedundantMemberInitCheck : public ClangTidyCheck {
 public:
   RedundantMemberInitCheck(StringRef Name, ClangTidyContext *Context)
-  : ClangTidyCheck(Name, Context) {}
+  : ClangTidyCheck(Name, Context),
+IgnoreBaseInCopyConstructors(
+Options.get("IgnoreBaseInCopyConstructors", 1)) {}
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  bool IgnoreBaseInCopyConstructors;
 };
 
 } // namespace readability
Index: clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/Redunda

[PATCH] D97625: fix check-clang-tools tests that fail due to Windows CRLF line endings

2022-02-04 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

Sorry I somehow missed the acceptance back on 10 Jan. I lack commit access, it 
would be great if you could push for me, thanks!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D97625/new/

https://reviews.llvm.org/D97625

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95714: clang-tidy: modernize-use-nullptr mistakenly fixes rewritten spaceship operator comparisons

2021-01-29 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc created this revision.
poelmanc added reviewers: aaron.ballman, angelgarcia, hokein.
poelmanc added a project: clang-tools-extra.
Herald added a subscriber: yaxunl.
poelmanc requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

`clang-tidy -std=c++20` with `modernize-use-nullptr` mistakenly inserts 
`nullptr` in place of the comparison operator if the comparison internally 
expands in the AST to a rewritten spaceship operator. This can be reproduced by 
running the new `modernize-use-nullptr-cxx20.cpp` test without applying the 
supplied patch to `UseNullptrCheck.cpp`; the current clang-tidy will mistakenly 
replace:

  result = (a1 < a2);

with

  result = (a1 nullptr a2);

Oops!

The supplied patch fixes this by adding just one comment and one line of code 
to `UseNullptrCheck.cpp`:

  // Skip implicit casts to 0 generated by operator<=> rewrites.
  unless(hasAncestor(cxxRewrittenBinaryOperator())),

I looked for a `hasGrandparent` matcher which would be more precise, but none 
exists. This fix slightly overly-aggressively eliminates matches, so even with 
this patch `modernize-use-nullptr` will not convert

  result = (a1 > (ptr == 0 ? a1 : a2));

to

  result = (a1 > (ptr == nullptr ? a1 : a2));

because `ptr == 0` has an ancestor that is a rewritten spaceship operator. 
Changing the proposed one-line fix to:

  unless(hasGrandparent(cxxRewrittenBinaryOperator())),

resolves this, but requires another 57 lines of code across AstMatchers.h, 
AstMatchersInternal.h, and AstMatchFinder.cpp to create `hasGrandparent`. I'd 
be happy to supply that patch instead if folks think it worthwhile? Maybe 
others in the future can benefit from `hasGrandparent`?


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D95714

Files:
  clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
@@ -0,0 +1,19 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-nullptr %t
+
+#include 
+
+class A {
+public:
+  auto operator<=>(const A &other) const = default;
+};
+
+void test_cxx_rewritten_binary_ops() {
+  A a1, a2;
+  bool result;
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 < a2);
+  // CHECK-FIXES: result = (a1 < a2);
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 >= a2);
+  // CHECK-FIXES: result = (a1 >= a2);
+}
Index: clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
===
--- clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
@@ -45,6 +45,8 @@
   TK_AsIs,
   castExpr(anyOf(ImplicitCastToNull,
  explicitCastExpr(hasDescendant(ImplicitCastToNull))),
+   // Skip implicit casts to 0 generated by operator<=> rewrites.
+   unless(hasAncestor(cxxRewrittenBinaryOperator())),
unless(hasAncestor(explicitCastExpr(
   .bind(CastSequence));
 }


Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
@@ -0,0 +1,19 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-nullptr %t
+
+#include 
+
+class A {
+public:
+  auto operator<=>(const A &other) const = default;
+};
+
+void test_cxx_rewritten_binary_ops() {
+  A a1, a2;
+  bool result;
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 < a2);
+  // CHECK-FIXES: result = (a1 < a2);
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 >= a2);
+  // CHECK-FIXES: result = (a1 >= a2);
+}
Index: clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
===
--- clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
@@ -45,6 +45,8 @@
   TK_AsIs,
   castExpr(anyOf(ImplicitCastToNull,
  explicitCastExpr(hasDescendant(ImplicitCastToNull))),
+   // Skip implicit casts to 0 generated by operator<=> rewrites.
+   unless(hasAncestor(cxxRewrittenBinaryOperator())),
unless(hasAncestor(explicitCastExpr(
   .bind(CastSequence));
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95725: clang-extra: fix incorrect use of std::lock_guard by adding variable name (identified by MSVC [[nodiscard]] error)

2021-01-29 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc created this revision.
poelmanc added reviewers: sammccall, ilya-biryukov.
poelmanc added a project: clang-tools-extra.
Herald added subscribers: usaxena95, kadircet, arphaman.
poelmanc requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

`std::lock_guard` is an RAII class that needs a variable name whose scope 
determines the guard's lifetime. This particular usage lacked a variable name, 
meaning the guard could be destroyed before the line that it was indented to 
protect.

This line was identified by building clang with the latest MSVC preview 
release, which declares the std::lock_guard constructor to be `[[nodiscard]]` 
to draw attention to such issues.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D95725

Files:
  clang-tools-extra/clangd/support/Function.h


Index: clang-tools-extra/clangd/support/Function.h
===
--- clang-tools-extra/clangd/support/Function.h
+++ clang-tools-extra/clangd/support/Function.h
@@ -51,7 +51,7 @@
 Subscription &operator=(Subscription &&Other) {
   // If *this is active, unsubscribe.
   if (Parent) {
-std::lock_guard(Parent->ListenersMu);
+std::lock_guard Guard(Parent->ListenersMu);
 llvm::erase_if(Parent->Listeners,
[&](const std::pair &P) {
  return P.second == ListenerID;


Index: clang-tools-extra/clangd/support/Function.h
===
--- clang-tools-extra/clangd/support/Function.h
+++ clang-tools-extra/clangd/support/Function.h
@@ -51,7 +51,7 @@
 Subscription &operator=(Subscription &&Other) {
   // If *this is active, unsubscribe.
   if (Parent) {
-std::lock_guard(Parent->ListenersMu);
+std::lock_guard Guard(Parent->ListenersMu);
 llvm::erase_if(Parent->Listeners,
[&](const std::pair &P) {
  return P.second == ListenerID;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95726: clang-tidy: modernize-use-nullptr mistakenly fixes rewritten spaceship operator comparisons - hasGrandparent version

2021-01-29 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc created this revision.
poelmanc added reviewers: aaron.ballman, angelgarcia, hokein.
poelmanc added a project: clang-tools-extra.
Herald added a subscriber: yaxunl.
poelmanc requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

As in https://reviews.llvm.org/D95714, `clang-tidy -std=c++20` with 
`modernize-use-nullptr` mistakenly inserts `nullptr` in place of the comparison 
operator if the comparison internally expands in the AST to a rewritten 
spaceship operator. This can be reproduced by running the new 
`modernize-use-nullptr-cxx20.cpp` test without applying the supplied patch to 
UseNullptrCheck.cpp; the current clang-tidy will mistakenly replace:

  result = (a1 < a2);

with

  result = (a1 nullptr a2);

Oops!

The supplied patch fixes this by adding just one comment and one line of code 
to UseNullptrCheck.cpp:

  // Skip implicit casts to 0 generated by operator<=> rewrites.
  unless(hasGrandparent(cxxRewrittenBinaryOperator())),

It also adds the new `hasGrandparent` matcher, which is necessary as opposed to 
`hasAncestor` to properly convert:

  result = (a1 > (ptr == 0 ? a1 : a2));

to

  result = (a1 > (ptr == nullptr ? a1 : a2));

In this case the AST has an "ancestor" that is a rewritten binary operator, but 
not a direct grandparent.

This is an alternative to https://reviews.llvm.org/D95714.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D95726

Files:
  clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/include/clang/ASTMatchers/ASTMatchersInternal.h
  clang/lib/ASTMatchers/ASTMatchFinder.cpp

Index: clang/lib/ASTMatchers/ASTMatchFinder.cpp
===
--- clang/lib/ASTMatchers/ASTMatchFinder.cpp
+++ clang/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -659,6 +659,8 @@
   ResultCache.clear();
 if (MatchMode == AncestorMatchMode::AMM_ParentOnly)
   return matchesParentOf(Node, Matcher, Builder);
+else if (MatchMode == AncestorMatchMode::AMM_GrandparentOnly)
+  return matchesGrandparentOf(Node, Matcher, Builder);
 return matchesAnyAncestorOf(Node, Ctx, Matcher, Builder);
   }
 
@@ -893,6 +895,18 @@
 return false;
   }
 
+  // Returns whether a direct grandparent of \p Node matches \p Matcher.
+  bool matchesGrandparentOf(const DynTypedNode &Node,
+  const DynTypedMatcher &Matcher,
+  BoundNodesTreeBuilder *Builder) {
+for (const auto &Parent : ActiveASTContext->getParents(Node)) {
+  if (matchesParentOf(Parent, Matcher, Builder)) {
+return true;
+  }
+}
+return false;
+  }
+
   // Returns whether an ancestor of \p Node matches \p Matcher.
   //
   // The order of matching (which can lead to different nodes being bound in
Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h
===
--- clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -654,7 +654,10 @@
 AMM_All,
 
 /// Direct parent only.
-AMM_ParentOnly
+AMM_ParentOnly,
+
+/// Direct grandparent only.
+AMM_GrandparentOnly
   };
 
   virtual ~ASTMatchFinder() = default;
@@ -1654,6 +1657,29 @@
   }
 };
 
+/// Matches nodes of type \c T that have a grandparent node of type
+/// \c GrandparentT for which the given inner matcher matches.
+///
+/// \c GrandparentT must be an AST base type.
+template 
+class HasGrandparentMatcher : public MatcherInterface {
+  static_assert(IsBaseType::value,
+"has parent only accepts base type matcher");
+
+  const DynTypedMatcher GrandparentMatcher;
+
+public:
+  explicit HasGrandparentMatcher(
+  const Matcher &GrandparentMatcher)
+  : GrandparentMatcher(GrandparentMatcher) {}
+
+  bool matches(const T &Node, ASTMatchFinder *Finder,
+   BoundNodesTreeBuilder *Builder) const override {
+return Finder->matchesAncestorOf(Node, this->GrandparentMatcher, Builder,
+ ASTMatchFinder::AMM_GrandparentOnly);
+  }
+};
+
 /// Matches nodes of type \c T that have at least one ancestor node of
 /// type \c AncestorT for which the given inner matcher matches.
 ///
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -3434,6 +3434,22 @@
 internal::TypeList>
 hasParent;
 
+/// Matches AST nodes that have a grandparent that matches the provided
+/// matcher.
+///
+/// Given
+/// \code
+/// void f() { for (;;) { int x = 42; if (true) { int x = 43; } } }
+/// \endcode
+/// \c compoundStmt(hasGrandparent(forStmt())) matches "{ int x = 43; }".
+///

[PATCH] D95726: clang-tidy: modernize-use-nullptr mistakenly fixes rewritten spaceship operator comparisons - hasGrandparent version

2021-01-29 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 320284.
poelmanc added a comment.

Fix test failure in `modernize-use-nullptr-cxx20.cpp` by replacing `#include 
` with some minimal equivalent `std` code.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95726/new/

https://reviews.llvm.org/D95726

Files:
  clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/include/clang/ASTMatchers/ASTMatchersInternal.h
  clang/lib/ASTMatchers/ASTMatchFinder.cpp

Index: clang/lib/ASTMatchers/ASTMatchFinder.cpp
===
--- clang/lib/ASTMatchers/ASTMatchFinder.cpp
+++ clang/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -659,6 +659,8 @@
   ResultCache.clear();
 if (MatchMode == AncestorMatchMode::AMM_ParentOnly)
   return matchesParentOf(Node, Matcher, Builder);
+else if (MatchMode == AncestorMatchMode::AMM_GrandparentOnly)
+  return matchesGrandparentOf(Node, Matcher, Builder);
 return matchesAnyAncestorOf(Node, Ctx, Matcher, Builder);
   }
 
@@ -893,6 +895,18 @@
 return false;
   }
 
+  // Returns whether a direct grandparent of \p Node matches \p Matcher.
+  bool matchesGrandparentOf(const DynTypedNode &Node,
+  const DynTypedMatcher &Matcher,
+  BoundNodesTreeBuilder *Builder) {
+for (const auto &Parent : ActiveASTContext->getParents(Node)) {
+  if (matchesParentOf(Parent, Matcher, Builder)) {
+return true;
+  }
+}
+return false;
+  }
+
   // Returns whether an ancestor of \p Node matches \p Matcher.
   //
   // The order of matching (which can lead to different nodes being bound in
Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h
===
--- clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -654,7 +654,10 @@
 AMM_All,
 
 /// Direct parent only.
-AMM_ParentOnly
+AMM_ParentOnly,
+
+/// Direct grandparent only.
+AMM_GrandparentOnly
   };
 
   virtual ~ASTMatchFinder() = default;
@@ -1654,6 +1657,29 @@
   }
 };
 
+/// Matches nodes of type \c T that have a grandparent node of type
+/// \c GrandparentT for which the given inner matcher matches.
+///
+/// \c GrandparentT must be an AST base type.
+template 
+class HasGrandparentMatcher : public MatcherInterface {
+  static_assert(IsBaseType::value,
+"has parent only accepts base type matcher");
+
+  const DynTypedMatcher GrandparentMatcher;
+
+public:
+  explicit HasGrandparentMatcher(
+  const Matcher &GrandparentMatcher)
+  : GrandparentMatcher(GrandparentMatcher) {}
+
+  bool matches(const T &Node, ASTMatchFinder *Finder,
+   BoundNodesTreeBuilder *Builder) const override {
+return Finder->matchesAncestorOf(Node, this->GrandparentMatcher, Builder,
+ ASTMatchFinder::AMM_GrandparentOnly);
+  }
+};
+
 /// Matches nodes of type \c T that have at least one ancestor node of
 /// type \c AncestorT for which the given inner matcher matches.
 ///
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -3434,6 +3434,22 @@
 internal::TypeList>
 hasParent;
 
+/// Matches AST nodes that have a grandparent that matches the provided
+/// matcher.
+///
+/// Given
+/// \code
+/// void f() { for (;;) { int x = 42; if (true) { int x = 43; } } }
+/// \endcode
+/// \c compoundStmt(hasGrandparent(forStmt())) matches "{ int x = 43; }".
+///
+/// Usable as: Any Matcher
+extern const internal::ArgumentAdaptingMatcherFunc<
+internal::HasGrandparentMatcher,
+internal::TypeList,
+internal::TypeList>
+hasGrandparent;
+
 /// Matches AST nodes that have an ancestor that matches the provided
 /// matcher.
 ///
Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
@@ -0,0 +1,52 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-nullptr %t
+
+// Not all systems have #include  to define std::std_ordering
+// required by operator<=>, so recreate minimal version for tests below.
+namespace std {
+
+struct strong_ordering {
+  static const strong_ordering less;
+  static const strong_ordering equal;
+  static const strong_ordering greater;
+  using zero_type = decltype(nullptr);
+
+  friend constexpr bool operator<(const strong_ordering value, zero_type) noexcept {
+return value.comparison_value < 0;
+  }
+
+  friend constexpr bool operator>(const strong_ordering value, zero_type) noexcept 

[PATCH] D95726: clang-tidy: modernize-use-nullptr mistakenly fixes rewritten spaceship operator comparisons - hasGrandparent version

2021-01-29 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

Fixed test failure in `modernize-use-nullptr-cxx20.cpp` by replacing `#include 
` with some minimal equivalent `std` code.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95726/new/

https://reviews.llvm.org/D95726

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95726: clang-tidy: modernize-use-nullptr mistakenly fixes rewritten spaceship operator comparisons - hasGrandparent version

2021-01-29 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

Fix test failure in `modernize-use-nullptr-cxx20.cpp` by replacing `#include 
` with some minimal equivalent `std` code.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95726/new/

https://reviews.llvm.org/D95726

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95714: clang-tidy: modernize-use-nullptr mistakenly fixes rewritten spaceship operator comparisons

2021-01-29 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 320286.
poelmanc added a comment.

Fix test failure in `modernize-use-nullptr-cxx20.cpp` by replacing `#include 
` with some minimal equivalent `std` code.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95714/new/

https://reviews.llvm.org/D95714

Files:
  clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
@@ -0,0 +1,48 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-nullptr %t
+
+// Not all systems have #include  to define std::std_ordering
+// required by operator<=>, so recreate minimal version for tests below.
+namespace std {
+
+struct strong_ordering {
+  static const strong_ordering less;
+  static const strong_ordering equal;
+  static const strong_ordering greater;
+  using zero_type = decltype(nullptr);
+
+  friend constexpr bool operator<(const strong_ordering value, zero_type) 
noexcept {
+return value.comparison_value < 0;
+  }
+
+  friend constexpr bool operator>(const strong_ordering value, zero_type) 
noexcept {
+return value.comparison_value > 0;
+  }
+
+  friend constexpr bool operator>=(const strong_ordering value, zero_type) 
noexcept {
+return value.comparison_value >= 0;
+  }
+
+  signed char comparison_value;
+};
+
+inline constexpr strong_ordering strong_ordering::less{-1};
+inline constexpr strong_ordering strong_ordering::equal{0};
+inline constexpr strong_ordering strong_ordering::greater{1};
+
+} // namespace std
+
+class A {
+public:
+  auto operator<=>(const A &other) const = default;
+};
+
+void test_cxx_rewritten_binary_ops() {
+  A a1, a2;
+  bool result;
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 < a2);
+  // CHECK-FIXES: result = (a1 < a2);
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 >= a2);
+  // CHECK-FIXES: result = (a1 >= a2);
+}
Index: clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
===
--- clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
@@ -45,6 +45,8 @@
   TK_AsIs,
   castExpr(anyOf(ImplicitCastToNull,
  explicitCastExpr(hasDescendant(ImplicitCastToNull))),
+   // Skip implicit casts to 0 generated by operator<=> rewrites.
+   unless(hasAncestor(cxxRewrittenBinaryOperator())),
unless(hasAncestor(explicitCastExpr(
   .bind(CastSequence));
 }


Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
@@ -0,0 +1,48 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-nullptr %t
+
+// Not all systems have #include  to define std::std_ordering
+// required by operator<=>, so recreate minimal version for tests below.
+namespace std {
+
+struct strong_ordering {
+  static const strong_ordering less;
+  static const strong_ordering equal;
+  static const strong_ordering greater;
+  using zero_type = decltype(nullptr);
+
+  friend constexpr bool operator<(const strong_ordering value, zero_type) noexcept {
+return value.comparison_value < 0;
+  }
+
+  friend constexpr bool operator>(const strong_ordering value, zero_type) noexcept {
+return value.comparison_value > 0;
+  }
+
+  friend constexpr bool operator>=(const strong_ordering value, zero_type) noexcept {
+return value.comparison_value >= 0;
+  }
+
+  signed char comparison_value;
+};
+
+inline constexpr strong_ordering strong_ordering::less{-1};
+inline constexpr strong_ordering strong_ordering::equal{0};
+inline constexpr strong_ordering strong_ordering::greater{1};
+
+} // namespace std
+
+class A {
+public:
+  auto operator<=>(const A &other) const = default;
+};
+
+void test_cxx_rewritten_binary_ops() {
+  A a1, a2;
+  bool result;
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 < a2);
+  // CHECK-FIXES: result = (a1 < a2);
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 >= a2);
+  // CHECK-FIXES: result = (a1 >= a2);
+}
Index: clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
===
--- clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
@@ -45,6 +45,8 @@
   TK_AsIs,
   castExpr(anyOf(ImplicitCastToNull,
  explicitCastExpr(hasDescendant(ImplicitCastToNull))),
+   // Skip implicit casts to 0 generated by operator<=> rewrites.
+   

[PATCH] D95726: clang-tidy: modernize-use-nullptr mistakenly fixes rewritten spaceship operator comparisons - hasGrandparent version

2021-01-30 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

Thanks for the quick feedback everyone. I agree too, withdrawing this in favor 
of https://reviews.llvm.org/D95714.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95726/new/

https://reviews.llvm.org/D95726

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95714: [clang-tidy] fix modernize-use-nullptr false positive with spaceship operator comparisons

2021-01-30 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 320330.
poelmanc added a comment.

Thanks to the great feedback, changed 
`unless(hasAncestor(cxxRewrittenBinaryOperator()))` to 
`unless(hasParent(expr(hasParent(cxxRewrittenBinaryOperator()` and added a 
test to verify the improvement (and removed an extraneous comment.)


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95714/new/

https://reviews.llvm.org/D95714

Files:
  clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
@@ -0,0 +1,50 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-nullptr %t
+
+namespace std {
+
+struct strong_ordering {
+  static const strong_ordering less;
+  static const strong_ordering equal;
+  static const strong_ordering greater;
+  using zero_type = decltype(nullptr);
+
+  friend constexpr bool operator<(const strong_ordering value, zero_type) 
noexcept {
+return value.comparison_value < 0;
+  }
+
+  friend constexpr bool operator>(const strong_ordering value, zero_type) 
noexcept {
+return value.comparison_value > 0;
+  }
+
+  friend constexpr bool operator>=(const strong_ordering value, zero_type) 
noexcept {
+return value.comparison_value >= 0;
+  }
+
+  signed char comparison_value;
+};
+
+inline constexpr strong_ordering strong_ordering::less{-1};
+inline constexpr strong_ordering strong_ordering::equal{0};
+inline constexpr strong_ordering strong_ordering::greater{1};
+
+} // namespace std
+
+class A {
+public:
+  auto operator<=>(const A &other) const = default;
+};
+
+void test_cxx_rewritten_binary_ops() {
+  A a1, a2;
+  bool result;
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 < a2);
+  // CHECK-FIXES: result = (a1 < a2);
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 >= a2);
+  // CHECK-FIXES: result = (a1 >= a2);
+  int *ptr = 0;
+  // CHECK-FIXES: int *ptr = nullptr;
+  result = (a1 > (ptr == 0 ? a1 : a2));
+  // CHECK-FIXES: result = (a1 > (ptr == nullptr ? a1 : a2));
+}
Index: clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
===
--- clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
@@ -45,6 +45,8 @@
   TK_AsIs,
   castExpr(anyOf(ImplicitCastToNull,
  explicitCastExpr(hasDescendant(ImplicitCastToNull))),
+   // Skip implicit casts to 0 generated by operator<=> rewrites.
+   
unless(hasParent(expr(hasParent(cxxRewrittenBinaryOperator(),
unless(hasAncestor(explicitCastExpr(
   .bind(CastSequence));
 }


Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
@@ -0,0 +1,50 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-nullptr %t
+
+namespace std {
+
+struct strong_ordering {
+  static const strong_ordering less;
+  static const strong_ordering equal;
+  static const strong_ordering greater;
+  using zero_type = decltype(nullptr);
+
+  friend constexpr bool operator<(const strong_ordering value, zero_type) noexcept {
+return value.comparison_value < 0;
+  }
+
+  friend constexpr bool operator>(const strong_ordering value, zero_type) noexcept {
+return value.comparison_value > 0;
+  }
+
+  friend constexpr bool operator>=(const strong_ordering value, zero_type) noexcept {
+return value.comparison_value >= 0;
+  }
+
+  signed char comparison_value;
+};
+
+inline constexpr strong_ordering strong_ordering::less{-1};
+inline constexpr strong_ordering strong_ordering::equal{0};
+inline constexpr strong_ordering strong_ordering::greater{1};
+
+} // namespace std
+
+class A {
+public:
+  auto operator<=>(const A &other) const = default;
+};
+
+void test_cxx_rewritten_binary_ops() {
+  A a1, a2;
+  bool result;
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 < a2);
+  // CHECK-FIXES: result = (a1 < a2);
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 >= a2);
+  // CHECK-FIXES: result = (a1 >= a2);
+  int *ptr = 0;
+  // CHECK-FIXES: int *ptr = nullptr;
+  result = (a1 > (ptr == 0 ? a1 : a2));
+  // CHECK-FIXES: result = (a1 > (ptr == nullptr ? a1 : a2));
+}
Index: clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
===
--- clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
@@ -45,6 +45,8 @@
   TK_AsIs,
   castExpr(a

[PATCH] D95714: [clang-tidy] fix modernize-use-nullptr false positive with spaceship operator comparisons

2021-01-30 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

@njames93 Thank you so much for the quick feedback, I made your suggested 
changes and added a test that it properly converts `result = (a1 > (ptr == 0 ? 
a1 : a2));` to `result = (a1 > (ptr == nullptr ? a1 : a2));` now.

In these examples so far, checking the grandparent works. Here's the AST:

  $ clang -std=c++20 -Xclang -ast-dump modernize-use-nullptr-cxx20.cpp
  ...
  |-BinaryOperator 0x22d30bec4e0  'bool' lvalue '=' // 
result = (a1 < a2); // result = (a1 > (ptr == 0 ? a1 : a2));
  | |-DeclRefExpr 0x22d30be8960  'bool' lvalue Var 0x22d30be88e0 
'result' 'bool'
  | `-ParenExpr 0x22d30bec4c0  'bool'
  |   `-CXXRewrittenBinaryOperator 0x22d30bec4a8  'bool'
  | `-CXXOperatorCallExpr 0x22d30bec470  'bool' '<' adl
  |   |-ImplicitCastExpr 0x22d30bec458  'bool (*)(const 
std::strong_ordering, std::strong_ordering::zero_type) noexcept' 

  |   | `-DeclRefExpr 0x22d30bec3d8  'bool (const 
std::strong_ordering, std::strong_ordering::zero_type) noexcept' lvalue 
Function 0x22d30ba9f28 'operator<' 'bool (const std::strong_ordering, 
std::strong_ordering::zero_type) noexcept'
  |   |-CXXOperatorCallExpr 0x22d30bec360  
'std::strong_ordering':'std::strong_ordering' '<=>'
  |   | |-ImplicitCastExpr 0x22d30bec348  'std::strong_ordering 
(*)(const A &) const noexcept' 
  |   | | `-DeclRefExpr 0x22d30be8a08  'std::strong_ordering 
(const A &) const noexcept' lvalue CXXMethod 0x22d30bedcd8 'operator<=>' 
'std::strong_ordering (const A &) const noexcept'
  |   | |-ImplicitCastExpr 0x22d30be89f0  'const A' lvalue 

  |   | | `-DeclRefExpr 0x22d30be8998  'A' lvalue Var 
0x22d30be8290 'a1' 'A'
  |   | `-ImplicitCastExpr 0x22d30be89d8  'const A' lvalue 

  |   |   `-DeclRefExpr 0x22d30be89b8  'A' lvalue Var 
0x22d30be87f0 'a2' 'A'
  |   `-ImplicitCastExpr 0x22d30bec3c0  
'std::strong_ordering::zero_type':'nullptr_t'  // Auto-generated 
cast we should ignore
  | `-IntegerLiteral 0x22d30bec398  'int' 0
  ...
  `-BinaryOperator 0x22d30becb20  'bool' lvalue '='
|-DeclRefExpr 0x22d30bec830  'bool' lvalue Var 0x22d30be88e0 
'result' 'bool'
`-ParenExpr 0x22d30becb00  'bool'
  `-CXXRewrittenBinaryOperator 0x22d30becae8  'bool'
`-CXXOperatorCallExpr 0x22d30becab0  'bool' '>' adl
  |-ImplicitCastExpr 0x22d30beca98  'bool (*)(const 
std::strong_ordering, std::strong_ordering::zero_type) noexcept' 

  | `-DeclRefExpr 0x22d30beca78  'bool (const 
std::strong_ordering, std::strong_ordering::zero_type) noexcept' lvalue 
Function 0x22d30baa1a0 'operator>' 'bool (const std::strong_ordering, 
std::strong_ordering::zero_type) noexcept'
  |-CXXOperatorCallExpr 0x22d30beca00  
'std::strong_ordering':'std::strong_ordering' '<=>'
  | |-ImplicitCastExpr 0x22d30bec9e8  'std::strong_ordering 
(*)(const A &) const noexcept' 
  | | `-DeclRefExpr 0x22d30bec9c8  'std::strong_ordering 
(const A &) const noexcept' lvalue CXXMethod 0x22d30bedcd8 'operator<=>' 
'std::strong_ordering (const A &) const noexcept'
  | |-ImplicitCastExpr 0x22d30bec9b0  'const A' lvalue 

  | | `-DeclRefExpr 0x22d30bec850  'A' lvalue Var 
0x22d30be8290 'a1' 'A'
  | `-ImplicitCastExpr 0x22d30bec998  'const A' 
lvalue 
  |   `-ParenExpr 0x22d30bec978  'A' lvalue
  | `-ConditionalOperator 0x22d30bec948  'A' 
lvalue
  |   |-BinaryOperator 0x22d30bec8e8  'bool' 
'=='
  |   | |-ImplicitCastExpr 0x22d30bec8b8  'int *' 

  |   | | `-DeclRefExpr 0x22d30bec870  'int *' lvalue 
Var 0x22d30bec758 'ptr' 'int *'
  |   | `-ImplicitCastExpr 0x22d30bec8d0  'int *' 
 // ptr == 0 cast that we want to convert to nullptr
  |   |   `-IntegerLiteral 0x22d30bec890  'int' 0
  |   |-DeclRefExpr 0x22d30bec908  'A' lvalue Var 
0x22d30be8290 'a1' 'A'
  |   `-DeclRefExpr 0x22d30bec928  'A' lvalue Var 
0x22d30be87f0 'a2' 'A'
  `-ImplicitCastExpr 0x22d30beca60  
'std::strong_ordering::zero_type':'nullptr_t'  // Auto-generated 
cast we should ignore
`-IntegerLiteral 0x22d30beca38  'int' 0

This looks a little bit different from your AST but I'm not sure what code your 
AST was generated from. If you have a test case I'd be happy to take a look. 
Thanks!


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95714/new/

https://reviews.llvm.org/D95714

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95714: [clang-tidy] fix modernize-use-nullptr false positive with spaceship operator comparisons

2021-01-31 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

In D95714#2532565 , @njames93 wrote:

> This does highlight an issue where the mimicked std library stubs used for 
> tests don't correspond exactly to what the stdlib actually looks like and can 
> result in subtly different ASTs that have added/removed implicit nodes.
>
> Going a little off point here but a few months back I pushed a fix for 
> another check that passed its tests. 
> However the bug report was re-opened as the bug was still observable in the 
> real word. 
> Turned out the implementation of std::string used for the test had a trivial 
> destructor resulting in the AST not needed to emit `CXXBindTemporaryExpr`s 
> all over the place, which threw off the matching logic.
>
> Unfortunately this kind of disparity is hard to detect in tests so it may be 
> wise to test this locally using the compare header from a real standard 
> library implementation (preferably all 3 main ones if you have the machines) 
> and see if this behaviour is correct.

Indeed the //mimicked std library// approach has real advantages like running 
fast and giving consistent results across platforms. But it also has drawbacks 
like the replication of //mimicked std// code across tests, and possible 
differences between test and real world behaviour. We could give tests a 
`CLANG_TIDY_TEST_NATIVE_STD` macro to switch between //mimicked std// code and 
real headers, and set up CI to test both ways, to catch these issues at the 
expense of added complexity. But that's a broader discussion.

Back to `modernize-use-nullptr`, these days I'm working in MSVC and the tests 
pass with MSVC's ``, with my mimicked compare, and a shorter mimicked 
`strong_ordering` that I found in `ASTTraverserTest.cpp`. But I fetched gcc's 
`` from 
https://raw.githubusercontent.com/gcc-mirror/gcc/master/libstdc%2B%2B-v3/libsupc%2B%2B/compare
 and now see the same ASTs as you, and the proposed fix fails.

Thoughts on which option seems like the best path forward?

1. In the ASTs I've seen so far the third child of the 
`CXXRewrittenBinaryOperator`'s `CXXOperatorCallExpr ` is the one to ignore. But 
comments in :268-283 imply that perhaps sometimes the `0` 
may appear first? There should be some way to determine which child was added 
by the `CXXRewrittenBinaryOperator` rewrite and skip that child, regardless of 
`std` implementation, but I have yet to figure that out.
2. Roll back to `hasAncestor`, fixing the immediate problem of creating invalid 
fixes (`a1 nullptr 2a`) and accepting that some rare but fixable code (`a1 < ( 
ptr == 0 ? a2 : a3`) will not be modernized to `nullptr`.
3. Change the bugfix approach here from AST-based to text-based. In 
`replaceWithNullptr` in `UseNullptrCheck.cpp:62`, add code to skip the planned 
replacement if the text we're about to replace with `nullptr` consists of `<`, 
`=`, and `>`. As a quick test, this version seems to make all tests pass and 
doesn't depend on std header implementation:

  static const std::string SuspiciousChars("<=>");
  char FirstCharToReplace = *SM.getCharacterData(StartLoc);
  char LastCharToReplace = *SM.getCharacterData(EndLoc);
  if (SuspiciousChars.find(FirstCharToReplace) != std::string::npos &&
  SuspiciousChars.find(LastCharToReplace) != std::string::npos)
return;


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95714/new/

https://reviews.llvm.org/D95714

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95714: [clang-tidy] fix modernize-use-nullptr false positive with spaceship operator comparisons

2021-01-31 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 320393.
poelmanc added a comment.

Thanks @steveire, that suggestion worked perfectly! I added the additional test 
case and shortened the mimicked `strong_ordering` code to a version from 
`clang/unittests.ASTMatchers/ASTMatchersTraversalTest.cpp`, but also manually 
tested this using both MSVC's and libstdc++v3's `` header.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95714/new/

https://reviews.llvm.org/D95714

Files:
  clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
@@ -0,0 +1,34 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-nullptr %t
+
+namespace std {
+struct strong_ordering {
+  int n;
+  constexpr operator int() const { return n; }
+  static const strong_ordering equal, greater, less;
+};
+constexpr strong_ordering strong_ordering::equal = {0};
+constexpr strong_ordering strong_ordering::greater = {1};
+constexpr strong_ordering strong_ordering::less = {-1};
+}
+
+class A {
+public:
+  auto operator<=>(const A &other) const = default;
+};
+
+void test_cxx_rewritten_binary_ops() {
+  A a1, a2;
+  bool result;
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 < a2);
+  // CHECK-FIXES: result = (a1 < a2);
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 >= a2);
+  // CHECK-FIXES: result = (a1 >= a2);
+  int *ptr = 0;
+  // CHECK-FIXES: int *ptr = nullptr;
+  result = (a1 > (ptr == 0 ? a1 : a2));
+  // CHECK-FIXES: result = (a1 > (ptr == nullptr ? a1 : a2));
+  result = (a1 > ((a1 > (ptr == 0 ? a1 : a2)) ? a1 : a2));
+  // CHECK-FIXES: result = (a1 > ((a1 > (ptr == nullptr ? a1 : a2)) ? a1 : 
a2));
+}
Index: clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
===
--- clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
@@ -41,12 +41,28 @@
   
unless(hasImplicitDestinationType(qualType(substTemplateTypeParmType(,
   unless(hasSourceExpression(hasType(sugaredNullptrType();
 
+  auto isOrHasDescendant = [](auto InnerMatcher) {
+return anyOf(InnerMatcher, hasDescendant(InnerMatcher));
+  };
+
   return traverse(
   TK_AsIs,
-  castExpr(anyOf(ImplicitCastToNull,
- explicitCastExpr(hasDescendant(ImplicitCastToNull))),
-   unless(hasAncestor(explicitCastExpr(
-  .bind(CastSequence));
+  anyOf(castExpr(anyOf(ImplicitCastToNull,
+   
explicitCastExpr(hasDescendant(ImplicitCastToNull))),
+ unless(hasAncestor(explicitCastExpr())),
+ unless(hasAncestor(cxxRewrittenBinaryOperator(
+.bind(CastSequence),
+cxxRewrittenBinaryOperator(
+// Match rewritten operators, but verify (in the check method)
+// that if an implicit cast is found, it is not from another
+// nested rewritten operator
+expr().bind("matchBinopOperands"),
+hasEitherOperand(isOrHasDescendant(
+implicitCastExpr(
+ImplicitCastToNull,
+hasAncestor(cxxRewrittenBinaryOperator().bind(
+"checkBinopOperands")))
+.bind(CastSequence));
 }
 
 bool isReplaceableRange(SourceLocation StartLoc, SourceLocation EndLoc,
@@ -480,6 +496,11 @@
   const auto *NullCast = Result.Nodes.getNodeAs(CastSequence);
   assert(NullCast && "Bad Callback. No node provided");
 
+  if (Result.Nodes.getNodeAs(
+  "matchBinopOperands") !=
+  Result.Nodes.getNodeAs("checkBinopOperands"))
+return;
+
   // Given an implicit null-ptr cast or an explicit cast with an implicit
   // null-to-pointer cast within use CastSequenceVisitor to identify sequences
   // of explicit casts that can be converted into 'nullptr'.


Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
@@ -0,0 +1,34 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-nullptr %t
+
+namespace std {
+struct strong_ordering {
+  int n;
+  constexpr operator int() const { return n; }
+  static const strong_ordering equal, greater, less;
+};
+constexpr strong_ordering strong_ordering::equal = {0};
+constexpr strong_ordering strong_ordering::greater = {1};
+constexpr strong_ordering strong_ordering::less = {-1};
+}
+
+class A {
+public:
+  auto operator<=>(const A &other) const = default;
+};

[PATCH] D95771: [clang-tidy] fix modernize-loop-convert to retain needed array-like operator[]

2021-01-31 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc created this revision.
poelmanc added reviewers: sammccall, hokein.
poelmanc added a project: clang-tools-extra.
Herald added a subscriber: xazax.hun.
poelmanc requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

`modernize-loop-convert` handles //array-like// objects like vectors fairly 
well, but strips slightly too much information from the iteration expression by 
converting:

  Vector> X;
  for (int J = 0; J < X[5].size(); ++J)
copyArg(X[5][J]);

to

  Vector> X;
  for (int J : X) // should be for (int J : X[5]) 
copyArg(J);

The `[5]` is a call to `operator[]` and gets stripped by 
`LoopConvertCheck::getContainerString`. This patch fixes that and adds several 
test cases.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D95771

Files:
  clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/modernize-loop-convert-multidimensional.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/modernize-loop-convert-multidimensional.cpp
===
--- /dev/null
+++ 
clang-tools-extra/test/clang-tidy/checkers/modernize-loop-convert-multidimensional.cpp
@@ -0,0 +1,70 @@
+// RUN: %check_clang_tidy %s modernize-loop-convert %t
+
+template 
+struct Vector {
+  using iterator = T*;
+  unsigned size() const;
+  const T &operator[](int) const;
+  T &operator[](int);
+  T *begin();
+  T *end();
+  const T *begin() const;
+  const T *end() const;
+};
+
+template 
+void copyArg(T);
+
+class TestArrayOfVector {
+  Vector W[2];
+
+  void foo() const {
+for (int I = 0; I < W[0].size(); ++I) {
+  if (W[0][I])
+copyArg(W[0][I]);
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use range-based for loop
+// CHECK-FIXES: for (int I : W[0]) {
+// CHECK-FIXES-NEXT: if (I)
+// CHECK-FIXES-NEXT: copyArg(I);
+  }
+};
+
+class TestVectorOfVector {
+  Vector> X;
+
+  void foo() const {
+for (int J = 0; J < X[0].size(); ++J) {
+  if (X[0][J])
+copyArg(X[0][J]);
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use range-based for loop
+// CHECK-FIXES: for (int J : X[0]) {
+// CHECK-FIXES-NEXT: if (J)
+// CHECK-FIXES-NEXT: copyArg(J);
+  }
+};
+
+void testVectorOfVectorOfVector() {
+  Vector>> Y;
+  for (int J = 0; J < Y[3].size(); ++J) {
+if (Y[3][J][7])
+  copyArg(Y[3][J][8]);
+  }
+  // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+  // CHECK-FIXES: for (auto & J : Y[3]) {
+  // CHECK-FIXES-NEXT: if (J[7])
+  // CHECK-FIXES-NEXT: copyArg(J[8]);
+};
+
+void testVectorOfVectorIterator() {
+  Vector> Z;
+  for (Vector::iterator it = Z[4].begin(); it != Z[4].end();  ++it) {
+if (*it)
+  copyArg(*it);
+  }
+  // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+  // CHECK-FIXES: for (int & it : Z[4]) {
+  // CHECK-FIXES-NEXT: if (it)
+  // CHECK-FIXES-NEXT: copyArg(it);
+};
Index: clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
===
--- clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
@@ -722,10 +722,11 @@
   if (isa(ContainerExpr)) {
 ContainerString = "this";
   } else {
-// For CXXOperatorCallExpr (e.g. vector_ptr->size()), its first argument is
-// the class object (vector_ptr) we are targeting.
+// For CXXOperatorCallExpr such as vector_ptr->size() we want the class
+// object vector_ptr, but for vector[2] we need the whole expression.
 if (const auto* E = dyn_cast(ContainerExpr))
-  ContainerExpr = E->getArg(0);
+  if ( E->getOperator() != OO_Subscript )
+ContainerExpr = E->getArg(0);
 ContainerString =
 getStringFromRange(Context->getSourceManager(), Context->getLangOpts(),
ContainerExpr->getSourceRange());


Index: clang-tools-extra/test/clang-tidy/checkers/modernize-loop-convert-multidimensional.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-loop-convert-multidimensional.cpp
@@ -0,0 +1,70 @@
+// RUN: %check_clang_tidy %s modernize-loop-convert %t
+
+template 
+struct Vector {
+  using iterator = T*;
+  unsigned size() const;
+  const T &operator[](int) const;
+  T &operator[](int);
+  T *begin();
+  T *end();
+  const T *begin() const;
+  const T *end() const;
+};
+
+template 
+void copyArg(T);
+
+class TestArrayOfVector {
+  Vector W[2];
+
+  void foo() const {
+for (int I = 0; I < W[0].size(); ++I) {
+  if (W[0][I])
+copyArg(W[0][I]);
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use range-based for loop
+// CHECK-FIXES: for (int I : W[0]) {
+// CHECK-FIXES-NEXT: if (I)
+// CHECK-FIXES-NEXT: copyArg(I);
+  }
+};
+
+class TestVectorOfVector {
+  Vector> X;
+

[PATCH] D95725: clang-extra: fix incorrect use of std::lock_guard by adding variable name (identified by MSVC [[nodiscard]] error)

2021-02-01 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 320594.
poelmanc added a comment.

Change Guard to Lock.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95725/new/

https://reviews.llvm.org/D95725

Files:
  clang-tools-extra/clangd/support/Function.h


Index: clang-tools-extra/clangd/support/Function.h
===
--- clang-tools-extra/clangd/support/Function.h
+++ clang-tools-extra/clangd/support/Function.h
@@ -51,7 +51,7 @@
 Subscription &operator=(Subscription &&Other) {
   // If *this is active, unsubscribe.
   if (Parent) {
-std::lock_guard(Parent->ListenersMu);
+std::lock_guard Lock(Parent->ListenersMu);
 llvm::erase_if(Parent->Listeners,
[&](const std::pair &P) {
  return P.second == ListenerID;


Index: clang-tools-extra/clangd/support/Function.h
===
--- clang-tools-extra/clangd/support/Function.h
+++ clang-tools-extra/clangd/support/Function.h
@@ -51,7 +51,7 @@
 Subscription &operator=(Subscription &&Other) {
   // If *this is active, unsubscribe.
   if (Parent) {
-std::lock_guard(Parent->ListenersMu);
+std::lock_guard Lock(Parent->ListenersMu);
 llvm::erase_if(Parent->Listeners,
[&](const std::pair &P) {
  return P.second == ListenerID;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95725: clang-extra: fix incorrect use of std::lock_guard by adding variable name (identified by MSVC [[nodiscard]] error)

2021-02-01 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc marked an inline comment as done.
poelmanc added a comment.

s/Guard/Lock/! I don't have commit access so appreciate a push.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95725/new/

https://reviews.llvm.org/D95725

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95714: [clang-tidy] fix modernize-use-nullptr false positive with spaceship operator comparisons

2021-02-01 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 320637.
poelmanc added a comment.

Add period to end of comment.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95714/new/

https://reviews.llvm.org/D95714

Files:
  clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
@@ -0,0 +1,34 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-nullptr %t
+
+namespace std {
+struct strong_ordering {
+  int n;
+  constexpr operator int() const { return n; }
+  static const strong_ordering equal, greater, less;
+};
+constexpr strong_ordering strong_ordering::equal = {0};
+constexpr strong_ordering strong_ordering::greater = {1};
+constexpr strong_ordering strong_ordering::less = {-1};
+}
+
+class A {
+public:
+  auto operator<=>(const A &other) const = default;
+};
+
+void test_cxx_rewritten_binary_ops() {
+  A a1, a2;
+  bool result;
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 < a2);
+  // CHECK-FIXES: result = (a1 < a2);
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 >= a2);
+  // CHECK-FIXES: result = (a1 >= a2);
+  int *ptr = 0;
+  // CHECK-FIXES: int *ptr = nullptr;
+  result = (a1 > (ptr == 0 ? a1 : a2));
+  // CHECK-FIXES: result = (a1 > (ptr == nullptr ? a1 : a2));
+  result = (a1 > ((a1 > (ptr == 0 ? a1 : a2)) ? a1 : a2));
+  // CHECK-FIXES: result = (a1 > ((a1 > (ptr == nullptr ? a1 : a2)) ? a1 : 
a2));
+}
Index: clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
===
--- clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
@@ -41,12 +41,28 @@
   
unless(hasImplicitDestinationType(qualType(substTemplateTypeParmType(,
   unless(hasSourceExpression(hasType(sugaredNullptrType();
 
+  auto isOrHasDescendant = [](auto InnerMatcher) {
+return anyOf(InnerMatcher, hasDescendant(InnerMatcher));
+  };
+
   return traverse(
   TK_AsIs,
-  castExpr(anyOf(ImplicitCastToNull,
- explicitCastExpr(hasDescendant(ImplicitCastToNull))),
-   unless(hasAncestor(explicitCastExpr(
-  .bind(CastSequence));
+  anyOf(castExpr(anyOf(ImplicitCastToNull,
+   
explicitCastExpr(hasDescendant(ImplicitCastToNull))),
+ unless(hasAncestor(explicitCastExpr())),
+ unless(hasAncestor(cxxRewrittenBinaryOperator(
+.bind(CastSequence),
+cxxRewrittenBinaryOperator(
+// Match rewritten operators, but verify (in the check method)
+// that if an implicit cast is found, it is not from another
+// nested rewritten operator.
+expr().bind("matchBinopOperands"),
+hasEitherOperand(isOrHasDescendant(
+implicitCastExpr(
+ImplicitCastToNull,
+hasAncestor(cxxRewrittenBinaryOperator().bind(
+"checkBinopOperands")))
+.bind(CastSequence));
 }
 
 bool isReplaceableRange(SourceLocation StartLoc, SourceLocation EndLoc,
@@ -480,6 +496,11 @@
   const auto *NullCast = Result.Nodes.getNodeAs(CastSequence);
   assert(NullCast && "Bad Callback. No node provided");
 
+  if (Result.Nodes.getNodeAs(
+  "matchBinopOperands") !=
+  Result.Nodes.getNodeAs("checkBinopOperands"))
+return;
+
   // Given an implicit null-ptr cast or an explicit cast with an implicit
   // null-to-pointer cast within use CastSequenceVisitor to identify sequences
   // of explicit casts that can be converted into 'nullptr'.


Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
@@ -0,0 +1,34 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-nullptr %t
+
+namespace std {
+struct strong_ordering {
+  int n;
+  constexpr operator int() const { return n; }
+  static const strong_ordering equal, greater, less;
+};
+constexpr strong_ordering strong_ordering::equal = {0};
+constexpr strong_ordering strong_ordering::greater = {1};
+constexpr strong_ordering strong_ordering::less = {-1};
+}
+
+class A {
+public:
+  auto operator<=>(const A &other) const = default;
+};
+
+void test_cxx_rewritten_binary_ops() {
+  A a1, a2;
+  bool result;
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 < a2);
+  // CHECK-FIXES: result = (a1 < a2);
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 >= a2);

[PATCH] D68682: format::cleanupAroundReplacements removes whole line when Removals leave previously non-blank line blank

2021-02-01 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 320678.
poelmanc changed the repository for this revision from rCTE Clang Tools Extra 
to rG LLVM Github Monorepo.
poelmanc added a comment.
Herald added subscribers: dexonsmith, mgorny.

Glad to be back after a year away from clang-tidy, and sorry to have let this 
patch linger. Running clang-tidy over a large codebase shows this patch still 
to be needed. I believe I've addressed all identified issues but welcome 
feedback.

@gribozavr @gribozavr2 requested changes to a very early version of this patch 
and I later reworked it to follow the `cleanupAroundReplacements` approach he 
suggested on 2019-10-11.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68682/new/

https://reviews.llvm.org/D68682

Files:
  clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-redundant-void-arg.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-control-flow.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability-simplify-bool-expr.cpp
  clang-tools-extra/unittests/clang-change-namespace/ChangeNamespaceTests.cpp
  clang/include/clang/Basic/CharInfo.h
  clang/include/clang/Format/Format.h
  clang/lib/AST/CommentLexer.cpp
  clang/lib/AST/CommentParser.cpp
  clang/lib/Format/Format.cpp
  clang/unittests/Format/CMakeLists.txt
  clang/unittests/Format/CleanupTest.cpp

Index: clang/unittests/Format/CleanupTest.cpp
===
--- clang/unittests/Format/CleanupTest.cpp
+++ clang/unittests/Format/CleanupTest.cpp
@@ -12,6 +12,7 @@
 #include "clang/Tooling/Core/Replacement.h"
 
 #include "gtest/gtest.h"
+#include "llvm/Testing/Support/Annotations.h"
 
 using clang::tooling::ReplacementTest;
 using clang::tooling::toReplacements;
@@ -320,6 +321,11 @@
 return tooling::Replacement(FileName, Offset, Length, Text);
   }
 
+  tooling::Replacement createReplacement(llvm::Annotations::Range Range,
+ StringRef Text) {
+return createReplacement(Range.Begin, Range.End - Range.Begin, Text);
+  }
+
   tooling::Replacement createInsertion(StringRef IncludeDirective) {
 return createReplacement(UINT_MAX, 0, IncludeDirective);
   }
@@ -373,10 +379,12 @@
  "namespace C {\n"
  "namespace D { int i; }\n"
  "inline namespace E { namespace { int y; } }\n"
+ "\n"
  "int x= 0;"
  "}";
-  std::string Expected = "\n\nnamespace C {\n"
- "namespace D { int i; }\n\n"
+  std::string Expected = "\nnamespace C {\n"
+ "namespace D { int i; }\n"
+ "\n"
  "int x= 0;"
  "}";
   tooling::Replacements Replaces =
@@ -386,6 +394,104 @@
   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
 }
 
+TEST_F(CleanUpReplacementsTest, RemoveLineWhenAllNonWhitespaceRemoved) {
+  llvm::Annotations Code = "namespace A {$r1[[ // Useless comment]]\n"
+   "  $r2[[int]] $r3[[x]]\t $r4[[=]] $r5[[0;]]\t\n"
+   "  int y\t = 0;$r6[[\t]]\n"
+   "} // namespace A\n";
+  std::string Expected = "namespace A {\n"
+ "  int y\t = 0;\n"
+ "} // namespace A\n";
+  tooling::Replacements Replaces =
+  toReplacements({createReplacement(Code.range("r1"), ""),
+  createReplacement(Code.range("r2"), ""),
+  createReplacement(Code.range("r3"), ""),
+  createReplacement(Code.range("r4"), ""),
+  createReplacement(Code.range("r5"), ""),
+  createReplacement(Code.range("r6"), "")});
+
+  EXPECT_EQ(Expected, apply(Code.code(), Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, RemoveLinesWhenAllNonWhitespaceRemoved) {
+  llvm::Annotations Code = R"cpp(struct A {
+  A()
+  $r3[[:]] $r1[[f()]]$r2[[,]]
+$r4[[g()]]
+  {}
+  int f = 0;
+  int g = 0;
+};)cpp";
+  std::string Expected = R"cpp(struct A {
+  A()
+  {}
+  int f = 0;
+  int g = 0;
+};)cpp";
+  tooling::Replacements Replaces =
+  toReplacements({createReplacement(Code.range("r1"), ""),
+  createReplacement(Code.range("r2"), ""),
+  createReplacement(Code.range("r3"), ""),
+  createReplacement(Code.range("r4"), "")});
+
+  EXPECT_EQ(Expected, apply(Code.code(), Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, KeepLinesWithInsertsOrReplacesEvenIfBlank) {
+  // Not using raw string literals so newlines and spaces are clear and explicit
+  llvm::Annotations Code = "struct A {\

[PATCH] D68682: format::cleanupAroundReplacements removes whole line when Removals leave previously non-blank line blank

2021-02-01 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc marked 14 inline comments as done.
poelmanc added inline comments.



Comment at: clang/lib/Format/Format.cpp:2381
+// if so adds a Replacement to NewReplacements that removes the entire line.
+llvm::Error MaybeRemoveBlankLine(tooling::Replacements &NewReplaces,
+ StringRef FilePath, StringRef Code,

kadircet wrote:
> kadircet wrote:
> > can we rather make this function return a `tooling::Replacement` ?
> name should be `maybeRemoveBlankLine`
`maybeRemoveBlankLine` needs to be called twice so I tried to put maximum logic 
in it so to avoid replicating logic at the two calling sites. It doesn't always 
create a replacement, so I believe we could return 
`optional`. Then the caller would have to check the 
`optional`, and if set  call `NewReplaces.add()`, then check that result... I 
can do that if you like but please take a fresh look at the updated 
implementation. Thanks!



Comment at: clang/lib/Format/Format.cpp:2394
+assert(LineEndPos >= CheckedThroughPos);
+StringRef TrailingText(FileText + CheckedThroughPos,
+   LineEndPos - CheckedThroughPos);

kadircet wrote:
> ```
> if(!isAllWhiteSpace(Code.substr(CheckedThroughPos, LineEndPos - 
> CheckedThroughPos))
>   return llvm::Error::success();
> ```
Coming back after a year I found my own code here a bit hard to read... Your 
feedback prompted me to use `StringRef` over `char*` and reduce the number of 
intermediate variables. I put your two suggested `isAllWhiteSpace` calls 
`isAllWhiteSpace` together with `&&`, feel free to suggest further improvement.




Comment at: clang/lib/Format/Format.cpp:2397
+assert(LineEndPos >= LineStartPos);
+StringRef OriginalLine(FileText + LineStartPos, LineEndPos - LineStartPos);
+if (isAllWhitespace(TrailingText) && !isAllWhitespace(OriginalLine)) {

kadircet wrote:
> ```
> if(isAllWhiteSpace(Code.substr(LineStartPos, CheckedThroughPos - 
> LineStartPos))
>   return llvm::Error::success();
> ```
> 
> Also move this to the top, as it doesn't actually require any of the 
> computations you performed.
> 
> I would actually keep a `HasDeleted` flag in the caller, updating it by 
> looking at length of replacements, and call this function iff we've deleted 
> something in that line, but up to you.
Used suggested `isAllWhitespace` together in the `if` clause with above 
`isAllWhitespace`.



Comment at: clang/lib/Format/Format.cpp:2403
+  (CheckedThroughPos > 0 &&
+   isVerticalWhitespace(FileText[CheckedThroughPos - 1]))
+  ? (FileText + LineEndPos)

kadircet wrote:
> i don't follow what this check is about.
> 
> the comment talks about a replacement removing a trailing newline, but check 
> is for a preceding whitespace, and it is not even at the `LineEndPos` ?
> how come we get a vertical whitespace, in the middle of a line?
I clarified the comment to include an example: when the code is `...  
foo\n\n...` and `foo\n` is removed by a replacement already, the second `\n` 
actually represents the //next// line which we don't want to remove.



Comment at: clang/unittests/Format/CleanupTest.cpp:368
+TEST_F(CleanUpReplacementsTest, RemoveLineWhenAllNonWhitespaceRemoved) {
+  std::string Code = "namespace A { // Useless comment\n"
+ "  int x\t = 0;\t\n"

kadircet wrote:
> poelmanc wrote:
> > kadircet wrote:
> > > could you replace these with raw string literals instead to get rid of 
> > > `\n`s.
> > I like that modernization suggestion but as a fairly new llvm contributor I 
> > follow the style I see in the surrounding code. Perhaps we should submit a 
> > seperate patch to modernize whole files at a time to use raw string 
> > literals and see how the change is received by the community.
> modernization of the existing code, and introducing old code are different 
> things. former is harder because we would like to keep the history clean, but 
> we tend to do the latter to make sure quality improves over time.
> 
> feel free to keep it if you want though, this one isn't so important.
I tried raw string literals, but these particular tests are all about tabs, 
spaces, and newlines which I found harder to see and reason about using raw 
string literals. I kept the raw string literals in 
`RemoveLinesWhenAllNonWhitespaceRemoved`.



Comment at: clang/unittests/Format/CleanupTest.cpp:376
+  tooling::Replacements Replaces =
+  toReplacements({createReplacement(getOffset(Code, 1, 14), 19, ""),
+  createReplacement(getOffset(Code, 2, 3), 3, ""),

kadircet wrote:
> poelmanc wrote:
> > kadircet wrote:
> > > can you make use of `Annotations` library in 
> > > `llvm/include/llvm/Testing/Support/Annotations.h` for getting offsets 
> > > into the code?
> > > 
> > > same for the following test ca

[PATCH] D95771: [clang-tidy] fix modernize-loop-convert to retain needed array-like operator[]

2021-02-02 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 320704.
poelmanc marked an inline comment as done.
poelmanc added a comment.

Fix formatting, add suggested test case (which works.)


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95771/new/

https://reviews.llvm.org/D95771

Files:
  clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/modernize-loop-convert-multidimensional.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/modernize-loop-convert-multidimensional.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-loop-convert-multidimensional.cpp
@@ -0,0 +1,79 @@
+// RUN: %check_clang_tidy %s modernize-loop-convert %t
+
+template 
+struct Vector {
+  using iterator = T*;
+  unsigned size() const;
+  const T &operator[](int) const;
+  T &operator[](int);
+  T *begin();
+  T *end();
+  const T *begin() const;
+  const T *end() const;
+};
+
+template 
+void copyArg(T);
+
+class TestArrayOfVector {
+  Vector W[2];
+
+  void foo() const {
+for (int I = 0; I < W[0].size(); ++I) {
+  if (W[0][I])
+copyArg(W[0][I]);
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use range-based for loop
+// CHECK-FIXES: for (int I : W[0]) {
+// CHECK-FIXES-NEXT: if (I)
+// CHECK-FIXES-NEXT: copyArg(I);
+  }
+};
+
+class TestVectorOfVector {
+  Vector> X;
+
+  void foo() const {
+for (int J = 0; J < X[0].size(); ++J) {
+  if (X[0][J])
+copyArg(X[0][J]);
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use range-based for loop
+// CHECK-FIXES: for (int J : X[0]) {
+// CHECK-FIXES-NEXT: if (J)
+// CHECK-FIXES-NEXT: copyArg(J);
+  }
+};
+
+void testVectorOfVectorOfVector() {
+  Vector>> Y;
+  for (int J = 0; J < Y[3].size(); ++J) {
+if (Y[3][J][7])
+  copyArg(Y[3][J][8]);
+  }
+  // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+  // CHECK-FIXES: for (auto & J : Y[3]) {
+  // CHECK-FIXES-NEXT: if (J[7])
+  // CHECK-FIXES-NEXT: copyArg(J[8]);
+
+  for (int J = 0; J < Y[3][4].size(); ++J) {
+if (Y[3][4][J])
+  copyArg(Y[3][4][J]);
+  }
+  // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+  // CHECK-FIXES: for (int J : Y[3][4]) {
+  // CHECK-FIXES-NEXT: if (J)
+  // CHECK-FIXES-NEXT: copyArg(J);
+}
+
+void testVectorOfVectorIterator() {
+  Vector> Z;
+  for (Vector::iterator it = Z[4].begin(); it != Z[4].end();  ++it) {
+if (*it)
+  copyArg(*it);
+  }
+  // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+  // CHECK-FIXES: for (int & it : Z[4]) {
+  // CHECK-FIXES-NEXT: if (it)
+  // CHECK-FIXES-NEXT: copyArg(it);
+}
Index: clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
===
--- clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
@@ -722,10 +722,11 @@
   if (isa(ContainerExpr)) {
 ContainerString = "this";
   } else {
-// For CXXOperatorCallExpr (e.g. vector_ptr->size()), its first argument is
-// the class object (vector_ptr) we are targeting.
+// For CXXOperatorCallExpr such as vector_ptr->size() we want the class
+// object vector_ptr, but for vector[2] we need the whole expression.
 if (const auto* E = dyn_cast(ContainerExpr))
-  ContainerExpr = E->getArg(0);
+  if (E->getOperator() != OO_Subscript)
+ContainerExpr = E->getArg(0);
 ContainerString =
 getStringFromRange(Context->getSourceManager(), Context->getLangOpts(),
ContainerExpr->getSourceRange());
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95771: [clang-tidy] fix modernize-loop-convert to retain needed array-like operator[]

2021-02-03 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

@njames93 Thanks for the review and for accepting this revision. I lack 
llvm-project commit access so if it's good to go I would greatly appreciate it 
if you or someone could push this whenever you have have a chance. Thanks!


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95771/new/

https://reviews.llvm.org/D95771

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95714: [clang-tidy] fix modernize-use-nullptr false positive with spaceship operator comparisons

2021-02-03 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

Thanks for all the great feedback I received here. To give credit where 
credit's due, this updated revision to UseNullptrCheck.cpp is now actually 100% 
@steveire's //suggested// code. Even one of the tests cases was his. Whenever 
it's ready to land I'd appreciate it if someone could push it as I lack 
llvm-project commit access.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95714/new/

https://reviews.llvm.org/D95714

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95714: [clang-tidy] fix modernize-use-nullptr false positive with spaceship operator comparisons

2021-02-03 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

In D95714#2540685 , @njames93 wrote:

> Can I ask if you could tidy the description of this, basically remove all the 
> stuff about hasGrandparent etc, probably best just remove everything after 
> `result = (a1 nullptr a2);` in the desc. It shows in the commit message and 
> its not strictly relevant.

Thanks, done. I never thought about all that showing up in the commit message, 
I'll be more concise.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95714/new/

https://reviews.llvm.org/D95714

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D68682: format::cleanupAroundReplacements removes whole line when Removals leave previously non-blank line blank

2021-02-04 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 321451.
poelmanc added a comment.
Herald added a subscriber: nullptr.cpp.

Change loop end condition in `findLineEnd` and add several `assert` statements.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68682/new/

https://reviews.llvm.org/D68682

Files:
  clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-redundant-void-arg.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-control-flow.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability-simplify-bool-expr.cpp
  clang-tools-extra/unittests/clang-change-namespace/ChangeNamespaceTests.cpp
  clang/include/clang/Basic/CharInfo.h
  clang/include/clang/Format/Format.h
  clang/lib/AST/CommentLexer.cpp
  clang/lib/AST/CommentParser.cpp
  clang/lib/Format/Format.cpp
  clang/unittests/Format/CMakeLists.txt
  clang/unittests/Format/CleanupTest.cpp

Index: clang/unittests/Format/CleanupTest.cpp
===
--- clang/unittests/Format/CleanupTest.cpp
+++ clang/unittests/Format/CleanupTest.cpp
@@ -12,6 +12,7 @@
 #include "clang/Tooling/Core/Replacement.h"
 
 #include "gtest/gtest.h"
+#include "llvm/Testing/Support/Annotations.h"
 
 using clang::tooling::ReplacementTest;
 using clang::tooling::toReplacements;
@@ -320,6 +321,11 @@
 return tooling::Replacement(FileName, Offset, Length, Text);
   }
 
+  tooling::Replacement createReplacement(llvm::Annotations::Range Range,
+ StringRef Text) {
+return createReplacement(Range.Begin, Range.End - Range.Begin, Text);
+  }
+
   tooling::Replacement createInsertion(StringRef IncludeDirective) {
 return createReplacement(UINT_MAX, 0, IncludeDirective);
   }
@@ -373,10 +379,12 @@
  "namespace C {\n"
  "namespace D { int i; }\n"
  "inline namespace E { namespace { int y; } }\n"
+ "\n"
  "int x= 0;"
  "}";
-  std::string Expected = "\n\nnamespace C {\n"
- "namespace D { int i; }\n\n"
+  std::string Expected = "\nnamespace C {\n"
+ "namespace D { int i; }\n"
+ "\n"
  "int x= 0;"
  "}";
   tooling::Replacements Replaces =
@@ -386,6 +394,104 @@
   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
 }
 
+TEST_F(CleanUpReplacementsTest, RemoveLineWhenAllNonWhitespaceRemoved) {
+  llvm::Annotations Code = "namespace A {$r1[[ // Useless comment]]\n"
+   "  $r2[[int]] $r3[[x]]\t $r4[[=]] $r5[[0;]]\t\n"
+   "  int y\t = 0;$r6[[\t]]\n"
+   "} // namespace A\n";
+  std::string Expected = "namespace A {\n"
+ "  int y\t = 0;\n"
+ "} // namespace A\n";
+  tooling::Replacements Replaces =
+  toReplacements({createReplacement(Code.range("r1"), ""),
+  createReplacement(Code.range("r2"), ""),
+  createReplacement(Code.range("r3"), ""),
+  createReplacement(Code.range("r4"), ""),
+  createReplacement(Code.range("r5"), ""),
+  createReplacement(Code.range("r6"), "")});
+
+  EXPECT_EQ(Expected, apply(Code.code(), Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, RemoveLinesWhenAllNonWhitespaceRemoved) {
+  llvm::Annotations Code = R"cpp(struct A {
+  A()
+  $r3[[:]] $r1[[f()]]$r2[[,]]
+$r4[[g()]]
+  {}
+  int f = 0;
+  int g = 0;
+};)cpp";
+  std::string Expected = R"cpp(struct A {
+  A()
+  {}
+  int f = 0;
+  int g = 0;
+};)cpp";
+  tooling::Replacements Replaces =
+  toReplacements({createReplacement(Code.range("r1"), ""),
+  createReplacement(Code.range("r2"), ""),
+  createReplacement(Code.range("r3"), ""),
+  createReplacement(Code.range("r4"), "")});
+
+  EXPECT_EQ(Expected, apply(Code.code(), Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, KeepLinesWithInsertsOrReplacesEvenIfBlank) {
+  // Not using raw string literals so newlines and spaces are clear and explicit
+  llvm::Annotations Code = "struct A {\n"
+ "  A() {}\n"
+ "$r3[[]]  $r1[[int]] $r2[[f;]]\n" // "  int f;\n"
+ "  \n"
+ "$r4[[  ]]\n"
+ "};";
+  std::string Expected = "struct A {\n"
+ "  A() {}\n"
+ "\n"
+ "\n"
+ "  \n"
+ "\t\n"
+ "};";
+  tooling::Replacements Replaces =
+  toRep

[PATCH] D95771: [clang-tidy] fix modernize-loop-convert to retain needed array-like operator[]

2021-02-06 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

In D95771#2547102 , @njames93 wrote:

> Should this be committed using `poelmanc `?

That or `Conrad Poelman ` would be great, thanks.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95771/new/

https://reviews.llvm.org/D95771

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D68682: format::cleanupAroundReplacements removes whole line when Removals leave previously non-blank line blank

2021-02-06 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

On 2 Feb Harbormaster found a bug  from my 
switching some char* code to use StringRef. I uploaded a new patch on 4 Feb, 
but Harbormaster does not appear to have rerun. What triggers Harbormaster - do 
I need to take some action? I haven't been able to find such options myself.

Please holler if there's a better place to ask this, thanks!


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68682/new/

https://reviews.llvm.org/D68682

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95771: [clang-tidy] fix modernize-loop-convert to retain needed array-like operator[]

2021-02-07 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

In D95771#2547366 , @njames93 wrote:

> In D95771#2547160 , @poelmanc wrote:
>
>> In D95771#2547102 , @njames93 wrote:
>>
>>> Should this be committed using `poelmanc `?
>>
>> That or `Conrad Poelman ` would be great, thanks.
>
> I committed using the email provided but its not attributed you on github. 
> It's attributed you here though. is that email not linked to your github 
> account?

Thanks for the commit, and thanks for the heads-up! I've now added the address 
in my github account.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95771/new/

https://reviews.llvm.org/D95771

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D68682: format::cleanupAroundReplacements removes whole line when Removals leave previously non-blank line blank

2021-02-07 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 322033.
poelmanc added a comment.

Update one one comment, hopefully trigger HarborMaster to rerun.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68682/new/

https://reviews.llvm.org/D68682

Files:
  clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-redundant-void-arg.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-control-flow.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability-simplify-bool-expr.cpp
  clang-tools-extra/unittests/clang-change-namespace/ChangeNamespaceTests.cpp
  clang/include/clang/Basic/CharInfo.h
  clang/include/clang/Format/Format.h
  clang/lib/AST/CommentLexer.cpp
  clang/lib/AST/CommentParser.cpp
  clang/lib/Format/Format.cpp
  clang/unittests/Format/CMakeLists.txt
  clang/unittests/Format/CleanupTest.cpp

Index: clang/unittests/Format/CleanupTest.cpp
===
--- clang/unittests/Format/CleanupTest.cpp
+++ clang/unittests/Format/CleanupTest.cpp
@@ -12,6 +12,7 @@
 #include "clang/Tooling/Core/Replacement.h"
 
 #include "gtest/gtest.h"
+#include "llvm/Testing/Support/Annotations.h"
 
 using clang::tooling::ReplacementTest;
 using clang::tooling::toReplacements;
@@ -320,6 +321,11 @@
 return tooling::Replacement(FileName, Offset, Length, Text);
   }
 
+  tooling::Replacement createReplacement(llvm::Annotations::Range Range,
+ StringRef Text) {
+return createReplacement(Range.Begin, Range.End - Range.Begin, Text);
+  }
+
   tooling::Replacement createInsertion(StringRef IncludeDirective) {
 return createReplacement(UINT_MAX, 0, IncludeDirective);
   }
@@ -373,10 +379,12 @@
  "namespace C {\n"
  "namespace D { int i; }\n"
  "inline namespace E { namespace { int y; } }\n"
+ "\n"
  "int x= 0;"
  "}";
-  std::string Expected = "\n\nnamespace C {\n"
- "namespace D { int i; }\n\n"
+  std::string Expected = "\nnamespace C {\n"
+ "namespace D { int i; }\n"
+ "\n"
  "int x= 0;"
  "}";
   tooling::Replacements Replaces =
@@ -386,6 +394,104 @@
   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
 }
 
+TEST_F(CleanUpReplacementsTest, RemoveLineWhenAllNonWhitespaceRemoved) {
+  llvm::Annotations Code = "namespace A {$r1[[ // Useless comment]]\n"
+   "  $r2[[int]] $r3[[x]]\t $r4[[=]] $r5[[0;]]\t\n"
+   "  int y\t = 0;$r6[[\t]]\n"
+   "} // namespace A\n";
+  std::string Expected = "namespace A {\n"
+ "  int y\t = 0;\n"
+ "} // namespace A\n";
+  tooling::Replacements Replaces =
+  toReplacements({createReplacement(Code.range("r1"), ""),
+  createReplacement(Code.range("r2"), ""),
+  createReplacement(Code.range("r3"), ""),
+  createReplacement(Code.range("r4"), ""),
+  createReplacement(Code.range("r5"), ""),
+  createReplacement(Code.range("r6"), "")});
+
+  EXPECT_EQ(Expected, apply(Code.code(), Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, RemoveLinesWhenAllNonWhitespaceRemoved) {
+  llvm::Annotations Code = R"cpp(struct A {
+  A()
+  $r3[[:]] $r1[[f()]]$r2[[,]]
+$r4[[g()]]
+  {}
+  int f = 0;
+  int g = 0;
+};)cpp";
+  std::string Expected = R"cpp(struct A {
+  A()
+  {}
+  int f = 0;
+  int g = 0;
+};)cpp";
+  tooling::Replacements Replaces =
+  toReplacements({createReplacement(Code.range("r1"), ""),
+  createReplacement(Code.range("r2"), ""),
+  createReplacement(Code.range("r3"), ""),
+  createReplacement(Code.range("r4"), "")});
+
+  EXPECT_EQ(Expected, apply(Code.code(), Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, KeepLinesWithInsertsOrReplacesEvenIfBlank) {
+  // Not using raw string literals so newlines and spaces are clear and explicit
+  llvm::Annotations Code = "struct A {\n"
+ "  A() {}\n"
+ "$r3[[]]  $r1[[int]] $r2[[f;]]\n" // "  int f;\n"
+ "  \n"
+ "$r4[[  ]]\n"
+ "};";
+  std::string Expected = "struct A {\n"
+ "  A() {}\n"
+ "\n"
+ "\n"
+ "  \n"
+ "\t\n"
+ "};";
+  tooling::Replacements Replaces =
+  toReplacements({createReplacement(Code.range("r1"), "   "),

[PATCH] D68682: format::cleanupAroundReplacements removes whole line when Removals leave previously non-blank line blank

2021-02-08 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 322108.
poelmanc added a comment.

Comment change, "beginning" to "start" for consistency, being sure to set 
Repository on "diff" page (not just on edit page) to see if 
https://github.com/google/llvm-premerge-checks/issues/263 was the problem.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68682/new/

https://reviews.llvm.org/D68682

Files:
  clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-redundant-void-arg.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-control-flow.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability-simplify-bool-expr.cpp
  clang-tools-extra/unittests/clang-change-namespace/ChangeNamespaceTests.cpp
  clang/include/clang/Basic/CharInfo.h
  clang/include/clang/Format/Format.h
  clang/lib/AST/CommentLexer.cpp
  clang/lib/AST/CommentParser.cpp
  clang/lib/Format/Format.cpp
  clang/unittests/Format/CMakeLists.txt
  clang/unittests/Format/CleanupTest.cpp

Index: clang/unittests/Format/CleanupTest.cpp
===
--- clang/unittests/Format/CleanupTest.cpp
+++ clang/unittests/Format/CleanupTest.cpp
@@ -12,6 +12,7 @@
 #include "clang/Tooling/Core/Replacement.h"
 
 #include "gtest/gtest.h"
+#include "llvm/Testing/Support/Annotations.h"
 
 using clang::tooling::ReplacementTest;
 using clang::tooling::toReplacements;
@@ -320,6 +321,11 @@
 return tooling::Replacement(FileName, Offset, Length, Text);
   }
 
+  tooling::Replacement createReplacement(llvm::Annotations::Range Range,
+ StringRef Text) {
+return createReplacement(Range.Begin, Range.End - Range.Begin, Text);
+  }
+
   tooling::Replacement createInsertion(StringRef IncludeDirective) {
 return createReplacement(UINT_MAX, 0, IncludeDirective);
   }
@@ -373,10 +379,12 @@
  "namespace C {\n"
  "namespace D { int i; }\n"
  "inline namespace E { namespace { int y; } }\n"
+ "\n"
  "int x= 0;"
  "}";
-  std::string Expected = "\n\nnamespace C {\n"
- "namespace D { int i; }\n\n"
+  std::string Expected = "\nnamespace C {\n"
+ "namespace D { int i; }\n"
+ "\n"
  "int x= 0;"
  "}";
   tooling::Replacements Replaces =
@@ -386,6 +394,104 @@
   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
 }
 
+TEST_F(CleanUpReplacementsTest, RemoveLineWhenAllNonWhitespaceRemoved) {
+  llvm::Annotations Code = "namespace A {$r1[[ // Useless comment]]\n"
+   "  $r2[[int]] $r3[[x]]\t $r4[[=]] $r5[[0;]]\t\n"
+   "  int y\t = 0;$r6[[\t]]\n"
+   "} // namespace A\n";
+  std::string Expected = "namespace A {\n"
+ "  int y\t = 0;\n"
+ "} // namespace A\n";
+  tooling::Replacements Replaces =
+  toReplacements({createReplacement(Code.range("r1"), ""),
+  createReplacement(Code.range("r2"), ""),
+  createReplacement(Code.range("r3"), ""),
+  createReplacement(Code.range("r4"), ""),
+  createReplacement(Code.range("r5"), ""),
+  createReplacement(Code.range("r6"), "")});
+
+  EXPECT_EQ(Expected, apply(Code.code(), Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, RemoveLinesWhenAllNonWhitespaceRemoved) {
+  llvm::Annotations Code = R"cpp(struct A {
+  A()
+  $r3[[:]] $r1[[f()]]$r2[[,]]
+$r4[[g()]]
+  {}
+  int f = 0;
+  int g = 0;
+};)cpp";
+  std::string Expected = R"cpp(struct A {
+  A()
+  {}
+  int f = 0;
+  int g = 0;
+};)cpp";
+  tooling::Replacements Replaces =
+  toReplacements({createReplacement(Code.range("r1"), ""),
+  createReplacement(Code.range("r2"), ""),
+  createReplacement(Code.range("r3"), ""),
+  createReplacement(Code.range("r4"), "")});
+
+  EXPECT_EQ(Expected, apply(Code.code(), Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, KeepLinesWithInsertsOrReplacesEvenIfBlank) {
+  // Not using raw string literals so newlines and spaces are clear and explicit
+  llvm::Annotations Code = "struct A {\n"
+ "  A() {}\n"
+ "$r3[[]]  $r1[[int]] $r2[[f;]]\n" // "  int f;\n"
+ "  \n"
+ "$r4[[  ]]\n"
+ "};";
+  std::string Expected = "struct A {\n"
+ "  A() {}\n"
+ "\n"
+ "\n"
+   

[PATCH] D95714: [clang-tidy] fix modernize-use-nullptr false positive with spaceship operator comparisons

2021-02-08 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

In D95714#2548735 , @njames93 wrote:

> LGTM, Same as last time for the commit?

That would be great, thanks!


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95714/new/

https://reviews.llvm.org/D95714

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95714: [clang-tidy] fix modernize-use-nullptr false positive with spaceship operator comparisons

2021-02-08 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 322253.
poelmanc added a comment.

Thanks for your patience, this one should work, as I used my normal `git show 
HEAD -U99` workflow.

(The requested change was just to add a period to a comment, so as a short-cut 
I tried "Raw Diff" -> copy -> "Update Diff" -> paste into "Raw Diff" field, -> 
add the period -> Continue -> Save. "Raw Diff" didn't show full context, but it 
appeared to work based on the web interface. I guess not. 
`modernize-use-nullptr-cxx20.cpp` is a whole new file, in case that matters.)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95714/new/

https://reviews.llvm.org/D95714

Files:
  clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
@@ -0,0 +1,34 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-nullptr %t
+
+namespace std {
+struct strong_ordering {
+  int n;
+  constexpr operator int() const { return n; }
+  static const strong_ordering equal, greater, less;
+};
+constexpr strong_ordering strong_ordering::equal = {0};
+constexpr strong_ordering strong_ordering::greater = {1};
+constexpr strong_ordering strong_ordering::less = {-1};
+}
+
+class A {
+public:
+  auto operator<=>(const A &other) const = default;
+};
+
+void test_cxx_rewritten_binary_ops() {
+  A a1, a2;
+  bool result;
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 < a2);
+  // CHECK-FIXES: result = (a1 < a2);
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 >= a2);
+  // CHECK-FIXES: result = (a1 >= a2);
+  int *ptr = 0;
+  // CHECK-FIXES: int *ptr = nullptr;
+  result = (a1 > (ptr == 0 ? a1 : a2));
+  // CHECK-FIXES: result = (a1 > (ptr == nullptr ? a1 : a2));
+  result = (a1 > ((a1 > (ptr == 0 ? a1 : a2)) ? a1 : a2));
+  // CHECK-FIXES: result = (a1 > ((a1 > (ptr == nullptr ? a1 : a2)) ? a1 : 
a2));
+}
Index: clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
===
--- clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
@@ -41,12 +41,28 @@
   
unless(hasImplicitDestinationType(qualType(substTemplateTypeParmType(,
   unless(hasSourceExpression(hasType(sugaredNullptrType();
 
+  auto isOrHasDescendant = [](auto InnerMatcher) {
+return anyOf(InnerMatcher, hasDescendant(InnerMatcher));
+  };
+
   return traverse(
   TK_AsIs,
-  castExpr(anyOf(ImplicitCastToNull,
- explicitCastExpr(hasDescendant(ImplicitCastToNull))),
-   unless(hasAncestor(explicitCastExpr(
-  .bind(CastSequence));
+  anyOf(castExpr(anyOf(ImplicitCastToNull,
+   
explicitCastExpr(hasDescendant(ImplicitCastToNull))),
+ unless(hasAncestor(explicitCastExpr())),
+ unless(hasAncestor(cxxRewrittenBinaryOperator(
+.bind(CastSequence),
+cxxRewrittenBinaryOperator(
+// Match rewritten operators, but verify (in the check method)
+// that if an implicit cast is found, it is not from another
+// nested rewritten operator.
+expr().bind("matchBinopOperands"),
+hasEitherOperand(isOrHasDescendant(
+implicitCastExpr(
+ImplicitCastToNull,
+hasAncestor(cxxRewrittenBinaryOperator().bind(
+"checkBinopOperands")))
+.bind(CastSequence));
 }
 
 bool isReplaceableRange(SourceLocation StartLoc, SourceLocation EndLoc,
@@ -480,6 +496,11 @@
   const auto *NullCast = Result.Nodes.getNodeAs(CastSequence);
   assert(NullCast && "Bad Callback. No node provided");
 
+  if (Result.Nodes.getNodeAs(
+  "matchBinopOperands") !=
+  Result.Nodes.getNodeAs("checkBinopOperands"))
+return;
+
   // Given an implicit null-ptr cast or an explicit cast with an implicit
   // null-to-pointer cast within use CastSequenceVisitor to identify sequences
   // of explicit casts that can be converted into 'nullptr'.


Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
@@ -0,0 +1,34 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-nullptr %t
+
+namespace std {
+struct strong_ordering {
+  int n;
+  constexpr operator int() const { return n; }
+  static const strong_ordering equal, greater, less;
+};
+constexpr strong_orderin

[PATCH] D68682: format::cleanupAroundReplacements removes whole line when Removals leave previously non-blank line blank

2021-02-08 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 322265.
poelmanc added a comment.

Call `llvm::Annoation` constructor rather than `operator=` to fix linux build 
issue, fix some issues identified by clang-format and clang-tidy.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68682/new/

https://reviews.llvm.org/D68682

Files:
  clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-redundant-void-arg.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-control-flow.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability-simplify-bool-expr.cpp
  clang-tools-extra/unittests/clang-change-namespace/ChangeNamespaceTests.cpp
  clang/include/clang/Basic/CharInfo.h
  clang/include/clang/Format/Format.h
  clang/lib/AST/CommentLexer.cpp
  clang/lib/AST/CommentParser.cpp
  clang/lib/Format/Format.cpp
  clang/unittests/Format/CMakeLists.txt
  clang/unittests/Format/CleanupTest.cpp

Index: clang/unittests/Format/CleanupTest.cpp
===
--- clang/unittests/Format/CleanupTest.cpp
+++ clang/unittests/Format/CleanupTest.cpp
@@ -11,6 +11,7 @@
 #include "../Tooling/ReplacementTest.h"
 #include "clang/Tooling/Core/Replacement.h"
 
+#include "llvm/Testing/Support/Annotations.h"
 #include "gtest/gtest.h"
 
 using clang::tooling::ReplacementTest;
@@ -320,6 +321,11 @@
 return tooling::Replacement(FileName, Offset, Length, Text);
   }
 
+  tooling::Replacement createReplacement(llvm::Annotations::Range Range,
+ StringRef Text) {
+return createReplacement(Range.Begin, Range.End - Range.Begin, Text);
+  }
+
   tooling::Replacement createInsertion(StringRef IncludeDirective) {
 return createReplacement(UINT_MAX, 0, IncludeDirective);
   }
@@ -373,10 +379,12 @@
  "namespace C {\n"
  "namespace D { int i; }\n"
  "inline namespace E { namespace { int y; } }\n"
+ "\n"
  "int x= 0;"
  "}";
-  std::string Expected = "\n\nnamespace C {\n"
- "namespace D { int i; }\n\n"
+  std::string Expected = "\nnamespace C {\n"
+ "namespace D { int i; }\n"
+ "\n"
  "int x= 0;"
  "}";
   tooling::Replacements Replaces =
@@ -386,6 +394,104 @@
   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
 }
 
+TEST_F(CleanUpReplacementsTest, RemoveLineWhenAllNonWhitespaceRemoved) {
+  llvm::Annotations Code("namespace A {$r1[[ // Useless comment]]\n"
+ "  $r2[[int]] $r3[[x]]\t $r4[[=]] $r5[[0;]]\t\n"
+ "  int y\t = 0;$r6[[\t]]\n"
+ "} // namespace A\n");
+  std::string Expected = "namespace A {\n"
+ "  int y\t = 0;\n"
+ "} // namespace A\n";
+  tooling::Replacements Replaces =
+  toReplacements({createReplacement(Code.range("r1"), ""),
+  createReplacement(Code.range("r2"), ""),
+  createReplacement(Code.range("r3"), ""),
+  createReplacement(Code.range("r4"), ""),
+  createReplacement(Code.range("r5"), ""),
+  createReplacement(Code.range("r6"), "")});
+
+  EXPECT_EQ(Expected, apply(Code.code(), Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, RemoveLinesWhenAllNonWhitespaceRemoved) {
+  llvm::Annotations Code(R"cpp(struct A {
+  A()
+  $r3[[:]] $r1[[f()]]$r2[[,]]
+$r4[[g()]]
+  {}
+  int f = 0;
+  int g = 0;
+};)cpp");
+  std::string Expected = R"cpp(struct A {
+  A()
+  {}
+  int f = 0;
+  int g = 0;
+};)cpp";
+  tooling::Replacements Replaces =
+  toReplacements({createReplacement(Code.range("r1"), ""),
+  createReplacement(Code.range("r2"), ""),
+  createReplacement(Code.range("r3"), ""),
+  createReplacement(Code.range("r4"), "")});
+
+  EXPECT_EQ(Expected, apply(Code.code(), Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, KeepLinesWithInsertsOrReplacesEvenIfBlank) {
+  // Not using raw string literals so newlines and spaces are clear and explicit
+  llvm::Annotations Code("struct A {\n"
+ "  A() {}\n"
+ "$r3[[]]  $r1[[int]] $r2[[f;]]\n" // "  int f;\n"
+ "  \n"
+ "$r4[[  ]]\n"
+ "};");
+  std::string Expected = "struct A {\n"
+ "  A() {}\n"
+ "\n"
+ "\n"
+ "  \n"
+ "\t\n"
+  

[PATCH] D68682: format::cleanupAroundReplacements removes whole line when Removals leave previously non-blank line blank

2021-02-08 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

In D68682#2547906 , @kadircet wrote:

> It looks like premerge tests skipped your last diff with id 321451 
> (https://reviews.llvm.org/harbormaster/?after=87950). You can re-trigger by 
> uploading a new diff, in the meantime i would also file a bug to 
> https://github.com/google/llvm-premerge-checks/issues. mentioning your diff 
> id.

Thanks @kadircet, actually just reviewing the current bug list explained the 
problem: https://github.com/google/llvm-premerge-checks/issues/263, //Build is 
not triggered if diff repository is not set//. I wasn't selecting //rG 
 LLVM Github Monorepo// per 
instructions at https://llvm.org/docs/Phabricator.html that said //Leave the 
Repository field blank//.

HarborMaster has now run and passes all tests on Windows and Linux.

1. clang-format for a new test case in 
`clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp`.
 That test case formatting matches real-world examples so I'm reluctant to 
change it - I believe it's clang-formatted but with different settings from 
llvm-project's.
2. clang-tidy finds 8 `int` vs `size_t` comparisons. While `int` feels safer 
when subtraction is involved (since one can `assert` variables stay positive), 
this particular code would work fine with `int` variables changed to `size_t`, 
or alternatively with `static_cast` to silence the warnings.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68682/new/

https://reviews.llvm.org/D68682

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95714: [clang-tidy] fix modernize-use-nullptr false positive with spaceship operator comparisons

2021-02-08 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 322302.
poelmanc added a comment.

Capitalize `IsOrHasDescendant`, add `} namespace std` per HarborMaster feedback.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95714/new/

https://reviews.llvm.org/D95714

Files:
  clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
@@ -0,0 +1,34 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-nullptr %t
+
+namespace std {
+struct strong_ordering {
+  int n;
+  constexpr operator int() const { return n; }
+  static const strong_ordering equal, greater, less;
+};
+constexpr strong_ordering strong_ordering::equal = {0};
+constexpr strong_ordering strong_ordering::greater = {1};
+constexpr strong_ordering strong_ordering::less = {-1};
+} // namespace std
+
+class A {
+public:
+  auto operator<=>(const A &other) const = default;
+};
+
+void test_cxx_rewritten_binary_ops() {
+  A a1, a2;
+  bool result;
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 < a2);
+  // CHECK-FIXES: result = (a1 < a2);
+  // should not change next line to (a1 nullptr a2)
+  result = (a1 >= a2);
+  // CHECK-FIXES: result = (a1 >= a2);
+  int *ptr = 0;
+  // CHECK-FIXES: int *ptr = nullptr;
+  result = (a1 > (ptr == 0 ? a1 : a2));
+  // CHECK-FIXES: result = (a1 > (ptr == nullptr ? a1 : a2));
+  result = (a1 > ((a1 > (ptr == 0 ? a1 : a2)) ? a1 : a2));
+  // CHECK-FIXES: result = (a1 > ((a1 > (ptr == nullptr ? a1 : a2)) ? a1 : 
a2));
+}
Index: clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
===
--- clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
@@ -41,12 +41,28 @@
   
unless(hasImplicitDestinationType(qualType(substTemplateTypeParmType(,
   unless(hasSourceExpression(hasType(sugaredNullptrType();
 
+  auto IsOrHasDescendant = [](auto InnerMatcher) {
+return anyOf(InnerMatcher, hasDescendant(InnerMatcher));
+  };
+
   return traverse(
   TK_AsIs,
-  castExpr(anyOf(ImplicitCastToNull,
- explicitCastExpr(hasDescendant(ImplicitCastToNull))),
-   unless(hasAncestor(explicitCastExpr(
-  .bind(CastSequence));
+  anyOf(castExpr(anyOf(ImplicitCastToNull,
+   
explicitCastExpr(hasDescendant(ImplicitCastToNull))),
+ unless(hasAncestor(explicitCastExpr())),
+ unless(hasAncestor(cxxRewrittenBinaryOperator(
+.bind(CastSequence),
+cxxRewrittenBinaryOperator(
+// Match rewritten operators, but verify (in the check method)
+// that if an implicit cast is found, it is not from another
+// nested rewritten operator.
+expr().bind("matchBinopOperands"),
+hasEitherOperand(IsOrHasDescendant(
+implicitCastExpr(
+ImplicitCastToNull,
+hasAncestor(cxxRewrittenBinaryOperator().bind(
+"checkBinopOperands")))
+.bind(CastSequence));
 }
 
 bool isReplaceableRange(SourceLocation StartLoc, SourceLocation EndLoc,
@@ -480,6 +496,11 @@
   const auto *NullCast = Result.Nodes.getNodeAs(CastSequence);
   assert(NullCast && "Bad Callback. No node provided");
 
+  if (Result.Nodes.getNodeAs(
+  "matchBinopOperands") !=
+  Result.Nodes.getNodeAs("checkBinopOperands"))
+return;
+
   // Given an implicit null-ptr cast or an explicit cast with an implicit
   // null-to-pointer cast within use CastSequenceVisitor to identify sequences
   // of explicit casts that can be converted into 'nullptr'.


Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-nullptr-cxx20.cpp
@@ -0,0 +1,34 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-nullptr %t
+
+namespace std {
+struct strong_ordering {
+  int n;
+  constexpr operator int() const { return n; }
+  static const strong_ordering equal, greater, less;
+};
+constexpr strong_ordering strong_ordering::equal = {0};
+constexpr strong_ordering strong_ordering::greater = {1};
+constexpr strong_ordering strong_ordering::less = {-1};
+} // namespace std
+
+class A {
+public:
+  auto operator<=>(const A &other) const = default;
+};
+
+void test_cxx_rewritten_binary_ops() {
+  A a1, a2;
+  bool result;
+  // should not change next line to (a1 nullptr a2)
+  result = (a

[PATCH] D96744: clang-format IncludeBlocks: Regroup determination of "main" for framework-style includes fix

2021-02-15 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc created this revision.
poelmanc added reviewers: MyDeveloperDay, hokein, sammccall.
poelmanc added projects: clang-tools-extra, clang-format.
poelmanc requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Most modern libraries and applications include files with relative paths from a 
root (e.g. `#include ` versus `#include "baz.h"`.) When 
regrouping, a file's "main include" should be left at the top (given priority 
0.) The existing `IncludeCategoryManager::isMainHeader()` checks only the file 
//stem// (e.g. `baz.h`), and fails to identify main includes with angle 
brackets despite a comment saying `// remove the surrounding "" or <>`.

This patch fixes these issues by comparing all directory components present in 
both the `#include` string and the file name, and by allowing angle bracket 
includes to be considered "main". It adds a new `IsMainHeader` unit test to 
check behavior of framework-style includes, which would fail without this patch.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D96744

Files:
  clang/lib/Tooling/Inclusions/HeaderIncludes.cpp
  clang/unittests/Tooling/HeaderIncludesTest.cpp


Index: clang/unittests/Tooling/HeaderIncludesTest.cpp
===
--- clang/unittests/Tooling/HeaderIncludesTest.cpp
+++ clang/unittests/Tooling/HeaderIncludesTest.cpp
@@ -91,6 +91,28 @@
   EXPECT_EQ(Expected, insert(Code, "\"a.h\""));
 }
 
+TEST_F(HeaderIncludesTest, IsMainHeader) {
+  Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp)
+  .IncludeStyle;
+  std::vector FileNames{"foo/bar/baz.cpp", "foo/bar/baz.cu.cpp",
+   "foo/bar/baz_test.cu.cpp"};
+  for (const StringRef &FileName : FileNames) {
+IncludeCategoryManager Manager(Style, FileName);
+// These framework-style includes should all be considered "main".
+EXPECT_EQ(Manager.getIncludePriority("", true), 0)
+<< "for source file " << FileName;
+EXPECT_EQ(Manager.getIncludePriority("\"bar/baz.h\"", true), 0)
+<< "for source file " << FileName;
+EXPECT_EQ(Manager.getIncludePriority("", true), 0)
+<< "for source file " << FileName;
+// These should not be considered "main" as the paths to baz.h differ.
+EXPECT_NE(Manager.getIncludePriority("", true), 0)
+<< "for source file " << FileName;
+EXPECT_NE(Manager.getIncludePriority("\"foo/baz.h\"", true), 0)
+<< "for source file " << FileName;
+  }
+}
+
 TEST_F(HeaderIncludesTest, InsertAfterMainHeader) {
   std::string Code = "#include \"fix.h\"\n"
  "\n"
Index: clang/lib/Tooling/Inclusions/HeaderIncludes.cpp
===
--- clang/lib/Tooling/Inclusions/HeaderIncludes.cpp
+++ clang/lib/Tooling/Inclusions/HeaderIncludes.cpp
@@ -233,9 +233,6 @@
   return Ret;
 }
 bool IncludeCategoryManager::isMainHeader(StringRef IncludeName) const {
-  if (!IncludeName.startswith("\""))
-return false;
-
   IncludeName =
   IncludeName.drop_front(1).drop_back(1); // remove the surrounding "" or 
<>
   // Not matchingStem: implementation files may have compound extensions but
@@ -259,8 +256,22 @@
   if (!Matching.empty()) {
 llvm::Regex MainIncludeRegex(HeaderStem.str() + Style.IncludeIsMainRegex,
  llvm::Regex::IgnoreCase);
-if (MainIncludeRegex.match(Matching))
+if (MainIncludeRegex.match(Matching)) {
+  // Matching is non-empty so these should be non-empty as well, making
+  // ++rbegin(IncludeName) and ++rbegin(FileName) safe.
+  assert(!IncludeName.empty());
+  assert(!FileName.empty());
+  // Checked stems above. Check remaining common path components here.
+  auto IncludePathRIter = ++llvm::sys::path::rbegin(IncludeName);
+  auto FilePathRiter = ++llvm::sys::path::rbegin(FileName);
+  for (; IncludePathRIter != llvm::sys::path::rend(IncludeName) &&
+ FilePathRiter != llvm::sys::path::rend(FileName);
+   ++IncludePathRIter, ++FilePathRiter) {
+if (*IncludePathRIter != *FilePathRiter)
+  return false;
+  }
   return true;
+}
   }
   return false;
 }


Index: clang/unittests/Tooling/HeaderIncludesTest.cpp
===
--- clang/unittests/Tooling/HeaderIncludesTest.cpp
+++ clang/unittests/Tooling/HeaderIncludesTest.cpp
@@ -91,6 +91,28 @@
   EXPECT_EQ(Expected, insert(Code, "\"a.h\""));
 }
 
+TEST_F(HeaderIncludesTest, IsMainHeader) {
+  Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp)
+  .IncludeStyle;
+  std::vector FileNames{"foo/bar/baz.cpp", "foo/bar/baz.cu.cpp",
+   "foo/bar/baz_test.cu.cpp"};
+  for (const StringRef &FileName : FileNames) {
+IncludeCategoryManager Manager(Style, FileName);
+// These framework

[PATCH] D96744: clang-format IncludeBlocks: Regroup determination of "main" for framework-style includes fix

2021-02-16 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

Thanks for the speedy reply and the great tool. With appropriate Regex and 
Priority settings, `IncludeCategories` worked flawlessly for me aside from not 
identifying the main header. Treating `#include "foo/bar/baz.h"` as the main 
header in file `bar/random/baz.h` seems like a bug, but I certainly see the 
dangers of changing current `<>` behavior. I also considered treating `<>` 
includes as main headers only if they also contain a forward-slash, e.g.:

  if (!IncludeName.startswith("\"") && !IncludeName.contains("/"))
return false;

That would resolve the `` case, although `#include ` in 
a file `anything/sys/types.h` would be identified as the main header. So making 
an option seems like the cleanest solution. Say, `bool 
IncludeIsMainAllowBraces`?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D96744/new/

https://reviews.llvm.org/D96744

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D96744: clang-format IncludeBlocks: Regroup determination of "main" for framework-style includes fix

2021-02-26 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

In D96744#2564828 , @MyDeveloperDay 
wrote:

> Does this need to be an option?

It's easy to add an option, but there are already two //main include//-related 
options, so before adding a third I wanted to give this some thought. As 
someone new to `IncludeCategories`, I was genuinely impressed at how easy it 
was to use and how it gave me such complete control over the grouping via 
regular expressions. Yet in comparison the determination of //main// headers 
was less clear and more hard-coded; I had to examine the source code to figure 
out that the comparison is case-insensitive, it doesn't consider `<>` includes, 
only file stems are considered (e.g. the `foo/bar` in `foo/bar/baz.h` is 
ignored), and the behaviors of `IncludeIsMainSourceRegex` and 
`IncludeIsMainRegex` were a bit murky.

That's all fixable with a patch and minor documentation tweaks, but I wanted to 
consider some alternatives. Users of the `IncludeCategories` feature are 
comfortable with regular expressions, so imagine eliminating special handling 
of //main headers// entirely, and instead enabling users to write their own 
`IncludeCategories` rules for putting main headers first? We'd need to give 
them some bits of the source file path to use in their `Regex`, say called 
`${SourceStem}` and `${SourcePath}`.

Users unconcerned with formatting `foo_test.cc` or `foo_proto.cc` files could 
get the current functionality by including a simple rule like:

  - Regex:   '"(.*\/)?${SourceStem}(\..*)?"'
Priority:0
CaseSensitive:   false

I want case sensitivity, matching at least one component of the path, and angle 
brackets, so I'd use something like:

  - Regex:   '[<"]${SourcePath:1}${SourceStem}\..*[>"]'
Priority:0
CaseSensitive:   true

Then adding a generally-useful `ApplyToSourcesRegex` feature to apply any 
category regex only to certain source files, and an ability to trim a regular 
expression from the end of `${SourceStem}`, gives users full control, including 
mimicking current `isMainHeader()` behavior with rules like:

  - Regex:   
'"(.*\/)?${SourceStem-}(\..*)?"'
Priority:0
CaseSensitive:   false
ApplyToSourcesRegex: 
`((.*\.(c|cc|cpp|c\+\+|cxx|m|mm))|)`

For backwards-compatibility we'd automatically add the above rule if no special 
`${Source` tokens appear in any rules, and we can deprecate 
`IncludeIsMainRegex` and `IncludeIsMainSourceRegex` at any point. The special 
tokens for use in `Regex` are defined as:

- `${SourcePath:}` is a regular expression matching `n` or more trailing 
components of the source directory file path, using forward slashes and 
including any trailing slash (`0 <= n < 10`)
- `${SourceStem}` is a string starting after the last `/` in the source file 
path and includes up to but excluding the first dot
- `${SourceStem-}` is `${SourceStem}` with any trailing characters matching 
regular expression `re` removed

I have this coded up and it passes the ToolingTests, but wanted to run the idea 
by others. Thoughts? Should I update this patch with these changes? Start a 
separate issue? Stick with a new option `IncludeIsMainAllowBraces`?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D96744/new/

https://reviews.llvm.org/D96744

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D97620: Fix DecisionForestBenchmark.cpp compile errors

2021-02-27 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc created this revision.
poelmanc added a reviewer: usaxena95.
poelmanc added a project: clang-tools-extra.
Herald added subscribers: kadircet, arphaman.
poelmanc requested review of this revision.
Herald added subscribers: cfe-commits, ilya-biryukov.
Herald added a project: clang.

clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp 
fails to compile since `"CompletionModel.h"` is auto-generated from 
clang-tools-extra/clangd/quality/model/features.json, which was changed in 
https://reviews.llvm.org/D94697 to remove `setFilterLength` and 
`setIsForbidden`, rename `setFileProximityDistance` and 
`setSymbolScopeDistance`, and add `setNumNameInContext` and 
`setFractionNameInContext`.  This patch removes calls to the two removed 
functions, updates calls to the two renamed functions, and adds calls to the 
two new functions. (`20` is an arbitrary choice for the `setNumNameInContext` 
argument.) It also changes the `FlipCoin` argument from float to double to 
silence lossy conversion warnings.

Note: I don't use this tool but encountered the build errors and took a shot at 
fixing them. Please holler if there's another recommended solution. Thanks!


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D97620

Files:
  
clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp


Index: 
clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp
===
--- 
clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp
+++ 
clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp
@@ -21,7 +21,7 @@
 namespace clangd {
 namespace {
 std::vector generateRandomDataset(int NumExamples) {
-  auto FlipCoin = [&](float Probability) {
+  auto FlipCoin = [&](double Probability) {
 return rand() % 1000 <= Probability * 1000;
   };
   auto RandInt = [&](int Max) { return rand() % Max; };
@@ -38,15 +38,15 @@
 E.setIsImplementationDetail(FlipCoin(0.3)); // Boolean.
 E.setNumReferences(RandInt(1)); // Can be large integer.
 E.setSymbolCategory(RandInt(10));   // 10 Symbol Category.
-
+E.setNumNameInContext(RandInt(20)); // 0 to 
Relevance.ContextWords->keys()
+E.setFractionNameInContext(RandFloat(1.0)); // Float in range [0,1].
 E.setIsNameInContext(FlipCoin(0.5)); // Boolean.
-E.setIsForbidden(FlipCoin(0.1)); // Boolean.
 E.setIsInBaseClass(FlipCoin(0.3));   // Boolean.
-E.setFileProximityDistance(
+E.setFileProximityDistanceCost(
 FlipCoin(0.1) ? 99 // Sometimes file distance is not available.
   : RandInt(20));
 E.setSemaFileProximityScore(RandFloat(1)); // Float in range [0,1].
-E.setSymbolScopeDistance(
+E.setSymbolScopeDistanceCost(
 FlipCoin(0.1) ? 99 // Sometimes scope distance is not available.
   : RandInt(20));
 E.setSemaSaysInScope(FlipCoin(0.5));  // Boolean.
@@ -56,7 +56,6 @@
 E.setHadContextType(FlipCoin(0.6));   // Boolean.
 E.setHadSymbolType(FlipCoin(0.6));// Boolean.
 E.setTypeMatchesPreferred(FlipCoin(0.5)); // Boolean.
-E.setFilterLength(RandInt(15));
 Examples.push_back(E);
   }
   return Examples;


Index: clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp
===
--- clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp
+++ clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp
@@ -21,7 +21,7 @@
 namespace clangd {
 namespace {
 std::vector generateRandomDataset(int NumExamples) {
-  auto FlipCoin = [&](float Probability) {
+  auto FlipCoin = [&](double Probability) {
 return rand() % 1000 <= Probability * 1000;
   };
   auto RandInt = [&](int Max) { return rand() % Max; };
@@ -38,15 +38,15 @@
 E.setIsImplementationDetail(FlipCoin(0.3)); // Boolean.
 E.setNumReferences(RandInt(1)); // Can be large integer.
 E.setSymbolCategory(RandInt(10));   // 10 Symbol Category.
-
+E.setNumNameInContext(RandInt(20)); // 0 to Relevance.ContextWords->keys()
+E.setFractionNameInContext(RandFloat(1.0)); // Float in range [0,1].
 E.setIsNameInContext(FlipCoin(0.5)); // Boolean.
-E.setIsForbidden(FlipCoin(0.1)); // Boolean.
 E.setIsInBaseClass(FlipCoin(0.3));   // Boolean.
-E.setFileProximityDistance(
+E.setFileProximityDistanceCost(
 FlipCoin(0.1) ? 99 // Sometimes file distance is not available.
   : RandInt(20));
 E.setSemaFileProximityScore(RandFloat(1)); // Float in range [0,1].
-E.setSymbolScopeDistance(
+E.setSymbolScopeDistanceCost(
 FlipCoin(0.1) ? 99 // Sometimes scope distance is not available.
   : RandInt(20));
 E.setSemaSaysInScope(FlipCoin(

[PATCH] D97620: Fix DecisionForestBenchmark.cpp compile errors

2021-02-27 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 326937.
poelmanc added a comment.

Shorten comment and add period.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D97620/new/

https://reviews.llvm.org/D97620

Files:
  
clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp


Index: 
clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp
===
--- 
clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp
+++ 
clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp
@@ -21,7 +21,7 @@
 namespace clangd {
 namespace {
 std::vector generateRandomDataset(int NumExamples) {
-  auto FlipCoin = [&](float Probability) {
+  auto FlipCoin = [&](double Probability) {
 return rand() % 1000 <= Probability * 1000;
   };
   auto RandInt = [&](int Max) { return rand() % Max; };
@@ -38,15 +38,15 @@
 E.setIsImplementationDetail(FlipCoin(0.3)); // Boolean.
 E.setNumReferences(RandInt(1)); // Can be large integer.
 E.setSymbolCategory(RandInt(10));   // 10 Symbol Category.
-
+E.setNumNameInContext(RandInt(20)); // 0 to ContextWords->keys().
+E.setFractionNameInContext(RandFloat(1.0)); // Float in range [0,1].
 E.setIsNameInContext(FlipCoin(0.5)); // Boolean.
-E.setIsForbidden(FlipCoin(0.1)); // Boolean.
 E.setIsInBaseClass(FlipCoin(0.3));   // Boolean.
-E.setFileProximityDistance(
+E.setFileProximityDistanceCost(
 FlipCoin(0.1) ? 99 // Sometimes file distance is not available.
   : RandInt(20));
 E.setSemaFileProximityScore(RandFloat(1)); // Float in range [0,1].
-E.setSymbolScopeDistance(
+E.setSymbolScopeDistanceCost(
 FlipCoin(0.1) ? 99 // Sometimes scope distance is not available.
   : RandInt(20));
 E.setSemaSaysInScope(FlipCoin(0.5));  // Boolean.
@@ -56,7 +56,6 @@
 E.setHadContextType(FlipCoin(0.6));   // Boolean.
 E.setHadSymbolType(FlipCoin(0.6));// Boolean.
 E.setTypeMatchesPreferred(FlipCoin(0.5)); // Boolean.
-E.setFilterLength(RandInt(15));
 Examples.push_back(E);
   }
   return Examples;


Index: clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp
===
--- clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp
+++ clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp
@@ -21,7 +21,7 @@
 namespace clangd {
 namespace {
 std::vector generateRandomDataset(int NumExamples) {
-  auto FlipCoin = [&](float Probability) {
+  auto FlipCoin = [&](double Probability) {
 return rand() % 1000 <= Probability * 1000;
   };
   auto RandInt = [&](int Max) { return rand() % Max; };
@@ -38,15 +38,15 @@
 E.setIsImplementationDetail(FlipCoin(0.3)); // Boolean.
 E.setNumReferences(RandInt(1)); // Can be large integer.
 E.setSymbolCategory(RandInt(10));   // 10 Symbol Category.
-
+E.setNumNameInContext(RandInt(20)); // 0 to ContextWords->keys().
+E.setFractionNameInContext(RandFloat(1.0)); // Float in range [0,1].
 E.setIsNameInContext(FlipCoin(0.5)); // Boolean.
-E.setIsForbidden(FlipCoin(0.1)); // Boolean.
 E.setIsInBaseClass(FlipCoin(0.3));   // Boolean.
-E.setFileProximityDistance(
+E.setFileProximityDistanceCost(
 FlipCoin(0.1) ? 99 // Sometimes file distance is not available.
   : RandInt(20));
 E.setSemaFileProximityScore(RandFloat(1)); // Float in range [0,1].
-E.setSymbolScopeDistance(
+E.setSymbolScopeDistanceCost(
 FlipCoin(0.1) ? 99 // Sometimes scope distance is not available.
   : RandInt(20));
 E.setSemaSaysInScope(FlipCoin(0.5));  // Boolean.
@@ -56,7 +56,6 @@
 E.setHadContextType(FlipCoin(0.6));   // Boolean.
 E.setHadSymbolType(FlipCoin(0.6));// Boolean.
 E.setTypeMatchesPreferred(FlipCoin(0.5)); // Boolean.
-E.setFilterLength(RandInt(15));
 Examples.push_back(E);
   }
   return Examples;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D97625: fix check-clang-tools tests that fail due to Windows CRLF line endings

2021-02-28 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc created this revision.
poelmanc added a reviewer: clang-tools-extra.
poelmanc added a project: clang-tools-extra.
Herald added a subscriber: jdoerfert.
poelmanc requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Running `check-clang-tools` on Windows produces 5 test failures:

  Failed Tests (5):
Clang Tools :: clang-apply-replacements/ClangRenameClassReplacements.cpp
Clang Tools :: clang-apply-replacements/basic.cpp
Clang Tools :: clang-apply-replacements/format.cpp
Clang Tools :: clang-move/move-used-helper-decls.cpp
Clang Tools :: clang-tidy/infrastructure/export-diagnostics.cpp

Four of these failures are simply due to fixed character position offsets 
differing on Windows versus Linux, since Windows line endings take up two 
characters instead of one:

- clang-apply-replacements/ClangRenameClassReplacements.cpp runs `clang-rename 
-offset=254`
- clang-apply-replacements/Inputs/basic/file[12].yaml specify e.g. `FileOffset: 
148` and `Offset: 298`
- clang-apply-replacements/Inputs/format/{no,yes}.yaml specify e.g. 
`FileOffset: 94` and `Offset: 94`
- clang-tidy/infrastructure/export-diagnostics.cpp specifies e.g. 
`CHECK-YAML-NEXT: FileOffset: 30`

(The move-used-helper-decls.cpp failure seems more complex; clang-move adds a 
blank line after `void HelperFun1() {}` when 
clang-move/Inputs/helper_decls_test.cpp has LF line endings, but does //not// 
add a blank line when the input files has CRLF line endings. That difference in 
behavior seems like it may be an actual bug, but I have yet to track it down.)

Do other folks developing on Windows see this? Performing a git checkout with 
Linux (LF) or "as-is" line endings would make the tests pass, but the 
underlying clang tools need to work on on input files with various line ending 
types, so it seems best to test the code against various line ending types. For 
example, last year I found a clang-tidy fix that //chomped// a CRLF line ending 
in half by implicitly assuming a line ending to be one byte, and the above 
clang-move issue could be similar. Ideally the Windows BuildKite job should 
test input files with CRLF line endings; since the above tests pass, I'd guess 
it's checking out test files only with LF line endings?

- I considered changing export-diagnostics.cpp to e.g. `CHECK-YAML-NEXT: 
FileOffset: 3[01]` to accept either, but that would relax the test on Linux - 
we really want exactly 30 for LF line endings, and exactly 31 for CRLF line 
endings.
- An ideal fix might somehow enable different offset numbers depending on the 
input file line endings, but that seems like a big change.
- Instead this patch adds a .gitattributes file to specify Linux LF line 
endings only for the above files that use `-offset`, `FileOffset` and `Offset` 
in their tests, CRLF line endings for the one crlf.cpp test, and auto for 
everything else.

I'm open to any other thoughts, ideas, or hints about testing clang tools on 
inputs with various line ending types.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D97625

Files:
  clang-tools-extra/test/.gitattributes


Index: clang-tools-extra/test/.gitattributes
===
--- /dev/null
+++ clang-tools-extra/test/.gitattributes
@@ -0,0 +1,19 @@
+# CRLF (Windows) line endings take two bytes instead of one, so any tests that
+# rely on or check fixed character -offset, Offset: or FileOffset: locations
+# will fail when run on input files checked out with different line endings.
+
+# Most test input files should use native line endings, to ensure that we run
+# tests against both line ending types.
+* text=auto
+
+# These test input files rely on one-byte Unix (LF) line-endings, as they use
+# fixed -offset, FileOffset:, or Offset: numbers in their tests.
+clang-apply-replacements/ClangRenameClassReplacements.cpp text eol=lf
+clang-apply-replacements/Inputs/basic/basic.h text eol=lf
+clang-apply-replacements/Inputs/format/no.cpp text eol=lf
+clang-apply-replacements/Inputs/format/yes.cpp text eol=lf
+clang-tidy/infrastructure/export-diagnostics.cpp text eol=lf
+
+# These test input files rely on two-byte Windows (CRLF) line endings.
+clang-apply-replacements/Inputs/crlf/crlf.cpp text eol=crlf
+clang-apply-replacements/Inputs/crlf/crlf.cpp.expected text eol=crlf


Index: clang-tools-extra/test/.gitattributes
===
--- /dev/null
+++ clang-tools-extra/test/.gitattributes
@@ -0,0 +1,19 @@
+# CRLF (Windows) line endings take two bytes instead of one, so any tests that
+# rely on or check fixed character -offset, Offset: or FileOffset: locations
+# will fail when run on input files checked out with different line endings.
+
+# Most test input files should use native line endings, to ensure that we run
+# tests against both line ending types.
+* text=auto
+
+# These test input files rely on one-byte Unix (LF)

[PATCH] D68682: format::cleanupAroundReplacements removes whole line when Removals leave previously non-blank line blank

2021-02-28 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 326957.
poelmanc added a comment.

Removed a function in modernize/LoopConvertCheck.cpp that's no longer needed 
due to this patch. Fixed clang-format and clang-tidy issues identified by 
HarborMaster in prior submission.

Hopefully it's ready to go, but as always I'm happy to receive any feedback.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68682/new/

https://reviews.llvm.org/D68682

Files:
  clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
  clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-redundant-void-arg.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-control-flow.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability-simplify-bool-expr.cpp
  clang-tools-extra/unittests/clang-change-namespace/ChangeNamespaceTests.cpp
  clang/include/clang/Basic/CharInfo.h
  clang/include/clang/Format/Format.h
  clang/lib/AST/CommentLexer.cpp
  clang/lib/AST/CommentParser.cpp
  clang/lib/Format/Format.cpp
  clang/unittests/Format/CMakeLists.txt
  clang/unittests/Format/CleanupTest.cpp

Index: clang/unittests/Format/CleanupTest.cpp
===
--- clang/unittests/Format/CleanupTest.cpp
+++ clang/unittests/Format/CleanupTest.cpp
@@ -11,6 +11,7 @@
 #include "../Tooling/ReplacementTest.h"
 #include "clang/Tooling/Core/Replacement.h"
 
+#include "llvm/Testing/Support/Annotations.h"
 #include "gtest/gtest.h"
 
 using clang::tooling::ReplacementTest;
@@ -320,6 +321,11 @@
 return tooling::Replacement(FileName, Offset, Length, Text);
   }
 
+  tooling::Replacement createReplacement(llvm::Annotations::Range Range,
+ StringRef Text) {
+return createReplacement(Range.Begin, Range.End - Range.Begin, Text);
+  }
+
   tooling::Replacement createInsertion(StringRef IncludeDirective) {
 return createReplacement(UINT_MAX, 0, IncludeDirective);
   }
@@ -373,10 +379,12 @@
  "namespace C {\n"
  "namespace D { int i; }\n"
  "inline namespace E { namespace { int y; } }\n"
+ "\n"
  "int x= 0;"
  "}";
-  std::string Expected = "\n\nnamespace C {\n"
- "namespace D { int i; }\n\n"
+  std::string Expected = "\nnamespace C {\n"
+ "namespace D { int i; }\n"
+ "\n"
  "int x= 0;"
  "}";
   tooling::Replacements Replaces =
@@ -386,6 +394,104 @@
   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
 }
 
+TEST_F(CleanUpReplacementsTest, RemoveLineWhenAllNonWhitespaceRemoved) {
+  llvm::Annotations Code("namespace A {$r1[[ // Useless comment]]\n"
+ "  $r2[[int]] $r3[[x]]\t $r4[[=]] $r5[[0;]]\t\n"
+ "  int y\t = 0;$r6[[\t]]\n"
+ "} // namespace A\n");
+  std::string Expected = "namespace A {\n"
+ "  int y\t = 0;\n"
+ "} // namespace A\n";
+  tooling::Replacements Replaces =
+  toReplacements({createReplacement(Code.range("r1"), ""),
+  createReplacement(Code.range("r2"), ""),
+  createReplacement(Code.range("r3"), ""),
+  createReplacement(Code.range("r4"), ""),
+  createReplacement(Code.range("r5"), ""),
+  createReplacement(Code.range("r6"), "")});
+
+  EXPECT_EQ(Expected, apply(Code.code(), Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, RemoveLinesWhenAllNonWhitespaceRemoved) {
+  llvm::Annotations Code(R"cpp(struct A {
+  A()
+  $r3[[:]] $r1[[f()]]$r2[[,]]
+$r4[[g()]]
+  {}
+  int f = 0;
+  int g = 0;
+};)cpp");
+  std::string Expected = R"cpp(struct A {
+  A()
+  {}
+  int f = 0;
+  int g = 0;
+};)cpp";
+  tooling::Replacements Replaces =
+  toReplacements({createReplacement(Code.range("r1"), ""),
+  createReplacement(Code.range("r2"), ""),
+  createReplacement(Code.range("r3"), ""),
+  createReplacement(Code.range("r4"), "")});
+
+  EXPECT_EQ(Expected, apply(Code.code(), Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, KeepLinesWithInsertsOrReplacesEvenIfBlank) {
+  // Not using raw string literals so newlines and spaces are clear and explicit
+  llvm::Annotations Code("struct A {\n"
+ "  A() {}\n"
+ "$r3[[]]  $r1[[int]] $r2[[f;]]\n" // "  int f;\n"
+ "  \n"
+ "$r4[[  ]]\n"
+ "};");
+  std::string Expected = "struct A {\n"
+ "  A() {}

[PATCH] D97620: Fix DecisionForestBenchmark.cpp compile errors

2021-03-01 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 327174.
poelmanc added a comment.

Fix comment.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D97620/new/

https://reviews.llvm.org/D97620

Files:
  
clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp


Index: 
clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp
===
--- 
clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp
+++ 
clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp
@@ -21,7 +21,7 @@
 namespace clangd {
 namespace {
 std::vector generateRandomDataset(int NumExamples) {
-  auto FlipCoin = [&](float Probability) {
+  auto FlipCoin = [&](double Probability) {
 return rand() % 1000 <= Probability * 1000;
   };
   auto RandInt = [&](int Max) { return rand() % Max; };
@@ -38,15 +38,15 @@
 E.setIsImplementationDetail(FlipCoin(0.3)); // Boolean.
 E.setNumReferences(RandInt(1)); // Can be large integer.
 E.setSymbolCategory(RandInt(10));   // 10 Symbol Category.
-
+E.setNumNameInContext(RandInt(20)); // 0 to ContextWords->size().
+E.setFractionNameInContext(RandFloat(1.0)); // Float in range [0,1].
 E.setIsNameInContext(FlipCoin(0.5)); // Boolean.
-E.setIsForbidden(FlipCoin(0.1)); // Boolean.
 E.setIsInBaseClass(FlipCoin(0.3));   // Boolean.
-E.setFileProximityDistance(
+E.setFileProximityDistanceCost(
 FlipCoin(0.1) ? 99 // Sometimes file distance is not available.
   : RandInt(20));
 E.setSemaFileProximityScore(RandFloat(1)); // Float in range [0,1].
-E.setSymbolScopeDistance(
+E.setSymbolScopeDistanceCost(
 FlipCoin(0.1) ? 99 // Sometimes scope distance is not available.
   : RandInt(20));
 E.setSemaSaysInScope(FlipCoin(0.5));  // Boolean.
@@ -56,7 +56,6 @@
 E.setHadContextType(FlipCoin(0.6));   // Boolean.
 E.setHadSymbolType(FlipCoin(0.6));// Boolean.
 E.setTypeMatchesPreferred(FlipCoin(0.5)); // Boolean.
-E.setFilterLength(RandInt(15));
 Examples.push_back(E);
   }
   return Examples;


Index: clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp
===
--- clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp
+++ clang-tools-extra/clangd/benchmarks/CompletionModel/DecisionForestBenchmark.cpp
@@ -21,7 +21,7 @@
 namespace clangd {
 namespace {
 std::vector generateRandomDataset(int NumExamples) {
-  auto FlipCoin = [&](float Probability) {
+  auto FlipCoin = [&](double Probability) {
 return rand() % 1000 <= Probability * 1000;
   };
   auto RandInt = [&](int Max) { return rand() % Max; };
@@ -38,15 +38,15 @@
 E.setIsImplementationDetail(FlipCoin(0.3)); // Boolean.
 E.setNumReferences(RandInt(1)); // Can be large integer.
 E.setSymbolCategory(RandInt(10));   // 10 Symbol Category.
-
+E.setNumNameInContext(RandInt(20)); // 0 to ContextWords->size().
+E.setFractionNameInContext(RandFloat(1.0)); // Float in range [0,1].
 E.setIsNameInContext(FlipCoin(0.5)); // Boolean.
-E.setIsForbidden(FlipCoin(0.1)); // Boolean.
 E.setIsInBaseClass(FlipCoin(0.3));   // Boolean.
-E.setFileProximityDistance(
+E.setFileProximityDistanceCost(
 FlipCoin(0.1) ? 99 // Sometimes file distance is not available.
   : RandInt(20));
 E.setSemaFileProximityScore(RandFloat(1)); // Float in range [0,1].
-E.setSymbolScopeDistance(
+E.setSymbolScopeDistanceCost(
 FlipCoin(0.1) ? 99 // Sometimes scope distance is not available.
   : RandInt(20));
 E.setSemaSaysInScope(FlipCoin(0.5));  // Boolean.
@@ -56,7 +56,6 @@
 E.setHadContextType(FlipCoin(0.6));   // Boolean.
 E.setHadSymbolType(FlipCoin(0.6));// Boolean.
 E.setTypeMatchesPreferred(FlipCoin(0.5)); // Boolean.
-E.setFilterLength(RandInt(15));
 Examples.push_back(E);
   }
   return Examples;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D97620: Fix DecisionForestBenchmark.cpp compile errors

2021-03-01 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc marked an inline comment as done.
poelmanc added a comment.

Fixed comment as requested (keys()->size().) I don't have commit access so if 
you can push it that would be great, thanks!


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D97620/new/

https://reviews.llvm.org/D97620

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D96744: clang-format IncludeBlocks: Regroup determination of "main" for framework-style includes fix

2023-08-01 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc abandoned this revision.
poelmanc added a comment.
Herald added a project: All.

We eventually updated our coding standards and our fairly massive code base to 
change only the very top "main" include from `#include ` to 
`#include "Foo.h"`.

For all include statements after that, we still use framework-style includes 
(`#include `).

It worked great and now we're happily using clang-format to order and group all 
our include statements, with no need for any changes to clang-format. Thanks to 
all for maintaining such an amazing tool!


Herald added a comment.

NOTE: Clang-Format Team Automated Review Comment

It looks like your clang-format review does not contain any unit tests, please 
try to ensure all code changes have a unit test (unless this is an `NFC` or 
refactoring, adding documentation etc..)

Add your unit tests in `clang/unittests/Format` and you can build with `ninja 
FormatTests`.  We recommend using the `verifyFormat(xxx)` format of unit tests 
rather than `EXPECT_EQ` as this will ensure you change is tolerant to random 
whitespace changes (see FormatTest.cpp as an example)

For situations where your change is altering the TokenAnnotator.cpp which can 
happen if you are trying to improve the annotation phase to ensure we are 
correctly identifying the type of a token, please add a token annotator test in 
`TokenAnnotatorTest.cpp`


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D96744/new/

https://reviews.llvm.org/D96744

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69238: Fix clang-tidy readability-redundant-string-init for c++17/c++2a

2019-10-29 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc marked 2 inline comments as done.
poelmanc added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp:67-70
+// With -std c++14 or earlier (!LangOps.CPlusPlus17), it was sufficient to
+// return CtorExpr->getSourceRange(). However, starting with c++17, parsing
+// the expression 'std::string Name = ""' results in a CtorExpr whose
+// SourceRange includes just '""' rather than the previous 'Name = ""'.

aaron.ballman wrote:
> Are you sure that this behavioral difference isn't just a bug in Clang? I 
> can't think of why the source range should differ based on language mode, so 
> I wonder if the correct thing to do is fix how we calculate the source range 
> in Clang?
Thanks and no, I'm not sure at all. At the end of my summary paragraph I wrote:

> Or, is it possible that this change in SourceRange is an unintentional 
> difference in the parsing code? If so fixing that might make more sense.

Before starting this patch, I built a Debug build of LLVM and stepped through 
LLVM parsing code while running clang-tidy on the 
readability-redundant-string-init.cpp file. I set breakpoints and inspected 
variable values under both -std c++14 and -std c++17. The call stacks were 
clearly different. I could sometimes inspect character positions in the file 
and see where an expression's SourceLoc was set. However, a SourceLoc is a 
single character position; I couldn't figure out where an expression's 
SourceRange was even set. So I gave up and went down the current approach.

Should we ping the LLVM mailing list and see if this change rings a bell with 
anyone there?


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69238/new/

https://reviews.llvm.org/D69238



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69548: Give clang-tidy readability-redundant-string-init a customizable list of string types to fix

2019-10-29 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 226987.
poelmanc added a comment.

Added release notes, fixed backticks in documentation, removed blank line, 
removed new hasListedName matcher and used existing hasAnyName matcher.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69548/new/

https://reviews.llvm.org/D69548

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
  clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
@@ -1,4 +1,8 @@
 // RUN: %check_clang_tidy %s readability-redundant-string-init %t
+// RUN:   -config="{CheckOptions: \
+// RUN: [{key: readability-redundant-string-init.StringNames, \
+// RUN:   value: "basic_string;OurTestString"}] \
+// RUN: }"
 
 namespace std {
 template 
@@ -139,3 +143,31 @@
 void Param3(std::string param = "") {}
 void Param4(STRING param = "") {}
 
+struct OurTestString {
+  OurTestString();
+  OurTestString(const OurTestString &);
+  // MSVC headers define two constructors instead of using optional arguments.
+  OurTestString(const char *);
+  ~OurTestString();
+};
+
+void OurTestStringTests() {
+  OurTestString a = "";
+  // CHECK-MESSAGES: [[@LINE-1]]:17: warning: redundant string initialization
+  // CHECK-FIXES: OurTestString a;
+  OurTestString b("");
+  // CHECK-MESSAGES: [[@LINE-1]]:17: warning: redundant string initialization
+  // CHECK-FIXES: OurTestString b;
+  OurTestString c = R"()";
+  // CHECK-MESSAGES: [[@LINE-1]]:17: warning: redundant string initialization
+  // CHECK-FIXES: OurTestString c;
+  OurTestString d(R"()");
+  // CHECK-MESSAGES: [[@LINE-1]]:17: warning: redundant string initialization
+  // CHECK-FIXES: OurTestString d;
+
+  OurTestString u = "u";
+  OurTestString w("w");
+  OurTestString x = R"(x)";
+  OurTestString y(R"(y)");
+  OurTestString z;
+}
Index: clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
===
--- clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
+++ clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
@@ -5,7 +5,8 @@
 
 Finds unnecessary string initializations.
 
-Examples:
+Examples
+
 
 .. code-block:: c++
 
@@ -17,3 +18,16 @@
 
   std::string a;
   std::string b;
+
+Options
+---
+
+.. option:: StringNames
+
+Default is `basic_string`.
+
+Semicolon-delimited list of base class names to apply this check to.
+By default `basic_string` applies to std::string and std::wstring.
+Set to e.g. `basic_string;StringRef;QString` to perform this check on
+custom classes as well.
+
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -130,6 +130,10 @@
 - The 'objc-avoid-spinlock' check was renamed to :doc:`darwin-avoid-spinlock
   `
 
+- The :doc:`readability-redundant-string-init
+  ` check now supports a
+  `StringNames` option enabling its application to custom string classes.
+
 Improvements to include-fixer
 -
 
Index: clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.h
===
--- clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.h
+++ clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.h
@@ -10,6 +10,8 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_STRING_INIT_H
 
 #include "../ClangTidyCheck.h"
+#include 
+#include 
 
 namespace clang {
 namespace tidy {
@@ -18,10 +20,13 @@
 /// Finds unnecessary string initializations.
 class RedundantStringInitCheck : public ClangTidyCheck {
 public:
-  RedundantStringInitCheck(StringRef Name, ClangTidyContext *Context)
-  : ClangTidyCheck(Name, Context) {}
+  RedundantStringInitCheck(StringRef Name, ClangTidyContext *Context);
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  std::vector StringNames;
 };
 
 } // namespace readability
Index: clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
===
--- clan

[PATCH] D69548: Give clang-tidy readability-redundant-string-init a customizable list of string types to fix

2019-10-29 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc marked 3 inline comments as done.
poelmanc added a comment.

@aaron.ballman Thanks for the `hasAnyName` feedback! From the name 
`internal::VariadicFunction` I assumed arguments were needed at compile-time, 
but thanks to your suggestion I found the overload taking `ArrayRef`.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69548/new/

https://reviews.llvm.org/D69548



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69548: Give clang-tidy readability-redundant-string-init a customizable list of string types to fix

2019-10-29 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc marked an inline comment as done.
poelmanc added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp:21
 
+const char DefaultStringNames[] = "basic_string";
+

aaron.ballman wrote:
> I think the default should probably be `::std::basic_string` to avoid getting 
> other things named `basic_string`?
The prior code had `basic_string` hard-coded at lines 27, 31, and 50 so I 
initially set the default to `basic_string` just to keep the default behavior 
unchanged.

I just now tried setting it to each of `std::basic_string`, 
`::std::basic_string`, and even `std::string;std::wstring` and the 
`readability-redundant-string-init.cpp` tests failed with any of those 
settings, so I've left it set to `basic_string`.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69548/new/

https://reviews.llvm.org/D69548



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D67460: clang-tidy: modernize-use-using work with multi-argument templates

2019-11-08 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

Thanks @aaron.ballman, I don't have commit access so will someone else commit 
this?

To address the minor nit, should I upload a new patch with 
post-increment/post-decrement changed to pre-increment/pre-decrement? (Does 
uploading changes undo the "Ready to Land" status?)


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D67460/new/

https://reviews.llvm.org/D67460



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69238: Fix clang-tidy readability-redundant-string-init for c++17/c++2a

2019-11-08 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

Just documenting here that I sent the following email to cfe-...@lists.llvm.org:

> When parsing a named declaration with an equals sign with clang -std 
> c++11/14, clang builds an initializer expression whose SourceRange covers 
> from the variable name through the end of the initial value:
> 
>   std::string foo = "bar";
>   ^~~
> 
> When parsing the same code with clang -std c++17/2x, the initializer 
> expression's SourceRange only includes the initial value itself, and not the 
> variable name or the equals sign:
> 
>   std::string foo = "bar";
> ^
> 
> If the string is initialized using parentheses rather than an equals sign, in 
> all of c++11/14/17/2x the initializer expression's SourceRange includes the 
> variable name and both parentheses:
> 
>   std::string foo("bar");
>   ^~
> 
> This difference has broken clang-tidy's readability-remove-redundant-string 
> for c++17 and c++2x, as described in at reviews.llvm.org/D69238 
> . Is this SourceRange difference 
> intentional, and if not does anyone have thoughts on how to make the 
> SourceRange consistent across C++ standards? Thanks!
> 
> P.S. I've tried stepping through clang-tidy parsing the `std::string a = "";` 
> line in 
> `clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp`
>  with -std=c++11 and again with -std=c++17. In both cases 
> `Sema::AddInitializerToDecl` seems to create a correct `InitializationKind` 
> with the `Locations[0]` properly pointing to the start of the variable name. 
> I'm not sure how or where that gets translated to the expression's 
> SourceRange later on in some way that presumably differs between c++11 and 
> c++17. If this SourceRange difference is unintentional and needs to be 
> tracked down and fixed, any tips on where to look would be appreciated.

I didn't receive any email responses, I believe it prompted @NoQ to look this 
over and comment - thanks!


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69238/new/

https://reviews.llvm.org/D69238



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69238: Fix clang-tidy readability-redundant-string-init for c++17/c++2a

2019-11-08 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

In D69238#1736365 , @NoQ wrote:

> I suspect that it's not just the source range, but the whole AST for the 
> initializer is different, due to C++17 mandatory copy elision in the 
> equals-initializer syntax. Like, before C++17 it was a temporary constructor, 
> a temporary materialization (ironic!), and a copy constructor, but in C++17 
> and after it's a single direct constructor which looks exactly like the old 
> temporary constructor (except not being a `CXXTemporaryObjectExpr`). You're 
> most likely talking about //different construct-expressions// in different 
> language modes.
>
> That said, it should probably be possible to change the source range anyway 
> somehow.


Thanks to all the encouragement here, I spent a few more hours stepping through 
code and have found a one-line change to clang\lib\Sema\SemaInit.cpp:8053 that 
fixes this bug! Change:

  SourceLocation Loc = CurInit.get()->getBeginLoc();

to

  SourceLocation Loc = Kind.getLocation();

For `SK_UserConversion`, `CurInit` is set at SemaInit.cpp:7899 to `Args[0]`, 
i.e. the first argument to the constructor, which is `""` in this case. By 
changing `Loc` to `Kind.getLocation()`, the `BuildCXXConstructExpr` at 
SemaInit.cpp:8064 gets created with a SourceRange spanning `a = ""`. With just 
that change, the SourceRange for an expression like `std::string a = ""` 
becomes consistent across C++11/14/17/2a and 
`readability-redundant-string-init` tests pass in all C++ modes (so we can 
throw away my 70 lines of manual parsing code.)

I have no experience with the clang parsing code so I don't know what other 
effects this change might have or who else we might want to check with before 
committing this. Should I change my "diff" here to just that?

> Also i don't see any tests for multiple declarations in a single `DeclStmt`, 
> i.e.
> 
>   string A = "a", B = "";
> 
> 
> ... - which source range do you expect to have if you warn on `B`?

For that example I'd expect the warning source range to cover `B = ""`. 
`readability-redundant-string-init.cpp` does include tests almost like that: 
`std::string a = "", b = "", c = "";` warns on 3 separate source ranges, while 
`std::string d = "u", e = "u", f = "u";` doesn't warn at all. I'm happy to add 
a line that has some of each. I just added `std::string g = "u", h = "", i = 
"uuu", j = "", k;` and confirmed that it warns and fixes correctly (in C++11/14 
mode it should pass already; in C++17/2a mode it works correctly with the 
current patch.)


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69238/new/

https://reviews.llvm.org/D69238



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69548: Give clang-tidy readability-redundant-string-init a customizable list of string types to fix

2019-11-08 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 228541.
poelmanc edited the summary of this revision.
poelmanc added a comment.

Now allows namespaces on types and defaults to `::std::basic_string` as 
requested. The code uses namespaced string type names to check types, and uses 
non-namespaced string type names to check for the required one-argument or 
two-argument-defaulted constructors.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69548/new/

https://reviews.llvm.org/D69548

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
  clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
@@ -1,4 +1,8 @@
-// RUN: %check_clang_tidy -std=c++11,c++14 %s readability-redundant-string-init %t
+// RUN: %check_clang_tidy -std=c++11,c++14 %s readability-redundant-string-init %t \
+// RUN:   -config="{CheckOptions: \
+// RUN: [{key: readability-redundant-string-init.StringNames, \
+// RUN:   value: "::std::basic_string;our::TestString"}] \
+// RUN: }"
 // FIXME: Fix the checker to work in C++17 mode.
 
 namespace std {
@@ -139,3 +143,82 @@
 void Param3(std::string param = "") {}
 void Param4(STRING param = "") {}
 
+namespace our {
+struct TestString {
+  TestString();
+  TestString(const TestString &);
+  TestString(const char *);
+  ~TestString();
+};
+}
+
+void ourTestStringTests() {
+  our::TestString a = "";
+  // CHECK-MESSAGES: [[@LINE-1]]:19: warning: redundant string initialization
+  // CHECK-FIXES: our::TestString a;
+  our::TestString b("");
+  // CHECK-MESSAGES: [[@LINE-1]]:19: warning: redundant string initialization
+  // CHECK-FIXES: our::TestString b;
+  our::TestString c = R"()";
+  // CHECK-MESSAGES: [[@LINE-1]]:19: warning: redundant string initialization
+  // CHECK-FIXES: our::TestString c;
+  our::TestString d(R"()");
+  // CHECK-MESSAGES: [[@LINE-1]]:19: warning: redundant string initialization
+  // CHECK-FIXES: our::TestString d;
+
+  our::TestString u = "u";
+  our::TestString w("w");
+  our::TestString x = R"(x)";
+  our::TestString y(R"(y)");
+  our::TestString z;
+}
+
+namespace their {
+using TestString = our::TestString;
+}
+
+// their::TestString is the same type so should warn / fix
+void theirTestStringTests() {
+  their::TestString a = "";
+  // CHECK-MESSAGES: [[@LINE-1]]:21: warning: redundant string initialization
+  // CHECK-FIXES: their::TestString a;
+  their::TestString b("");
+  // CHECK-MESSAGES: [[@LINE-1]]:21: warning: redundant string initialization
+  // CHECK-FIXES: their::TestString b;
+}
+
+namespace other {
+// Identical declarations to above but different type
+struct TestString {
+  TestString();
+  TestString(const TestString &);
+  TestString(const char *);
+  ~TestString();
+};
+
+// Identical declarations to above but different type
+template 
+class allocator {};
+template 
+class char_traits {};
+template , typename A = std::allocator>
+struct basic_string {
+  basic_string();
+  basic_string(const basic_string &);
+  basic_string(const C *, const A &a = A());
+  ~basic_string();
+};
+typedef basic_string string;
+typedef basic_string wstring;
+}
+
+// other::TestString, other::string, other::wstring are unrelated to the types
+// being checked. No warnings / fixes should be produced for these types.
+void otherTestStringTests() {
+  other::TestString a = "";
+  other::TestString b("");
+  other::string c = "";
+  other::string d("");
+  other::wstring e = L"";
+  other::wstring f(L"");
+}
Index: clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
===
--- clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
+++ clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
@@ -5,7 +5,8 @@
 
 Finds unnecessary string initializations.
 
-Examples:
+Examples
+
 
 .. code-block:: c++
 
@@ -17,3 +18,15 @@
 
   std::string a;
   std::string b;
+
+Options
+---
+
+.. option:: StringNames
+
+Default is `::std::basic_string`.
+
+Semicolon-delimited list of base class names to apply this check to.
+By default `::std::basic_string` applies to std::string and std::wstring.
+Set to e.g. `::std::basic_string;llvm::StringRef;QString` to perform this
+check on custom classes.
Index: clang-tools-extra/docs/ReleaseNotes.rst
==

[PATCH] D69238: Fix clang-tidy readability-redundant-string-init for c++17/c++2a

2019-11-08 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

In D69238#1739429 , @gribozavr2 wrote:

> If it is indeed the extra AST node for the elidable constructor, see if you 
> can use the `ignoringElidableConstructorCall` AST matcher to ignore it, 
> therefore smoothing over AST differences between language modes.


Thanks for the tip. Adding `ignoringElidableConstructorCall` in front of 
`cxxConstructExpr` for the `EmptyStringCtorExpr` and 
`EmptyStringCtorExprWithTemporaries` in RedundantStringInitCheck.cpp resulted 
in the checker no longer matching any of `std::string a = ""` lines, i.e. 
basically disabling the check for those types of lines.

Is there a tool to print the AST? That would show whether the AST already has 
some expression with the right SourceRange.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69238/new/

https://reviews.llvm.org/D69238



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69145: Give readability-redundant-member-init an option IgnoreBaseInCopyConstructors to avoid breaking code with gcc -Werror=extra

2019-11-08 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

In D69145#1725026 , @malcolm.parsons 
wrote:

> I like that this check warns about copy constructors that don't copy.
>  The warning can be suppressed with a NOLINT comment if not copying is 
> intentional.


Thanks for the comment! It's not clear to me how you suggest proceeding though.

I think it would be great to have a warning about "copy constructors that don't 
copy", which I would expect to warn regardless of whether the default 
initialization is explicit, e.g.

  MyClass( const MyClass& other) : BaseClass() {...}`

or implicit, e.g.

  MyClass( const MyClass& other) {...}

An intelligent "copy constructors that don't copy" warning might even examine 
the `{...}` to see what's being handled there.

Unfortunately currently we have two tools each of which warns in one case but 
not the other:

- `gcc -Wextra` warns only in the latter case, and can be fixed by changing 
each occurrence to the former.
- clang-tidy's current `readability-redundant-member-init` check warns only in 
the former case, and fixes it by changing each occurrence to the latter.
  - (Also clang-tidy's warning about `: BaseClass()` being redundant isn't a 
very clear warning about copy constructor that don't copy.)

This patch just offers an option to make peace between the two tools.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69145/new/

https://reviews.llvm.org/D69145



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69238: Fix clang-tidy readability-redundant-string-init for c++17/c++2a

2019-11-08 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 228556.
poelmanc edited the summary of this revision.

Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69238/new/

https://reviews.llvm.org/D69238

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init-msvc.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
@@ -1,5 +1,4 @@
-// RUN: %check_clang_tidy -std=c++11,c++14 %s 
readability-redundant-string-init %t
-// FIXME: Fix the checker to work in C++17 mode.
+// RUN: %check_clang_tidy %s readability-redundant-string-init %t
 
 namespace std {
 template 
@@ -131,6 +130,11 @@
   // CHECK-FIXES: std::string a, b, c;
 
   std::string d = "u", e = "u", f = "u";
+
+  std::string g = "u", h = "", i = "uuu", j = "", k;
+  // CHECK-MESSAGES: [[@LINE-1]]:24: warning: redundant string initialization
+  // CHECK-MESSAGES: [[@LINE-2]]:43: warning: redundant string initialization
+  // CHECK-FIXES: std::string g = "u", h, i = "uuu", j, k;
 }
 
 // These cases should not generate warnings.
Index: 
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init-msvc.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init-msvc.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init-msvc.cpp
@@ -1,5 +1,4 @@
-// RUN: %check_clang_tidy -std=c++11,c++14 %s 
readability-redundant-string-init %t
-// FIXME: Fix the checker to work in C++17 mode.
+// RUN: %check_clang_tidy %s readability-redundant-string-init %t
 
 namespace std {
 template 
Index: clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
@@ -46,23 +46,23 @@
   // string bar("");
   Finder->addMatcher(
   namedDecl(
-  varDecl(hasType(hasUnqualifiedDesugaredType(recordType(
-  
hasDeclaration(cxxRecordDecl(hasName("basic_string")),
-  hasInitializer(expr(ignoringImplicit(anyOf(
-  EmptyStringCtorExpr,
-  EmptyStringCtorExprWithTemporaries)))
- .bind("expr"))),
-  unless(parmVarDecl()))
-  .bind("decl"),
+  varDecl(
+  hasType(hasUnqualifiedDesugaredType(recordType(
+  hasDeclaration(cxxRecordDecl(hasName("basic_string")),
+  hasInitializer(expr(ignoringImplicit(anyOf(
+  EmptyStringCtorExpr, EmptyStringCtorExprWithTemporaries)
+  .bind("vardecl"),
+  unless(parmVarDecl())),
   this);
 }
 
 void RedundantStringInitCheck::check(const MatchFinder::MatchResult &Result) {
-  const auto *CtorExpr = Result.Nodes.getNodeAs("expr");
-  const auto *Decl = Result.Nodes.getNodeAs("decl");
-  diag(CtorExpr->getExprLoc(), "redundant string initialization")
-  << FixItHint::CreateReplacement(CtorExpr->getSourceRange(),
-  Decl->getName());
+  const auto *VDecl = Result.Nodes.getNodeAs("vardecl");
+  // VarDecl's getSourceRange() spans 'string foo = ""' or 'string bar("")'.
+  // So start at getLocation() to span just 'foo = ""' or 'bar("")'.
+  SourceRange ReplaceRange(VDecl->getLocation(), VDecl->getEndLoc());
+  diag(VDecl->getLocation(), "redundant string initialization")
+  << FixItHint::CreateReplacement(ReplaceRange, VDecl->getName());
 }
 
 } // namespace readability


Index: clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
@@ -1,5 +1,4 @@
-// RUN: %check_clang_tidy -std=c++11,c++14 %s readability-redundant-string-init %t
-// FIXME: Fix the checker to work in C++17 mode.
+// RUN: %check_clang_tidy %s readability-redundant-string-init %t
 
 namespace std {
 template 
@@ -131,6 +130,11 @@
   // CHECK-FIXES: std::string a, b, c;
 
   std::string d = "u", e = "u", f = "u";
+
+  std::string g = "u", h = "", i = "uuu", j = "", k;
+  // CHECK-MESSAGES: [[@LINE-1]]:24: warning: redundant string initialization
+  // CHECK-MESSAGES: [[@LINE-

[PATCH] D69238: Fix clang-tidy readability-redundant-string-init for c++17/c++2a

2019-11-08 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

In D69238#1739627 , @NoQ wrote:

> Clang's `-ast-dump` 
> .


Wow. That makes this so much easier... Thank you so much!

Looking at the AST showed that the `CXXConstructExpr`s that 
`readability-redundant-string-init` previously relied upon for `SourceRange` 
were being elided in C++17/2a, but that `VarDecl`s consistently held all the 
right info across all C++ modes. So I completely rewrote this patch to get the 
`SourceRange` from the `VarDecl`. All tests pass.

In case anyone cares or for posterity, what follows are a bunch of probably 
unnecessary details.

I made a super minimal readability-redundant-string-init.cpp:

  namespace std {
  struct string {
string();
string(const char *);
  };
  }
  
  void f() {
std::string a = "", b = "foo", c, d(""), e("bar");
  }

Running `clang -Xclang -ast-dump -std=c++11 
readability-redundant-string-init.cpp` yields:

  `-FunctionDecl 0x27a33bfd610  line:8:6 f 'void ()'
`-CompoundStmt 0x27a33bf6c78 
  `-DeclStmt 0x27a33bf6c60 
|-VarDecl 0x27a33bfd788  col:15 a 
'std::string':'std::string' cinit
| `-ExprWithCleanups 0x27a33bfddd0  
'std::string':'std::string'
|   `-CXXConstructExpr 0x27a33bfdda0  
'std::string':'std::string' 'void (std::string &&) noexcept' elidable
| `-MaterializeTemporaryExpr 0x27a33bfdd48  
'std::string':'std::string' xvalue
|   `-ImplicitCastExpr 0x27a33bfdc20  
'std::string':'std::string' 
| `-CXXConstructExpr 0x27a33bfdbf0  
'std::string':'std::string' 'void (const char *)'
|   `-ImplicitCastExpr 0x27a33bfdbd8  'const char *' 

| `-StringLiteral 0x27a33bfd868  'const char [1]' 
lvalue ""
|-VarDecl 0x27a33bfde08  col:23 b 
'std::string':'std::string' cinit
| `-ExprWithCleanups 0x27a33bfdfb0  
'std::string':'std::string'
|   `-CXXConstructExpr 0x27a33bfdf80  
'std::string':'std::string' 'void (std::string &&) noexcept' elidable
| `-MaterializeTemporaryExpr 0x27a33bfdf68  
'std::string':'std::string' xvalue
|   `-ImplicitCastExpr 0x27a33bfdf50  
'std::string':'std::string' 
| `-CXXConstructExpr 0x27a33bfdf20  
'std::string':'std::string' 'void (const char *)'
|   `-ImplicitCastExpr 0x27a33bfdf08  'const char *' 

| `-StringLiteral 0x27a33bfdee8  'const char [4]' 
lvalue "foo"
|-VarDecl 0x27a33bfdfe8  col:34 c 
'std::string':'std::string' callinit
| `-CXXConstructExpr 0x27a33bfe050  'std::string':'std::string' 
'void ()'
|-VarDecl 0x27a33bfe098  col:37 d 
'std::string':'std::string' callinit
| `-CXXConstructExpr 0x27a33bf6af0  
'std::string':'std::string' 'void (const char *)'
|   `-ImplicitCastExpr 0x27a33bf6ad8  'const char *' 

| `-StringLiteral 0x27a33bf6aa0  'const char [1]' lvalue ""
`-VarDecl 0x27a33bf6b40  col:44 e 
'std::string':'std::string' callinit
  `-CXXConstructExpr 0x27a33bf6c00  
'std::string':'std::string' 'void (const char *)'
`-ImplicitCastExpr 0x27a33bf6be8  'const char *' 

  `-StringLiteral 0x27a33bf6ba8  'const char [4]' lvalue 
"bar"

With -std=c++11, all of the outer `CXXConstructExpr` have the correct range to 
replace with just the variable names, which explains why all is fine with C++11.

Then running `clang -Xclang -ast-dump -std=c++17 
readability-redundant-string-init.cpp` yields:

  `-FunctionDecl 0x2b8e6ac96b0  line:8:6 f 'void ()'
`-CompoundStmt 0x2b8e6acc608 
  `-DeclStmt 0x2b8e6acc5f0 
|-VarDecl 0x2b8e6ac9828  col:15 a 
'std::string':'std::string' cinit
| `-ImplicitCastExpr 0x2b8e6ac9cc0  'std::string':'std::string' 

|   `-CXXConstructExpr 0x2b8e6ac9c90  
'std::string':'std::string' 'void (const char *)'
| `-ImplicitCastExpr 0x2b8e6ac9c78  'const char *' 

|   `-StringLiteral 0x2b8e6ac9908  'const char [1]' lvalue 
""
|-VarDecl 0x2b8e6ac9e08  col:23 b 
'std::string':'std::string' cinit
| `-ImplicitCastExpr 0x2b8e6ac9f50  'std::string':'std::string' 

|   `-CXXConstructExpr 0x2b8e6ac9f20  
'std::string':'std::string' 'void (const char *)'
| `-ImplicitCastExpr 0x2b8e6ac9f08  'const char *' 

|   `-StringLiteral 0x2b8e6ac9ee8  'const char [4]' lvalue 
"foo"
|-VarDecl 0x2b8e6ac9f88  col:34 c 
'std::string':'std::string' callinit
| `-CXXConstructExpr 0x2b8e6ac9ff0  'std::string':'std::string' 
'void ()'
|-VarDecl 0x2b8e6aca038  col:37 d 
'std::string':'std::string' callinit
| `-CXXConstructExpr 0x2b8e6aca0f0  
'std::string':'std::string' 'void (const char *)'
|   `-ImplicitCastExpr 0x2b8e6aca0d8  'const char *' 

| `-StringLiteral 0x2b8e6aca0a0  'const char [1]' lvalue ""
`-VarDecl 0x2b8e6acc4d0  col:44 e 
'std::string':

[PATCH] D68682: Clang-tidy fix removals removing all non-blank text from a line should remove the line

2019-11-08 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 228558.
poelmanc added a comment.

I just rebased this patch on the latest master. I believe I've addressed all 
the comments raised so far. Should I add mention of this change to the release 
notes?


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68682/new/

https://reviews.llvm.org/D68682

Files:
  clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-control-flow.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp
  clang/include/clang/AST/CommentLexer.h
  clang/include/clang/AST/CommentParser.h
  clang/include/clang/Format/Format.h
  clang/lib/AST/CommentLexer.cpp
  clang/lib/AST/CommentParser.cpp
  clang/lib/Format/Format.cpp

Index: clang/lib/Format/Format.cpp
===
--- clang/lib/Format/Format.cpp
+++ clang/lib/Format/Format.cpp
@@ -25,6 +25,9 @@
 #include "UnwrappedLineParser.h"
 #include "UsingDeclarationsSorter.h"
 #include "WhitespaceManager.h"
+#include "clang/AST/CommentLexer.h"
+#include "clang/AST/CommentParser.h"
+#include "clang/Basic/CharInfo.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/DiagnosticOptions.h"
 #include "clang/Basic/SourceManager.h"
@@ -2356,6 +2359,85 @@
 
 } // anonymous namespace
 
+llvm::Expected
+removeNewlyBlankLines(StringRef Code, const tooling::Replacements &Replaces) {
+  tooling::Replacements NewReplaces(Replaces);
+  // pair< LineStartPos, CheckedThroughPos > of lines that have been checked
+  // and confirmed that the replacement result so far will be entirely blank.
+  std::list> PotentialWholeLineCuts;
+  int LineStartPos = -1;
+  int LineCheckedThroughPos = -1;
+  bool LineBlankSoFar = true;
+  const char *FileText = Code.data();
+  StringRef FilePath; // Must be the same for every Replacement
+  for (const auto &R : Replaces) {
+assert(FilePath.empty() || FilePath == R.getFilePath());
+FilePath = R.getFilePath();
+const int RStartPos = R.getOffset();
+
+int CurrentRLineStartPos = RStartPos;
+while (CurrentRLineStartPos > 0 &&
+   !isVerticalWhitespace(FileText[CurrentRLineStartPos - 1])) {
+  --CurrentRLineStartPos;
+}
+
+assert(CurrentRLineStartPos >= LineStartPos);
+if (CurrentRLineStartPos != LineStartPos) {
+  // We've moved on to a new line. Wrap up the old one before moving on.
+  if (LineBlankSoFar) {
+PotentialWholeLineCuts.push_back(
+std::make_pair(LineStartPos, LineCheckedThroughPos));
+  }
+  LineCheckedThroughPos = CurrentRLineStartPos;
+  LineStartPos = CurrentRLineStartPos;
+  LineBlankSoFar = true;
+}
+
+// Check to see if line from LineCheckedThroughPos to here is blank.
+assert(RStartPos >= LineCheckedThroughPos);
+StringRef PriorTextToCheck(FileText + LineCheckedThroughPos,
+   RStartPos - LineCheckedThroughPos);
+StringRef ReplacementText = R.getReplacementText();
+LineBlankSoFar = LineBlankSoFar && isWhitespace(PriorTextToCheck) &&
+ ReplacementText.empty();
+LineCheckedThroughPos = R.getOffset() + R.getLength();
+  }
+
+  if (LineBlankSoFar) {
+PotentialWholeLineCuts.push_back(
+std::make_pair(LineStartPos, LineCheckedThroughPos));
+  }
+
+  // Now remove whole line if and only if (a) rest of line is blank, and
+  // (b) the original line was *not* blank.
+  for (const auto &LineCheckedThrough : PotentialWholeLineCuts) {
+const int LineStartPos = LineCheckedThrough.first;
+const int CheckedThroughPos = LineCheckedThrough.second;
+
+int LineEndPos = CheckedThroughPos;
+while (LineEndPos < Code.size() &&
+   !isVerticalWhitespace(FileText[LineEndPos])) {
+  ++LineEndPos;
+}
+
+assert(LineEndPos >= CheckedThroughPos);
+StringRef TrailingText(FileText + CheckedThroughPos,
+   LineEndPos - CheckedThroughPos);
+assert(LineEndPos >= LineStartPos);
+StringRef OriginalLine(FileText + LineStartPos, LineEndPos - LineStartPos);
+if (isWhitespace(TrailingText) && !isWhitespace(OriginalLine)) {
+  const char *CutTo = skipNewline(FileText + LineEndPos, Code.end());
+  int CutCount = CutTo - FileText - LineStartPos;
+  llvm::Error Err = NewReplaces.add(
+  tooling::Replacement(FilePath, LineStartPos, CutCount, ""));
+  if (Err) {
+return llvm::Expected(std::move(Err));
+  }
+}
+  }
+  return NewReplaces;
+}
+
 llvm::Expected
 cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces,
   const FormatStyle &Style) {
@@ -2369,7 +2451,12 @@
   // Make header insertion replacements insert new headers into correct blocks.
   tooling::Replacements NewReplaces =

[PATCH] D67460: clang-tidy: modernize-use-using work with multi-argument templates

2019-11-11 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 228767.
poelmanc added a comment.

Changed post-increment/decrement to pre-increment/decrement.


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 
+class TwoArgTemplate {
+  typedef TwoArgTemplate self;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
+  // CHECK-FIXES: using self = TwoArgTemplate;
+};
+
+template 
+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 
+struct Q {};
+
+constexpr bool b[1] = {true};
+
+typedef Q Q_t, *Q_p;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef Q Q_t, *Q_p;
+
+typedef Q Q2_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Q2_t = Q;
+
+struct T {
+  constexpr T(bool) {}
+
+  static constexpr bool b = true;
+};
+
+typedef Q Q3_t, *Q3_p;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef Q Q3_t, *Q3_p;
+
+typedef Q Q3_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Q3_t = Q;
+
+typedef TwoArgTemplate >, S<(0 < 0), Q > > Nested_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Nested_t = TwoArgTemplate >, S<(0 < 0), Q > >;
+
+template 
+class Variadic {};
+
+typedef Variadic >, S<(0 < 0), Variadic > > > Variadic_t;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Variadic_t = Variadic >, S<(0 < 0), Variadic > > >
+
+typedef Variadic >, S<(0 < 0), Variadic > > > Variadic_t, *Variadic_p;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef Variadic >, S<(0 < 0), Variadic > > > 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 && AngleB

[PATCH] D67460: clang-tidy: modernize-use-using work with multi-argument templates

2019-11-11 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc marked 2 inline comments as done.
poelmanc added a comment.

Done, thanks.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D67460/new/

https://reviews.llvm.org/D67460



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69238: Fix clang-tidy readability-redundant-string-init for c++17/c++2a

2019-11-11 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

In D69238#1740914 , @gribozavr2 wrote:

> Thanks! Do you have commit access or do you need me to commit for you?


I don't have commit access, if you could commit it for me that would be great. 
Thanks!


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69238/new/

https://reviews.llvm.org/D69238



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69548: Give clang-tidy readability-redundant-string-init a customizable list of string types to fix

2019-11-11 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 228769.
poelmanc added a comment.

Make requested fixes to documentation.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69548/new/

https://reviews.llvm.org/D69548

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
  clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
@@ -1,4 +1,8 @@
-// RUN: %check_clang_tidy -std=c++11,c++14 %s readability-redundant-string-init %t
+// RUN: %check_clang_tidy -std=c++11,c++14 %s readability-redundant-string-init %t \
+// RUN:   -config="{CheckOptions: \
+// RUN: [{key: readability-redundant-string-init.StringNames, \
+// RUN:   value: "::std::basic_string;our::TestString"}] \
+// RUN: }"
 // FIXME: Fix the checker to work in C++17 mode.
 
 namespace std {
@@ -139,3 +143,82 @@
 void Param3(std::string param = "") {}
 void Param4(STRING param = "") {}
 
+namespace our {
+struct TestString {
+  TestString();
+  TestString(const TestString &);
+  TestString(const char *);
+  ~TestString();
+};
+}
+
+void ourTestStringTests() {
+  our::TestString a = "";
+  // CHECK-MESSAGES: [[@LINE-1]]:19: warning: redundant string initialization
+  // CHECK-FIXES: our::TestString a;
+  our::TestString b("");
+  // CHECK-MESSAGES: [[@LINE-1]]:19: warning: redundant string initialization
+  // CHECK-FIXES: our::TestString b;
+  our::TestString c = R"()";
+  // CHECK-MESSAGES: [[@LINE-1]]:19: warning: redundant string initialization
+  // CHECK-FIXES: our::TestString c;
+  our::TestString d(R"()");
+  // CHECK-MESSAGES: [[@LINE-1]]:19: warning: redundant string initialization
+  // CHECK-FIXES: our::TestString d;
+
+  our::TestString u = "u";
+  our::TestString w("w");
+  our::TestString x = R"(x)";
+  our::TestString y(R"(y)");
+  our::TestString z;
+}
+
+namespace their {
+using TestString = our::TestString;
+}
+
+// their::TestString is the same type so should warn / fix
+void theirTestStringTests() {
+  their::TestString a = "";
+  // CHECK-MESSAGES: [[@LINE-1]]:21: warning: redundant string initialization
+  // CHECK-FIXES: their::TestString a;
+  their::TestString b("");
+  // CHECK-MESSAGES: [[@LINE-1]]:21: warning: redundant string initialization
+  // CHECK-FIXES: their::TestString b;
+}
+
+namespace other {
+// Identical declarations to above but different type
+struct TestString {
+  TestString();
+  TestString(const TestString &);
+  TestString(const char *);
+  ~TestString();
+};
+
+// Identical declarations to above but different type
+template 
+class allocator {};
+template 
+class char_traits {};
+template , typename A = std::allocator>
+struct basic_string {
+  basic_string();
+  basic_string(const basic_string &);
+  basic_string(const C *, const A &a = A());
+  ~basic_string();
+};
+typedef basic_string string;
+typedef basic_string wstring;
+}
+
+// other::TestString, other::string, other::wstring are unrelated to the types
+// being checked. No warnings / fixes should be produced for these types.
+void otherTestStringTests() {
+  other::TestString a = "";
+  other::TestString b("");
+  other::string c = "";
+  other::string d("");
+  other::wstring e = L"";
+  other::wstring f(L"");
+}
Index: clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
===
--- clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
+++ clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
@@ -5,7 +5,8 @@
 
 Finds unnecessary string initializations.
 
-Examples:
+Examples
+
 
 .. code-block:: c++
 
@@ -17,3 +18,15 @@
 
   std::string a;
   std::string b;
+
+Options
+---
+
+.. option:: StringNames
+
+Default is `::std::basic_string`.
+
+Semicolon-delimited list of class names to apply this check to.
+By default `::std::basic_string` applies to ``std::string`` and
+``std::wstring``. Set to e.g. `::std::basic_string;llvm::StringRef;QString`
+to perform this check on custom classes.
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -153,6 +153,10 @@
   Finds non-static member functions that can be made ``const``
   because the functions don't use ``this`` in a non-const way.
 
+- The :doc:`read

[PATCH] D68682: Clang-tidy fix removals removing all non-blank text from a line should remove the line

2019-11-11 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 228795.
poelmanc edited the summary of this revision.
poelmanc added a comment.

Move isWhitespace and skipNewlines to clang/Basic/CharInfo.h (renaming to 
isWhitespaceStringRef and skipNewlinesChars to resolve name clashes) and add 
double-quotes around "/n" and "/r" in comments.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68682/new/

https://reviews.llvm.org/D68682

Files:
  clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-control-flow.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp
  clang/include/clang/Basic/CharInfo.h
  clang/include/clang/Format/Format.h
  clang/lib/AST/CommentLexer.cpp
  clang/lib/AST/CommentParser.cpp
  clang/lib/Format/Format.cpp

Index: clang/lib/Format/Format.cpp
===
--- clang/lib/Format/Format.cpp
+++ clang/lib/Format/Format.cpp
@@ -25,6 +25,7 @@
 #include "UnwrappedLineParser.h"
 #include "UsingDeclarationsSorter.h"
 #include "WhitespaceManager.h"
+#include "clang/Basic/CharInfo.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/DiagnosticOptions.h"
 #include "clang/Basic/SourceManager.h"
@@ -2356,6 +2357,87 @@
 
 } // anonymous namespace
 
+llvm::Expected
+removeNewlyBlankLines(StringRef Code, const tooling::Replacements &Replaces) {
+  tooling::Replacements NewReplaces(Replaces);
+  // pair< LineStartPos, CheckedThroughPos > of lines that have been checked
+  // and confirmed that the replacement result so far will be entirely blank.
+  std::vector> PotentialWholeLineCuts;
+  int LineStartPos = -1;
+  int LineCheckedThroughPos = -1;
+  bool LineBlankSoFar = true;
+  const char *FileText = Code.data();
+  StringRef FilePath; // Must be the same for every Replacement
+  for (const auto &R : Replaces) {
+assert(FilePath.empty() || FilePath == R.getFilePath());
+FilePath = R.getFilePath();
+const int RStartPos = R.getOffset();
+
+int CurrentRLineStartPos = RStartPos;
+while (CurrentRLineStartPos > 0 &&
+   !isVerticalWhitespace(FileText[CurrentRLineStartPos - 1])) {
+  --CurrentRLineStartPos;
+}
+
+assert(CurrentRLineStartPos >= LineStartPos);
+if (CurrentRLineStartPos != LineStartPos) {
+  // We've moved on to a new line. Wrap up the old one before moving on.
+  if (LineBlankSoFar) {
+PotentialWholeLineCuts.push_back(
+std::make_pair(LineStartPos, LineCheckedThroughPos));
+  }
+  LineCheckedThroughPos = CurrentRLineStartPos;
+  LineStartPos = CurrentRLineStartPos;
+  LineBlankSoFar = true;
+}
+
+// Check to see if line from LineCheckedThroughPos to here is blank.
+assert(RStartPos >= LineCheckedThroughPos);
+StringRef PriorTextToCheck(FileText + LineCheckedThroughPos,
+   RStartPos - LineCheckedThroughPos);
+StringRef ReplacementText = R.getReplacementText();
+LineBlankSoFar = LineBlankSoFar &&
+ isWhitespaceStringRef(PriorTextToCheck) &&
+ ReplacementText.empty();
+LineCheckedThroughPos = R.getOffset() + R.getLength();
+  }
+
+  if (LineBlankSoFar) {
+PotentialWholeLineCuts.push_back(
+std::make_pair(LineStartPos, LineCheckedThroughPos));
+  }
+
+  // Now remove whole line if and only if (a) rest of line is blank, and
+  // (b) the original line was *not* blank.
+  for (const auto &LineCheckedThrough : PotentialWholeLineCuts) {
+const int LineStartPos = LineCheckedThrough.first;
+const int CheckedThroughPos = LineCheckedThrough.second;
+
+int LineEndPos = CheckedThroughPos;
+while (LineEndPos < Code.size() &&
+   !isVerticalWhitespace(FileText[LineEndPos])) {
+  ++LineEndPos;
+}
+
+assert(LineEndPos >= CheckedThroughPos);
+StringRef TrailingText(FileText + CheckedThroughPos,
+   LineEndPos - CheckedThroughPos);
+assert(LineEndPos >= LineStartPos);
+StringRef OriginalLine(FileText + LineStartPos, LineEndPos - LineStartPos);
+if (isWhitespaceStringRef(TrailingText) &&
+!isWhitespaceStringRef(OriginalLine)) {
+  const char *CutTo = skipNewlineChars(FileText + LineEndPos, Code.end());
+  int CutCount = CutTo - FileText - LineStartPos;
+  llvm::Error Err = NewReplaces.add(
+  tooling::Replacement(FilePath, LineStartPos, CutCount, ""));
+  if (Err) {
+return llvm::Expected(std::move(Err));
+  }
+}
+  }
+  return NewReplaces;
+}
+
 llvm::Expected
 cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces,
   const FormatStyle &Style) {
@@ -2369,7 +2451,12 @@
   // Make header insertion replacements insert new headers into correct blocks.
   tooling::Rep

[PATCH] D68682: Clang-tidy fix removals removing all non-blank text from a line should remove the line

2019-11-11 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc marked 4 inline comments as done.
poelmanc added inline comments.



Comment at: clang/lib/AST/CommentLexer.cpp:20
+
+// Consider moving this useful function to a more general utility location.
+const char *skipNewline(const char *BufferPtr, const char *BufferEnd) {

gribozavr2 wrote:
> Please do so in this change. clang/include/clang/Basic/CharInfo.h?
Done. I renamed to skipNewlineChars to remind callers it might skip multiple (1 
or 2) characters, and to avoid a name clash with very similar function 
skipNewline helper function at DependencyDirectivesSourceMinimizer.cpp:228. 
That version modifies its first argument and returns the number of characters 
skipped (0, 1, or 2.)

We could alternatively remove DependencyDirectivesSourceMinimizer.cpp's local 
skipNewline() helper function and call this version, but one location (line 
370) would require a few lines of logic that I don't know how to test.



Comment at: clang/lib/AST/CommentParser.cpp:19
 
-static inline bool isWhitespace(llvm::StringRef S) {
+// Consider moving this useful function to a more general utility location.
+bool isWhitespace(llvm::StringRef S) {

gribozavr2 wrote:
> clang/include/clang/Basic/CharInfo.h ?
Done. I renamed it to `isWhitespaceStringRef` to avoid making it an overload of 
the existing `isWhitespace(unsigned char)`, which causes ambiguous overload 
errors at QueryParser.cpp:42 & CommentSema.cpp:237.

We could alternatively keep this as an `isWhitespace` overload and instead 
change those two lines to use a `static_cast(&clang::isWhitespace)` or precede them with a line like:
```
bool (*isWhitespaceOverload)(unsigned char) = &clang::isWhitespace;
```


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68682/new/

https://reviews.llvm.org/D68682



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D70144: clang-tidy: modernize-use-equals-default avoid adding redundant semicolons

2019-11-12 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc created this revision.
poelmanc added reviewers: malcolm.parsons, angelgarcia, aaron.ballman.
Herald added subscribers: cfe-commits, mgehre.
Herald added a project: clang.

`modernize-use-equals-default` replaces default constructors/destructors with 
`= default;`. When the optional semicolon after a member function 
 is present, this results in 
two consecutive semicolons.

This small patch checks to see if the next non-comment token after the code to 
be replaced is a semicolon, and if so offers a replacement of `= default` 
rather than `= default;`.

This patch adds trailing comments and semicolons to about 5 existing tests.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D70144

Files:
  clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default-copy.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default.cpp
@@ -7,7 +7,7 @@
   ~OL();
 };
 
-OL::OL() {}
+OL::OL() {};
 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use '= default' to define a 
trivial default constructor [modernize-use-equals-default]
 // CHECK-FIXES: OL::OL() = default;
 OL::~OL() {}
@@ -17,9 +17,9 @@
 // Inline definitions.
 class IL {
 public:
-  IL() {}
+  IL() {}   ; // Note embedded tab on this line
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
-  // CHECK-FIXES: IL() = default;
+  // CHECK-FIXES: IL() = default; // Note embedded tab on this line
   ~IL() {}
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
   // CHECK-FIXES: ~IL() = default;
@@ -46,18 +46,20 @@
 // Default member initializer
 class DMI {
 public:
-  DMI() {}
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
-  // CHECK-FIXES: DMI() = default;
+  DMI() {} // Comment before semi-colon on next line
+  ;
+  // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default'
+  // CHECK-FIXES: DMI() = default // Comment before semi-colon on next line
+  // CHECK-FIXES-NEXT:   ;
   int Field = 5;
 };
 
 // Class member
 class CM {
 public:
-  CM() {}
+  CM() {} /* Comments */ /* before */ /* semicolon */;
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
-  // CHECK-FIXES: CM() = default;
+  // CHECK-FIXES: CM() = default /* Comments */ /* before */ /* semicolon */;
   OL o;
 };
 
@@ -66,7 +68,7 @@
   Priv() {}
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
   // CHECK-FIXES: Priv() = default;
-  ~Priv() {}
+  ~Priv() {};
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
   // CHECK-FIXES: ~Priv() = default;
 };
Index: 
clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default-copy.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default-copy.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default-copy.cpp
@@ -119,7 +119,7 @@
 struct BF {
   BF() = default;
   BF(const BF &Other) : Field1(Other.Field1), Field2(Other.Field2), 
Field3(Other.Field3),
-Field4(Other.Field4) {}
+Field4(Other.Field4) {};
   // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default'
   // CHECK-FIXES: BF(const BF &Other) {{$}}
   // CHECK-FIXES: = default;
Index: clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp
===
--- clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp
@@ -302,9 +302,19 @@
   auto Diag = diag(Location, "use '= default' to define a trivial " +
  SpecialFunctionName);
 
-  if (ApplyFix)
-Diag << FixItHint::CreateReplacement(Body->getSourceRange(), "= default;")
+  if (ApplyFix) {
+// Peek ahead to see if there's a semicolon after Body->getSourceRange()
+Optional Token;
+do {
+  Token = Lexer::findNextToken(
+  Body->getSourceRange().getEnd().getLocWithOffset(1),
+  Result.Context->getSourceManager(), Result.Context->getLangOpts());
+} while (Token && Token->is(tok::comment));
+StringRef Replacement =
+Token && Token->is(tok::semi) ? "= default" : "= default;";
+Diag << FixItHint::CreateReplacement(Body->getSourceRange(), Replacement)
  << RemoveInitializers;
+  }
 }
 
 } // namespace modernize


Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default.cpp
===
--- clang-tools-e

[PATCH] D70165: clang-tidy: modernize-use-override new option AllowOverrideAndFinal

2019-11-12 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc created this revision.
poelmanc added reviewers: alexfh, djasper.
Herald added subscribers: cfe-commits, mgehre.
Herald added a project: clang.

In addition to adding `override` wherever possible, clang-tidy's 
`modernize-use-override` nicely removes `virtual` when `override` or `final` is 
specified, and further removes `override` when `final` is specified. While this 
is great default behavior, when code needs to be compiled with `gcc` at high 
warning levels that include `gcc -Wsuggest-override` or `gcc 
-Werror=suggest-override`, clang-tidy's removal of the redundant `override` 
keyword causes gcc to emit a warning or error. This discrepancy / conflict has 
been noted by others including a comment on Stack Overflow 

 and by Mozzilla's Firefox developers 
.

This patch adds an AllowOverrideAndFinal option defaulting to `0` - thus 
preserving current behavior - that when enabled allows both `override` and 
`final` to co-exist, while still fixing all other issues.

The patch includes a test file verifying all combinations of 
``virtual``/``override``/``final``, and mentions the new option in the release 
notes.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D70165

Files:
  clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp
  clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/modernize-use-override.rst
  
clang-tools-extra/test/clang-tidy/checkers/modernize-use-override-allow-override-and-final.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-override-allow-override-and-final.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-override-allow-override-and-final.cpp
@@ -0,0 +1,40 @@
+// RUN: %check_clang_tidy %s modernize-use-override %t -- \
+// RUN:   -config="{CheckOptions: [{key: modernize-use-override.AllowOverrideAndFinal, value: 1}]}"
+
+struct Base {
+  virtual ~Base();
+  virtual void a();
+  virtual void b();
+  virtual void c();
+  virtual void d();
+  virtual void e();
+  virtual void f();
+  virtual void g();
+  virtual void h();
+  virtual void i();
+};
+
+struct Simple : public Base {
+  virtual ~Simple();
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: prefer using 'override' or (rarely) 'final' instead of 'virtual' [modernize-use-override]
+  // CHECK-FIXES: {{^}}  ~Simple() override;
+  virtual void a() override;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: 'virtual' is redundant since the function is already declared 'override' [modernize-use-override]
+  // CHECK-FIXES: {{^}}  void a() override;
+  virtual void b() final;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: 'virtual' is redundant since the function is already declared 'final' [modernize-use-override]
+  // CHECK-FIXES: {{^}}  void b() final;
+  virtual void c() final override;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: 'virtual' is redundant since the function is already declared 'final' [modernize-use-override]
+  // CHECK-FIXES: {{^}}  void c() final override;
+  virtual void d() override final;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: 'virtual' is redundant since the function is already declared 'final' [modernize-use-override]
+  // CHECK-FIXES: {{^}}  void d() override final;
+  void e() final override;
+  void f() override final;
+  void g() final;
+  void h() override;
+  void i();
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: annotate this function with 'override' or (rarely) 'final' [modernize-use-override]
+  // CHECK-FIXES: {{^}}  void i() override;
+};
Index: clang-tools-extra/docs/clang-tidy/checks/modernize-use-override.rst
===
--- clang-tools-extra/docs/clang-tidy/checks/modernize-use-override.rst
+++ clang-tools-extra/docs/clang-tidy/checks/modernize-use-override.rst
@@ -27,6 +27,14 @@
 
If set to non-zero, this check will not diagnose destructors. Default is `0`.
 
+.. option:: AllowOverrideAndFinal
+
+   If set to non-zero, this check will not diagnose ``override`` as redundant
+   with ``final``. This is useful when code will be compiled by a compiler with
+   warning/error checking flags requiring ``override`` explicitly on overriden
+   members, such as ``gcc -Wsuggest-override``/``gcc -Werror=suggest-override``.
+   Default is `0`.
+
 .. option:: OverrideSpelling
 
Specifies a macro to use instead of ``override``. This is useful when
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -153,6 +153,12 @@
   Finds non-static member functions that can be made ``const``
   b

[PATCH] D70144: clang-tidy: modernize-use-equals-default avoid adding redundant semicolons

2019-11-13 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc marked an inline comment as done.
poelmanc added inline comments.



Comment at: clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp:306
+  if (ApplyFix) {
+// Peek ahead to see if there's a semicolon after Body->getSourceRange()
+Optional Token;

JonasToth wrote:
> There should be utility code in `clang-tidy/util/` that deals with custom 
> lexing, that should be able to do the job.
Thanks for the quick feedback! I looked there and couldn't find a utility 
function that searched (a) //forward// rather than backwards, and (b) for any 
token //not// of a given list of types. Here's a new helper function that could 
be placed in LexerUtils.h if you think it's generally useful:

```
// Analogous to findNextAnyTokenKind, finds next token not of
// the given set of TokenKinds. Useful for skipping comments.
template 
Optional findNextTokenSkippingKind(SourceLocation Start,
  const SourceManager &SM,
  const LangOptions &LangOpts,
  TokenKind TK, TokenKinds... TKs) {
  Optional CurrentToken;
  do {
Optional CurrentToken = Lexer::findNextToken(Start, SM, LangOpts);
  } while (CurrentToken && CurrentToken.isOneOf(TK, TKs...));
  return CurrentToken;
}
```

Then the `do` loop below can be simplified to:
```
  Optional Token = findNextTokenSkippingKind(
  Body->getSourceRange().getEnd().getLocWithOffset(1),
  Result.Context->getSourceManager(), Result.Context->getLangOpts(),
  tok::comment);
```


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D70144/new/

https://reviews.llvm.org/D70144



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D70144: clang-tidy: modernize-use-equals-default avoid adding redundant semicolons

2019-11-13 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 229161.
poelmanc edited the summary of this revision.
poelmanc added a comment.

Update to add and use new `findNextTokenSkippingComments` and 
`findNextTokenSkippingKind` utility functions. Since the former calls the 
latter with just one token type, this required generalizing `Token::isOneOf()` 
to work with 1-to-N token kinds versus requiring 2-to-N.

Also added a release note.

To me the change to `Token::isOneOf()` is an improvement (less code and more 
flexibility when calling it from variadic templates), but if the team prefers 
not to modify `Token::isOneOf()`, we could eliminate the 
`findNextTokenSkippingKind` utility function and instead implement 
`findNextTokenSkippingComments` directly.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D70144/new/

https://reviews.llvm.org/D70144

Files:
  clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp
  clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
  clang-tools-extra/clang-tidy/utils/LexerUtils.h
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default-copy.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default.cpp
  clang/include/clang/Lex/Token.h

Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default.cpp
@@ -7,7 +7,7 @@
   ~OL();
 };
 
-OL::OL() {}
+OL::OL() {};
 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use '= default' to define a trivial default constructor [modernize-use-equals-default]
 // CHECK-FIXES: OL::OL() = default;
 OL::~OL() {}
@@ -17,9 +17,9 @@
 // Inline definitions.
 class IL {
 public:
-  IL() {}
+  IL() {} 	 ; // Note embedded tab on this line
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
-  // CHECK-FIXES: IL() = default;
+  // CHECK-FIXES: IL() = default 	 ; // Note embedded tab on this line
   ~IL() {}
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
   // CHECK-FIXES: ~IL() = default;
@@ -46,18 +46,20 @@
 // Default member initializer
 class DMI {
 public:
-  DMI() {}
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
-  // CHECK-FIXES: DMI() = default;
+  DMI() {} // Comment before semi-colon on next line
+  ;
+  // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default'
+  // CHECK-FIXES: DMI() = default // Comment before semi-colon on next line
+  // CHECK-FIXES-NEXT:   ;
   int Field = 5;
 };
 
 // Class member
 class CM {
 public:
-  CM() {}
+  CM() {} /* Comments */ /* before */ /* semicolon */;
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
-  // CHECK-FIXES: CM() = default;
+  // CHECK-FIXES: CM() = default /* Comments */ /* before */ /* semicolon */;
   OL o;
 };
 
@@ -66,7 +68,7 @@
   Priv() {}
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
   // CHECK-FIXES: Priv() = default;
-  ~Priv() {}
+  ~Priv() {};
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
   // CHECK-FIXES: ~Priv() = default;
 };
Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default-copy.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default-copy.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default-copy.cpp
@@ -119,7 +119,7 @@
 struct BF {
   BF() = default;
   BF(const BF &Other) : Field1(Other.Field1), Field2(Other.Field2), Field3(Other.Field3),
-Field4(Other.Field4) {}
+Field4(Other.Field4) {};
   // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default'
   // CHECK-FIXES: BF(const BF &Other) {{$}}
   // CHECK-FIXES: = default;
Index: clang/include/clang/Lex/Token.h
===
--- clang/include/clang/Lex/Token.h
+++ clang/include/clang/Lex/Token.h
@@ -96,12 +96,14 @@
   /// "if (Tok.is(tok::l_brace)) {...}".
   bool is(tok::TokenKind K) const { return Kind == K; }
   bool isNot(tok::TokenKind K) const { return Kind != K; }
-  bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const {
-return is(K1) || is(K2);
+
+  /// Single argument overload provides base case for recursive template below
+  bool isOneOf(tok::TokenKind K) const {
+return is(K);
   }
   template 
-  bool isOneOf(tok::TokenKind K1, tok::TokenKind K2, Ts... Ks) const {
-return is(K1) || isOneOf(K2, Ks...);
+  bool isOneOf(tok::TokenKind K1, Ts... Ks) const {
+return is(K1) || isOneOf(Ks...);
   }
 
   /// Return true if this is a raw identifier (when lexing
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-ex

[PATCH] D70144: clang-tidy: modernize-use-equals-default avoid adding redundant semicolons

2019-11-13 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc updated this revision to Diff 229202.
poelmanc added a comment.

Change to add just one helper function `findNextTokenSkippingComments` to 
`LexerUtils.h`, requiring no change to `Token::isOneOf`, and properly call it 
from `UseEqualsDefaultCheck.cpp`.

In D70144#1744737 , @JonasToth wrote:

> Are you using the lexer-util functions? Maybe i am just to tired, but they 
> seem to be unused.


Sorry, that was not you! I was experimenting with the `git show` command to 
generate these patches and failed to check the results closely. The correct 
calling code should be in the updated diff.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D70144/new/

https://reviews.llvm.org/D70144

Files:
  clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp
  clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
  clang-tools-extra/clang-tidy/utils/LexerUtils.h
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default-copy.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default.cpp
@@ -7,7 +7,7 @@
   ~OL();
 };
 
-OL::OL() {}
+OL::OL() {};
 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use '= default' to define a trivial default constructor [modernize-use-equals-default]
 // CHECK-FIXES: OL::OL() = default;
 OL::~OL() {}
@@ -17,9 +17,9 @@
 // Inline definitions.
 class IL {
 public:
-  IL() {}
+  IL() {} 	 ; // Note embedded tab on this line
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
-  // CHECK-FIXES: IL() = default;
+  // CHECK-FIXES: IL() = default 	 ; // Note embedded tab on this line
   ~IL() {}
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
   // CHECK-FIXES: ~IL() = default;
@@ -46,18 +46,20 @@
 // Default member initializer
 class DMI {
 public:
-  DMI() {}
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
-  // CHECK-FIXES: DMI() = default;
+  DMI() {} // Comment before semi-colon on next line
+  ;
+  // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default'
+  // CHECK-FIXES: DMI() = default // Comment before semi-colon on next line
+  // CHECK-FIXES-NEXT:   ;
   int Field = 5;
 };
 
 // Class member
 class CM {
 public:
-  CM() {}
+  CM() {} /* Comments */ /* before */ /* semicolon */;
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
-  // CHECK-FIXES: CM() = default;
+  // CHECK-FIXES: CM() = default /* Comments */ /* before */ /* semicolon */;
   OL o;
 };
 
@@ -66,7 +68,7 @@
   Priv() {}
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
   // CHECK-FIXES: Priv() = default;
-  ~Priv() {}
+  ~Priv() {};
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
   // CHECK-FIXES: ~Priv() = default;
 };
Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default-copy.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default-copy.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default-copy.cpp
@@ -119,7 +119,7 @@
 struct BF {
   BF() = default;
   BF(const BF &Other) : Field1(Other.Field1), Field2(Other.Field2), Field3(Other.Field3),
-Field4(Other.Field4) {}
+Field4(Other.Field4) {};
   // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default'
   // CHECK-FIXES: BF(const BF &Other) {{$}}
   // CHECK-FIXES: = default;
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -141,6 +141,10 @@
 - The 'objc-avoid-spinlock' check was renamed to :doc:`darwin-avoid-spinlock
   `
 
+- The :doc:`modernize-use-equals-default
+  ` fix no longer adds
+  semicolons where they would be redundant.
+
 - New :doc:`readability-redundant-access-specifiers
   ` check.
 
Index: clang-tools-extra/clang-tidy/utils/LexerUtils.h
===
--- clang-tools-extra/clang-tidy/utils/LexerUtils.h
+++ clang-tools-extra/clang-tidy/utils/LexerUtils.h
@@ -80,6 +80,11 @@
   }
 }
 
+// Finds next token that's not a comment.
+Optional findNextTokenSkippingComments(SourceLocation Start,
+  const SourceManager &SM,
+  const LangOptions &LangOpts);
+
 /// Re-lex the provide \p Range and return \c false if either a macro spans
 /// multiple tokens, a pre-processor directive or failure to retrieve the
 ///

[PATCH] D70165: clang-tidy: modernize-use-override new option AllowOverrideAndFinal

2019-11-13 Thread Conrad Poelman via Phabricator via cfe-commits
poelmanc added a comment.

In D70165#1744007 , @JonasToth wrote:

> LGTM!
>  Did you check on a real code-base that suffers from the issue, if that works 
> as expected?


Thanks! I have now run it on our real code base and it worked as expected.

I lack commit access and would appreciate anyone committing this on my behalf.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D70165/new/

https://reviews.llvm.org/D70165



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


  1   2   >