[PATCH] D50852: [clang-tidy] abseil-auto-make-unique

2018-08-18 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

In https://reviews.llvm.org/D50852#1202774, @lebedev.ri wrote:

> 1. Please always upload all patches with full context.
> 2. There already is `modernize-use-auto`. Does it handle this case? Then this 
> should be just an alias to that check. Else, i think it would be best to 
> extend that one, and still alias.


First of all, thanks, Hugo, for your check!

My +1 for extending `modernize-use-auto` as currently it doesn't support cases 
your check supports.
Because replacing

  std::unique_ptr< int >y = std::make_unique();

with

  auto y = std::make_unique();

is logically the same as replacing

  long long int *y = new long long int (42);

with

  auto* y = new long long int (42);

So your check should extend the existing one and not create one more check IMHO.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D50852



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


[PATCH] D50852: [clang-tidy] abseil-auto-make-unique

2018-08-18 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added inline comments.



Comment at: clang-tidy/abseil/AutoMakeUniqueCheck.cpp:21
+void AutoMakeUniqueCheck::registerMatchers(MatchFinder* finder) {
+  if (!getLangOpts().CPlusPlus) return;
+

JonasToth wrote:
> Please clang-format, `return` on next line.
`auto` first appeared in C++11, so you may use `getLangOpts().CPlusPlus11`
And `std::make_unique` is a part of C++14, so even `getLangOpts().CPlusPlus14.



Comment at: clang-tidy/abseil/AutoMakeUniqueCheck.cpp:66
+  const auto* var_decl = result.Nodes.getNodeAs("var_decl");
+  const auto* make_unique_decl =
+  result.Nodes.getNodeAs("make_unique_decl");

You may move this definition after the next `if`+`return`.



Comment at: docs/clang-tidy/checks/abseil-auto-make-unique.rst:10
+
+  std::unique_ptr x = MakeUnique(...);
+

`MakeUnique`? Maybe `std/abseil::make_unique`?


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D50852



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


[PATCH] D45927: [clang-tidy] [modernize-use-auto] Correct way to calculate a type name length for multi-token types

2018-05-14 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 146677.
zinovy.nis added a comment.

- Fix for templated type names. Thanks AlexanderK for pointing.


https://reviews.llvm.org/D45927

Files:
  clang-tidy/modernize/UseAutoCheck.cpp
  docs/clang-tidy/checks/modernize-use-auto.rst
  test/clang-tidy/modernize-use-auto-min-type-name-length.cpp

Index: test/clang-tidy/modernize-use-auto-min-type-name-length.cpp
===
--- test/clang-tidy/modernize-use-auto-min-type-name-length.cpp
+++ test/clang-tidy/modernize-use-auto-min-type-name-length.cpp
@@ -1,30 +1,85 @@
-// RUN: %check_clang_tidy %s modernize-use-auto %t -- \
-// RUN:   -config="{CheckOptions: [{key: modernize-use-auto.MinTypeNameLength, value: '5'}]}" \
-// RUN:   -- -std=c++11 -frtti
-
-extern int foo();
-
-using VeryVeryVeryLongTypeName = int;
+// RUN: %check_clang_tidy -check-suffix=0-0 %s modernize-use-auto %t  -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 0}, {key: modernize-use-auto.MinTypeNameLength, value: 0}]}" -- --std=c++11 -frtti
+// RUN: %check_clang_tidy -check-suffix=0-8 %s modernize-use-auto %t  -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 0}, {key: modernize-use-auto.MinTypeNameLength, value: 8}]}" -- --std=c++11 -frtti
+// RUN: %check_clang_tidy -check-suffix=1-0 %s modernize-use-auto %t  -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 1}, {key: modernize-use-auto.MinTypeNameLength, value: 0}]}" -- --std=c++11 -frtti
+// RUN: %check_clang_tidy -check-suffix=1-8 %s modernize-use-auto %t  -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 1}, {key: modernize-use-auto.MinTypeNameLength, value: 8}]}" -- --std=c++11 -frtti
+
+template  extern T foo();
+template  struct P {  explicit P(T t) : t_(t) {}  T t_;};
+template  P *foo_ptr();
+template  P &foo_ref();
 
 int bar() {
-  int a = static_cast(foo());
-  // strlen('int') = 4 <  5, so skip it,
-  // even strlen('VeryVeryVeryLongTypeName') > 5.
-
-  unsigned b = static_cast(foo());
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name [modernize-use-auto]
-  // CHECK-FIXES: auto b = static_cast(foo());
-
-  bool c = static_cast(foo());
-  // strlen('bool') = 4 <  5, so skip it.
-
-  const bool c1 = static_cast(foo());
-  // strlen('bool') = 4 <  5, so skip it, even there's a 'const'.
-
-  unsigned long long ull = static_cast(foo());
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name [modernize-use-auto]
-  // CHECK-FIXES: auto ull = static_cast(foo());
+  {
+// Lenth(long) = 4
+long i = static_cast(foo());
+// CHECK-FIXES-0-0: auto i = {{.*}}
+// CHECK-FIXES-0-8: long i = {{.*}}
+// CHECK-FIXES-1-0: auto  i = {{.*}}
+// CHECK-FIXES-1-8: long i = {{.*}}
+const long ci = static_cast(foo());
+// CHECK-FIXES-0-0: auto ci = {{.*}}
+// CHECK-FIXES-0-8: long ci = {{.*}}
+// CHECK-FIXES-1-0: auto  ci = {{.*}}
+// CHECK-FIXES-1-8: long ci = {{.*}}
+long *pi = static_cast(foo());
+// CHECK-FIXES-0-0: auto *pi = {{.*}}
+// CHECK-FIXES-0-8: long *pi = {{.*}}
+// CHECK-FIXES-1-0: auto pi = {{.*}}
+// CHECK-FIXES-1-8: long *pi = {{.*}}
+
+// Length(long   *) is still 5
+long  * pi2 = static_cast(foo());
+// CHECK-FIXES-0-0: auto  * pi2 = {{.*}}
+// CHECK-FIXES-0-8: long  * pi2 = {{.*}}
+// CHECK-FIXES-1-0: auto  pi2 = {{.*}}
+// CHECK-FIXES-1-8: long  * pi2 = {{.*}}
+ 
+// Length(long **) = 6
+long **ppi = static_cast(foo());
+// CHECK-FIXES-0-0: auto **ppi = {{.*}}
+// CHECK-FIXES-0-8: long **ppi = {{.*}}
+// CHECK-FIXES-1-0: auto ppi = {{.*}}
+// CHECK-FIXES-1-8: long **ppi = {{.*}}
+  }
+
+  {
+// Lenth(long int) = 4 + 1 + 3 = 8
+// Lenth(longint) is still 8
+long int i = static_cast(foo());
+// CHECK-FIXES-0-0: auto i = {{.*}}
+// CHECK-FIXES-0-8: auto i = {{.*}}
+// CHECK-FIXES-1-0: auto  i = {{.*}}
+// CHECK-FIXES-1-8: auto  i = {{.*}}
+
+long int *pi = static_cast(foo());
+// CHECK-FIXES-0-0: auto *pi = {{.*}}
+// CHECK-FIXES-0-8: auto *pi = {{.*}}
+// CHECK-FIXES-1-0: auto pi = {{.*}}
+// CHECK-FIXES-1-8: auto pi = {{.*}}
+  }
+
+  // Templates
+  {
+// Length(P) = 7
+P& i = static_cast&>(foo_ref());
+// CHECK-FIXES-0-0: auto& i = {{.*}}
+// CHECK-FIXES-0-8: P& i = {{.*}}
+// CHECK-FIXES-1-0: auto & i = {{.*}}
+// CHECK-FIXES-1-8: P& i = {{.*}}
+
+// Length(P) = 8
+P& pi = static_cast &>(foo_ref());
+// CHECK-FIXES-0-0: auto& pi = {{.*}}
+// CHECK-FIXES-0-8: auto& pi = {{.*}}
+// CHECK-FIXES-1-0: auto & pi = {{.*}}
+// CHECK-FIXES-1-8: auto & pi = {{.*}}
+
+P* pi2 = static_cast*>(foo_ptr());
+// CHECK-FIXES-0-0: auto* pi2 = {{.*}}
+// CHECK-FIXES

[PATCH] D45927: [clang-tidy] [modernize-use-auto] Correct way to calculate a type name length for multi-token types

2018-05-16 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis marked an inline comment as done.
zinovy.nis added inline comments.



Comment at: modernize/UseAutoCheck.cpp:40
+? Alpha
+: (std::isspace(C) || (!RemoveStars && C == '*')) ? Space
+  : Punctuation;

rsmith wrote:
> `isspace` here is wrong: it's a locale-sensitive check. Clang assumes UTF-8 
> throughout; you can use `isWhitespace` from clang/Basic/CharInfo.h to test if 
> the character should be treated as whitespace.
Thanks!


https://reviews.llvm.org/D45927



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


[PATCH] D45927: [clang-tidy] [modernize-use-auto] Correct way to calculate a type name length for multi-token types

2018-05-18 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis marked an inline comment as done.
zinovy.nis added a comment.

Alexander, can you please have a look at the latest patch? Thanks.


https://reviews.llvm.org/D45927



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


[PATCH] D47122: [clang-tidy] SimplifyBoolenExpr doesn't add parens if unary negotiation is of ExprWithCleanups type

2018-05-20 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis created this revision.
zinovy.nis added reviewers: alexfh, aaron.ballman.
zinovy.nis added a project: clang-tools-extra.
Herald added subscribers: cfe-commits, xazax.hun.

  using A = std::string;
  bool foo(A &s) {
A S;
if (GetValue(s) && S != (A)s)
  return false;
return true;
  }

is fixed into (w/o this patch)

  ...
  return !GetValue(s) && S != (A)s; // negotiation affects first operand only
  }

instead of (with this patch)

  ...
  return !(GetValue(s) && S != (A)s); // note parens for the whole expression
  }


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D47122

Files:
  clang-tidy/readability/SimplifyBooleanExprCheck.cpp
  test/clang-tidy/readability-simplify-bool-expr.cpp


Index: test/clang-tidy/readability-simplify-bool-expr.cpp
===
--- test/clang-tidy/readability-simplify-bool-expr.cpp
+++ test/clang-tidy/readability-simplify-bool-expr.cpp
@@ -938,3 +938,15 @@
 }
 // CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
 // CHECK-FIXES: return p->m != 0;{{$}}
+
+bool operator!=(const A&, const A&) { return false; }
+extern bool GetValue(A s);
+bool expr_with_cleanups(A &s) {
+  A S;
+  if (GetValue(s) && S != (A)s)
+return false;
+
+  return true;
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: !(GetValue(s) && S != (A)s);{{$}}
Index: clang-tidy/readability/SimplifyBooleanExprCheck.cpp
===
--- clang-tidy/readability/SimplifyBooleanExprCheck.cpp
+++ clang-tidy/readability/SimplifyBooleanExprCheck.cpp
@@ -75,6 +75,8 @@
 
 bool needsParensAfterUnaryNegation(const Expr *E) {
   E = E->IgnoreImpCasts();
+  if (auto *EC = dyn_cast(E))
+E = EC->getSubExpr();
   if (isa(E) || isa(E))
 return true;
 


Index: test/clang-tidy/readability-simplify-bool-expr.cpp
===
--- test/clang-tidy/readability-simplify-bool-expr.cpp
+++ test/clang-tidy/readability-simplify-bool-expr.cpp
@@ -938,3 +938,15 @@
 }
 // CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
 // CHECK-FIXES: return p->m != 0;{{$}}
+
+bool operator!=(const A&, const A&) { return false; }
+extern bool GetValue(A s);
+bool expr_with_cleanups(A &s) {
+  A S;
+  if (GetValue(s) && S != (A)s)
+return false;
+
+  return true;
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: !(GetValue(s) && S != (A)s);{{$}}
Index: clang-tidy/readability/SimplifyBooleanExprCheck.cpp
===
--- clang-tidy/readability/SimplifyBooleanExprCheck.cpp
+++ clang-tidy/readability/SimplifyBooleanExprCheck.cpp
@@ -75,6 +75,8 @@
 
 bool needsParensAfterUnaryNegation(const Expr *E) {
   E = E->IgnoreImpCasts();
+  if (auto *EC = dyn_cast(E))
+E = EC->getSubExpr();
   if (isa(E) || isa(E))
 return true;
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D47122: [clang-tidy] SimplifyBoolenExpr doesn't add parens if unary negotiation is of ExprWithCleanups type

2018-05-21 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 147836.
zinovy.nis edited the summary of this revision.
zinovy.nis added a comment.

- More accurate place to fix.


https://reviews.llvm.org/D47122

Files:
  clang-tidy/readability/SimplifyBooleanExprCheck.cpp
  test/clang-tidy/readability-simplify-bool-expr.cpp


Index: test/clang-tidy/readability-simplify-bool-expr.cpp
===
--- test/clang-tidy/readability-simplify-bool-expr.cpp
+++ test/clang-tidy/readability-simplify-bool-expr.cpp
@@ -938,3 +938,13 @@
 }
 // CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
 // CHECK-FIXES: return p->m != 0;{{$}}
+
+bool operator!=(const A&, const A&) { return false; }
+bool expr_with_cleanups(A &S) {
+  if (S != (A)S)
+return false;
+
+  return true;
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: S == (A)S;{{$}}
Index: clang-tidy/readability/SimplifyBooleanExprCheck.cpp
===
--- clang-tidy/readability/SimplifyBooleanExprCheck.cpp
+++ clang-tidy/readability/SimplifyBooleanExprCheck.cpp
@@ -195,6 +195,9 @@
 std::string replacementExpression(const MatchFinder::MatchResult &Result,
   bool Negated, const Expr *E) {
   E = E->ignoreParenBaseCasts();
+  if (const auto *EC = dyn_cast(E))
+E = EC->getSubExpr();
+
   const bool NeedsStaticCast = needsStaticCast(E);
   if (Negated) {
 if (const auto *UnOp = dyn_cast(E)) {


Index: test/clang-tidy/readability-simplify-bool-expr.cpp
===
--- test/clang-tidy/readability-simplify-bool-expr.cpp
+++ test/clang-tidy/readability-simplify-bool-expr.cpp
@@ -938,3 +938,13 @@
 }
 // CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
 // CHECK-FIXES: return p->m != 0;{{$}}
+
+bool operator!=(const A&, const A&) { return false; }
+bool expr_with_cleanups(A &S) {
+  if (S != (A)S)
+return false;
+
+  return true;
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: S == (A)S;{{$}}
Index: clang-tidy/readability/SimplifyBooleanExprCheck.cpp
===
--- clang-tidy/readability/SimplifyBooleanExprCheck.cpp
+++ clang-tidy/readability/SimplifyBooleanExprCheck.cpp
@@ -195,6 +195,9 @@
 std::string replacementExpression(const MatchFinder::MatchResult &Result,
   bool Negated, const Expr *E) {
   E = E->ignoreParenBaseCasts();
+  if (const auto *EC = dyn_cast(E))
+E = EC->getSubExpr();
+
   const bool NeedsStaticCast = needsStaticCast(E);
   if (Negated) {
 if (const auto *UnOp = dyn_cast(E)) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D47122: [clang-tidy] SimplifyBoolenExpr doesn't add parens if unary negotiation is of ExprWithCleanups type

2018-05-22 Thread Zinovy Nis via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL333003: [clang-tidy] SimplifyBoolenExpr doesn't add 
parens if unary negotiation is of… (authored by zinovy.nis, committed by ).
Herald added subscribers: llvm-commits, klimek.

Changed prior to commit:
  https://reviews.llvm.org/D47122?vs=147836&id=148046#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D47122

Files:
  clang-tools-extra/trunk/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
  clang-tools-extra/trunk/test/clang-tidy/readability-simplify-bool-expr.cpp


Index: 
clang-tools-extra/trunk/test/clang-tidy/readability-simplify-bool-expr.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/readability-simplify-bool-expr.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/readability-simplify-bool-expr.cpp
@@ -938,3 +938,13 @@
 }
 // CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
 // CHECK-FIXES: return p->m != 0;{{$}}
+
+bool operator!=(const A&, const A&) { return false; }
+bool expr_with_cleanups(A &S) {
+  if (S != (A)S)
+return false;
+
+  return true;
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: S == (A)S;{{$}}
Index: 
clang-tools-extra/trunk/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
@@ -195,6 +195,9 @@
 std::string replacementExpression(const MatchFinder::MatchResult &Result,
   bool Negated, const Expr *E) {
   E = E->ignoreParenBaseCasts();
+  if (const auto *EC = dyn_cast(E))
+E = EC->getSubExpr();
+
   const bool NeedsStaticCast = needsStaticCast(E);
   if (Negated) {
 if (const auto *UnOp = dyn_cast(E)) {


Index: clang-tools-extra/trunk/test/clang-tidy/readability-simplify-bool-expr.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/readability-simplify-bool-expr.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/readability-simplify-bool-expr.cpp
@@ -938,3 +938,13 @@
 }
 // CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
 // CHECK-FIXES: return p->m != 0;{{$}}
+
+bool operator!=(const A&, const A&) { return false; }
+bool expr_with_cleanups(A &S) {
+  if (S != (A)S)
+return false;
+
+  return true;
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: S == (A)S;{{$}}
Index: clang-tools-extra/trunk/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
@@ -195,6 +195,9 @@
 std::string replacementExpression(const MatchFinder::MatchResult &Result,
   bool Negated, const Expr *E) {
   E = E->ignoreParenBaseCasts();
+  if (const auto *EC = dyn_cast(E))
+E = EC->getSubExpr();
+
   const bool NeedsStaticCast = needsStaticCast(E);
   if (Negated) {
 if (const auto *UnOp = dyn_cast(E)) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D47122: [clang-tidy] SimplifyBoolenExpr doesn't add parens if unary negotiation is of ExprWithCleanups type

2018-05-22 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added inline comments.



Comment at: 
clang-tools-extra/trunk/clang-tidy/readability/SimplifyBooleanExprCheck.cpp:198
   E = E->ignoreParenBaseCasts();
+  if (const auto *EC = dyn_cast(E))
+E = EC->getSubExpr();

malcolm.parsons wrote:
> `E->IgnoreImplicit()` can be used to ignore `ExprWithCleanups`
Thanks. But it seems to be too agressive:


```
return (i & 1) != 0;
```

becomes 

```
return static_cast(i & 1);
```



Repository:
  rL LLVM

https://reviews.llvm.org/D47122



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


[PATCH] D47122: [clang-tidy] SimplifyBoolenExpr doesn't add parens if unary negotiation is of ExprWithCleanups type

2018-05-22 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added inline comments.



Comment at: 
clang-tools-extra/trunk/clang-tidy/readability/SimplifyBooleanExprCheck.cpp:198
   E = E->ignoreParenBaseCasts();
+  if (const auto *EC = dyn_cast(E))
+E = EC->getSubExpr();

zinovy.nis wrote:
> malcolm.parsons wrote:
> > `E->IgnoreImplicit()` can be used to ignore `ExprWithCleanups`
> Thanks. But it seems to be too agressive:
> 
> 
> ```
> return (i & 1) != 0;
> ```
> 
> becomes 
> 
> ```
> return static_cast(i & 1);
> ```
> 
```
  if (!isa(E))
E = E->IgnoreImplicit();

```

works properly but looks a bit verbose. What do you think?


Repository:
  rL LLVM

https://reviews.llvm.org/D47122



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


[PATCH] D44295: Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-09 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis created this revision.
zinovy.nis added reviewers: klimek, alexfh.
zinovy.nis added a project: clang-tools-extra.
Herald added a subscriber: mgorny.

Warns if one calls grand-..parent's virtual method in child's virtual method 
instead of parent's. Can automatically fix such cases by retargeting calls to 
parent.

class A {
... 
int virtual foo() {...}
}

class B: public A {
int foo() override {...}
}

class C: public B {
...
int foo() override {... A::foo()...} // will be replaced with "...B::foo()..."
}


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/bugprone/ParentVirtualCallCheck.cpp
  clang-tidy/bugprone/ParentVirtualCallCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-parent-virtual-call.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/bugprone-parent-virtual-call.cpp

Index: test/clang-tidy/bugprone-parent-virtual-call.cpp
===
--- /dev/null
+++ test/clang-tidy/bugprone-parent-virtual-call.cpp
@@ -0,0 +1,103 @@
+// RUN: %check_clang_tidy %s bugprone-parent-virtual-call %t
+
+extern int f();
+
+class A {
+public:
+  A() = default;
+  virtual ~A() = default;
+
+  virtual int virt_1() { return f() + 1; }
+  virtual int virt_2() { return f() + 2; }
+
+  int non_virt() { return f() + 3; }
+  static int stat() { return f() + 4; }
+};
+
+class B : public A {
+public:
+  B() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+
+class C : public B {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_1() override { return B::virt_1() + B::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_2() override { return B::virt_1() + B::virt_1(); }
+
+  // Test that non-virtual and static methods are not affected by this cherker.
+  int method_c() { return A::stat() + A::non_virt(); }
+};
+
+// Test that the check affects grand-grand..-parent calls too.
+class D : public C {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_1() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_2() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+};
+
+// Test classes in anonymous namespaces.
+namespace {
+class BN : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+} // namespace N
+
+class CN : public BN {
+public:
+  int virt_1() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean '(anonymous namespace)::BN'?
+  // CHECK-FIXES:  int virt_1() override { return BN::virt_1() + BN::virt_1(); }
+  int virt_2() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean '(anonymous namespace)::BN'?
+  // CHECK-FIXES:  int virt_2() override { return BN::virt_1() + BN::virt_1(); }
+};
+
+// Test multiple inheritance fixes
+class AA {
+public:
+  AA() = default;
+  virtual ~AA() = default;
+
+  virtual int virt_1() { return f() + 1; }
+  virtual int virt_2() { return f() + 2; }
+
+  int non_virt() { return f() + 3; }
+  static int stat() { return f() + 4; }
+};
+
+class BB_1 : virtual public AA {
+public:
+  BB_1() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return AA::virt_1() + 3; }
+  int virt_2() override { return AA::virt_2() + 4; }
+};
+
+class BB_2 : virtual public AA {
+public:
+BB_2() = default;
+};
+
+class CC : public BB_1, public BB_2 {
+public:
+  int virt_1() override { return AA::virt_1() + 3; }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'AA::virt_1' is a grand-parent's method, not parent's. Did you mean 'BB_1' or 'BB_2'? [bugprone-parent-virtual-call]
+  // No fix av

[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-09 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 137783.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/bugprone/ParentVirtualCallCheck.cpp
  clang-tidy/bugprone/ParentVirtualCallCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-parent-virtual-call.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/bugprone-parent-virtual-call.cpp

Index: test/clang-tidy/bugprone-parent-virtual-call.cpp
===
--- /dev/null
+++ test/clang-tidy/bugprone-parent-virtual-call.cpp
@@ -0,0 +1,116 @@
+// RUN: %check_clang_tidy %s bugprone-parent-virtual-call %t
+
+extern int f();
+
+class A {
+public:
+  A() = default;
+  virtual ~A() = default;
+
+  virtual int virt_1() { return f() + 1; }
+  virtual int virt_2() { return f() + 2; }
+
+  int non_virt() { return f() + 3; }
+  static int stat() { return f() + 4; }
+};
+
+class B : public A {
+public:
+  B() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+
+class C : public B {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_1() override { return B::virt_1() + B::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_2() override { return B::virt_1() + B::virt_1(); }
+
+  // Test that non-virtual and static methods are not affected by this cherker.
+  int method_c() { return A::stat() + A::non_virt(); }
+};
+
+// Test that the check affects grand-grand..-parent calls too.
+class D : public C {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_1() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_2() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+};
+
+// Test classes in anonymous namespaces.
+namespace {
+class BN : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+} // namespace N
+
+class CN : public BN {
+public:
+  int virt_1() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean '(anonymous namespace)::BN'?
+  // CHECK-FIXES:  int virt_1() override { return BN::virt_1() + BN::virt_1(); }
+  int virt_2() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean '(anonymous namespace)::BN'?
+  // CHECK-FIXES:  int virt_2() override { return BN::virt_1() + BN::virt_1(); }
+};
+
+// Test multiple inheritance fixes
+class AA {
+public:
+  AA() = default;
+  virtual ~AA() = default;
+
+  virtual int virt_1() { return f() + 1; }
+  virtual int virt_2() { return f() + 2; }
+
+  int non_virt() { return f() + 3; }
+  static int stat() { return f() + 4; }
+};
+
+class BB_1 : virtual public AA {
+public:
+  BB_1() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return AA::virt_1() + 3; }
+  int virt_2() override { return AA::virt_2() + 4; }
+};
+
+class BB_2 : virtual public AA {
+public:
+BB_2() = default;
+};
+
+class CC : public BB_1, public BB_2 {
+public:
+  int virt_1() override { return AA::virt_1() + 3; }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'AA::virt_1' is a grand-parent's method, not parent's. Did you mean 'BB_1' or 'BB_2'? [bugprone-parent-virtual-call]
+  // No fix available due to multiple choice of parent class.
+};
+
+// Test templated classes.
+template  class BF : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+};
+
+class CF : public BF {
+public:
+  int virt_1() override { return A::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'BF'?
+  // CHECK-FIXES:  int virt_1() override { return BF::virt_1(); }
+};
Index: docs/clang

[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-09 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 137781.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/bugprone/ParentVirtualCallCheck.cpp
  clang-tidy/bugprone/ParentVirtualCallCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-parent-virtual-call.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/bugprone-parent-virtual-call.cpp

Index: test/clang-tidy/bugprone-parent-virtual-call.cpp
===
--- /dev/null
+++ test/clang-tidy/bugprone-parent-virtual-call.cpp
@@ -0,0 +1,116 @@
+// RUN: %check_clang_tidy %s bugprone-parent-virtual-call %t
+
+extern int f();
+
+class A {
+public:
+  A() = default;
+  virtual ~A() = default;
+
+  virtual int virt_1() { return f() + 1; }
+  virtual int virt_2() { return f() + 2; }
+
+  int non_virt() { return f() + 3; }
+  static int stat() { return f() + 4; }
+};
+
+class B : public A {
+public:
+  B() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+
+class C : public B {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_1() override { return B::virt_1() + B::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_2() override { return B::virt_1() + B::virt_1(); }
+
+  // Test that non-virtual and static methods are not affected by this cherker.
+  int method_c() { return A::stat() + A::non_virt(); }
+};
+
+// Test that the check affects grand-grand..-parent calls too.
+class D : public C {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_1() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_2() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+};
+
+// Test classes in anonymous namespaces.
+namespace {
+class BN : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+} // namespace N
+
+class CN : public BN {
+public:
+  int virt_1() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean '(anonymous namespace)::BN'?
+  // CHECK-FIXES:  int virt_1() override { return BN::virt_1() + BN::virt_1(); }
+  int virt_2() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean '(anonymous namespace)::BN'?
+  // CHECK-FIXES:  int virt_2() override { return BN::virt_1() + BN::virt_1(); }
+};
+
+// Test multiple inheritance fixes
+class AA {
+public:
+  AA() = default;
+  virtual ~AA() = default;
+
+  virtual int virt_1() { return f() + 1; }
+  virtual int virt_2() { return f() + 2; }
+
+  int non_virt() { return f() + 3; }
+  static int stat() { return f() + 4; }
+};
+
+class BB_1 : virtual public AA {
+public:
+  BB_1() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return AA::virt_1() + 3; }
+  int virt_2() override { return AA::virt_2() + 4; }
+};
+
+class BB_2 : virtual public AA {
+public:
+BB_2() = default;
+};
+
+class CC : public BB_1, public BB_2 {
+public:
+  int virt_1() override { return AA::virt_1() + 3; }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'AA::virt_1' is a grand-parent's method, not parent's. Did you mean 'BB_1' or 'BB_2'? [bugprone-parent-virtual-call]
+  // No fix available due to multiple choise of parent class.
+};
+
+// Test templated classes.
+template  class BF : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+};
+
+class CF : public BF {
+public:
+  int virt_1() override { return A::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'BF'?
+  // CHECK-FIXES:  int virt_1() override { return BF::virt_1(); }
+};
Index: docs/clang

[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-09 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added inline comments.



Comment at: clang-tidy/bugprone/ParentVirtualCallCheck.cpp:152
+Member->getQualifierLoc().getSourceRange(),
+GetNameAsString(*(Parents.front())) + "::");
+  }

malcolm.parsons wrote:
> What does this do for templated parent classes?
Please see my last test case in updated revision.



Comment at: docs/clang-tidy/checks/bugprone-parent-virtual-call.rst:6
+
+FIXME: Describe what patterns does the check detect and why. Give examples.

malcolm.parsons wrote:
> FIXME.
Oops. Thanks!



Comment at: test/clang-tidy/bugprone-parent-virtual-call.cpp:102
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'AA::virt_1' is a 
grand-parent's method, not parent's. Did you mean 'BB_1' or 'BB_2'? 
[bugprone-parent-virtual-call]
+  // No fix available due to multiple choise of parent class.
+};

malcolm.parsons wrote:
> typo: choice
Thanks!


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295



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


[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-09 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 137787.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/bugprone/ParentVirtualCallCheck.cpp
  clang-tidy/bugprone/ParentVirtualCallCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-parent-virtual-call.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/bugprone-parent-virtual-call.cpp

Index: test/clang-tidy/bugprone-parent-virtual-call.cpp
===
--- /dev/null
+++ test/clang-tidy/bugprone-parent-virtual-call.cpp
@@ -0,0 +1,116 @@
+// RUN: %check_clang_tidy %s bugprone-parent-virtual-call %t
+
+extern int f();
+
+class A {
+public:
+  A() = default;
+  virtual ~A() = default;
+
+  virtual int virt_1() { return f() + 1; }
+  virtual int virt_2() { return f() + 2; }
+
+  int non_virt() { return f() + 3; }
+  static int stat() { return f() + 4; }
+};
+
+class B : public A {
+public:
+  B() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+
+class C : public B {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_1() override { return B::virt_1() + B::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_2() override { return B::virt_1() + B::virt_1(); }
+
+  // Test that non-virtual and static methods are not affected by this cherker.
+  int method_c() { return A::stat() + A::non_virt(); }
+};
+
+// Test that the check affects grand-grand..-parent calls too.
+class D : public C {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_1() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_2() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+};
+
+// Test classes in anonymous namespaces.
+namespace {
+class BN : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+} // namespace N
+
+class CN : public BN {
+public:
+  int virt_1() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean '(anonymous namespace)::BN'?
+  // CHECK-FIXES:  int virt_1() override { return BN::virt_1() + BN::virt_1(); }
+  int virt_2() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean '(anonymous namespace)::BN'?
+  // CHECK-FIXES:  int virt_2() override { return BN::virt_1() + BN::virt_1(); }
+};
+
+// Test multiple inheritance fixes
+class AA {
+public:
+  AA() = default;
+  virtual ~AA() = default;
+
+  virtual int virt_1() { return f() + 1; }
+  virtual int virt_2() { return f() + 2; }
+
+  int non_virt() { return f() + 3; }
+  static int stat() { return f() + 4; }
+};
+
+class BB_1 : virtual public AA {
+public:
+  BB_1() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return AA::virt_1() + 3; }
+  int virt_2() override { return AA::virt_2() + 4; }
+};
+
+class BB_2 : virtual public AA {
+public:
+BB_2() = default;
+};
+
+class CC : public BB_1, public BB_2 {
+public:
+  int virt_1() override { return AA::virt_1() + 3; }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'AA::virt_1' is a grand-parent's method, not parent's. Did you mean 'BB_1' or 'BB_2'? [bugprone-parent-virtual-call]
+  // No fix available due to multiple choice of parent class.
+};
+
+// Test templated classes.
+template  class BF : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+};
+
+class CF : public BF {
+public:
+  int virt_1() override { return A::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'BF'?
+  // CHECK-FIXES:  int virt_1() override { return BF::virt_1(); }
+};
Index: docs/clang

[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-10 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 137911.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/bugprone/ParentVirtualCallCheck.cpp
  clang-tidy/bugprone/ParentVirtualCallCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-parent-virtual-call.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/bugprone-parent-virtual-call.cpp

Index: test/clang-tidy/bugprone-parent-virtual-call.cpp
===
--- /dev/null
+++ test/clang-tidy/bugprone-parent-virtual-call.cpp
@@ -0,0 +1,129 @@
+// RUN: %check_clang_tidy %s bugprone-parent-virtual-call %t
+
+extern int foo();
+
+class A {
+public:
+  A() = default;
+  virtual ~A() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class B : public A {
+public:
+  B() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+
+class C : public B {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_1() override { return B::virt_1() + B::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_2() override { return B::virt_1() + B::virt_1(); }
+
+  // Test that non-virtual and static methods are not affected by this cherker.
+  int method_c() { return A::stat() + A::non_virt(); }
+};
+
+// Test that the check affects grand-grand..-parent calls too.
+class D : public C {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_1() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_2() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+};
+
+// Test classes in anonymous namespaces.
+namespace {
+class BN : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+} // namespace N
+
+class CN : public BN {
+public:
+  int virt_1() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean '(anonymous namespace)::BN'?
+  // CHECK-FIXES:  int virt_1() override { return BN::virt_1() + BN::virt_1(); }
+  int virt_2() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean '(anonymous namespace)::BN'?
+  // CHECK-FIXES:  int virt_2() override { return BN::virt_1() + BN::virt_1(); }
+};
+
+// Test multiple inheritance fixes
+class AA {
+public:
+  AA() = default;
+  virtual ~AA() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class BB_1 : virtual public AA {
+public:
+  BB_1() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return AA::virt_1() + 3; }
+  int virt_2() override { return AA::virt_2() + 4; }
+};
+
+class BB_2 : virtual public AA {
+public:
+BB_2() = default;
+};
+
+class CC : public BB_1, public BB_2 {
+public:
+  int virt_1() override { return AA::virt_1() + 3; }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'AA::virt_1' is a grand-parent's method, not parent's. Did you mean 'BB_1' or 'BB_2'? [bugprone-parent-virtual-call]
+  // No fix available due to multiple choice of parent class.
+};
+
+// Test templated classes.
+template  class BF : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+};
+
+// Test templated parent class.
+class CF : public BF {
+public:
+  int virt_1() override { return A::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'BF'?
+  // CHECK-FIXES:  int virt_1() over

[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-11 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis marked an inline comment as done.
zinovy.nis added inline comments.



Comment at: test/clang-tidy/bugprone-parent-virtual-call.cpp:125
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's 
method, not parent's. Did you mean 'BF'?
+  // CHECK-FIXES:  int virt_1() override { return BF::virt_1(); }
+};

malcolm.parsons wrote:
> Does this fixit compile?
Thanks for pointing. Hope I fixed this case in the latest patch. Please have a 
look at it.



Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295



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


[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-11 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 137951.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/bugprone/ParentVirtualCallCheck.cpp
  clang-tidy/bugprone/ParentVirtualCallCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-parent-virtual-call.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/bugprone-parent-virtual-call.cpp

Index: test/clang-tidy/bugprone-parent-virtual-call.cpp
===
--- /dev/null
+++ test/clang-tidy/bugprone-parent-virtual-call.cpp
@@ -0,0 +1,129 @@
+// RUN: %check_clang_tidy %s bugprone-parent-virtual-call %t
+
+extern int foo();
+
+class A {
+public:
+  A() = default;
+  virtual ~A() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class B : public A {
+public:
+  B() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+
+class C : public B {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_1() override { return B::virt_1() + B::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_2() override { return B::virt_1() + B::virt_1(); }
+
+  // Test that non-virtual and static methods are not affected by this cherker.
+  int method_c() { return A::stat() + A::non_virt(); }
+};
+
+// Test that the check affects grand-grand..-parent calls too.
+class D : public C {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_1() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_2() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+};
+
+// Test classes in anonymous namespaces.
+namespace {
+class BN : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+} // namespace N
+
+class CN : public BN {
+public:
+  int virt_1() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'BN'?
+  // CHECK-FIXES:  int virt_1() override { return BN::virt_1() + BN::virt_1(); }
+  int virt_2() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'BN'?
+  // CHECK-FIXES:  int virt_2() override { return BN::virt_1() + BN::virt_1(); }
+};
+
+// Test multiple inheritance fixes
+class AA {
+public:
+  AA() = default;
+  virtual ~AA() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class BB_1 : virtual public AA {
+public:
+  BB_1() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return AA::virt_1() + 3; }
+  int virt_2() override { return AA::virt_2() + 4; }
+};
+
+class BB_2 : virtual public AA {
+public:
+BB_2() = default;
+};
+
+class CC : public BB_1, public BB_2 {
+public:
+  int virt_1() override { return AA::virt_1() + 3; }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'AA::virt_1' is a grand-parent's method, not parent's. Did you mean 'BB_1' or 'BB_2'? [bugprone-parent-virtual-call]
+  // No fix available due to multiple choice of parent class.
+};
+
+// Test templated classes.
+template  class BF : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+};
+
+// Test templated parent class.
+class CF : public BF {
+public:
+  int virt_1() override { return A::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'BF'?
+  // CHECK-FIXES:  int virt_1() override { return BF::virt_1(); }
+};
+
+// Test b

[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-11 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 137952.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/bugprone/ParentVirtualCallCheck.cpp
  clang-tidy/bugprone/ParentVirtualCallCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-parent-virtual-call.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/bugprone-parent-virtual-call.cpp

Index: test/clang-tidy/bugprone-parent-virtual-call.cpp
===
--- /dev/null
+++ test/clang-tidy/bugprone-parent-virtual-call.cpp
@@ -0,0 +1,129 @@
+// RUN: %check_clang_tidy %s bugprone-parent-virtual-call %t
+
+extern int foo();
+
+class A {
+public:
+  A() = default;
+  virtual ~A() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class B : public A {
+public:
+  B() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+
+class C : public B {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_1() override { return B::virt_1() + B::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_2() override { return B::virt_1() + B::virt_1(); }
+
+  // Test that non-virtual and static methods are not affected by this cherker.
+  int method_c() { return A::stat() + A::non_virt(); }
+};
+
+// Test that the check affects grand-grand..-parent calls too.
+class D : public C {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_1() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_2() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+};
+
+// Test classes in anonymous namespaces.
+namespace {
+class BN : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+} // namespace N
+
+class CN : public BN {
+public:
+  int virt_1() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'BN'?
+  // CHECK-FIXES:  int virt_1() override { return BN::virt_1() + BN::virt_1(); }
+  int virt_2() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'BN'?
+  // CHECK-FIXES:  int virt_2() override { return BN::virt_1() + BN::virt_1(); }
+};
+
+// Test multiple inheritance fixes
+class AA {
+public:
+  AA() = default;
+  virtual ~AA() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class BB_1 : virtual public AA {
+public:
+  BB_1() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return AA::virt_1() + 3; }
+  int virt_2() override { return AA::virt_2() + 4; }
+};
+
+class BB_2 : virtual public AA {
+public:
+BB_2() = default;
+};
+
+class CC : public BB_1, public BB_2 {
+public:
+  int virt_1() override { return AA::virt_1() + 3; }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'AA::virt_1' is a grand-parent's method, not parent's. Did you mean 'BB_1' or 'BB_2'? [bugprone-parent-virtual-call]
+  // No fix available due to multiple choice of parent class.
+};
+
+// Test templated classes.
+template  class BF : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+};
+
+// Test templated parent class.
+class CF : public BF {
+public:
+  int virt_1() override { return A::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'BF'?
+  // CHECK-FIXES:  int virt_1() override { return BF::virt_1(); }
+};
+
+// Test b

[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-11 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 137953.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/bugprone/ParentVirtualCallCheck.cpp
  clang-tidy/bugprone/ParentVirtualCallCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-parent-virtual-call.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/bugprone-parent-virtual-call.cpp

Index: test/clang-tidy/bugprone-parent-virtual-call.cpp
===
--- /dev/null
+++ test/clang-tidy/bugprone-parent-virtual-call.cpp
@@ -0,0 +1,129 @@
+// RUN: %check_clang_tidy %s bugprone-parent-virtual-call %t
+
+extern int foo();
+
+class A {
+public:
+  A() = default;
+  virtual ~A() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class B : public A {
+public:
+  B() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+
+class C : public B {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_1() override { return B::virt_1() + B::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_2() override { return B::virt_1() + B::virt_1(); }
+
+  // Test that non-virtual and static methods are not affected by this cherker.
+  int method_c() { return A::stat() + A::non_virt(); }
+};
+
+// Test that the check affects grand-grand..-parent calls too.
+class D : public C {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_1() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_2() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+};
+
+// Test classes in anonymous namespaces.
+namespace {
+class BN : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+} // namespace N
+
+class CN : public BN {
+public:
+  int virt_1() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'BN'?
+  // CHECK-FIXES:  int virt_1() override { return BN::virt_1() + BN::virt_1(); }
+  int virt_2() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'BN'?
+  // CHECK-FIXES:  int virt_2() override { return BN::virt_1() + BN::virt_1(); }
+};
+
+// Test multiple inheritance fixes
+class AA {
+public:
+  AA() = default;
+  virtual ~AA() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class BB_1 : virtual public AA {
+public:
+  BB_1() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return AA::virt_1() + 3; }
+  int virt_2() override { return AA::virt_2() + 4; }
+};
+
+class BB_2 : virtual public AA {
+public:
+BB_2() = default;
+};
+
+class CC : public BB_1, public BB_2 {
+public:
+  int virt_1() override { return AA::virt_1() + 3; }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'AA::virt_1' is a grand-parent's method, not parent's. Did you mean 'BB_1' or 'BB_2'? [bugprone-parent-virtual-call]
+  // No fix available due to multiple choice of parent class.
+};
+
+// Test templated classes.
+template  class BF : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+};
+
+// Test templated parent class.
+class CF : public BF {
+public:
+  int virt_1() override { return A::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'BF'?
+  // CHECK-FIXES:  int virt_1() override { return BF::virt_1(); }
+};
+
+// Test b

[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-13 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 138254.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/bugprone/ParentVirtualCallCheck.cpp
  clang-tidy/bugprone/ParentVirtualCallCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-parent-virtual-call.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/bugprone-parent-virtual-call.cpp

Index: test/clang-tidy/bugprone-parent-virtual-call.cpp
===
--- /dev/null
+++ test/clang-tidy/bugprone-parent-virtual-call.cpp
@@ -0,0 +1,127 @@
+// RUN: %check_clang_tidy %s bugprone-parent-virtual-call %t
+
+extern int foo();
+
+class A {
+public:
+  A() = default;
+  virtual ~A() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class B : public A {
+public:
+  B() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+
+class C : public B {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_1() override { return B::virt_1() + B::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_2() override { return B::virt_1() + B::virt_1(); }
+
+  // Test that non-virtual and static methods are not affected by this cherker.
+  int method_c() { return A::stat() + A::non_virt(); }
+};
+
+// Test that the check affects grand-grand..-parent calls too.
+class D : public C {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_1() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_2() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+};
+
+// Test classes in anonymous namespaces.
+namespace {
+class BN : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+} // namespace N
+
+class CN : public BN {
+public:
+  int virt_1() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'BN'?
+  // CHECK-FIXES:  int virt_1() override { return BN::virt_1() + BN::virt_1(); }
+  int virt_2() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'BN'?
+  // CHECK-FIXES:  int virt_2() override { return BN::virt_1() + BN::virt_1(); }
+};
+
+// Test multiple inheritance fixes
+class AA {
+public:
+  AA() = default;
+  virtual ~AA() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class BB_1 : virtual public AA {
+public:
+  BB_1() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return AA::virt_1() + 3; }
+  int virt_2() override { return AA::virt_2() + 4; }
+};
+
+class BB_2 : virtual public AA {
+public:
+BB_2() = default;
+};
+
+class CC : public BB_1, public BB_2 {
+public:
+  int virt_1() override { return AA::virt_1() + 3; }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'AA::virt_1' is a grand-parent's method, not parent's. Did you mean 'BB_1' or 'BB_2'? [bugprone-parent-virtual-call]
+  // No fix available due to multiple choice of parent class.
+};
+
+// Test templated classes.
+template  class BF : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+};
+
+// Test templated parent class.
+class CF : public BF {
+public:
+  int virt_1() override { return A::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'BF'?
+};
+
+// Test both templated class and its parent class.
+template  class DF : pub

[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-13 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis marked an inline comment as done and an inline comment as not done.
zinovy.nis added inline comments.



Comment at: test/clang-tidy/bugprone-parent-virtual-call.cpp:115
+  int virt_1() override { return A::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's 
method, not parent's. Did you mean 'BF'?
+  // CHECK-FIXES:  int virt_1() override { return BF::virt_1(); }

malcolm.parsons wrote:
> There isn't an F in scope.
> The base class isn't a dependent type here, so no template params are needed.
Finally I decided not to propose a fix for templated parent.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295



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


[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-15 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 138596.
zinovy.nis marked 10 inline comments as done.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/bugprone/ParentVirtualCallCheck.cpp
  clang-tidy/bugprone/ParentVirtualCallCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-parent-virtual-call.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/bugprone-parent-virtual-call.cpp

Index: test/clang-tidy/bugprone-parent-virtual-call.cpp
===
--- /dev/null
+++ test/clang-tidy/bugprone-parent-virtual-call.cpp
@@ -0,0 +1,127 @@
+// RUN: %check_clang_tidy %s bugprone-parent-virtual-call %t
+
+extern int foo();
+
+class A {
+public:
+  A() = default;
+  virtual ~A() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class B : public A {
+public:
+  B() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+
+class C : public B {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_1() override { return B::virt_1() + B::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'B'?
+  // CHECK-FIXES:  int virt_2() override { return B::virt_1() + B::virt_1(); }
+
+  // Test that non-virtual and static methods are not affected by this cherker.
+  int method_c() { return A::stat() + A::non_virt(); }
+};
+
+// Test that the check affects grand-grand..-parent calls too.
+class D : public C {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_1() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'B::virt_1' is a grand-parent's method, not parent's. Did you mean 'C'?
+  // CHECK-FIXES:  int virt_2() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+};
+
+// Test classes in anonymous namespaces.
+namespace {
+class BN : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+} // namespace N
+
+class CN : public BN {
+public:
+  int virt_1() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'BN'?
+  // CHECK-FIXES:  int virt_1() override { return BN::virt_1() + BN::virt_1(); }
+  int virt_2() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'BN'?
+  // CHECK-FIXES:  int virt_2() override { return BN::virt_1() + BN::virt_1(); }
+};
+
+// Test multiple inheritance fixes
+class AA {
+public:
+  AA() = default;
+  virtual ~AA() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class BB_1 : virtual public AA {
+public:
+  BB_1() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return AA::virt_1() + 3; }
+  int virt_2() override { return AA::virt_2() + 4; }
+};
+
+class BB_2 : virtual public AA {
+public:
+BB_2() = default;
+};
+
+class CC : public BB_1, public BB_2 {
+public:
+  int virt_1() override { return AA::virt_1() + 3; }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'AA::virt_1' is a grand-parent's method, not parent's. Did you mean 'BB_1' or 'BB_2'? [bugprone-parent-virtual-call]
+  // No fix available due to multiple choice of parent class.
+};
+
+// Test templated classes.
+template  class BF : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+};
+
+// Test templated parent class.
+class CF : public BF {
+public:
+  int virt_1() override { return A::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: 'A::virt_1' is a grand-parent's method, not parent's. Did you mean 'BF'?
+};
+
+// Test both templated class a

[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-15 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 138597.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/bugprone/ParentVirtualCallCheck.cpp
  clang-tidy/bugprone/ParentVirtualCallCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-parent-virtual-call.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/bugprone-parent-virtual-call.cpp

Index: test/clang-tidy/bugprone-parent-virtual-call.cpp
===
--- /dev/null
+++ test/clang-tidy/bugprone-parent-virtual-call.cpp
@@ -0,0 +1,139 @@
+// RUN: %check_clang_tidy %s bugprone-parent-virtual-call %t
+
+extern int foo();
+
+class A {
+public:
+  A() = default;
+  virtual ~A() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class B : public A {
+public:
+  B() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+
+class C : public B {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: Qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'B'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_1() override { return B::virt_1() + B::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: Qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'B'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_2() override { return B::virt_1() + B::virt_1(); }
+
+  // Test that non-virtual and static methods are not affected by this cherker.
+  int method_c() { return A::stat() + A::non_virt(); }
+};
+
+// Test that the check affects grand-grand..-parent calls too.
+class D : public C {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: Qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'C'? [bugprone-parent-virtual-call]
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: Qualified function name B::virt_1 refers to a function not from a direct base class; did you mean 'C'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_1() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: Qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'C'? [bugprone-parent-virtual-call]
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: Qualified function name B::virt_1 refers to a function not from a direct base class; did you mean 'C'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_2() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+};
+
+// Test classes in anonymous namespaces.
+namespace {
+class BN : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+} // namespace N
+
+class CN : public BN {
+public:
+  int virt_1() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: Qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'BN'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_1() override { return BN::virt_1() + BN::virt_1(); }
+  int virt_2() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: Qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'BN'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_2() override { return BN::virt_1() + BN::virt_1(); }
+};
+
+// Test multiple inheritance fixes
+class AA {
+public:
+  AA() = default;
+  virtual ~AA() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class BB_1 : virtual public AA {
+public:
+  BB_1() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return AA::virt_1() + 3; }
+  int virt_2() override { return AA::virt_2() + 4; }
+};
+
+class BB_2 : virtual public AA {
+public:
+BB_2() = default;
+};
+
+class CC : public BB_1, public BB_2 {
+public:
+  int virt_1() override { return AA::virt_1() + 3; }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: Qualified function name AA::virt_1 refers to a function not from a direct base class; did you mean 'BB_1' or 'BB_2'? [bugprone-parent-virt

[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-15 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added inline comments.



Comment at: clang-tidy/bugprone/ParentVirtualCallCheck.cpp:128
+  diag(Member->getQualifierLoc().getSourceRange().getBegin(),
+   "'%0' is a grand-parent's method, not parent's. Did you mean %1?")
+  << CalleeName << ParentsStr;

aaron.ballman wrote:
> The diagnostic should not contain punctuation aside from the question mark.
> 
> Also, the diagnostic uses some novel terminology in "grandparent's method". 
> How about: "qualified function name %0 refers to a function that is not 
> defined by a direct base class; did you mean %1?"
"is not defined by a direct base class" is not a correct proposal. Issues that 
this check finds are all about calling a grand-parent's method instead of 
parent's whether base class defines this method or not.

How about 

> Qualified function name %0 refers to a function not from a direct base class; 
> did you mean %1?

?


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295



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


[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-15 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 138598.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/bugprone/ParentVirtualCallCheck.cpp
  clang-tidy/bugprone/ParentVirtualCallCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-parent-virtual-call.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/bugprone-parent-virtual-call.cpp

Index: test/clang-tidy/bugprone-parent-virtual-call.cpp
===
--- /dev/null
+++ test/clang-tidy/bugprone-parent-virtual-call.cpp
@@ -0,0 +1,139 @@
+// RUN: %check_clang_tidy %s bugprone-parent-virtual-call %t
+
+extern int foo();
+
+class A {
+public:
+  A() = default;
+  virtual ~A() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class B : public A {
+public:
+  B() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+
+class C : public B {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'B'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_1() override { return B::virt_1() + B::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'B'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_2() override { return B::virt_1() + B::virt_1(); }
+
+  // Test that non-virtual and static methods are not affected by this cherker.
+  int method_c() { return A::stat() + A::non_virt(); }
+};
+
+// Test that the check affects grand-grand..-parent calls too.
+class D : public C {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'C'? [bugprone-parent-virtual-call]
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: qualified function name B::virt_1 refers to a function not from a direct base class; did you mean 'C'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_1() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'C'? [bugprone-parent-virtual-call]
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: qualified function name B::virt_1 refers to a function not from a direct base class; did you mean 'C'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_2() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+};
+
+// Test classes in anonymous namespaces.
+namespace {
+class BN : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+} // namespace N
+
+class CN : public BN {
+public:
+  int virt_1() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'BN'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_1() override { return BN::virt_1() + BN::virt_1(); }
+  int virt_2() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'BN'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_2() override { return BN::virt_1() + BN::virt_1(); }
+};
+
+// Test multiple inheritance fixes
+class AA {
+public:
+  AA() = default;
+  virtual ~AA() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class BB_1 : virtual public AA {
+public:
+  BB_1() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return AA::virt_1() + 3; }
+  int virt_2() override { return AA::virt_2() + 4; }
+};
+
+class BB_2 : virtual public AA {
+public:
+BB_2() = default;
+};
+
+class CC : public BB_1, public BB_2 {
+public:
+  int virt_1() override { return AA::virt_1() + 3; }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name AA::virt_1 refers to a function not from a direct base class; did you mean 'BB_1' or 'BB_2'? [bugprone-parent-virt

[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-15 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 138599.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/bugprone/ParentVirtualCallCheck.cpp
  clang-tidy/bugprone/ParentVirtualCallCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-parent-virtual-call.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/bugprone-parent-virtual-call.cpp

Index: test/clang-tidy/bugprone-parent-virtual-call.cpp
===
--- /dev/null
+++ test/clang-tidy/bugprone-parent-virtual-call.cpp
@@ -0,0 +1,139 @@
+// RUN: %check_clang_tidy %s bugprone-parent-virtual-call %t
+
+extern int foo();
+
+class A {
+public:
+  A() = default;
+  virtual ~A() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class B : public A {
+public:
+  B() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+
+class C : public B {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'B'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_1() override { return B::virt_1() + B::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'B'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_2() override { return B::virt_1() + B::virt_1(); }
+
+  // Test that non-virtual and static methods are not affected by this cherker.
+  int method_c() { return A::stat() + A::non_virt(); }
+};
+
+// Test that the check affects grand-grand..-parent calls too.
+class D : public C {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'C'? [bugprone-parent-virtual-call]
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: qualified function name B::virt_1 refers to a function not from a direct base class; did you mean 'C'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_1() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'C'? [bugprone-parent-virtual-call]
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: qualified function name B::virt_1 refers to a function not from a direct base class; did you mean 'C'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_2() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+};
+
+// Test classes in anonymous namespaces.
+namespace {
+class BN : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+} // namespace N
+
+class CN : public BN {
+public:
+  int virt_1() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'BN'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_1() override { return BN::virt_1() + BN::virt_1(); }
+  int virt_2() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'BN'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_2() override { return BN::virt_1() + BN::virt_1(); }
+};
+
+// Test multiple inheritance fixes
+class AA {
+public:
+  AA() = default;
+  virtual ~AA() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class BB_1 : virtual public AA {
+public:
+  BB_1() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return AA::virt_1() + 3; }
+  int virt_2() override { return AA::virt_2() + 4; }
+};
+
+class BB_2 : virtual public AA {
+public:
+BB_2() = default;
+};
+
+class CC : public BB_1, public BB_2 {
+public:
+  int virt_1() override { return AA::virt_1() + 3; }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name AA::virt_1 refers to a function not from a direct base class; did you mean 'BB_1' or 'BB_2'? [bugprone-parent-virt

[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-15 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 138601.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/bugprone/ParentVirtualCallCheck.cpp
  clang-tidy/bugprone/ParentVirtualCallCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-parent-virtual-call.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/bugprone-parent-virtual-call.cpp

Index: test/clang-tidy/bugprone-parent-virtual-call.cpp
===
--- /dev/null
+++ test/clang-tidy/bugprone-parent-virtual-call.cpp
@@ -0,0 +1,139 @@
+// RUN: %check_clang_tidy %s bugprone-parent-virtual-call %t
+
+extern int foo();
+
+class A {
+public:
+  A() = default;
+  virtual ~A() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class B : public A {
+public:
+  B() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+
+class C : public B {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'B'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_1() override { return B::virt_1() + B::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'B'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_2() override { return B::virt_1() + B::virt_1(); }
+
+  // Test that non-virtual and static methods are not affected by this cherker.
+  int method_c() { return A::stat() + A::non_virt(); }
+};
+
+// Test that the check affects grand-grand..-parent calls too.
+class D : public C {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'C'? [bugprone-parent-virtual-call]
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: qualified function name B::virt_1 refers to a function not from a direct base class; did you mean 'C'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_1() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'C'? [bugprone-parent-virtual-call]
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: qualified function name B::virt_1 refers to a function not from a direct base class; did you mean 'C'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_2() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+};
+
+// Test classes in anonymous namespaces.
+namespace {
+class BN : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+} // namespace N
+
+class CN : public BN {
+public:
+  int virt_1() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'BN'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_1() override { return BN::virt_1() + BN::virt_1(); }
+  int virt_2() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name A::virt_1 refers to a function not from a direct base class; did you mean 'BN'? [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_2() override { return BN::virt_1() + BN::virt_1(); }
+};
+
+// Test multiple inheritance fixes
+class AA {
+public:
+  AA() = default;
+  virtual ~AA() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class BB_1 : virtual public AA {
+public:
+  BB_1() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return AA::virt_1() + 3; }
+  int virt_2() override { return AA::virt_2() + 4; }
+};
+
+class BB_2 : virtual public AA {
+public:
+BB_2() = default;
+};
+
+class CC : public BB_1, public BB_2 {
+public:
+  int virt_1() override { return AA::virt_1() + 3; }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name AA::virt_1 refers to a function not from a direct base class; did you mean 'BB_1' or 'BB_2'? [bugprone-parent-virt

[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-15 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added inline comments.



Comment at: test/clang-tidy/bugprone-parent-virtual-call.cpp:127
+// Just to instantiate DF.
+int bar() { return (new DF())->virt_1(); }

aaron.ballman wrote:
> What should happen in this case?
> ```
> struct Base {
>   virtual void f() {}
> };
> 
> struct Intermediary : Base {
> };
> 
> struct Derived : Intermediary {
>   void f() override {
> Base::f(); // I would expect this not to diagnose
>   }
> };
> ```
> This would be a reasonable test case to add.
Please see `// Test virtual method is diagnosted although not overridden in 
parent.` section in the test file.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295



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


[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-16 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added inline comments.



Comment at: test/clang-tidy/bugprone-parent-virtual-call.cpp:105
+
+// Test virtual method is diagnosted although not overridden in parent.
+class BI : public A {

aaron.ballman wrote:
> Typo: diagnosted -> diagnosed
oops, thanks.



Comment at: test/clang-tidy/bugprone-parent-virtual-call.cpp:113
+  int virt_1() override { return A::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name 
A::virt_1 refers to a function not from a direct base class; did you mean 'BI'? 
[bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_1() override { return BI::virt_1(); }

aaron.ballman wrote:
> This seems like a false positive to me. Yes, the virtual function is 
> technically exposed in `BI`, but why is the programmer obligated to call that 
> one rather than the one from `A`, which is written in the source?
IMHO it's a matter of safety. Today virt_1() is not overridden in BI, but 
tomorrow someone will implement BI::virt_1() and it will silently lead to bugs 
or whatever.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295



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


[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-16 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added inline comments.



Comment at: test/clang-tidy/bugprone-parent-virtual-call.cpp:113
+  int virt_1() override { return A::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name 
A::virt_1 refers to a function not from a direct base class; did you mean 'BI'? 
[bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_1() override { return BI::virt_1(); }

aaron.ballman wrote:
> zinovy.nis wrote:
> > aaron.ballman wrote:
> > > This seems like a false positive to me. Yes, the virtual function is 
> > > technically exposed in `BI`, but why is the programmer obligated to call 
> > > that one rather than the one from `A`, which is written in the source?
> > IMHO it's a matter of safety. Today virt_1() is not overridden in BI, but 
> > tomorrow someone will implement BI::virt_1() and it will silently lead to 
> > bugs or whatever.
> If tomorrow someone implements `BI::virt_1()`, then the check will start 
> diagnosing at that point.
Correct, but anyway I don't think it's a problem.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295



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


[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-18 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 138858.
zinovy.nis edited the summary of this revision.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/bugprone/ParentVirtualCallCheck.cpp
  clang-tidy/bugprone/ParentVirtualCallCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-parent-virtual-call.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/bugprone-parent-virtual-call.cpp

Index: test/clang-tidy/bugprone-parent-virtual-call.cpp
===
--- /dev/null
+++ test/clang-tidy/bugprone-parent-virtual-call.cpp
@@ -0,0 +1,138 @@
+// RUN: %check_clang_tidy %s bugprone-parent-virtual-call %t
+
+extern int foo();
+
+class A {
+public:
+  A() = default;
+  virtual ~A() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class B : public A {
+public:
+  B() = default;
+
+  // Nothing to fix: calls to direct parent.
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+
+class C : public B {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name A::virt_1 refers to a member which was overridden in subclass 'B' [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_1() override { return B::virt_1() + B::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name A::virt_1 refers to a member which was overridden in subclass 'B' [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_2() override { return B::virt_1() + B::virt_1(); }
+
+  // Test that non-virtual and static methods are not affected by this cherker.
+  int method_c() { return A::stat() + A::non_virt(); }
+};
+
+// Test that the check affects grand-grand..-parent calls too.
+class D : public C {
+public:
+  int virt_1() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name A::virt_1 refers to a member which was overridden in subclass 'C' [bugprone-parent-virtual-call]
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: qualified name B::virt_1 refers to a member which was overridden in subclass 'C' [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_1() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+  int virt_2() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name A::virt_1 refers to a member which was overridden in subclass 'C' [bugprone-parent-virtual-call]
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: qualified name B::virt_1 refers to a member which was overridden in subclass 'C' [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_2() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+};
+
+// Test classes in anonymous namespaces.
+namespace {
+class BN : public A {
+public:
+  int virt_1() override { return A::virt_1() + 3; }
+  int virt_2() override { return A::virt_2() + 4; }
+};
+} // namespace N
+
+class CN : public BN {
+public:
+  int virt_1() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name A::virt_1 refers to a member which was overridden in subclass 'BN' [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_1() override { return BN::virt_1() + BN::virt_1(); }
+  int virt_2() override { return A::virt_1() + BN::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name A::virt_1 refers to a member which was overridden in subclass 'BN' [bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_2() override { return BN::virt_1() + BN::virt_1(); }
+};
+
+// Test multiple inheritance fixes
+class AA {
+public:
+  AA() = default;
+  virtual ~AA() = default;
+
+  virtual int virt_1() { return foo() + 1; }
+  virtual int virt_2() { return foo() + 2; }
+
+  int non_virt() { return foo() + 3; }
+  static int stat() { return foo() + 4; }
+};
+
+class BB_1 : virtual public AA {
+public:
+  BB_1() = default;
+
+  // Nothing to fix: calls to parent.
+  int virt_1() override { return AA::virt_1() + 3; }
+  int virt_2() override { return AA::virt_2() + 4; }
+};
+
+class BB_2 : virtual public AA {
+public:
+  BB_2() = default;
+  int virt_1() override { return AA::virt_1() + 3; }
+};
+
+class CC : public BB_1, public BB_2 {
+public:
+  int virt_1() override { return AA::virt_1() + 3; }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name AA::virt_1 refers to a member which was overridden in subclasses 'BB_1' and 'BB_2' [bugprone-parent-virtual-call]
+  // No fix available due to multiple choice of parent class.
+};
+
+// Test 

[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-18 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis marked 5 inline comments as done.
zinovy.nis added inline comments.



Comment at: test/clang-tidy/bugprone-parent-virtual-call.cpp:113
+  int virt_1() override { return A::virt_1(); }
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified function name 
A::virt_1 refers to a function not from a direct base class; did you mean 'BI'? 
[bugprone-parent-virtual-call]
+  // CHECK-FIXES:  int virt_1() override { return BI::virt_1(); }

aaron.ballman wrote:
> zinovy.nis wrote:
> > aaron.ballman wrote:
> > > zinovy.nis wrote:
> > > > aaron.ballman wrote:
> > > > > This seems like a false positive to me. Yes, the virtual function is 
> > > > > technically exposed in `BI`, but why is the programmer obligated to 
> > > > > call that one rather than the one from `A`, which is written in the 
> > > > > source?
> > > > IMHO it's a matter of safety. Today virt_1() is not overridden in BI, 
> > > > but tomorrow someone will implement BI::virt_1() and it will silently 
> > > > lead to bugs or whatever.
> > > If tomorrow someone implements `BI::virt_1()`, then the check will start 
> > > diagnosing at that point.
> > Correct, but anyway I don't think it's a problem.
> I'd prefer to see this changed to not diagnose. I don't relish the idea of 
> explaining why that code diagnoses as it stands.
Done. Now the check looks for a most recent class with the overridden method. 
Please review this change.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295



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


[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-18 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis marked 6 inline comments as done.
zinovy.nis added inline comments.



Comment at: clang-tidy/bugprone/ParentVirtualCallCheck.cpp:128
+  diag(Member->getQualifierLoc().getSourceRange().getBegin(),
+   "'%0' is a grand-parent's method, not parent's. Did you mean %1?")
+  << CalleeName << ParentsStr;

aaron.ballman wrote:
> zinovy.nis wrote:
> > aaron.ballman wrote:
> > > The diagnostic should not contain punctuation aside from the question 
> > > mark.
> > > 
> > > Also, the diagnostic uses some novel terminology in "grandparent's 
> > > method". How about: "qualified function name %0 refers to a function that 
> > > is not defined by a direct base class; did you mean %1?"
> > "is not defined by a direct base class" is not a correct proposal. Issues 
> > that this check finds are all about calling a grand-parent's method instead 
> > of parent's whether base class defines this method or not.
> > 
> > How about 
> > 
> > > Qualified function name %0 refers to a function not from a direct base 
> > > class; did you mean %1?
> > 
> > ?
> Not keen on "from", but we could use `"qualified function name %q0 refers to 
> a function that is not explicitly declared by a direct base class; did you 
> mean %1?"`
Changed to  

> qualified name %0 refers to a member which was overridden in subclass%1"




Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295



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


[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-19 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis marked 2 inline comments as done.
zinovy.nis added a comment.

Hope I satisfied all your requests now.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295



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


[PATCH] D44295: [clang-tidy] Detects and fixes calls to grand-...parent virtual methods instead of calls to parent's virtual methods

2018-03-19 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

Gentle ping)


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44295



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


[PATCH] D45927: [clang-tidy] [modernize-use-auto] Correct way to calculate a type name length for multi-token types

2018-06-15 Thread Zinovy Nis via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rCTE334829: [clang-tidy] This patch is a fix for D45405 where 
spaces were mistakenly… (authored by zinovy.nis, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D45927?vs=146677&id=151500#toc

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D45927

Files:
  clang-tidy/modernize/UseAutoCheck.cpp
  docs/clang-tidy/checks/modernize-use-auto.rst
  test/clang-tidy/modernize-use-auto-min-type-name-length.cpp

Index: test/clang-tidy/modernize-use-auto-min-type-name-length.cpp
===
--- test/clang-tidy/modernize-use-auto-min-type-name-length.cpp
+++ test/clang-tidy/modernize-use-auto-min-type-name-length.cpp
@@ -1,30 +1,85 @@
-// RUN: %check_clang_tidy %s modernize-use-auto %t -- \
-// RUN:   -config="{CheckOptions: [{key: modernize-use-auto.MinTypeNameLength, value: '5'}]}" \
-// RUN:   -- -std=c++11 -frtti
-
-extern int foo();
-
-using VeryVeryVeryLongTypeName = int;
+// RUN: %check_clang_tidy -check-suffix=0-0 %s modernize-use-auto %t  -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 0}, {key: modernize-use-auto.MinTypeNameLength, value: 0}]}" -- --std=c++11 -frtti
+// RUN: %check_clang_tidy -check-suffix=0-8 %s modernize-use-auto %t  -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 0}, {key: modernize-use-auto.MinTypeNameLength, value: 8}]}" -- --std=c++11 -frtti
+// RUN: %check_clang_tidy -check-suffix=1-0 %s modernize-use-auto %t  -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 1}, {key: modernize-use-auto.MinTypeNameLength, value: 0}]}" -- --std=c++11 -frtti
+// RUN: %check_clang_tidy -check-suffix=1-8 %s modernize-use-auto %t  -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 1}, {key: modernize-use-auto.MinTypeNameLength, value: 8}]}" -- --std=c++11 -frtti
+
+template  extern T foo();
+template  struct P {  explicit P(T t) : t_(t) {}  T t_;};
+template  P *foo_ptr();
+template  P &foo_ref();
 
 int bar() {
-  int a = static_cast(foo());
-  // strlen('int') = 4 <  5, so skip it,
-  // even strlen('VeryVeryVeryLongTypeName') > 5.
-
-  unsigned b = static_cast(foo());
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name [modernize-use-auto]
-  // CHECK-FIXES: auto b = static_cast(foo());
-
-  bool c = static_cast(foo());
-  // strlen('bool') = 4 <  5, so skip it.
-
-  const bool c1 = static_cast(foo());
-  // strlen('bool') = 4 <  5, so skip it, even there's a 'const'.
-
-  unsigned long long ull = static_cast(foo());
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name [modernize-use-auto]
-  // CHECK-FIXES: auto ull = static_cast(foo());
+  {
+// Lenth(long) = 4
+long i = static_cast(foo());
+// CHECK-FIXES-0-0: auto i = {{.*}}
+// CHECK-FIXES-0-8: long i = {{.*}}
+// CHECK-FIXES-1-0: auto  i = {{.*}}
+// CHECK-FIXES-1-8: long i = {{.*}}
+const long ci = static_cast(foo());
+// CHECK-FIXES-0-0: auto ci = {{.*}}
+// CHECK-FIXES-0-8: long ci = {{.*}}
+// CHECK-FIXES-1-0: auto  ci = {{.*}}
+// CHECK-FIXES-1-8: long ci = {{.*}}
+long *pi = static_cast(foo());
+// CHECK-FIXES-0-0: auto *pi = {{.*}}
+// CHECK-FIXES-0-8: long *pi = {{.*}}
+// CHECK-FIXES-1-0: auto pi = {{.*}}
+// CHECK-FIXES-1-8: long *pi = {{.*}}
+
+// Length(long   *) is still 5
+long  * pi2 = static_cast(foo());
+// CHECK-FIXES-0-0: auto  * pi2 = {{.*}}
+// CHECK-FIXES-0-8: long  * pi2 = {{.*}}
+// CHECK-FIXES-1-0: auto  pi2 = {{.*}}
+// CHECK-FIXES-1-8: long  * pi2 = {{.*}}
+
+// Length(long **) = 6
+long **ppi = static_cast(foo());
+// CHECK-FIXES-0-0: auto **ppi = {{.*}}
+// CHECK-FIXES-0-8: long **ppi = {{.*}}
+// CHECK-FIXES-1-0: auto ppi = {{.*}}
+// CHECK-FIXES-1-8: long **ppi = {{.*}}
+  }
+
+  {
+// Lenth(long int) = 4 + 1 + 3 = 8
+// Lenth(longint) is still 8
+long int i = static_cast(foo());
+// CHECK-FIXES-0-0: auto i = {{.*}}
+// CHECK-FIXES-0-8: auto i = {{.*}}
+// CHECK-FIXES-1-0: auto  i = {{.*}}
+// CHECK-FIXES-1-8: auto  i = {{.*}}
+
+long int *pi = static_cast(foo());
+// CHECK-FIXES-0-0: auto *pi = {{.*}}
+// CHECK-FIXES-0-8: auto *pi = {{.*}}
+// CHECK-FIXES-1-0: auto pi = {{.*}}
+// CHECK-FIXES-1-8: auto pi = {{.*}}
+  }
+
+  // Templates
+  {
+// Length(P) = 7
+P& i = static_cast&>(foo_ref());
+// CHECK-FIXES-0-0: auto& i = {{.*}}
+// CHECK-FIXES-0-8: P& i = {{.*}}
+// CHECK-FIXES-1-0: auto & i = {{.*}}
+// CHECK-FIXES-1-8: P& i = {{.*}}
+
+// Length(P) = 8
+P& pi = static_cast &>(foo_ref());
+// CHECK-FIXES-0-0: auto& pi = {{.*}}
+// CHECK-FIXES-0-8: auto& pi = {{.

[PATCH] D52771: [clang-tidy] Non-private member variables in classes (MISRA, CppCoreGuidelines, HICPP)

2018-10-11 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added inline comments.



Comment at: test/clang-tidy/misc-non-private-member-variables-in-classes.cpp:1
+// RUN: %check_clang_tidy -check-suffix=NONPRIVATE %s 
misc-non-private-member-variables-in-classes %t
+// RUN: %check_clang_tidy -check-suffix=NONPRIVATE %s 
misc-non-private-member-variables-in-classes %t -- -config='{CheckOptions: 
[{key: 
misc-non-private-member-variables-in-classes.IgnorePublicMemberVariables, 
value: 0}, {key: 
misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic,
 value: 0}]}' --

JonasToth wrote:
> lebedev.ri wrote:
> > JonasToth wrote:
> > > I would prefer multiple test-files instead of mixing them all together.
> > Hmm, no. Then the tests will have to be duplicated in N files,
> > because i really do want to see what each of these 4 configurations do on 
> > the *same* input.
> > 
> > It only looks ugly because the script only supports `-check-suffix=`,
> > and not `-check-suffixes=`, which would significantly cut down on 
> > check-lines.
> Ok, if you prefer this.
Not an issue anymore. You can use `-check-suffixes` since now.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D52771



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


[PATCH] D52971: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py to support multiple prefixes

2018-10-12 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

In https://reviews.llvm.org/D52971#1262200, @ymandel wrote:

> Hi,
>
> It looks like this change has disabled FileCheck for all clang-tidy lit tests 
> that don't use check-prefixes.  So, they all trivially pass even if their 
> CHECK... lines are wrong.  An easy repro is just to randomly modify any CHECK 
> line in a lit file (e.g. 
> llvm/tools/clang/tools/extra/test/clang-tidy/readability-avoid-const-params-in-decls.cpp)
>  and run ninja check-clang-tools.
>
> In check_clang_tidy.py, if you add back (slightly modified) lines 93-95 to 
> the else branch (line 132), it seems to fix the problem.  For example, add:
>
>   has_check_fixes = check_fixes_prefixes[0] in input_text
>   has_check_messages = check_messages_prefixes[0] in input_text
>   has_check_notes = check_notes_prefixes[0] in input_text


Oh, thanks. I'll fix it a bit later today. Sorry.


Repository:
  rL LLVM

https://reviews.llvm.org/D52971



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


[PATCH] D53194: [clang-tidy] Fix check_clang_tidy.py trivially passing default CHECK

2018-10-12 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis created this revision.
zinovy.nis added reviewers: ymandel, alexfh.
zinovy.nis added a project: clang-tools-extra.
Herald added subscribers: cfe-commits, xazax.hun.

In https://reviews.llvm.org/D52971#1262200, @ymandel wrote:

> Hi,
> 
> It looks like this change has disabled FileCheck for all clang-tidy lit tests 
> that don't use check-prefixes.  So, they all trivially pass even if their 
> CHECK... lines are wrong.  An easy repro is just to randomly modify any CHECK 
> line in a lit file (e.g. 
> llvm/tools/clang/tools/extra/test/clang-tidy/readability-avoid-const-params-in-decls.cpp)
>  and run ninja check-clang-tools.
> 
> In check_clang_tidy.py, if you add back (slightly modified) lines 93-95 to 
> the else branch (line 132), it seems to fix the problem.  For example, add:
> 
>   has_check_fixes = check_fixes_prefixes[0] in input_text
>   has_check_messages = check_messages_prefixes[0] in input_text
>   has_check_notes = check_notes_prefixes[0] in input_text


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D53194

Files:
  test/clang-tidy/check_clang_tidy.py


Index: test/clang-tidy/check_clang_tidy.py
===
--- test/clang-tidy/check_clang_tidy.py
+++ test/clang-tidy/check_clang_tidy.py
@@ -51,7 +51,7 @@
   parser.add_argument('check_name')
   parser.add_argument('temp_file_name')
   parser.add_argument('-check-suffix', '-check-suffixes',
-  default=[], type=csv,
+  default=[''], type=csv,
   help="comma-separated list of FileCheck suffixes")
 
   args, extra_args = parser.parse_known_args()
@@ -96,41 +96,37 @@
   has_check_messages = False
   has_check_notes = False
 
-  if any(args.check_suffix):
-for check in args.check_suffix:
-  if not re.match('^[A-Z0-9\-]+$', check):
-sys.exit('Only A..Z, 0..9 and "-" are ' +
-  'allowed in check suffixes list, but "%s" was given' % (check))
-
-  file_check_suffix = '-' + check
-  check_fixes_prefix = 'CHECK-FIXES' + file_check_suffix
-  check_messages_prefix = 'CHECK-MESSAGES' + file_check_suffix
-  check_notes_prefix = 'CHECK-NOTES' + file_check_suffix
-
-  has_check_fix = check_fixes_prefix in input_text 
-  has_check_message = check_messages_prefix in input_text
-  has_check_note = check_notes_prefix in input_text 
-
-  if has_check_note and has_check_message:
-sys.exit('Please use either %s or %s but not both' %
-  (check_notes_prefix, check_messages_prefix))
-
-  if not has_check_fix and not has_check_message and not has_check_note:
-sys.exit('%s, %s or %s not found in the input' %
-  (check_fixes_prefix, check_messages_prefix, check_notes_prefix))
-
-  has_check_fixes = has_check_fixes or has_check_fix
-  has_check_messages = has_check_messages or has_check_message
-  has_check_notes = has_check_notes or has_check_note
-
-  check_fixes_prefixes.append(check_fixes_prefix)
-  check_messages_prefixes.append(check_messages_prefix)
-  check_notes_prefixes.append(check_notes_prefix)
-  else:
-check_fixes_prefixes = ['CHECK-FIXES']
-check_messages_prefixes = ['CHECK-MESSAGES']
-check_notes_prefixes = ['CHECK-NOTES']
+  for check in args.check_suffix:
+if check and not re.match('^[A-Z0-9\-]+$', check):
+  sys.exit('Only A..Z, 0..9 and "-" are ' +
+'allowed in check suffixes list, but "%s" was given' % (check))
 
+file_check_suffix = ('-' + check) if check else ''
+check_fixes_prefix = 'CHECK-FIXES' + file_check_suffix
+check_messages_prefix = 'CHECK-MESSAGES' + file_check_suffix
+check_notes_prefix = 'CHECK-NOTES' + file_check_suffix
+
+has_check_fix = check_fixes_prefix in input_text
+has_check_message = check_messages_prefix in input_text
+has_check_note = check_notes_prefix in input_text
+
+if has_check_note and has_check_message:
+  sys.exit('Please use either %s or %s but not both' %
+(check_notes_prefix, check_messages_prefix))
+
+if not has_check_fix and not has_check_message and not has_check_note:
+  sys.exit('%s, %s or %s not found in the input' %
+(check_fixes_prefix, check_messages_prefix, check_notes_prefix))
+
+has_check_fixes = has_check_fixes or has_check_fix
+has_check_messages = has_check_messages or has_check_message
+has_check_notes = has_check_notes or has_check_note
+
+check_fixes_prefixes.append(check_fixes_prefix)
+check_messages_prefixes.append(check_messages_prefix)
+check_notes_prefixes.append(check_notes_prefix)
+
+  assert has_check_fixes or has_check_messages or has_check_notes
   # Remove the contents of the CHECK lines to avoid CHECKs matching on
   # themselves.  We need to keep the comments to preserve line numbers while
   # avoiding empty lines which could potentially trigger formatting-related


Index: test/clang-tidy/check_clang_tidy.py
=

[PATCH] D53194: [clang-tidy] Fix check_clang_tidy.py trivially passing default CHECK

2018-10-12 Thread Zinovy Nis via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL344343: [clang-tidy] Fix check_clang_tidy.py trivially 
passing default CHECK (authored by zinovy.nis, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D53194?vs=169379&id=169388#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D53194

Files:
  clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy.py


Index: clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy.py
===
--- clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy.py
+++ clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy.py
@@ -51,7 +51,7 @@
   parser.add_argument('check_name')
   parser.add_argument('temp_file_name')
   parser.add_argument('-check-suffix', '-check-suffixes',
-  default=[], type=csv,
+  default=[''], type=csv,
   help="comma-separated list of FileCheck suffixes")
 
   args, extra_args = parser.parse_known_args()
@@ -96,41 +96,37 @@
   has_check_messages = False
   has_check_notes = False
 
-  if any(args.check_suffix):
-for check in args.check_suffix:
-  if not re.match('^[A-Z0-9\-]+$', check):
-sys.exit('Only A..Z, 0..9 and "-" are ' +
-  'allowed in check suffixes list, but "%s" was given' % (check))
-
-  file_check_suffix = '-' + check
-  check_fixes_prefix = 'CHECK-FIXES' + file_check_suffix
-  check_messages_prefix = 'CHECK-MESSAGES' + file_check_suffix
-  check_notes_prefix = 'CHECK-NOTES' + file_check_suffix
-
-  has_check_fix = check_fixes_prefix in input_text 
-  has_check_message = check_messages_prefix in input_text
-  has_check_note = check_notes_prefix in input_text 
-
-  if has_check_note and has_check_message:
-sys.exit('Please use either %s or %s but not both' %
-  (check_notes_prefix, check_messages_prefix))
-
-  if not has_check_fix and not has_check_message and not has_check_note:
-sys.exit('%s, %s or %s not found in the input' %
-  (check_fixes_prefix, check_messages_prefix, check_notes_prefix))
-
-  has_check_fixes = has_check_fixes or has_check_fix
-  has_check_messages = has_check_messages or has_check_message
-  has_check_notes = has_check_notes or has_check_note
-
-  check_fixes_prefixes.append(check_fixes_prefix)
-  check_messages_prefixes.append(check_messages_prefix)
-  check_notes_prefixes.append(check_notes_prefix)
-  else:
-check_fixes_prefixes = ['CHECK-FIXES']
-check_messages_prefixes = ['CHECK-MESSAGES']
-check_notes_prefixes = ['CHECK-NOTES']
+  for check in args.check_suffix:
+if check and not re.match('^[A-Z0-9\-]+$', check):
+  sys.exit('Only A..Z, 0..9 and "-" are ' +
+'allowed in check suffixes list, but "%s" was given' % (check))
+
+file_check_suffix = ('-' + check) if check else ''
+check_fixes_prefix = 'CHECK-FIXES' + file_check_suffix
+check_messages_prefix = 'CHECK-MESSAGES' + file_check_suffix
+check_notes_prefix = 'CHECK-NOTES' + file_check_suffix
+
+has_check_fix = check_fixes_prefix in input_text
+has_check_message = check_messages_prefix in input_text
+has_check_note = check_notes_prefix in input_text
+
+if has_check_note and has_check_message:
+  sys.exit('Please use either %s or %s but not both' %
+(check_notes_prefix, check_messages_prefix))
+
+if not has_check_fix and not has_check_message and not has_check_note:
+  sys.exit('%s, %s or %s not found in the input' %
+(check_fixes_prefix, check_messages_prefix, check_notes_prefix))
+
+has_check_fixes = has_check_fixes or has_check_fix
+has_check_messages = has_check_messages or has_check_message
+has_check_notes = has_check_notes or has_check_note
+
+check_fixes_prefixes.append(check_fixes_prefix)
+check_messages_prefixes.append(check_messages_prefix)
+check_notes_prefixes.append(check_notes_prefix)
 
+  assert has_check_fixes or has_check_messages or has_check_notes
   # Remove the contents of the CHECK lines to avoid CHECKs matching on
   # themselves.  We need to keep the comments to preserve line numbers while
   # avoiding empty lines which could potentially trigger formatting-related


Index: clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy.py
===
--- clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy.py
+++ clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy.py
@@ -51,7 +51,7 @@
   parser.add_argument('check_name')
   parser.add_argument('temp_file_name')
   parser.add_argument('-check-suffix', '-check-suffixes',
-  default=[], type=csv,
+  default=[''], type=csv,
   help="comma-separated list of FileCheck suffixes")
 
   args, extra_args = parser.parse_known_args()

[PATCH] D57662: [clang-tidy] Parallelize clang-tidy-diff.py

2019-03-06 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 189562.
zinovy.nis added a comment.

- honest '--export-fixes': multiple yamls are merged into the resulting one.
- minor cosmetic fixes.


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

https://reviews.llvm.org/D57662

Files:
  clang-tidy/tool/clang-tidy-diff.py
  clang-tidy/tool/run-clang-tidy.py

Index: clang-tidy/tool/run-clang-tidy.py
===
--- clang-tidy/tool/run-clang-tidy.py
+++ clang-tidy/tool/run-clang-tidy.py
@@ -279,8 +279,8 @@
   if file_name_re.search(name):
 task_queue.put(name)
 
-# Wait for all threads to be done.
-task_queue.join()
+  # Wait for all threads to be done.
+  task_queue.join()
 if len(failed_files):
   return_code = 1
 
Index: clang-tidy/tool/clang-tidy-diff.py
===
--- clang-tidy/tool/clang-tidy-diff.py
+++ clang-tidy/tool/clang-tidy-diff.py
@@ -24,10 +24,88 @@
 """
 
 import argparse
+import glob
 import json
+import multiprocessing
+import os
 import re
+import shutil
 import subprocess
 import sys
+import tempfile
+import threading
+import traceback
+import yaml
+
+is_py2 = sys.version[0] == '2'
+
+if is_py2:
+import Queue as queue
+else:
+import queue as queue
+
+
+def run_tidy(task_queue, lock, timeout):
+  watchdog = None
+  while True:
+command = task_queue.get()
+try:
+  proc = subprocess.Popen(command,
+  stdout=subprocess.PIPE,
+  stderr=subprocess.PIPE)
+
+  if timeout is not None:
+watchdog = threading.Timer(timeout, proc.kill)
+watchdog.start()
+
+  stdout, stderr = proc.communicate()
+
+  with lock:
+sys.stdout.write(stdout.decode('utf-8') + '\n')
+if stderr:
+  sys.stderr.write(stderr.decode('utf-8') + '\n')
+except Exception as e:
+  with lock:
+sys.stderr.write('Failed: ' + str(e) + ': '.join(command) + '\n')
+finally:
+  with lock:
+if (not timeout is None) and (not watchdog is None):
+  if not watchdog.is_alive():
+  sys.stderr.write('Terminated by timeout: ' +
+   ' '.join(command) + '\n')
+  watchdog.cancel()
+  task_queue.task_done()
+
+
+def start_workers(max_tasks, tidy_caller, task_queue, lock, timeout):
+  for _ in range(max_tasks):
+t = threading.Thread(target=tidy_caller, args=(task_queue, lock, timeout))
+t.daemon = True
+t.start()
+
+def merge_replacement_files(tmpdir, mergefile):
+  """Merge all replacement files in a directory into a single file"""
+  # The fixes suggested by clang-tidy >= 4.0.0 are given under
+  # the top level key 'Diagnostics' in the output yaml files
+  mergekey="Diagnostics"
+  merged=[]
+  for replacefile in glob.iglob(os.path.join(tmpdir, '*.yaml')):
+content = yaml.safe_load(open(replacefile, 'r'))
+if not content:
+  continue # Skip empty files.
+merged.extend(content.get(mergekey, []))
+
+  if merged:
+# MainSourceFile: The key is required by the definition inside
+# include/clang/Tooling/ReplacementsYaml.h, but the value
+# is actually never used inside clang-apply-replacements,
+# so we set it to '' here.
+output = { 'MainSourceFile': '', mergekey: merged }
+with open(mergefile, 'w') as out:
+  yaml.safe_dump(output, out)
+  else:
+# Empty the file:
+open(mergefile, 'w').close()
 
 
 def main():
@@ -48,6 +126,10 @@
   help='custom pattern selecting file paths to check '
   '(case insensitive, overridden by -regex)')
 
+  parser.add_argument('-j', type=int, default=1,
+  help='number of tidy instances to be run in parallel.')
+  parser.add_argument('-timeout', type=int, default=None,
+  help='timeout per each file in seconds.')
   parser.add_argument('-fix', action='store_true', default=False,
   help='apply suggested fixes')
   parser.add_argument('-checks',
@@ -84,7 +166,7 @@
 match = re.search('^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % args.p, line)
 if match:
   filename = match.group(2)
-if filename == None:
+if filename is None:
   continue
 
 if args.regex is not None:
@@ -102,44 +184,83 @@
 line_count = int(match.group(3))
   if line_count == 0:
 continue
-  end_line = start_line + line_count - 1;
+  end_line = start_line + line_count - 1
   lines_by_file.setdefault(filename, []).append([start_line, end_line])
 
-  if len(lines_by_file) == 0:
+  if not any(lines_by_file):
 print("No relevant changes found.")
 sys.exit(0)
 
-  line_filter_json = json.dumps(
-[{"name" : name, "lines" : lines_by_file[name]} for name in lines_by_file],
-separators = (',', ':'))
+  max_task_count = args.j
+  if max_task_count == 0:
+  max_task_count = multipro

[PATCH] D57662: [clang-tidy] Parallelize clang-tidy-diff.py

2019-03-08 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

Gentle ping.


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

https://reviews.llvm.org/D57662



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


[PATCH] D59449: [clang-tidy] Integrate clang-tidy-diff.py machinery into run-clang-tidy.py

2019-03-16 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis created this revision.
zinovy.nis added reviewers: alexfh, bkramer.
zinovy.nis added a project: clang-tools-extra.
Herald added subscribers: cfe-commits, xazax.hun.
Herald added a reviewer: serge-sans-paille.
Herald added a project: clang.

This patch adds a new `--diff[=2]` option to `run-clang-tidy.py` to run 
`clang-tidy` checks against the given diff only, instead of the whole file.

Usage:

  git show -U2 | /some/path/1/run-clang-tidy.py --diff=1 -clang-tidy-binary 
/some/path/2/clang-tidy.exe -p out/Debug -checks=-*,performance-* option_regex


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D59449

Files:
  clang-tidy/tool/run-clang-tidy.py

Index: clang-tidy/tool/run-clang-tidy.py
===
--- clang-tidy/tool/run-clang-tidy.py
+++ clang-tidy/tool/run-clang-tidy.py
@@ -7,7 +7,6 @@
 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 #
 #======#
-# FIXME: Integrate with clang-tidy-diff.py
 
 """
 Parallel clang-tidy runner
@@ -56,6 +55,10 @@
 else:
 import queue as queue
 
+quote = ""
+if sys.platform != 'win32':
+  quote = "'"
+
 def find_compilation_database(path):
   """Adjusts the directory until a compilation database is found."""
   result = './'
@@ -73,7 +76,7 @@
   return os.path.normpath(os.path.join(directory, f))
 
 
-def get_tidy_invocation(f, clang_tidy_binary, checks, tmpdir, build_path,
+def get_tidy_invocation(f, lines, clang_tidy_binary, checks, tmpdir, build_path,
 header_filter, extra_arg, extra_arg_before, quiet,
 config):
   """Gets a command line for clang-tidy."""
@@ -83,6 +86,12 @@
   else:
 # Show warnings in all in-project headers by default.
 start.append('-header-filter=^' + build_path + '/.*')
+
+  if lines is not None:
+line_json = json.dumps([{"name": f, "lines": lines}], separators=(',', ':'))
+# Run clang-tidy on files containing changes.
+start.append('-line-filter=' + quote + line_json + quote)
+
   if checks:
 start.append('-checks=' + checks)
   if tmpdir is not None:
@@ -155,8 +164,9 @@
 def run_tidy(args, tmpdir, build_path, queue, lock, failed_files):
   """Takes filenames out of queue and runs clang-tidy on them."""
   while True:
-name = queue.get()
-invocation = get_tidy_invocation(name, args.clang_tidy_binary, args.checks,
+(name, lines) = queue.get()
+invocation = get_tidy_invocation(name, lines,
+ args.clang_tidy_binary, args.checks,
  tmpdir, build_path, args.header_filter,
  args.extra_arg, args.extra_arg_before,
  args.quiet, args.config)
@@ -172,11 +182,42 @@
 queue.task_done()
 
 
+def get_changed_lines(prefix_len):
+  iregex = '^%s$' % r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc)'
+  lines_by_file = {}
+  filename = None
+  for line in sys.stdin:
+match = re.search('^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % prefix_len, line)
+if match:
+  filename = match.group(2)
+if filename is None:
+  continue
+
+if not re.match(iregex, filename, re.IGNORECASE):
+  continue
+
+match = re.search('^@@.*\+(\d+)(,(\d+))?', line)
+if match:
+  start_line = int(match.group(1))
+  line_count = 1
+  if match.group(3):
+line_count = int(match.group(3))
+  if line_count == 0:
+continue
+  end_line = start_line + line_count - 1
+  lines_by_file.setdefault(filename, []).append([start_line, end_line])
+
+  return lines_by_file
+
+
 def main():
   parser = argparse.ArgumentParser(description='Runs clang-tidy over all files '
'in a compilation database. Requires '
'clang-tidy and clang-apply-replacements in '
'$PATH.')
+  parser.add_argument('--diff', default=None, const=2, nargs='?', type=int,
+  help='check only the diff read from stdin.'
+  ' Strip the smallest prefix containing DIFF[=2] slashes')
   parser.add_argument('-clang-tidy-binary', metavar='PATH',
   default='clang-tidy',
   help='path to clang-tidy binary')
@@ -244,11 +285,6 @@
 print("Unable to run clang-tidy.", file=sys.stderr)
 sys.exit(1)
 
-  # Load the database and extract all files.
-  database = json.load(open(os.path.join(build_path, db_path)))
-  files = [make_absolute(entry['file'], entry['directory'])
-   for entry in database]
-
   max_task = args.j
   if max_task == 0:
 max_task = multiprocessing.cpu_count()
@@ -260,6 +296,16 @@
 
   # Build up a big regexy filter from all command line arguments.
   file_name_re = re.compile('|'.join(args.files))
+  files = None
+  changed_lines = None
+  if args.diff is not None:
+changed_

[PATCH] D57662: [clang-tidy] Parallelize clang-tidy-diff.py

2019-03-19 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

One more gentle ping.


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

https://reviews.llvm.org/D57662



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


[PATCH] D59449: [clang-tidy] Integrate clang-tidy-diff.py machinery into run-clang-tidy.py

2019-03-19 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

Any comments?


Repository:
  rCTE Clang Tools Extra

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

https://reviews.llvm.org/D59449



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


[PATCH] D59449: [clang-tidy] Integrate clang-tidy-diff.py machinery into run-clang-tidy.py

2019-03-19 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

In D59449#1435032 , @alexfh wrote:

> How is this functionality different from the clang-tidy-diff.py script with 
> the -j option being added in the other patch?


It's the same.


Repository:
  rCTE Clang Tools Extra

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

https://reviews.llvm.org/D59449



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


[PATCH] D57662: [clang-tidy] Parallelize clang-tidy-diff.py

2019-03-20 Thread Zinovy Nis via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rCTE356547: [clang-tidy] Parallelize clang-tidy-diff.py 
(authored by zinovy.nis, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D57662?vs=189562&id=191474#toc

Repository:
  rCTE Clang Tools Extra

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

https://reviews.llvm.org/D57662

Files:
  clang-tidy/tool/clang-tidy-diff.py

Index: clang-tidy/tool/clang-tidy-diff.py
===
--- clang-tidy/tool/clang-tidy-diff.py
+++ clang-tidy/tool/clang-tidy-diff.py
@@ -24,10 +24,88 @@
 """
 
 import argparse
+import glob
 import json
+import multiprocessing
+import os
 import re
+import shutil
 import subprocess
 import sys
+import tempfile
+import threading
+import traceback
+import yaml
+
+is_py2 = sys.version[0] == '2'
+
+if is_py2:
+import Queue as queue
+else:
+import queue as queue
+
+
+def run_tidy(task_queue, lock, timeout):
+  watchdog = None
+  while True:
+command = task_queue.get()
+try:
+  proc = subprocess.Popen(command,
+  stdout=subprocess.PIPE,
+  stderr=subprocess.PIPE)
+
+  if timeout is not None:
+watchdog = threading.Timer(timeout, proc.kill)
+watchdog.start()
+
+  stdout, stderr = proc.communicate()
+
+  with lock:
+sys.stdout.write(stdout.decode('utf-8') + '\n')
+if stderr:
+  sys.stderr.write(stderr.decode('utf-8') + '\n')
+except Exception as e:
+  with lock:
+sys.stderr.write('Failed: ' + str(e) + ': '.join(command) + '\n')
+finally:
+  with lock:
+if (not timeout is None) and (not watchdog is None):
+  if not watchdog.is_alive():
+  sys.stderr.write('Terminated by timeout: ' +
+   ' '.join(command) + '\n')
+  watchdog.cancel()
+  task_queue.task_done()
+
+
+def start_workers(max_tasks, tidy_caller, task_queue, lock, timeout):
+  for _ in range(max_tasks):
+t = threading.Thread(target=tidy_caller, args=(task_queue, lock, timeout))
+t.daemon = True
+t.start()
+
+def merge_replacement_files(tmpdir, mergefile):
+  """Merge all replacement files in a directory into a single file"""
+  # The fixes suggested by clang-tidy >= 4.0.0 are given under
+  # the top level key 'Diagnostics' in the output yaml files
+  mergekey="Diagnostics"
+  merged=[]
+  for replacefile in glob.iglob(os.path.join(tmpdir, '*.yaml')):
+content = yaml.safe_load(open(replacefile, 'r'))
+if not content:
+  continue # Skip empty files.
+merged.extend(content.get(mergekey, []))
+
+  if merged:
+# MainSourceFile: The key is required by the definition inside
+# include/clang/Tooling/ReplacementsYaml.h, but the value
+# is actually never used inside clang-apply-replacements,
+# so we set it to '' here.
+output = { 'MainSourceFile': '', mergekey: merged }
+with open(mergefile, 'w') as out:
+  yaml.safe_dump(output, out)
+  else:
+# Empty the file:
+open(mergefile, 'w').close()
 
 
 def main():
@@ -48,6 +126,10 @@
   help='custom pattern selecting file paths to check '
   '(case insensitive, overridden by -regex)')
 
+  parser.add_argument('-j', type=int, default=1,
+  help='number of tidy instances to be run in parallel.')
+  parser.add_argument('-timeout', type=int, default=None,
+  help='timeout per each file in seconds.')
   parser.add_argument('-fix', action='store_true', default=False,
   help='apply suggested fixes')
   parser.add_argument('-checks',
@@ -84,7 +166,7 @@
 match = re.search('^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % args.p, line)
 if match:
   filename = match.group(2)
-if filename == None:
+if filename is None:
   continue
 
 if args.regex is not None:
@@ -102,44 +184,83 @@
 line_count = int(match.group(3))
   if line_count == 0:
 continue
-  end_line = start_line + line_count - 1;
+  end_line = start_line + line_count - 1
   lines_by_file.setdefault(filename, []).append([start_line, end_line])
 
-  if len(lines_by_file) == 0:
+  if not any(lines_by_file):
 print("No relevant changes found.")
 sys.exit(0)
 
-  line_filter_json = json.dumps(
-[{"name" : name, "lines" : lines_by_file[name]} for name in lines_by_file],
-separators = (',', ':'))
-
-  quote = "";
-  if sys.platform == 'win32':
-line_filter_json=re.sub(r'"', r'"""', line_filter_json)
-  else:
-quote = "'";
+  max_task_count = args.j
+  if max_task_count == 0:
+  max_task_count = multiprocessing.cpu_count()
+  max_task_count = min(len(lines_by_file), max_task_count)
 
-  # Run clang-tidy on files containing changes.
-  command = [args.clang_tidy_binary]
-  command.append('-line-filter=' + quote + line_filter_

[PATCH] D59734: [clang-tidy] Handle missing yaml module in run-clang-tidy.py

2019-03-23 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis created this revision.
zinovy.nis added reviewers: alexfh, bkramer, kuhar.
zinovy.nis added a project: clang-tools-extra.
Herald added subscribers: cfe-commits, xazax.hun.
Herald added a reviewer: serge-sans-paille.
Herald added a project: clang.

The Yaml module is missing on some systems and on many clang buildbots. But the 
test for run-clang-tidy.py doesn't fail due to `not` statement masking the 
python runtime error.

This patch conditionally imports and enables the yaml module only if it's 
present in system. If not, then `-export-fixes` is disabled, the same as for 
`clang-tidy-diff.py`.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D59734

Files:
  clang-tidy/tool/run-clang-tidy.py
  test/clang-tidy/run-clang-tidy.cpp


Index: test/clang-tidy/run-clang-tidy.cpp
===
--- test/clang-tidy/run-clang-tidy.cpp
+++ test/clang-tidy/run-clang-tidy.cpp
@@ -1,3 +1,4 @@
+// RUN: %run_clang_tidy --help
 // RUN: rm -rf %t
 // RUN: mkdir %t
 // RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c 
%/t/test.cpp\",\"file\":\"%/t/test.cpp\"}]" | sed -e 's/\\//g' > 
%t/compile_commands.json
Index: clang-tidy/tool/run-clang-tidy.py
===
--- clang-tidy/tool/run-clang-tidy.py
+++ clang-tidy/tool/run-clang-tidy.py
@@ -47,7 +47,12 @@
 import tempfile
 import threading
 import traceback
-import yaml
+
+yaml_imported = True
+try:
+  import yaml
+except ImportError:
+  yaml_imported = False
 
 is_py2 = sys.version[0] == '2'
 
@@ -199,9 +204,10 @@
   'headers to output diagnostics from. Diagnostics from '
   'the main file of each translation unit are always '
   'displayed.')
-  parser.add_argument('-export-fixes', metavar='filename', dest='export_fixes',
-  help='Create a yaml file to store suggested fixes in, '
-  'which can be applied with clang-apply-replacements.')
+  if yaml_imported:
+parser.add_argument('-export-fixes', metavar='filename', 
dest='export_fixes',
+help='Create a yaml file to store suggested fixes in, '
+'which can be applied with clang-apply-replacements.')
   parser.add_argument('-j', type=int, default=0,
   help='number of tidy instances to be run in parallel.')
   parser.add_argument('files', nargs='*', default=['.*'],
@@ -254,7 +260,7 @@
 max_task = multiprocessing.cpu_count()
 
   tmpdir = None
-  if args.fix or args.export_fixes:
+  if args.fix or (yaml_imported and  args.export_fixes):
 check_clang_apply_replacements_binary(args)
 tmpdir = tempfile.mkdtemp()
 
@@ -292,7 +298,7 @@
   shutil.rmtree(tmpdir)
 os.kill(0, 9)
 
-  if args.export_fixes:
+  if yaml_imported and args.export_fixes:
 print('Writing fixes to ' + args.export_fixes + ' ...')
 try:
   merge_replacement_files(tmpdir, args.export_fixes)


Index: test/clang-tidy/run-clang-tidy.cpp
===
--- test/clang-tidy/run-clang-tidy.cpp
+++ test/clang-tidy/run-clang-tidy.cpp
@@ -1,3 +1,4 @@
+// RUN: %run_clang_tidy --help
 // RUN: rm -rf %t
 // RUN: mkdir %t
 // RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %/t/test.cpp\",\"file\":\"%/t/test.cpp\"}]" | sed -e 's/\\//g' > %t/compile_commands.json
Index: clang-tidy/tool/run-clang-tidy.py
===
--- clang-tidy/tool/run-clang-tidy.py
+++ clang-tidy/tool/run-clang-tidy.py
@@ -47,7 +47,12 @@
 import tempfile
 import threading
 import traceback
-import yaml
+
+yaml_imported = True
+try:
+  import yaml
+except ImportError:
+  yaml_imported = False
 
 is_py2 = sys.version[0] == '2'
 
@@ -199,9 +204,10 @@
   'headers to output diagnostics from. Diagnostics from '
   'the main file of each translation unit are always '
   'displayed.')
-  parser.add_argument('-export-fixes', metavar='filename', dest='export_fixes',
-  help='Create a yaml file to store suggested fixes in, '
-  'which can be applied with clang-apply-replacements.')
+  if yaml_imported:
+parser.add_argument('-export-fixes', metavar='filename', dest='export_fixes',
+help='Create a yaml file to store suggested fixes in, '
+'which can be applied with clang-apply-replacements.')
   parser.add_argument('-j', type=int, default=0,
   help='number of tidy instances to be run in parallel.')
   parser.add_argument('files', nargs='*', default=['.*'],
@@ -254,7 +260,7 @@
 max_task = multiprocessing.cpu_count()
 
   tmpdir = None
-  if args.fix or args.export_fixes:
+  if args.fix or (yaml_imported and  args.export_fixes):
 check_clang_apply_replacements_binary(args)
 tmpd

[PATCH] D59734: [clang-tidy] Handle missing yaml module in run-clang-tidy.py

2019-03-23 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis marked an inline comment as done.
zinovy.nis added inline comments.



Comment at: test/clang-tidy/run-clang-tidy.cpp:1
+// RUN: %run_clang_tidy --help
 // RUN: rm -rf %t

Just check that python doesn't complain on the script code and imported modules.


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

https://reviews.llvm.org/D59734



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


[PATCH] D59734: [clang-tidy] Handle missing yaml module in run-clang-tidy.py

2019-03-23 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 191992.

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

https://reviews.llvm.org/D59734

Files:
  clang-tidy/tool/run-clang-tidy.py
  test/clang-tidy/run-clang-tidy.cpp


Index: test/clang-tidy/run-clang-tidy.cpp
===
--- test/clang-tidy/run-clang-tidy.cpp
+++ test/clang-tidy/run-clang-tidy.cpp
@@ -1,3 +1,4 @@
+// RUN: %run_clang_tidy --help
 // RUN: rm -rf %t
 // RUN: mkdir %t
 // RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c 
%/t/test.cpp\",\"file\":\"%/t/test.cpp\"}]" | sed -e 's/\\//g' > 
%t/compile_commands.json
Index: clang-tidy/tool/run-clang-tidy.py
===
--- clang-tidy/tool/run-clang-tidy.py
+++ clang-tidy/tool/run-clang-tidy.py
@@ -47,7 +47,12 @@
 import tempfile
 import threading
 import traceback
-import yaml
+
+yaml_imported = True
+try:
+  import yaml
+except ImportError:
+  yaml_imported = False
 
 is_py2 = sys.version[0] == '2'
 
@@ -199,9 +204,10 @@
   'headers to output diagnostics from. Diagnostics from '
   'the main file of each translation unit are always '
   'displayed.')
-  parser.add_argument('-export-fixes', metavar='filename', dest='export_fixes',
-  help='Create a yaml file to store suggested fixes in, '
-  'which can be applied with clang-apply-replacements.')
+  if yaml_imported:
+parser.add_argument('-export-fixes', metavar='filename', 
dest='export_fixes',
+help='Create a yaml file to store suggested fixes in, '
+'which can be applied with clang-apply-replacements.')
   parser.add_argument('-j', type=int, default=0,
   help='number of tidy instances to be run in parallel.')
   parser.add_argument('files', nargs='*', default=['.*'],
@@ -254,7 +260,7 @@
 max_task = multiprocessing.cpu_count()
 
   tmpdir = None
-  if args.fix or args.export_fixes:
+  if args.fix or (yaml_imported and  args.export_fixes):
 check_clang_apply_replacements_binary(args)
 tmpdir = tempfile.mkdtemp()
 
@@ -292,7 +298,7 @@
   shutil.rmtree(tmpdir)
 os.kill(0, 9)
 
-  if args.export_fixes:
+  if yaml_imported and args.export_fixes:
 print('Writing fixes to ' + args.export_fixes + ' ...')
 try:
   merge_replacement_files(tmpdir, args.export_fixes)


Index: test/clang-tidy/run-clang-tidy.cpp
===
--- test/clang-tidy/run-clang-tidy.cpp
+++ test/clang-tidy/run-clang-tidy.cpp
@@ -1,3 +1,4 @@
+// RUN: %run_clang_tidy --help
 // RUN: rm -rf %t
 // RUN: mkdir %t
 // RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %/t/test.cpp\",\"file\":\"%/t/test.cpp\"}]" | sed -e 's/\\//g' > %t/compile_commands.json
Index: clang-tidy/tool/run-clang-tidy.py
===
--- clang-tidy/tool/run-clang-tidy.py
+++ clang-tidy/tool/run-clang-tidy.py
@@ -47,7 +47,12 @@
 import tempfile
 import threading
 import traceback
-import yaml
+
+yaml_imported = True
+try:
+  import yaml
+except ImportError:
+  yaml_imported = False
 
 is_py2 = sys.version[0] == '2'
 
@@ -199,9 +204,10 @@
   'headers to output diagnostics from. Diagnostics from '
   'the main file of each translation unit are always '
   'displayed.')
-  parser.add_argument('-export-fixes', metavar='filename', dest='export_fixes',
-  help='Create a yaml file to store suggested fixes in, '
-  'which can be applied with clang-apply-replacements.')
+  if yaml_imported:
+parser.add_argument('-export-fixes', metavar='filename', dest='export_fixes',
+help='Create a yaml file to store suggested fixes in, '
+'which can be applied with clang-apply-replacements.')
   parser.add_argument('-j', type=int, default=0,
   help='number of tidy instances to be run in parallel.')
   parser.add_argument('files', nargs='*', default=['.*'],
@@ -254,7 +260,7 @@
 max_task = multiprocessing.cpu_count()
 
   tmpdir = None
-  if args.fix or args.export_fixes:
+  if args.fix or (yaml_imported and  args.export_fixes):
 check_clang_apply_replacements_binary(args)
 tmpdir = tempfile.mkdtemp()
 
@@ -292,7 +298,7 @@
   shutil.rmtree(tmpdir)
 os.kill(0, 9)
 
-  if args.export_fixes:
+  if yaml_imported and args.export_fixes:
 print('Writing fixes to ' + args.export_fixes + ' ...')
 try:
   merge_replacement_files(tmpdir, args.export_fixes)
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D59734: [clang-tidy] Handle missing yaml module in run-clang-tidy.py

2019-03-25 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis marked an inline comment as done.
zinovy.nis added inline comments.



Comment at: clang-tidy/tool/run-clang-tidy.py:210
+help='Create a yaml file to store suggested fixes in, '
+'which can be applied with clang-apply-replacements.')
   parser.add_argument('-j', type=int, default=0,

serge-sans-paille wrote:
> could be
> 
> ```
> if yaml:
> parser.add_argument('-export-fixes', metavar='filename', 
> dest='export_fixes',
>   ​help='Create a yaml file to store suggested 
> fixes in, '
>   ​'which can be applied with 
> clang-apply-replacements.')
> else:
> parser.export_fixes = False
> ```
> 
> This would make later condition easier to read.
Looks strange. Not sure this works.


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

https://reviews.llvm.org/D59734



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


[PATCH] D59734: [clang-tidy] Handle missing yaml module in run-clang-tidy.py

2019-03-25 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 192137.

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

https://reviews.llvm.org/D59734

Files:
  clang-tidy/tool/run-clang-tidy.py
  test/clang-tidy/run-clang-tidy.cpp


Index: test/clang-tidy/run-clang-tidy.cpp
===
--- test/clang-tidy/run-clang-tidy.cpp
+++ test/clang-tidy/run-clang-tidy.cpp
@@ -1,3 +1,4 @@
+// RUN: %run_clang_tidy --help
 // RUN: rm -rf %t
 // RUN: mkdir %t
 // RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c 
%/t/test.cpp\",\"file\":\"%/t/test.cpp\"}]" | sed -e 's/\\//g' > 
%t/compile_commands.json
Index: clang-tidy/tool/run-clang-tidy.py
===
--- clang-tidy/tool/run-clang-tidy.py
+++ clang-tidy/tool/run-clang-tidy.py
@@ -47,7 +47,11 @@
 import tempfile
 import threading
 import traceback
-import yaml
+
+try:
+  import yaml
+except ImportError:
+  yaml = None
 
 is_py2 = sys.version[0] == '2'
 
@@ -199,9 +203,10 @@
   'headers to output diagnostics from. Diagnostics from '
   'the main file of each translation unit are always '
   'displayed.')
-  parser.add_argument('-export-fixes', metavar='filename', dest='export_fixes',
-  help='Create a yaml file to store suggested fixes in, '
-  'which can be applied with clang-apply-replacements.')
+  if yaml:
+parser.add_argument('-export-fixes', metavar='filename', 
dest='export_fixes',
+help='Create a yaml file to store suggested fixes in, '
+'which can be applied with clang-apply-replacements.')
   parser.add_argument('-j', type=int, default=0,
   help='number of tidy instances to be run in parallel.')
   parser.add_argument('files', nargs='*', default=['.*'],
@@ -254,7 +259,7 @@
 max_task = multiprocessing.cpu_count()
 
   tmpdir = None
-  if args.fix or args.export_fixes:
+  if args.fix or (yaml and args.export_fixes):
 check_clang_apply_replacements_binary(args)
 tmpdir = tempfile.mkdtemp()
 
@@ -292,7 +297,7 @@
   shutil.rmtree(tmpdir)
 os.kill(0, 9)
 
-  if args.export_fixes:
+  if yaml and args.export_fixes:
 print('Writing fixes to ' + args.export_fixes + ' ...')
 try:
   merge_replacement_files(tmpdir, args.export_fixes)


Index: test/clang-tidy/run-clang-tidy.cpp
===
--- test/clang-tidy/run-clang-tidy.cpp
+++ test/clang-tidy/run-clang-tidy.cpp
@@ -1,3 +1,4 @@
+// RUN: %run_clang_tidy --help
 // RUN: rm -rf %t
 // RUN: mkdir %t
 // RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %/t/test.cpp\",\"file\":\"%/t/test.cpp\"}]" | sed -e 's/\\//g' > %t/compile_commands.json
Index: clang-tidy/tool/run-clang-tidy.py
===
--- clang-tidy/tool/run-clang-tidy.py
+++ clang-tidy/tool/run-clang-tidy.py
@@ -47,7 +47,11 @@
 import tempfile
 import threading
 import traceback
-import yaml
+
+try:
+  import yaml
+except ImportError:
+  yaml = None
 
 is_py2 = sys.version[0] == '2'
 
@@ -199,9 +203,10 @@
   'headers to output diagnostics from. Diagnostics from '
   'the main file of each translation unit are always '
   'displayed.')
-  parser.add_argument('-export-fixes', metavar='filename', dest='export_fixes',
-  help='Create a yaml file to store suggested fixes in, '
-  'which can be applied with clang-apply-replacements.')
+  if yaml:
+parser.add_argument('-export-fixes', metavar='filename', dest='export_fixes',
+help='Create a yaml file to store suggested fixes in, '
+'which can be applied with clang-apply-replacements.')
   parser.add_argument('-j', type=int, default=0,
   help='number of tidy instances to be run in parallel.')
   parser.add_argument('files', nargs='*', default=['.*'],
@@ -254,7 +259,7 @@
 max_task = multiprocessing.cpu_count()
 
   tmpdir = None
-  if args.fix or args.export_fixes:
+  if args.fix or (yaml and args.export_fixes):
 check_clang_apply_replacements_binary(args)
 tmpdir = tempfile.mkdtemp()
 
@@ -292,7 +297,7 @@
   shutil.rmtree(tmpdir)
 os.kill(0, 9)
 
-  if args.export_fixes:
+  if yaml and args.export_fixes:
 print('Writing fixes to ' + args.export_fixes + ' ...')
 try:
   merge_replacement_files(tmpdir, args.export_fixes)
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D59734: [clang-tidy] Handle missing yaml module in run-clang-tidy.py

2019-03-27 Thread Zinovy Nis via Phabricator via cfe-commits
This revision was not accepted when it landed; it landed in state "Needs 
Review".
This revision was automatically updated to reflect the committed changes.
Closed by commit rL357114: [clang-tidy] Handle missing yaml module in 
run-clang-tidy.py (authored by zinovy.nis, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D59734?vs=192137&id=192495#toc

Repository:
  rL LLVM

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

https://reviews.llvm.org/D59734

Files:
  clang-tools-extra/trunk/clang-tidy/tool/clang-tidy-diff.py
  clang-tools-extra/trunk/clang-tidy/tool/run-clang-tidy.py
  clang-tools-extra/trunk/test/clang-tidy/bugprone-parent-virtual-call.cpp
  clang-tools-extra/trunk/test/clang-tidy/run-clang-tidy.cpp

Index: clang-tools-extra/trunk/clang-tidy/tool/run-clang-tidy.py
===
--- clang-tools-extra/trunk/clang-tidy/tool/run-clang-tidy.py
+++ clang-tools-extra/trunk/clang-tidy/tool/run-clang-tidy.py
@@ -47,7 +47,11 @@
 import tempfile
 import threading
 import traceback
-import yaml
+
+try:
+  import yaml
+except ImportError:
+  yaml = None
 
 is_py2 = sys.version[0] == '2'
 
@@ -199,9 +203,10 @@
   'headers to output diagnostics from. Diagnostics from '
   'the main file of each translation unit are always '
   'displayed.')
-  parser.add_argument('-export-fixes', metavar='filename', dest='export_fixes',
-  help='Create a yaml file to store suggested fixes in, '
-  'which can be applied with clang-apply-replacements.')
+  if yaml:
+parser.add_argument('-export-fixes', metavar='filename', dest='export_fixes',
+help='Create a yaml file to store suggested fixes in, '
+'which can be applied with clang-apply-replacements.')
   parser.add_argument('-j', type=int, default=0,
   help='number of tidy instances to be run in parallel.')
   parser.add_argument('files', nargs='*', default=['.*'],
@@ -254,7 +259,7 @@
 max_task = multiprocessing.cpu_count()
 
   tmpdir = None
-  if args.fix or args.export_fixes:
+  if args.fix or (yaml and args.export_fixes):
 check_clang_apply_replacements_binary(args)
 tmpdir = tempfile.mkdtemp()
 
@@ -292,7 +297,7 @@
   shutil.rmtree(tmpdir)
 os.kill(0, 9)
 
-  if args.export_fixes:
+  if yaml and args.export_fixes:
 print('Writing fixes to ' + args.export_fixes + ' ...')
 try:
   merge_replacement_files(tmpdir, args.export_fixes)
Index: clang-tools-extra/trunk/clang-tidy/tool/clang-tidy-diff.py
===
--- clang-tools-extra/trunk/clang-tidy/tool/clang-tidy-diff.py
+++ clang-tools-extra/trunk/clang-tidy/tool/clang-tidy-diff.py
@@ -36,11 +36,10 @@
 import threading
 import traceback
 
-yaml_imported = True
 try:
   import yaml
 except ImportError:
-  yaml_imported = False
+  yaml = None
 
 is_py2 = sys.version[0] == '2'
 
@@ -144,7 +143,7 @@
   default='')
   parser.add_argument('-path', dest='build_path',
   help='Path used to read a compile command database.')
-  if yaml_imported:
+  if yaml:
 parser.add_argument('-export-fixes', metavar='FILE', dest='export_fixes',
 help='Create a yaml file to store suggested fixes in, '
 'which can be applied with clang-apply-replacements.')
@@ -204,7 +203,7 @@
   max_task_count = min(len(lines_by_file), max_task_count)
 
   tmpdir = None
-  if yaml_imported and args.export_fixes:
+  if yaml and args.export_fixes:
 tmpdir = tempfile.mkdtemp()
 
   # Tasks for clang-tidy.
@@ -238,7 +237,7 @@
 # Run clang-tidy on files containing changes.
 command = [args.clang_tidy_binary]
 command.append('-line-filter=' + line_filter_json)
-if yaml_imported and args.export_fixes:
+if yaml and args.export_fixes:
   # Get a temporary file. We immediately close the handle so clang-tidy can
   # overwrite it.
   (handle, tmp_name) = tempfile.mkstemp(suffix='.yaml', dir=tmpdir)
@@ -253,7 +252,7 @@
   # Wait for all threads to be done.
   task_queue.join()
 
-  if yaml_imported and args.export_fixes:
+  if yaml and args.export_fixes:
 print('Writing fixes to ' + args.export_fixes + ' ...')
 try:
   merge_replacement_files(tmpdir, args.export_fixes)
Index: clang-tools-extra/trunk/test/clang-tidy/run-clang-tidy.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/run-clang-tidy.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/run-clang-tidy.cpp
@@ -1,3 +1,4 @@
+// RUN: %run_clang_tidy --help
 // RUN: rm -rf %t
 // RUN: mkdir %t
 // RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %/t/test.cpp\",\"file\":\"%/t/test.cpp\"}]" | sed -e 's/

[PATCH] D59449: [clang-tidy] Integrate clang-tidy-diff.py machinery into run-clang-tidy.py

2019-03-28 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

In D59449#1446839 , @thakis wrote:

> Can we delete clang-tidy-diff.py with this? (Or delete most of its contents 
> and make it forward to this script?)


I don't mind deleting clang-tidy-diff.py, but someone may want to use it for 
some legacy reasons. AFAIK @alexf says they are using it.

> Or delete most of its contents and make it forward to this script

IMO it's a bad idea as these scripts are completely standalone now and it is 
useful.


Repository:
  rCTE Clang Tools Extra

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

https://reviews.llvm.org/D59449



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


[PATCH] D59449: [clang-tidy] Integrate clang-tidy-diff.py machinery into run-clang-tidy.py

2019-03-31 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 193023.
zinovy.nis added a comment.
Herald added a subscriber: jdoerfert.

Added a test.


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

https://reviews.llvm.org/D59449

Files:
  clang-tidy/tool/run-clang-tidy.py
  test/clang-tidy/run-clang-tidy-diff.cpp

Index: test/clang-tidy/run-clang-tidy-diff.cpp
===
--- /dev/null
+++ test/clang-tidy/run-clang-tidy-diff.cpp
@@ -0,0 +1,27 @@
+// REQUIRES: shell
+// RUN: mkdir -p "%t"
+// RUN: cd   "%t"
+// RUN: sed 's/placeholder_for_f/f/' %s > diff_to.cpp
+// RUN: echo '[{"directory": "%t", "command": "clang++ -o test.o -std=c++11 diff_to.cpp", "file": "diff_to.cpp"}]' > compile_commands.json
+// RUN: clang-tidy -checks=-*,modernize-use-override diff_to.cpp -- -std=c++11 | FileCheck -check-prefix=CHECK-SANITY %s
+// RUN: not diff -U0 %s diff_to.cpp | %run_clang_tidy --diff=0 -checks=-*,modernize-use-override2>&1 | FileCheck %s
+// RUN: not diff -U0 %s diff_to.cpp | %run_clang_tidy --diff=0 -checks=-*,modernize-use-override -quiet 2>&1 | FileCheck -check-prefix=CHECK-QUIET %s
+// RUN: not diff -U0 %s diff_to.cpp | %run_clang_tidy --diff=0 -checks=-*,modernize-use-override2>&1 | FileCheck -check-prefix=CHECK %s
+struct A {
+  virtual void f() {}
+  virtual void g() {}
+};
+// CHECK-NOT: warning:
+// CHECK-QUIET-NOT: warning:
+struct B : public A {
+  void placeholder_for_f() {}
+// CHECK-SANITY: [[@LINE-1]]:8: warning: annotate this
+// CHECK: [[@LINE-2]]:8: warning: annotate this
+// CHECK-QUIET: [[@LINE-3]]:8: warning: annotate this
+  void g() {}
+// CHECK-SANITY: [[@LINE-1]]:8: warning: annotate this
+// CHECK-NOT: warning:
+// CHECK-QUIET-NOT: warning:
+};
+// CHECK-SANITY-NOT: Suppressed
+// CHECK-QUIET-NOT: Suppressed
Index: clang-tidy/tool/run-clang-tidy.py
===
--- clang-tidy/tool/run-clang-tidy.py
+++ clang-tidy/tool/run-clang-tidy.py
@@ -7,7 +7,6 @@
 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 #
 #======#
-# FIXME: Integrate with clang-tidy-diff.py
 
 """
 Parallel clang-tidy runner
@@ -60,6 +59,7 @@
 else:
 import queue as queue
 
+
 def find_compilation_database(path):
   """Adjusts the directory until a compilation database is found."""
   result = './'
@@ -77,7 +77,7 @@
   return os.path.normpath(os.path.join(directory, f))
 
 
-def get_tidy_invocation(f, clang_tidy_binary, checks, tmpdir, build_path,
+def get_tidy_invocation(f, lines, clang_tidy_binary, checks, tmpdir, build_path,
 header_filter, extra_arg, extra_arg_before, quiet,
 config):
   """Gets a command line for clang-tidy."""
@@ -87,6 +87,12 @@
   else:
 # Show warnings in all in-project headers by default.
 start.append('-header-filter=^' + build_path + '/.*')
+
+  if lines is not None:
+line_json = json.dumps([{"name": f, "lines": lines}], separators=(',', ':'))
+# Run clang-tidy on files containing changes.
+start.append('-line-filter=' + line_json)
+
   if checks:
 start.append('-checks=' + checks)
   if tmpdir is not None:
@@ -159,8 +165,9 @@
 def run_tidy(args, tmpdir, build_path, queue, lock, failed_files):
   """Takes filenames out of queue and runs clang-tidy on them."""
   while True:
-name = queue.get()
-invocation = get_tidy_invocation(name, args.clang_tidy_binary, args.checks,
+(name, lines) = queue.get()
+invocation = get_tidy_invocation(name, lines,
+ args.clang_tidy_binary, args.checks,
  tmpdir, build_path, args.header_filter,
  args.extra_arg, args.extra_arg_before,
  args.quiet, args.config)
@@ -176,11 +183,42 @@
 queue.task_done()
 
 
+def get_changed_lines(prefix_len):
+  iregex = '^%s$' % r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc)'
+  lines_by_file = {}
+  filename = None
+  for line in sys.stdin:
+match = re.search('^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % prefix_len, line)
+if match:
+  filename = match.group(2)
+if filename is None:
+  continue
+
+if not re.match(iregex, filename, re.IGNORECASE):
+  continue
+
+match = re.search('^@@.*\+(\d+)(,(\d+))?', line)
+if match:
+  start_line = int(match.group(1))
+  line_count = 1
+  if match.group(3):
+line_count = int(match.group(3))
+  if line_count == 0:
+continue
+  end_line = start_line + line_count - 1
+  lines_by_file.setdefault(filename, []).append([start_line, end_line])
+
+  return lines_by_file
+
+
 def main():
   parser = argparse.ArgumentParser(description='Runs clang-tidy over all files '
'in a compilation database. Requires '
'clang-tidy and 

[PATCH] D59449: [clang-tidy] Integrate clang-tidy-diff.py machinery into run-clang-tidy.py

2019-04-01 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

Gentle ping.


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

https://reviews.llvm.org/D59449



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


[PATCH] D59449: [clang-tidy] Integrate clang-tidy-diff.py machinery into run-clang-tidy.py

2019-04-01 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

> Why not just use clang-tidy-diff.py? The clang-tidy-diff.py script has a 
> distinct and somewhat self-documenting name and a very specific purpose (find 
> clang-tidy regressions in a patch), while run-clang-tidy.py is more focused 
> on running over larger bodies of code with a purpose of analyzing or cleaning 
> up. Is there any benefit in having all functionality in run-clang-tidy.py?

Both scripts have almost the same implementation, almost the same syntax (at 
least after -j and -timeout we introduced). So why not merge them.


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

https://reviews.llvm.org/D59449



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


[PATCH] D59449: [clang-tidy] Integrate clang-tidy-diff.py machinery into run-clang-tidy.py

2019-04-03 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

@alexfh, do you still have any objections?


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

https://reviews.llvm.org/D59449



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


[PATCH] D45776: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py

2018-10-03 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

In https://reviews.llvm.org/D45776#1251256, @lebedev.ri wrote:

> Did this intentionally omit the possibility to pass a group of prefixes, like 
> `FileCheck` supports?
>  Usefulness of this feature is somewhat penalized by this.


I did not fully realize what do you mean. Can you please provide a sample? I 
see only single `-check-prefix=` in `FileCheck`.


Repository:
  rL LLVM

https://reviews.llvm.org/D45776



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


[PATCH] D52971: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py to support multiple prefixes

2018-10-07 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis created this revision.
zinovy.nis added reviewers: lebedev.ri, alexfh.
zinovy.nis added a project: clang-tools-extra.
Herald added subscribers: cfe-commits, xazax.hun.

The patch extends the existing command line option `-check_suffix` to accept 
multiple comma-separated prefixes.

  // RUN: %check_clang_tidy -check-suffix=USING-C,USING-D %s 
misc-unused-using-decls %t -- -- ...


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D52971

Files:
  test/clang-tidy/check_clang_tidy.cpp
  test/clang-tidy/check_clang_tidy.py

Index: test/clang-tidy/check_clang_tidy.py
===
--- test/clang-tidy/check_clang_tidy.py
+++ test/clang-tidy/check_clang_tidy.py
@@ -18,7 +18,7 @@
 Usage:
   check_clang_tidy.py [-resource-dir=] \
 [-assume-filename=] \
-[-check-suffix=] \
+[-check-suffix=] \
\
 -- [optional clang-tidy arguments]
 
@@ -38,15 +38,18 @@
 f.write(text)
 f.truncate()
 
+def csv(string):
+  return string.split(',')
+
 def main():
   parser = argparse.ArgumentParser()
   parser.add_argument('-expect-clang-tidy-error', action='store_true')
   parser.add_argument('-resource-dir')
   parser.add_argument('-assume-filename')
-  parser.add_argument('-check-suffix', default='')
   parser.add_argument('input_file_name')
   parser.add_argument('check_name')
   parser.add_argument('temp_file_name')
+  parser.add_argument('-check-suffix', default=[], type=csv, help="comma-separated list of FileCheck suffixes")
 
   args, extra_args = parser.parse_known_args()
 
@@ -72,14 +75,6 @@
   clang_tidy_extra_args.extend(
   ['-fobjc-abi-version=2', '-fobjc-arc'])
 
-  if args.check_suffix and not re.match('^[A-Z0-9\-]+$', args.check_suffix):
-sys.exit('Only A..Z, 0..9 and "-" are allowed in check suffix, but "%s" was given' % (args.check_suffix))
-
-  file_check_suffix = ('-' + args.check_suffix) if args.check_suffix else ''
-  check_fixes_prefix = 'CHECK-FIXES' + file_check_suffix
-  check_messages_prefix = 'CHECK-MESSAGES' + file_check_suffix
-  check_notes_prefix = 'CHECK-NOTES' + file_check_suffix
-
   # Tests should not rely on STL being available, and instead provide mock
   # implementations of relevant APIs.
   clang_tidy_extra_args.append('-nostdinc++')
@@ -90,15 +85,33 @@
   with open(input_file_name, 'r') as input_file:
 input_text = input_file.read()
 
-  has_check_fixes = check_fixes_prefix in input_text
-  has_check_messages = check_messages_prefix in input_text
-  has_check_notes = check_notes_prefix in input_text
+  check_fixes_prefixes = []
+  check_messages_prefixes = []
+  check_notes_prefixes = []
+
+  if any(args.check_suffix):
+for check in args.check_suffix:
+  if not re.match('^[A-Z0-9\-,]+$', check):
+sys.exit('Only A..Z, 0..9, "," and "-" are ' +
+  'allowed in check suffixes list, but "%s" was given' % (check))
+  file_check_suffix = '-' + check
+  check_fixes_prefixes.append('CHECK-FIXES' + file_check_suffix)
+  check_messages_prefixes.append('CHECK-MESSAGES' + file_check_suffix)
+  check_notes_prefixes.append('CHECK-NOTES' + file_check_suffix)
+  else:
+check_fixes_prefixes = ['CHECK-FIXES']
+check_messages_prefixes = ['CHECK-MESSAGES']
+check_notes_prefixes = ['CHECK-NOTES']
+
+  has_check_fixes = any(prefix in input_text for prefix in check_fixes_prefixes)
+  has_check_messages = any(prefix in input_text for prefix in check_messages_prefixes)
+  has_check_notes = any(prefix in input_text for prefix in check_notes_prefixes)
 
   if not has_check_fixes and not has_check_messages and not has_check_notes:
-sys.exit('%s, %s or %s not found in the input' % (check_fixes_prefix,
- check_messages_prefix, check_notes_prefix) )
+sys.exit('%s, %s or %s not found in the input' %
+ (check_fixes_prefixes, check_messages_prefixes, check_notes_prefixes))
 
-  if has_check_notes and has_check_messages:
+  if any(set(check_notes_prefixes) & set(check_messages_prefixes)):
 sys.exit('Please use either CHECK-NOTES or CHECK-MESSAGES but not both')
 
   # Remove the contents of the CHECK lines to avoid CHECKs matching on
@@ -143,7 +156,8 @@
 try:
   subprocess.check_output(
   ['FileCheck', '-input-file=' + temp_file_name, input_file_name,
-   '-check-prefix=' + check_fixes_prefix, '-strict-whitespace'],
+   '-check-prefixes=' + ','.join(check_fixes_prefixes),
+   '-strict-whitespace'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -155,7 +169,7 @@
 try:
   subprocess.check_output(
   ['FileCheck', '-input-file=' + messages_file, input_file_name,
-   '-check-prefix=' + check_messages_prefix,
+   '-check-prefixes=' + ','.join(check_messages_prefixes),
'-implicit-check-not={{warning|error}}:'],
   stderr=subprocess.STDOUT)

[PATCH] D45776: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py

2018-10-07 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

In https://reviews.llvm.org/D45776#1253944, @lebedev.ri wrote:

> >> Did this intentionally omit the possibility to pass a group of prefixes, 
> >> like `FileCheck` supports?
> >>  Usefulness of this feature is somewhat penalized by this.


Done. Please review this https://reviews.llvm.org/D52971


Repository:
  rL LLVM

https://reviews.llvm.org/D45776



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


[PATCH] D52971: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py to support multiple prefixes

2018-10-07 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 168609.
zinovy.nis added a comment.

Removed "," from the list of allowed suffix characters.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D52971

Files:
  test/clang-tidy/check_clang_tidy.cpp
  test/clang-tidy/check_clang_tidy.py

Index: test/clang-tidy/check_clang_tidy.py
===
--- test/clang-tidy/check_clang_tidy.py
+++ test/clang-tidy/check_clang_tidy.py
@@ -18,7 +18,7 @@
 Usage:
   check_clang_tidy.py [-resource-dir=] \
 [-assume-filename=] \
-[-check-suffix=] \
+[-check-suffix=] \
\
 -- [optional clang-tidy arguments]
 
@@ -38,15 +38,18 @@
 f.write(text)
 f.truncate()
 
+def csv(string):
+  return string.split(',')
+
 def main():
   parser = argparse.ArgumentParser()
   parser.add_argument('-expect-clang-tidy-error', action='store_true')
   parser.add_argument('-resource-dir')
   parser.add_argument('-assume-filename')
-  parser.add_argument('-check-suffix', default='')
   parser.add_argument('input_file_name')
   parser.add_argument('check_name')
   parser.add_argument('temp_file_name')
+  parser.add_argument('-check-suffix', default=[], type=csv, help="comma-separated list of FileCheck suffixes")
 
   args, extra_args = parser.parse_known_args()
 
@@ -72,14 +75,6 @@
   clang_tidy_extra_args.extend(
   ['-fobjc-abi-version=2', '-fobjc-arc'])
 
-  if args.check_suffix and not re.match('^[A-Z0-9\-]+$', args.check_suffix):
-sys.exit('Only A..Z, 0..9 and "-" are allowed in check suffix, but "%s" was given' % (args.check_suffix))
-
-  file_check_suffix = ('-' + args.check_suffix) if args.check_suffix else ''
-  check_fixes_prefix = 'CHECK-FIXES' + file_check_suffix
-  check_messages_prefix = 'CHECK-MESSAGES' + file_check_suffix
-  check_notes_prefix = 'CHECK-NOTES' + file_check_suffix
-
   # Tests should not rely on STL being available, and instead provide mock
   # implementations of relevant APIs.
   clang_tidy_extra_args.append('-nostdinc++')
@@ -90,15 +85,33 @@
   with open(input_file_name, 'r') as input_file:
 input_text = input_file.read()
 
-  has_check_fixes = check_fixes_prefix in input_text
-  has_check_messages = check_messages_prefix in input_text
-  has_check_notes = check_notes_prefix in input_text
+  check_fixes_prefixes = []
+  check_messages_prefixes = []
+  check_notes_prefixes = []
+
+  if any(args.check_suffix):
+for check in args.check_suffix:
+  if not re.match('^[A-Z0-9\-]+$', check):
+sys.exit('Only A..Z, 0..9 and "-" are ' +
+  'allowed in check suffixes list, but "%s" was given' % (check))
+  file_check_suffix = '-' + check
+  check_fixes_prefixes.append('CHECK-FIXES' + file_check_suffix)
+  check_messages_prefixes.append('CHECK-MESSAGES' + file_check_suffix)
+  check_notes_prefixes.append('CHECK-NOTES' + file_check_suffix)
+  else:
+check_fixes_prefixes = ['CHECK-FIXES']
+check_messages_prefixes = ['CHECK-MESSAGES']
+check_notes_prefixes = ['CHECK-NOTES']
+
+  has_check_fixes = any(prefix in input_text for prefix in check_fixes_prefixes)
+  has_check_messages = any(prefix in input_text for prefix in check_messages_prefixes)
+  has_check_notes = any(prefix in input_text for prefix in check_notes_prefixes)
 
   if not has_check_fixes and not has_check_messages and not has_check_notes:
-sys.exit('%s, %s or %s not found in the input' % (check_fixes_prefix,
- check_messages_prefix, check_notes_prefix) )
+sys.exit('%s, %s or %s not found in the input' %
+ (check_fixes_prefixes, check_messages_prefixes, check_notes_prefixes))
 
-  if has_check_notes and has_check_messages:
+  if any(set(check_notes_prefixes) & set(check_messages_prefixes)):
 sys.exit('Please use either CHECK-NOTES or CHECK-MESSAGES but not both')
 
   # Remove the contents of the CHECK lines to avoid CHECKs matching on
@@ -143,7 +156,8 @@
 try:
   subprocess.check_output(
   ['FileCheck', '-input-file=' + temp_file_name, input_file_name,
-   '-check-prefix=' + check_fixes_prefix, '-strict-whitespace'],
+   '-check-prefixes=' + ','.join(check_fixes_prefixes),
+   '-strict-whitespace'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -155,7 +169,7 @@
 try:
   subprocess.check_output(
   ['FileCheck', '-input-file=' + messages_file, input_file_name,
-   '-check-prefix=' + check_messages_prefix,
+   '-check-prefixes=' + ','.join(check_messages_prefixes),
'-implicit-check-not={{warning|error}}:'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
@@ -170,7 +184,7 @@
 try:
   subprocess.check_output(
   ['FileCheck', '-input-file=' + notes_file, input_file_name,
-   '-check-prefix=' + check_notes_prefix,
+   '-check-prefixes=' +

[PATCH] D52971: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py to support multiple prefixes

2018-10-07 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis marked an inline comment as done.
zinovy.nis added inline comments.



Comment at: test/clang-tidy/check_clang_tidy.py:94-95
+for check in args.check_suffix:
+  if not re.match('^[A-Z0-9\-,]+$', check):
+sys.exit('Only A..Z, 0..9, "," and "-" are ' +
+  'allowed in check suffixes list, but "%s" was given' % (check))

lebedev.ri wrote:
> How `,` can be allowed if that is the suffix separator?
> Also, i think `_` can be supported.
When discussing the previous patch Alex said on underscores: 

> I don't know whether it makes sense to endorse (or even allow) the use of 
> underscore in the check suffix. The mix of underscores and dashes looks ugly 
> and is prone to errors.

So it was intentionally.



Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D52971



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


[PATCH] D52971: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py to support multiple prefixes

2018-10-08 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

In https://reviews.llvm.org/D52971#1257702, @JonasToth wrote:

> The change looks good in principle. I think it would make sense to migrate 
> one test already, to use the new capability and check if everything works as 
> expected. The current tests still run fine?


Yes, all the existing tests pass successfully.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D52971



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


[PATCH] D52971: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py to support multiple prefixes

2018-10-08 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

In https://reviews.llvm.org/D52971#1257705, @alexfh wrote:

> Looks good with a comment.


It can break the compatibility. May be it worth to add an alias 
"-check-suffixes" for this option?


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D52971



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


[PATCH] D52971: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py to support multiple prefixes

2018-10-08 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 168690.
zinovy.nis added a comment.

- Fixed diagnostics;
- Interchangeable alias introduced: `-check-suffixes` for `-check-suffix`.


https://reviews.llvm.org/D52971

Files:
  test/clang-tidy/check_clang_tidy.cpp
  test/clang-tidy/check_clang_tidy.py

Index: test/clang-tidy/check_clang_tidy.py
===
--- test/clang-tidy/check_clang_tidy.py
+++ test/clang-tidy/check_clang_tidy.py
@@ -18,7 +18,7 @@
 Usage:
   check_clang_tidy.py [-resource-dir=] \
 [-assume-filename=] \
-[-check-suffix=] \
+[-check-suffix=] \
\
 -- [optional clang-tidy arguments]
 
@@ -38,15 +38,20 @@
 f.write(text)
 f.truncate()
 
+def csv(string):
+  return string.split(',')
+
 def main():
   parser = argparse.ArgumentParser()
   parser.add_argument('-expect-clang-tidy-error', action='store_true')
   parser.add_argument('-resource-dir')
   parser.add_argument('-assume-filename')
-  parser.add_argument('-check-suffix', default='')
   parser.add_argument('input_file_name')
   parser.add_argument('check_name')
   parser.add_argument('temp_file_name')
+  parser.add_argument('-check-suffix', '-check-suffixes',
+  default=[], type=csv,
+  help="comma-separated list of FileCheck suffixes")
 
   args, extra_args = parser.parse_known_args()
 
@@ -72,14 +77,6 @@
   clang_tidy_extra_args.extend(
   ['-fobjc-abi-version=2', '-fobjc-arc'])
 
-  if args.check_suffix and not re.match('^[A-Z0-9\-]+$', args.check_suffix):
-sys.exit('Only A..Z, 0..9 and "-" are allowed in check suffix, but "%s" was given' % (args.check_suffix))
-
-  file_check_suffix = ('-' + args.check_suffix) if args.check_suffix else ''
-  check_fixes_prefix = 'CHECK-FIXES' + file_check_suffix
-  check_messages_prefix = 'CHECK-MESSAGES' + file_check_suffix
-  check_notes_prefix = 'CHECK-NOTES' + file_check_suffix
-
   # Tests should not rely on STL being available, and instead provide mock
   # implementations of relevant APIs.
   clang_tidy_extra_args.append('-nostdinc++')
@@ -90,16 +87,48 @@
   with open(input_file_name, 'r') as input_file:
 input_text = input_file.read()
 
-  has_check_fixes = check_fixes_prefix in input_text
-  has_check_messages = check_messages_prefix in input_text
-  has_check_notes = check_notes_prefix in input_text
-
-  if not has_check_fixes and not has_check_messages and not has_check_notes:
-sys.exit('%s, %s or %s not found in the input' % (check_fixes_prefix,
- check_messages_prefix, check_notes_prefix) )
-
-  if has_check_notes and has_check_messages:
-sys.exit('Please use either CHECK-NOTES or CHECK-MESSAGES but not both')
+  check_fixes_prefixes = []
+  check_messages_prefixes = []
+  check_notes_prefixes = []
+
+  has_check_fixes = False
+  has_check_messages = False
+  has_check_notes = False
+
+  if any(args.check_suffix):
+for check in args.check_suffix:
+  if not re.match('^[A-Z0-9\-]+$', check):
+sys.exit('Only A..Z, 0..9 and "-" are ' +
+  'allowed in check suffixes list, but "%s" was given' % (check))
+
+  file_check_suffix = '-' + check
+  check_fixes_prefix = 'CHECK-FIXES' + file_check_suffix
+  check_messages_prefix = 'CHECK-MESSAGES' + file_check_suffix
+  check_notes_prefix = 'CHECK-NOTES' + file_check_suffix
+
+  has_check_fix = check_fixes_prefix in input_text 
+  has_check_message = check_messages_prefix in input_text
+  has_check_note = check_notes_prefix in input_text 
+
+  if has_check_note and has_check_message:
+sys.exit('Please use either %s or %s but not both' %
+  (check_notes_prefix, check_messages_prefix))
+
+  if not has_check_fix and not has_check_message and not has_check_note:
+sys.exit('%s, %s or %s not found in the input' %
+  (check_fixes_prefix, check_messages_prefix, check_notes_prefix))
+
+  has_check_fixes = has_check_fixes or has_check_fix
+  has_check_messages = has_check_messages or has_check_message
+  has_check_notes = has_check_notes or has_check_note
+
+  check_fixes_prefixes.append(check_fixes_prefix)
+  check_messages_prefixes.append(check_messages_prefix)
+  check_notes_prefixes.append(check_notes_prefix)
+  else:
+check_fixes_prefixes = ['CHECK-FIXES']
+check_messages_prefixes = ['CHECK-MESSAGES']
+check_notes_prefixes = ['CHECK-NOTES']
 
   # Remove the contents of the CHECK lines to avoid CHECKs matching on
   # themselves.  We need to keep the comments to preserve line numbers while
@@ -143,7 +172,8 @@
 try:
   subprocess.check_output(
   ['FileCheck', '-input-file=' + temp_file_name, input_file_name,
-   '-check-prefix=' + check_fixes_prefix, '-strict-whitespace'],
+   '-check-prefixes=' + ','.join(check_fixes_prefixes),
+   '-strict-whitespace'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as 

[PATCH] D52971: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py to support multiple prefixes

2018-10-08 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

In https://reviews.llvm.org/D52971#1257702, @JonasToth wrote:

> I think it would make sense to migrate one test already, to use the new 
> capability


This change was inspired by Roman Lebedev (lebedev.ri), so we expect him to 
provide us with such a test soon ;-)


https://reviews.llvm.org/D52971



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


[PATCH] D52971: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py to support multiple prefixes

2018-10-08 Thread Zinovy Nis via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL344015: [clang-tidy] The patch extends the existing command 
line option -check-suffix  (authored by zinovy.nis, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D52971?vs=168690&id=168745#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D52971

Files:
  clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy.cpp
  clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy.py

Index: clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy.py
===
--- clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy.py
+++ clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy.py
@@ -18,7 +18,8 @@
 Usage:
   check_clang_tidy.py [-resource-dir=] \
 [-assume-filename=] \
-[-check-suffix=] \
+[-check-suffix=] \
+[-check-suffixes=] \
\
 -- [optional clang-tidy arguments]
 
@@ -38,15 +39,20 @@
 f.write(text)
 f.truncate()
 
+def csv(string):
+  return string.split(',')
+
 def main():
   parser = argparse.ArgumentParser()
   parser.add_argument('-expect-clang-tidy-error', action='store_true')
   parser.add_argument('-resource-dir')
   parser.add_argument('-assume-filename')
-  parser.add_argument('-check-suffix', default='')
   parser.add_argument('input_file_name')
   parser.add_argument('check_name')
   parser.add_argument('temp_file_name')
+  parser.add_argument('-check-suffix', '-check-suffixes',
+  default=[], type=csv,
+  help="comma-separated list of FileCheck suffixes")
 
   args, extra_args = parser.parse_known_args()
 
@@ -72,14 +78,6 @@
   clang_tidy_extra_args.extend(
   ['-fobjc-abi-version=2', '-fobjc-arc'])
 
-  if args.check_suffix and not re.match('^[A-Z0-9\-]+$', args.check_suffix):
-sys.exit('Only A..Z, 0..9 and "-" are allowed in check suffix, but "%s" was given' % (args.check_suffix))
-
-  file_check_suffix = ('-' + args.check_suffix) if args.check_suffix else ''
-  check_fixes_prefix = 'CHECK-FIXES' + file_check_suffix
-  check_messages_prefix = 'CHECK-MESSAGES' + file_check_suffix
-  check_notes_prefix = 'CHECK-NOTES' + file_check_suffix
-
   # Tests should not rely on STL being available, and instead provide mock
   # implementations of relevant APIs.
   clang_tidy_extra_args.append('-nostdinc++')
@@ -90,16 +88,48 @@
   with open(input_file_name, 'r') as input_file:
 input_text = input_file.read()
 
-  has_check_fixes = check_fixes_prefix in input_text
-  has_check_messages = check_messages_prefix in input_text
-  has_check_notes = check_notes_prefix in input_text
-
-  if not has_check_fixes and not has_check_messages and not has_check_notes:
-sys.exit('%s, %s or %s not found in the input' % (check_fixes_prefix,
- check_messages_prefix, check_notes_prefix) )
-
-  if has_check_notes and has_check_messages:
-sys.exit('Please use either CHECK-NOTES or CHECK-MESSAGES but not both')
+  check_fixes_prefixes = []
+  check_messages_prefixes = []
+  check_notes_prefixes = []
+
+  has_check_fixes = False
+  has_check_messages = False
+  has_check_notes = False
+
+  if any(args.check_suffix):
+for check in args.check_suffix:
+  if not re.match('^[A-Z0-9\-]+$', check):
+sys.exit('Only A..Z, 0..9 and "-" are ' +
+  'allowed in check suffixes list, but "%s" was given' % (check))
+
+  file_check_suffix = '-' + check
+  check_fixes_prefix = 'CHECK-FIXES' + file_check_suffix
+  check_messages_prefix = 'CHECK-MESSAGES' + file_check_suffix
+  check_notes_prefix = 'CHECK-NOTES' + file_check_suffix
+
+  has_check_fix = check_fixes_prefix in input_text 
+  has_check_message = check_messages_prefix in input_text
+  has_check_note = check_notes_prefix in input_text 
+
+  if has_check_note and has_check_message:
+sys.exit('Please use either %s or %s but not both' %
+  (check_notes_prefix, check_messages_prefix))
+
+  if not has_check_fix and not has_check_message and not has_check_note:
+sys.exit('%s, %s or %s not found in the input' %
+  (check_fixes_prefix, check_messages_prefix, check_notes_prefix))
+
+  has_check_fixes = has_check_fixes or has_check_fix
+  has_check_messages = has_check_messages or has_check_message
+  has_check_notes = has_check_notes or has_check_note
+
+  check_fixes_prefixes.append(check_fixes_prefix)
+  check_messages_prefixes.append(check_messages_prefix)
+  check_notes_prefixes.append(check_notes_prefix)
+  else:
+check_fixes_prefixes = ['CHECK-FIXES']
+check_messages_prefixes = ['CHECK-MESSAGES']
+check_notes_prefixes = ['CHECK-NOTES']
 
   # Remove the contents of the CHECK lines to avoid CHECKs matching on
   # themselves.  We need to keep the comments to preserve line numbers while
@@ -143,7 +173,8 @@
 try:
   subprocess.chec

[PATCH] D57662: [clang-tidy] Parallelise clang-tidy-diff.py

2019-02-03 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis created this revision.
zinovy.nis added reviewers: alexfh, ehsan.
zinovy.nis added a project: clang-tools-extra.
Herald added subscribers: cfe-commits, xazax.hun.
Herald added a reviewer: serge-sans-paille.
Herald added a project: clang.

This patch has 2 rationales:

- large patches lead to long command lines and often cause max command line 
length restrictions imposed by OS;
- clang-tidy runs are independent and can be done in parallel, the same as done 
for run-clang-tidy.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D57662

Files:
  clang-tidy/tool/clang-tidy-diff.py

Index: clang-tidy/tool/clang-tidy-diff.py
===
--- clang-tidy/tool/clang-tidy-diff.py
+++ clang-tidy/tool/clang-tidy-diff.py
@@ -25,9 +25,50 @@
 
 import argparse
 import json
+import multiprocessing
+import os
 import re
 import subprocess
 import sys
+import threading
+
+is_py2 = sys.version[0] == '2'
+
+if is_py2:
+import Queue as queue
+else:
+import queue as queue
+
+def run_tidy(task_queue, lock, timeout):
+  while True:
+command = task_queue.get()
+proc = subprocess.Popen(command,
+stdout=subprocess.PIPE,
+stderr=subprocess.PIPE)
+if not timeout is None:
+  watchdog = threading.Timer(timeout, proc.kill)
+try:
+  if not timeout is None:
+watchdog.start()
+  stdout, stderr = proc.communicate()
+  with lock:
+sys.stdout.write(command + '\n' + stdout.decode('utf-8') + '\n')
+if len(stderr) > 0:
+  sys.stderr.write(stderr.decode('utf-8') + '\n')
+finally:
+  if not timeout is None:
+if not watchdog.is_alive():
+  with lock:
+sys.stderr.write(command + "\tterminated after timeout\n")
+watchdog.cancel()
+  task_queue.task_done()
+
+
+def run_workers(max_tasks, tidy_caller, task_queue, lock, timeout):
+  for _ in range(max_tasks):
+t = threading.Thread(target=tidy_caller, args=(task_queue, lock, timeout))
+t.daemon = True
+t.start()
 
 
 def main():
@@ -48,6 +89,10 @@
   help='custom pattern selecting file paths to check '
   '(case insensitive, overridden by -regex)')
 
+  parser.add_argument('-j', type=int, default=0,
+  help='number of tidy instances to be run in parallel.')
+  parser.add_argument('-timeout', type=int, default=None,
+  help='timeout per each file in seconds.')
   parser.add_argument('-fix', action='store_true', default=False,
   help='apply suggested fixes')
   parser.add_argument('-checks',
@@ -84,7 +129,7 @@
 match = re.search('^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % args.p, line)
 if match:
   filename = match.group(2)
-if filename == None:
+if filename is None:
   continue
 
 if args.regex is not None:
@@ -102,44 +147,68 @@
 line_count = int(match.group(3))
   if line_count == 0:
 continue
-  end_line = start_line + line_count - 1;
+  end_line = start_line + line_count - 1
   lines_by_file.setdefault(filename, []).append([start_line, end_line])
 
-  if len(lines_by_file) == 0:
+  if not any(lines_by_file):
 print("No relevant changes found.")
 sys.exit(0)
 
-  line_filter_json = json.dumps(
-[{"name" : name, "lines" : lines_by_file[name]} for name in lines_by_file],
-separators = (',', ':'))
+  max_task = args.j
+  if max_task == 0:
+  max_task = multiprocessing.cpu_count()
+  max_task = min(len(lines_by_file), max_task)
 
-  quote = "";
-  if sys.platform == 'win32':
-line_filter_json=re.sub(r'"', r'"""', line_filter_json)
-  else:
-quote = "'";
+  # Tasks for clang-tidy.
+  task_queue = queue.Queue(max_task)
+  # A lock for console output.
+  lock = threading.Lock()
 
-  # Run clang-tidy on files containing changes.
-  command = [args.clang_tidy_binary]
-  command.append('-line-filter=' + quote + line_filter_json + quote)
+  # Run a pool of clang-tidy workers.
+  run_workers(max_task, run_tidy, task_queue, lock, args.timeout)
+
+  # Run a watchdog.
+  quote = ""
+  if sys.platform != 'win32':
+quote = "'"
+
+  # Form the common args list.
+  common_clang_tidy_args = []
   if args.fix:
-command.append('-fix')
+common_clang_tidy_args.append('-fix')
   if args.export_fixes:
-command.append('-export-fixes=' + args.export_fixes)
+common_clang_tidy_args.append('-export-fixes=' + args.export_fixes)
   if args.checks != '':
-command.append('-checks=' + quote + args.checks + quote)
+common_clang_tidy_args.append('-checks=' + quote + args.checks + quote)
   if args.quiet:
-command.append('-quiet')
+common_clang_tidy_args.append('-quiet')
   if args.build_path is not None:
-command.append('-p=%s' % args.build_path)
-  command.extend(lines_by_file.keys())
+common_clang_tidy_args.append('-p=%s' % args.build_path)
   for ar

[PATCH] D57662: [clang-tidy] Parallelise clang-tidy-diff.py

2019-02-04 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 185085.
zinovy.nis added a comment.

Fixed minor typos.


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

https://reviews.llvm.org/D57662

Files:
  clang-tidy/tool/clang-tidy-diff.py

Index: clang-tidy/tool/clang-tidy-diff.py
===
--- clang-tidy/tool/clang-tidy-diff.py
+++ clang-tidy/tool/clang-tidy-diff.py
@@ -25,9 +25,56 @@
 
 import argparse
 import json
+import multiprocessing
+import os
 import re
 import subprocess
 import sys
+import threading
+
+is_py2 = sys.version[0] == '2'
+
+if is_py2:
+import Queue as queue
+else:
+import queue as queue
+
+def run_tidy(task_queue, lock, timeout):
+  watchdog = None
+  while True:
+command = task_queue.get()
+try:
+  proc = subprocess.Popen(command,
+  stdout=subprocess.PIPE,
+  stderr=subprocess.PIPE)
+
+  if not timeout is None:
+watchdog = threading.Timer(timeout, proc.kill)
+watchdog.start()
+
+  stdout, stderr = proc.communicate()
+
+  with lock:
+sys.stdout.write(' '.join(command) + '\n' + stdout.decode('utf-8') + '\n')
+if stderr:
+  sys.stderr.write(stderr.decode('utf-8') + '\n')
+except:
+  with lock:
+sys.stderr.write('Failed: ' + str(sys.exc_info()[0]) + ' '.join(command) + '\n')
+finally:
+  with lock:
+if (not timeout is None) and (not watchdog is None):
+  if not watchdog.is_alive():
+  sys.stderr.write('Terminated by timeout: ' + ' '.join(command) + '\n')
+  watchdog.cancel()
+  task_queue.task_done()
+
+
+def run_workers(max_tasks, tidy_caller, task_queue, lock, timeout):
+  for _ in range(max_tasks):
+t = threading.Thread(target=tidy_caller, args=(task_queue, lock, timeout))
+t.daemon = True
+t.start()
 
 
 def main():
@@ -48,6 +95,10 @@
   help='custom pattern selecting file paths to check '
   '(case insensitive, overridden by -regex)')
 
+  parser.add_argument('-j', type=int, default=0,
+  help='number of tidy instances to be run in parallel.')
+  parser.add_argument('-timeout', type=int, default=None,
+  help='timeout per each file in seconds.')
   parser.add_argument('-fix', action='store_true', default=False,
   help='apply suggested fixes')
   parser.add_argument('-checks',
@@ -84,7 +135,7 @@
 match = re.search('^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % args.p, line)
 if match:
   filename = match.group(2)
-if filename == None:
+if filename is None:
   continue
 
 if args.regex is not None:
@@ -102,44 +153,65 @@
 line_count = int(match.group(3))
   if line_count == 0:
 continue
-  end_line = start_line + line_count - 1;
+  end_line = start_line + line_count - 1
   lines_by_file.setdefault(filename, []).append([start_line, end_line])
 
-  if len(lines_by_file) == 0:
+  if not any(lines_by_file):
 print("No relevant changes found.")
 sys.exit(0)
 
-  line_filter_json = json.dumps(
-[{"name" : name, "lines" : lines_by_file[name]} for name in lines_by_file],
-separators = (',', ':'))
+  max_task = args.j
+  if max_task == 0:
+  max_task = multiprocessing.cpu_count()
+  max_task = min(len(lines_by_file), max_task)
 
-  quote = "";
-  if sys.platform == 'win32':
-line_filter_json=re.sub(r'"', r'"""', line_filter_json)
-  else:
-quote = "'";
+  # Tasks for clang-tidy.
+  task_queue = queue.Queue(max_task)
+  # A lock for console output.
+  lock = threading.Lock()
 
-  # Run clang-tidy on files containing changes.
-  command = [args.clang_tidy_binary]
-  command.append('-line-filter=' + quote + line_filter_json + quote)
+  # Run a pool of clang-tidy workers.
+  run_workers(max_task, run_tidy, task_queue, lock, args.timeout)
+
+  # Run a watchdog.
+  quote = ""
+  if sys.platform != 'win32':
+quote = "'"
+
+  # Form the common args list.
+  common_clang_tidy_args = []
   if args.fix:
-command.append('-fix')
+common_clang_tidy_args.append('-fix')
   if args.export_fixes:
-command.append('-export-fixes=' + args.export_fixes)
+common_clang_tidy_args.append('-export-fixes=' + args.export_fixes)
   if args.checks != '':
-command.append('-checks=' + quote + args.checks + quote)
+common_clang_tidy_args.append('-checks=' + quote + args.checks + quote)
   if args.quiet:
-command.append('-quiet')
+common_clang_tidy_args.append('-quiet')
   if args.build_path is not None:
-command.append('-p=%s' % args.build_path)
-  command.extend(lines_by_file.keys())
+common_clang_tidy_args.append('-p=%s' % args.build_path)
   for arg in args.extra_arg:
-  command.append('-extra-arg=%s' % arg)
+common_clang_tidy_args.append('-extra-arg=%s' % arg)
   for arg in args.extra_arg_before:
-  command.append('-extra-arg-be

[PATCH] D57662: [clang-tidy] Parallelise clang-tidy-diff.py

2019-02-04 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 185087.

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

https://reviews.llvm.org/D57662

Files:
  clang-tidy/tool/clang-tidy-diff.py

Index: clang-tidy/tool/clang-tidy-diff.py
===
--- clang-tidy/tool/clang-tidy-diff.py
+++ clang-tidy/tool/clang-tidy-diff.py
@@ -25,9 +25,56 @@
 
 import argparse
 import json
+import multiprocessing
+import os
 import re
 import subprocess
 import sys
+import threading
+
+is_py2 = sys.version[0] == '2'
+
+if is_py2:
+import Queue as queue
+else:
+import queue as queue
+
+def run_tidy(task_queue, lock, timeout):
+  watchdog = None
+  while True:
+command = task_queue.get()
+try:
+  proc = subprocess.Popen(command,
+  stdout=subprocess.PIPE,
+  stderr=subprocess.PIPE)
+
+  if not timeout is None:
+watchdog = threading.Timer(timeout, proc.kill)
+watchdog.start()
+
+  stdout, stderr = proc.communicate()
+
+  with lock:
+sys.stdout.write(' '.join(command) + '\n' + stdout.decode('utf-8') + '\n')
+if stderr:
+  sys.stderr.write(stderr.decode('utf-8') + '\n')
+except:
+  with lock:
+sys.stderr.write('Failed: ' + str(sys.exc_info()[0]) + ' '.join(command) + '\n')
+finally:
+  with lock:
+if (not timeout is None) and (not watchdog is None):
+  if not watchdog.is_alive():
+  sys.stderr.write('Terminated by timeout: ' + ' '.join(command) + '\n')
+  watchdog.cancel()
+  task_queue.task_done()
+
+
+def run_workers(max_tasks, tidy_caller, task_queue, lock, timeout):
+  for _ in range(max_tasks):
+t = threading.Thread(target=tidy_caller, args=(task_queue, lock, timeout))
+t.daemon = True
+t.start()
 
 
 def main():
@@ -48,6 +95,10 @@
   help='custom pattern selecting file paths to check '
   '(case insensitive, overridden by -regex)')
 
+  parser.add_argument('-j', type=int, default=0,
+  help='number of tidy instances to be run in parallel.')
+  parser.add_argument('-timeout', type=int, default=None,
+  help='timeout per each file in seconds.')
   parser.add_argument('-fix', action='store_true', default=False,
   help='apply suggested fixes')
   parser.add_argument('-checks',
@@ -84,7 +135,7 @@
 match = re.search('^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % args.p, line)
 if match:
   filename = match.group(2)
-if filename == None:
+if filename is None:
   continue
 
 if args.regex is not None:
@@ -102,44 +153,64 @@
 line_count = int(match.group(3))
   if line_count == 0:
 continue
-  end_line = start_line + line_count - 1;
+  end_line = start_line + line_count - 1
   lines_by_file.setdefault(filename, []).append([start_line, end_line])
 
-  if len(lines_by_file) == 0:
+  if not any(lines_by_file):
 print("No relevant changes found.")
 sys.exit(0)
 
-  line_filter_json = json.dumps(
-[{"name" : name, "lines" : lines_by_file[name]} for name in lines_by_file],
-separators = (',', ':'))
+  max_task = args.j
+  if max_task == 0:
+  max_task = multiprocessing.cpu_count()
+  max_task = min(len(lines_by_file), max_task)
 
-  quote = "";
-  if sys.platform == 'win32':
-line_filter_json=re.sub(r'"', r'"""', line_filter_json)
-  else:
-quote = "'";
+  # Tasks for clang-tidy.
+  task_queue = queue.Queue(max_task)
+  # A lock for console output.
+  lock = threading.Lock()
 
-  # Run clang-tidy on files containing changes.
-  command = [args.clang_tidy_binary]
-  command.append('-line-filter=' + quote + line_filter_json + quote)
+  # Run a pool of clang-tidy workers.
+  run_workers(max_task, run_tidy, task_queue, lock, args.timeout)
+
+  quote = ""
+  if sys.platform != 'win32':
+quote = "'"
+
+  # Form the common args list.
+  common_clang_tidy_args = []
   if args.fix:
-command.append('-fix')
+common_clang_tidy_args.append('-fix')
   if args.export_fixes:
-command.append('-export-fixes=' + args.export_fixes)
+common_clang_tidy_args.append('-export-fixes=' + args.export_fixes)
   if args.checks != '':
-command.append('-checks=' + quote + args.checks + quote)
+common_clang_tidy_args.append('-checks=' + quote + args.checks + quote)
   if args.quiet:
-command.append('-quiet')
+common_clang_tidy_args.append('-quiet')
   if args.build_path is not None:
-command.append('-p=%s' % args.build_path)
-  command.extend(lines_by_file.keys())
+common_clang_tidy_args.append('-p=%s' % args.build_path)
   for arg in args.extra_arg:
-  command.append('-extra-arg=%s' % arg)
+common_clang_tidy_args.append('-extra-arg=%s' % arg)
   for arg in args.extra_arg_before:
-  command.append('-extra-arg-before=%s' % arg)
-  command.extend(clang_tidy_args)
+common_clang_t

[PATCH] D57662: [clang-tidy] Parallelise clang-tidy-diff.py

2019-02-10 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

Gentle ping.


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

https://reviews.llvm.org/D57662



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


[PATCH] D57662: [clang-tidy] Parallelise clang-tidy-diff.py

2019-02-11 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

In D57662#1392509 , @MyDeveloperDay 
wrote:

> Just a question.. If clang tidy is running with -fix in parallel, what stops 
> each clang-tidy invocation altering a common header at the same time?


You are right. May be it worth disabling `-fix` for `j != 1`.


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

https://reviews.llvm.org/D57662



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


[PATCH] D57662: [clang-tidy] Parallelise clang-tidy-diff.py

2019-02-11 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

> I only say this because I think I might have seen it happen when I was 
> running `run-clang-tidy.py` over a large code base with a fairly aggressive 
> check/fixit, but frankly I was too new to LLVM to know it wasn't something I 
> might have done wrong.

A bit strange as `run-clang-tidy.py` explicitly collects fixes in separate 
files and after all merges them into a single fix in a thread/process-safe 
manner. Not like my current patch.


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

https://reviews.llvm.org/D57662



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


[PATCH] D57662: [clang-tidy] Parallelise clang-tidy-diff.py

2019-02-12 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 186514.
zinovy.nis added a comment.

`-j` and `-export-fixes` were made mutually exclusive.


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

https://reviews.llvm.org/D57662

Files:
  clang-tidy/tool/clang-tidy-diff.py

Index: clang-tidy/tool/clang-tidy-diff.py
===
--- clang-tidy/tool/clang-tidy-diff.py
+++ clang-tidy/tool/clang-tidy-diff.py
@@ -25,9 +25,56 @@
 
 import argparse
 import json
+import multiprocessing
+import os
 import re
 import subprocess
 import sys
+import threading
+
+is_py2 = sys.version[0] == '2'
+
+if is_py2:
+import Queue as queue
+else:
+import queue as queue
+
+def run_tidy(task_queue, lock, timeout):
+  watchdog = None
+  while True:
+command = task_queue.get()
+try:
+  proc = subprocess.Popen(command,
+  stdout=subprocess.PIPE,
+  stderr=subprocess.PIPE)
+
+  if not timeout is None:
+watchdog = threading.Timer(timeout, proc.kill)
+watchdog.start()
+
+  stdout, stderr = proc.communicate()
+
+  with lock:
+sys.stdout.write(' '.join(command) + '\n' + stdout.decode('utf-8') + '\n')
+if stderr:
+  sys.stderr.write(stderr.decode('utf-8') + '\n')
+except:
+  with lock:
+sys.stderr.write('Failed: ' + str(sys.exc_info()[0]) + ' '.join(command) + '\n')
+finally:
+  with lock:
+if (not timeout is None) and (not watchdog is None):
+  if not watchdog.is_alive():
+  sys.stderr.write('Terminated by timeout: ' + ' '.join(command) + '\n')
+  watchdog.cancel()
+  task_queue.task_done()
+
+
+def run_workers(max_tasks, tidy_caller, task_queue, lock, timeout):
+  for _ in range(max_tasks):
+t = threading.Thread(target=tidy_caller, args=(task_queue, lock, timeout))
+t.daemon = True
+t.start()
 
 
 def main():
@@ -48,6 +95,10 @@
   help='custom pattern selecting file paths to check '
   '(case insensitive, overridden by -regex)')
 
+  parser.add_argument('-j', type=int, default=0,
+  help='number of tidy instances to be run in parallel.')
+  parser.add_argument('-timeout', type=int, default=None,
+  help='timeout per each file in seconds.')
   parser.add_argument('-fix', action='store_true', default=False,
   help='apply suggested fixes')
   parser.add_argument('-checks',
@@ -77,6 +128,11 @@
 
   args = parser.parse_args(argv)
 
+  if args.j == 0 or args.j > 1:
+if args.export_fixes:
+  print("error: -export-fixes and -j are mutually exclusive.")
+  sys.exit(1)
+
   # Extract changed lines for each file.
   filename = None
   lines_by_file = {}
@@ -84,7 +140,7 @@
 match = re.search('^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % args.p, line)
 if match:
   filename = match.group(2)
-if filename == None:
+if filename is None:
   continue
 
 if args.regex is not None:
@@ -102,44 +158,64 @@
 line_count = int(match.group(3))
   if line_count == 0:
 continue
-  end_line = start_line + line_count - 1;
+  end_line = start_line + line_count - 1
   lines_by_file.setdefault(filename, []).append([start_line, end_line])
 
-  if len(lines_by_file) == 0:
+  if not any(lines_by_file):
 print("No relevant changes found.")
 sys.exit(0)
 
-  line_filter_json = json.dumps(
-[{"name" : name, "lines" : lines_by_file[name]} for name in lines_by_file],
-separators = (',', ':'))
+  max_task = args.j
+  if max_task == 0:
+  max_task = multiprocessing.cpu_count()
+  max_task = min(len(lines_by_file), max_task)
+
+  # Tasks for clang-tidy.
+  task_queue = queue.Queue(max_task)
+  # A lock for console output.
+  lock = threading.Lock()
 
-  quote = "";
-  if sys.platform == 'win32':
-line_filter_json=re.sub(r'"', r'"""', line_filter_json)
-  else:
-quote = "'";
+  # Run a pool of clang-tidy workers.
+  run_workers(max_task, run_tidy, task_queue, lock, args.timeout)
 
-  # Run clang-tidy on files containing changes.
-  command = [args.clang_tidy_binary]
-  command.append('-line-filter=' + quote + line_filter_json + quote)
+  quote = ""
+  if sys.platform != 'win32':
+quote = "'"
+
+  # Form the common args list.
+  common_clang_tidy_args = []
   if args.fix:
-command.append('-fix')
+common_clang_tidy_args.append('-fix')
   if args.export_fixes:
-command.append('-export-fixes=' + args.export_fixes)
+common_clang_tidy_args.append('-export-fixes=' + args.export_fixes)
   if args.checks != '':
-command.append('-checks=' + quote + args.checks + quote)
+common_clang_tidy_args.append('-checks=' + quote + args.checks + quote)
   if args.quiet:
-command.append('-quiet')
+common_clang_tidy_args.append('-quiet')
   if args.build_path is not None:
-command.append('-p=%s' % args.build_path)
-  

[PATCH] D57662: [clang-tidy] Parallelise clang-tidy-diff.py

2019-02-13 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

Any comments?


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

https://reviews.llvm.org/D57662



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


[PATCH] D57662: [clang-tidy] Parallelise clang-tidy-diff.py

2019-02-14 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis marked an inline comment as done.
zinovy.nis added inline comments.



Comment at: clang-tidy/tool/clang-tidy-diff.py:76
+t = threading.Thread(target=tidy_caller, args=(task_queue, lock, timeout))
+t.daemon = True
+t.start()

JonasToth wrote:
> why daemonize? Who kills that thread in the end? I think it's not the best 
> choice.
The script can be interrupted with keyabord or other signal, so it need not 
wait for any worker thread.


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

https://reviews.llvm.org/D57662



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


[PATCH] D57662: [clang-tidy] Parallelise clang-tidy-diff.py

2019-02-15 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis marked an inline comment as done.
zinovy.nis added inline comments.



Comment at: clang-tidy/tool/clang-tidy-diff.py:98
 
+  parser.add_argument('-j', type=int, default=0,
+  help='number of tidy instances to be run in parallel.')

alexfh wrote:
> The "clang-tidy runs are independent" assumption is unfortunately not valid 
> for our internal compilation database integration, so making `-j0` the 
> default will break it. Let's make it `1`.
Do you mean you run it with `-fix` or like this?


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

https://reviews.llvm.org/D57662



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


[PATCH] D57662: [clang-tidy] Parallelise clang-tidy-diff.py

2019-02-19 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 187421.
zinovy.nis added a comment.

- `-j` is `1` by default;
- fixed minor remarks;


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

https://reviews.llvm.org/D57662

Files:
  clang-tidy/tool/clang-tidy-diff.py

Index: clang-tidy/tool/clang-tidy-diff.py
===
--- clang-tidy/tool/clang-tidy-diff.py
+++ clang-tidy/tool/clang-tidy-diff.py
@@ -25,9 +25,56 @@
 
 import argparse
 import json
+import multiprocessing
+import os
 import re
 import subprocess
 import sys
+import threading
+
+is_py2 = sys.version[0] == '2'
+
+if is_py2:
+import Queue as queue
+else:
+import queue as queue
+
+def run_tidy(task_queue, lock, timeout):
+  watchdog = None
+  while True:
+command = task_queue.get()
+try:
+  proc = subprocess.Popen(command,
+  stdout=subprocess.PIPE,
+  stderr=subprocess.PIPE)
+
+  if timeout is not None:
+watchdog = threading.Timer(timeout, proc.kill)
+watchdog.start()
+
+  stdout, stderr = proc.communicate()
+
+  with lock:
+sys.stdout.write((' '.join(command)).decode('utf-8') + '\n' + stdout.decode('utf-8') + '\n')
+if stderr:
+  sys.stderr.write(stderr.decode('utf-8') + '\n')
+except Exception as e:
+  with lock:
+sys.stderr.write('Failed: ' + str(e) + ' '.join(command) + '\n')
+finally:
+  with lock:
+if (not timeout is None) and (not watchdog is None):
+  if not watchdog.is_alive():
+  sys.stderr.write('Terminated by timeout: ' + ' '.join(command) + '\n')
+  watchdog.cancel()
+  task_queue.task_done()
+
+
+def run_workers(max_tasks, tidy_caller, task_queue, lock, timeout):
+  for _ in range(max_tasks):
+t = threading.Thread(target=tidy_caller, args=(task_queue, lock, timeout))
+t.daemon = True
+t.start()
 
 
 def main():
@@ -48,6 +95,10 @@
   help='custom pattern selecting file paths to check '
   '(case insensitive, overridden by -regex)')
 
+  parser.add_argument('-j', type=int, default=1,
+  help='number of tidy instances to be run in parallel.')
+  parser.add_argument('-timeout', type=int, default=None,
+  help='timeout per each file in seconds.')
   parser.add_argument('-fix', action='store_true', default=False,
   help='apply suggested fixes')
   parser.add_argument('-checks',
@@ -77,6 +128,11 @@
 
   args = parser.parse_args(argv)
 
+  if args.j == 0 or args.j > 1:
+if args.export_fixes:
+  print("error: -export-fixes and -j are mutually exclusive.")
+  sys.exit(1)
+
   # Extract changed lines for each file.
   filename = None
   lines_by_file = {}
@@ -84,7 +140,7 @@
 match = re.search('^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % args.p, line)
 if match:
   filename = match.group(2)
-if filename == None:
+if filename is None:
   continue
 
 if args.regex is not None:
@@ -102,44 +158,64 @@
 line_count = int(match.group(3))
   if line_count == 0:
 continue
-  end_line = start_line + line_count - 1;
+  end_line = start_line + line_count - 1
   lines_by_file.setdefault(filename, []).append([start_line, end_line])
 
-  if len(lines_by_file) == 0:
+  if not any(lines_by_file):
 print("No relevant changes found.")
 sys.exit(0)
 
-  line_filter_json = json.dumps(
-[{"name" : name, "lines" : lines_by_file[name]} for name in lines_by_file],
-separators = (',', ':'))
+  max_task = args.j
+  if max_task == 0:
+  max_task = multiprocessing.cpu_count()
+  max_task = min(len(lines_by_file), max_task)
+
+  # Tasks for clang-tidy.
+  task_queue = queue.Queue(max_task)
+  # A lock for console output.
+  lock = threading.Lock()
 
-  quote = "";
-  if sys.platform == 'win32':
-line_filter_json=re.sub(r'"', r'"""', line_filter_json)
-  else:
-quote = "'";
+  # Run a pool of clang-tidy workers.
+  run_workers(max_task, run_tidy, task_queue, lock, args.timeout)
 
-  # Run clang-tidy on files containing changes.
-  command = [args.clang_tidy_binary]
-  command.append('-line-filter=' + quote + line_filter_json + quote)
+  quote = ""
+  if sys.platform != 'win32':
+quote = "'"
+
+  # Form the common args list.
+  common_clang_tidy_args = []
   if args.fix:
-command.append('-fix')
+common_clang_tidy_args.append('-fix')
   if args.export_fixes:
-command.append('-export-fixes=' + args.export_fixes)
+common_clang_tidy_args.append('-export-fixes=' + args.export_fixes)
   if args.checks != '':
-command.append('-checks=' + quote + args.checks + quote)
+common_clang_tidy_args.append('-checks=' + quote + args.checks + quote)
   if args.quiet:
-command.append('-quiet')
+common_clang_tidy_args.append('-quiet')
   if args.build_path is not None:
-command.append('-p=%s' % args.buil

[PATCH] D57662: [clang-tidy] Parallelise clang-tidy-diff.py

2019-02-22 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis marked an inline comment as done.
zinovy.nis added inline comments.



Comment at: clang-tidy/tool/clang-tidy-diff.py:133
+if args.export_fixes:
+  print("error: -export-fixes and -j are mutually exclusive.")
+  sys.exit(1)

alexfh wrote:
> What's wrong with -export-fixes and -j? Different clang-tidy processes could 
> export the fixes to different files (e.g. the -export-fixes= value could be 
> used as a prefix of the filename with a sequential or random suffix. WDYT?
I can copy/paste (shame on me!) a code from `run-clang-tidy.py` that does just 
what we need.


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

https://reviews.llvm.org/D57662



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


[PATCH] D65104: [clang-tidy] Add FixItHint for performance-noexcept-move-constructor

2019-07-22 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis created this revision.
zinovy.nis added reviewers: alexfh, rsmith, aaron.ballman.
Herald added subscribers: cfe-commits, xazax.hun.
Herald added a project: clang.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D65104

Files:
  clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
  test/clang-tidy/performance-noexcept-move-constructor-fix.cpp

Index: test/clang-tidy/performance-noexcept-move-constructor-fix.cpp
===
--- test/clang-tidy/performance-noexcept-move-constructor-fix.cpp
+++ test/clang-tidy/performance-noexcept-move-constructor-fix.cpp
@@ -0,0 +1,67 @@
+// RUN: %check_clang_tidy %s performance-noexcept-move-constructor %t
+
+struct C_1 {
+ ~C_1() {}
+ C_1(int a) {}
+ C_1(C_1&& a) :C_1(5) {}
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+ C_1& operator=(C_1&&) { return *this; }
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+};
+
+struct C_2 {
+ ~C_2() {}
+ C_2(C_2&& a);
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+ C_2& operator=(C_2&&);
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+};
+
+C_2::C_2(C_2&& a) {}
+// CHECK-FIXES:{{.*}}noexcept{{.*}}
+C_2& C_2::operator=(C_2&&) { return *this; }
+// CHECK-FIXES:{{.*}}noexcept{{.*}}
+
+struct C_4 {
+ ~C_4() {}
+ C_4(C_4&& a);
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+ C_4& operator=(C_4&& a);
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+};
+
+C_4::C_4(C_4&& a) = default;
+// CHECK-FIXES:{{.*}}noexcept{{.*}}
+C_4& C_4::operator=(C_4&& a) = default;
+// CHECK-FIXES:{{.*}}noexcept{{.*}}
+
+template 
+struct C_5 {
+ C_5(C_5&&) {}
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+ ~C_5() {}
+ C_5& operator=(C_5&& a) = default;
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+};
+
+template 
+struct C_6 {
+ C_6(C_6&&) {}
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+ ~C_6() {}
+ auto operator=(C_6&& a)->C_6 = default;
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+};
+
+template 
+struct C_7 {
+ C_7(C_7&&) {}
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+ ~C_7() {}
+ auto operator=(C_7&& a)->C_7;
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+};
+
+template 
+auto C_7::operator=(C_7&& a) -> C_7 {}
+// CHECK-FIXES:{{.*}}noexcept{{.*}}
Index: clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
===
--- clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
+++ clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
@@ -9,6 +9,7 @@
 #include "NoexceptMoveConstructorCheck.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/FixIt.h"
 
 using namespace clang::ast_matchers;
 
@@ -33,7 +34,7 @@
 const MatchFinder::MatchResult &Result) {
   if (const auto *Decl = Result.Nodes.getNodeAs("decl")) {
 StringRef MethodType = "assignment operator";
-if (const auto *Ctor = dyn_cast(Decl)) {
+if (const CXXConstructorDecl *Ctor = dyn_cast(Decl)) {
   if (!Ctor->isMoveConstructor())
 return;
   MethodType = "constructor";
@@ -47,9 +48,20 @@
   return;
 
 if (!isNoexceptExceptionSpec(ProtoType->getExceptionSpecType())) {
-  diag(Decl->getLocation(), "move %0s should be marked noexcept")
+  auto Diag =
+  diag(Decl->getLocation(), "move %0s should be marked noexcept")
   << MethodType;
-  // FIXME: Add a fixit.
+  // Add FixIt hints.
+  SourceManager &SM = *Result.SourceManager;
+  assert(Decl->getNumParams() > 0);
+  SourceLocation NoexceptLoc = Decl->getParamDecl(Decl->getNumParams() - 1)
+   ->getSourceRange()
+   .getEnd();
+  if (NoexceptLoc.isValid())
+NoexceptLoc = Lexer::findLocationAfterToken(
+NoexceptLoc, tok::r_paren, SM, Result.Context->getLangOpts(), true);
+  if (NoexceptLoc.isValid())
+Diag << FixItHint::CreateInsertion(NoexceptLoc, " noexcept ");
   return;
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D65104: [clang-tidy] Add FixItHint for performance-noexcept-move-constructor

2019-07-22 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 211147.

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

https://reviews.llvm.org/D65104

Files:
  clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
  test/clang-tidy/performance-noexcept-move-constructor-fix.cpp

Index: test/clang-tidy/performance-noexcept-move-constructor-fix.cpp
===
--- test/clang-tidy/performance-noexcept-move-constructor-fix.cpp
+++ test/clang-tidy/performance-noexcept-move-constructor-fix.cpp
@@ -0,0 +1,67 @@
+// RUN: %check_clang_tidy %s performance-noexcept-move-constructor %t
+
+struct C_1 {
+ ~C_1() {}
+ C_1(int a) {}
+ C_1(C_1&& a) :C_1(5) {}
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+ C_1& operator=(C_1&&) { return *this; }
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+};
+
+struct C_2 {
+ ~C_2() {}
+ C_2(C_2&& a);
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+ C_2& operator=(C_2&&);
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+};
+
+C_2::C_2(C_2&& a) {}
+// CHECK-FIXES:{{.*}}noexcept{{.*}}
+C_2& C_2::operator=(C_2&&) { return *this; }
+// CHECK-FIXES:{{.*}}noexcept{{.*}}
+
+struct C_4 {
+ ~C_4() {}
+ C_4(C_4&& a);
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+ C_4& operator=(C_4&& a);
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+};
+
+C_4::C_4(C_4&& a) = default;
+// CHECK-FIXES:{{.*}}noexcept{{.*}}
+C_4& C_4::operator=(C_4&& a) = default;
+// CHECK-FIXES:{{.*}}noexcept{{.*}}
+
+template 
+struct C_5 {
+ C_5(C_5&&) {}
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+ ~C_5() {}
+ C_5& operator=(C_5&& a) = default;
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+};
+
+template 
+struct C_6 {
+ C_6(C_6&&) {}
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+ ~C_6() {}
+ auto operator=(C_6&& a)->C_6 = default;
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+};
+
+template 
+struct C_7 {
+ C_7(C_7&&) {}
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+ ~C_7() {}
+ auto operator=(C_7&& a)->C_7;
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+};
+
+template 
+auto C_7::operator=(C_7&& a) -> C_7 {}
+// CHECK-FIXES:{{.*}}noexcept{{.*}}
Index: clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
===
--- clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
+++ clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
@@ -9,6 +9,7 @@
 #include "NoexceptMoveConstructorCheck.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/FixIt.h"
 
 using namespace clang::ast_matchers;
 
@@ -47,9 +48,20 @@
   return;
 
 if (!isNoexceptExceptionSpec(ProtoType->getExceptionSpecType())) {
-  diag(Decl->getLocation(), "move %0s should be marked noexcept")
+  auto Diag =
+  diag(Decl->getLocation(), "move %0s should be marked noexcept")
   << MethodType;
-  // FIXME: Add a fixit.
+  // Add FixIt hints.
+  SourceManager &SM = *Result.SourceManager;
+  assert(Decl->getNumParams() > 0);
+  SourceLocation NoexceptLoc = Decl->getParamDecl(Decl->getNumParams() - 1)
+   ->getSourceRange()
+   .getEnd();
+  if (NoexceptLoc.isValid())
+NoexceptLoc = Lexer::findLocationAfterToken(
+NoexceptLoc, tok::r_paren, SM, Result.Context->getLangOpts(), true);
+  if (NoexceptLoc.isValid())
+Diag << FixItHint::CreateInsertion(NoexceptLoc, " noexcept ");
   return;
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D65104: [clang-tidy] Add FixItHint for performance-noexcept-move-constructor

2019-07-23 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis marked an inline comment as done.
zinovy.nis added inline comments.



Comment at: clang-tidy/performance/NoexceptMoveConstructorCheck.cpp:57
+  assert(Decl->getNumParams() > 0);
+  SourceLocation NoexceptLoc = Decl->getParamDecl(Decl->getNumParams() - 1)
+   ->getSourceRange()

aaron.ballman wrote:
> Does `getParamDecl()->getEndLoc()` not give the correct answer?
Unfortunately not. In that case 

`C_1(C_1&& a) :C_1(5) {}` turns into `C_1(C_1&& a noexcept) :C_1(5) {}`. 
instead of `C_1(C_1&& a) noexcept :C_1(5) {}`


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

https://reviews.llvm.org/D65104



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


[PATCH] D65104: [clang-tidy] Add FixItHint for performance-noexcept-move-constructor

2019-07-23 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 211428.
zinovy.nis added a comment.

- Fixed tests.


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

https://reviews.llvm.org/D65104

Files:
  clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
  test/clang-tidy/performance-noexcept-move-constructor-fix.cpp

Index: test/clang-tidy/performance-noexcept-move-constructor-fix.cpp
===
--- /dev/null
+++ test/clang-tidy/performance-noexcept-move-constructor-fix.cpp
@@ -0,0 +1,67 @@
+// RUN: %check_clang_tidy %s performance-noexcept-move-constructor %t
+
+struct C_1 {
+ ~C_1() {}
+ C_1(int a) {}
+ C_1(C_1&& a) :C_1(5) {}
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+ C_1& operator=(C_1&&) { return *this; }
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+};
+
+struct C_2 {
+ ~C_2() {}
+ C_2(C_2&& a);
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+ C_2& operator=(C_2&&);
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+};
+
+C_2::C_2(C_2&& a) {}
+// CHECK-FIXES:{{.*}}noexcept{{.*}}
+C_2& C_2::operator=(C_2&&) { return *this; }
+// CHECK-FIXES:{{.*}}noexcept{{.*}}
+
+struct C_4 {
+ ~C_4() {}
+ C_4(C_4&& a);
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+ C_4& operator=(C_4&& a);
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+};
+
+C_4::C_4(C_4&& a) = default;
+// CHECK-FIXES:{{.*}}noexcept{{.*}}
+C_4& C_4::operator=(C_4&& a) = default;
+// CHECK-FIXES:{{.*}}noexcept{{.*}}
+
+template 
+struct C_5 {
+ C_5(C_5&&) {}
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+ ~C_5() {}
+ C_5& operator=(C_5&& a) = default;
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+};
+
+template 
+struct C_6 {
+ C_6(C_6&&) {}
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+ ~C_6() {}
+ auto operator=(C_6&& a)->C_6 = default;
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+};
+
+template 
+struct C_7 {
+ C_7(C_7&&) {}
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+ ~C_7() {}
+ auto operator=(C_7&& a)->C_7;
+ // CHECK-FIXES:{{.*}}noexcept{{.*}}
+};
+
+template 
+auto C_7::operator=(C_7&& a) -> C_7 {}
+// CHECK-FIXES:{{.*}}noexcept{{.*}}
Index: clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
===
--- clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
+++ clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
@@ -9,6 +9,7 @@
 #include "NoexceptMoveConstructorCheck.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/FixIt.h"
 
 using namespace clang::ast_matchers;
 
@@ -47,9 +48,20 @@
   return;
 
 if (!isNoexceptExceptionSpec(ProtoType->getExceptionSpecType())) {
-  diag(Decl->getLocation(), "move %0s should be marked noexcept")
+  auto Diag =
+  diag(Decl->getLocation(), "move %0s should be marked noexcept")
   << MethodType;
-  // FIXME: Add a fixit.
+  // Add FixIt hints.
+  SourceManager &SM = *Result.SourceManager;
+  assert(Decl->getNumParams() > 0);
+  SourceLocation NoexceptLoc = Decl->getParamDecl(Decl->getNumParams() - 1)
+   ->getSourceRange()
+   .getEnd();
+  if (NoexceptLoc.isValid())
+NoexceptLoc = Lexer::findLocationAfterToken(
+NoexceptLoc, tok::r_paren, SM, Result.Context->getLangOpts(), true);
+  if (NoexceptLoc.isValid())
+Diag << FixItHint::CreateInsertion(NoexceptLoc, " noexcept ");
   return;
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D65104: [clang-tidy] Add FixItHint for performance-noexcept-move-constructor

2019-07-23 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 211429.

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

https://reviews.llvm.org/D65104

Files:
  clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
  test/clang-tidy/performance-noexcept-move-constructor-fix.cpp

Index: test/clang-tidy/performance-noexcept-move-constructor-fix.cpp
===
--- /dev/null
+++ test/clang-tidy/performance-noexcept-move-constructor-fix.cpp
@@ -0,0 +1,67 @@
+// RUN: %check_clang_tidy %s performance-noexcept-move-constructor %t
+
+struct C_1 {
+ ~C_1() {}
+ C_1(int a) {}
+ C_1(C_1&& a) :C_1(5) {}
+ // CHECK-FIXES: ){{.*}}noexcept{{.*}}:
+ C_1& operator=(C_1&&) { return *this; }
+ // CHECK-FIXES: ){{.*}}noexcept{{.*}} {
+};
+
+struct C_2 {
+ ~C_2() {}
+ C_2(C_2&& a);
+// CHECK-FIXES: ){{.*}}noexcept{{.*}};
+ C_2& operator=(C_2&&);
+// CHECK-FIXES: ){{.*}}noexcept{{.*}};
+};
+
+C_2::C_2(C_2&& a) {}
+// CHECK-FIXES: ){{.*}}noexcept{{.*}} {}
+C_2& C_2::operator=(C_2&&) { return *this; }
+// CHECK-FIXES: ){{.*}}noexcept{{.*}} {
+
+struct C_3 {
+ ~C_3() {}
+ C_3(C_3&& a);
+// CHECK-FIXES: ){{.*}}noexcept{{.*}};
+ C_3& operator=(C_3&& a);
+// CHECK-FIXES: ){{.*}}noexcept{{.*}};
+};
+
+C_3::C_3(C_3&& a) = default;
+// CHECK-FIXES: ){{.*}}noexcept{{.*}} = default;
+C_3& C_3::operator=(C_3&& a) = default;
+// CHECK-FIXES: ){{.*}}noexcept{{.*}} = default;
+
+template 
+struct C_4 {
+ C_4(C_4&&) {}
+// CHECK-FIXES: ){{.*}}noexcept{{.*}} {}
+ ~C_4() {}
+ C_4& operator=(C_4&& a) = default;
+// CHECK-FIXES: ){{.*}}noexcept{{.*}} = default;
+};
+
+template 
+struct C_5 {
+ C_5(C_5&&) {}
+// CHECK-FIXES:){{.*}}noexcept{{.*}} {}
+ ~C_5() {}
+ auto operator=(C_5&& a)->C_5 = default;
+// CHECK-FIXES:){{.*}}noexcept{{.*}} = default;
+};
+
+template 
+struct C_6 {
+ C_6(C_6&&) {}
+// CHECK-FIXES:){{.*}}noexcept{{.*}} {}
+ ~C_6() {}
+ auto operator=(C_6&& a)->C_6;
+// CHECK-FIXES:){{.*}}noexcept{{.*}};
+};
+
+template 
+auto C_6::operator=(C_6&& a) -> C_6 {}
+// CHECK-FIXES: ){{.*}}noexcept{{.*}} {}
Index: clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
===
--- clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
+++ clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
@@ -9,6 +9,7 @@
 #include "NoexceptMoveConstructorCheck.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/FixIt.h"
 
 using namespace clang::ast_matchers;
 
@@ -47,9 +48,20 @@
   return;
 
 if (!isNoexceptExceptionSpec(ProtoType->getExceptionSpecType())) {
-  diag(Decl->getLocation(), "move %0s should be marked noexcept")
+  auto Diag =
+  diag(Decl->getLocation(), "move %0s should be marked noexcept")
   << MethodType;
-  // FIXME: Add a fixit.
+  // Add FixIt hints.
+  SourceManager &SM = *Result.SourceManager;
+  assert(Decl->getNumParams() > 0);
+  SourceLocation NoexceptLoc = Decl->getParamDecl(Decl->getNumParams() - 1)
+   ->getSourceRange()
+   .getEnd();
+  if (NoexceptLoc.isValid())
+NoexceptLoc = Lexer::findLocationAfterToken(
+NoexceptLoc, tok::r_paren, SM, Result.Context->getLangOpts(), true);
+  if (NoexceptLoc.isValid())
+Diag << FixItHint::CreateInsertion(NoexceptLoc, " noexcept ");
   return;
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D65104: [clang-tidy] Add FixItHint for performance-noexcept-move-constructor

2019-08-04 Thread Zinovy Nis via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL367785: [clang-tidy] Add FixItHint for 
performance-noexcept-move-constructor (authored by zinovy.nis, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D65104?vs=211429&id=213244#toc

Repository:
  rL LLVM

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

https://reviews.llvm.org/D65104

Files:
  
clang-tools-extra/trunk/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
  
clang-tools-extra/trunk/test/clang-tidy/performance-noexcept-move-constructor-fix.cpp

Index: clang-tools-extra/trunk/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
@@ -9,6 +9,7 @@
 #include "NoexceptMoveConstructorCheck.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/FixIt.h"
 
 using namespace clang::ast_matchers;
 
@@ -47,9 +48,20 @@
   return;
 
 if (!isNoexceptExceptionSpec(ProtoType->getExceptionSpecType())) {
-  diag(Decl->getLocation(), "move %0s should be marked noexcept")
+  auto Diag =
+  diag(Decl->getLocation(), "move %0s should be marked noexcept")
   << MethodType;
-  // FIXME: Add a fixit.
+  // Add FixIt hints.
+  SourceManager &SM = *Result.SourceManager;
+  assert(Decl->getNumParams() > 0);
+  SourceLocation NoexceptLoc = Decl->getParamDecl(Decl->getNumParams() - 1)
+   ->getSourceRange()
+   .getEnd();
+  if (NoexceptLoc.isValid())
+NoexceptLoc = Lexer::findLocationAfterToken(
+NoexceptLoc, tok::r_paren, SM, Result.Context->getLangOpts(), true);
+  if (NoexceptLoc.isValid())
+Diag << FixItHint::CreateInsertion(NoexceptLoc, " noexcept ");
   return;
 }
 
Index: clang-tools-extra/trunk/test/clang-tidy/performance-noexcept-move-constructor-fix.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/performance-noexcept-move-constructor-fix.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/performance-noexcept-move-constructor-fix.cpp
@@ -0,0 +1,67 @@
+// RUN: %check_clang_tidy %s performance-noexcept-move-constructor %t
+
+struct C_1 {
+ ~C_1() {}
+ C_1(int a) {}
+ C_1(C_1&& a) :C_1(5) {}
+ // CHECK-FIXES: ){{.*}}noexcept{{.*}}:
+ C_1& operator=(C_1&&) { return *this; }
+ // CHECK-FIXES: ){{.*}}noexcept{{.*}} {
+};
+
+struct C_2 {
+ ~C_2() {}
+ C_2(C_2&& a);
+// CHECK-FIXES: ){{.*}}noexcept{{.*}};
+ C_2& operator=(C_2&&);
+// CHECK-FIXES: ){{.*}}noexcept{{.*}};
+};
+
+C_2::C_2(C_2&& a) {}
+// CHECK-FIXES: ){{.*}}noexcept{{.*}} {}
+C_2& C_2::operator=(C_2&&) { return *this; }
+// CHECK-FIXES: ){{.*}}noexcept{{.*}} {
+
+struct C_3 {
+ ~C_3() {}
+ C_3(C_3&& a);
+// CHECK-FIXES: ){{.*}}noexcept{{.*}};
+ C_3& operator=(C_3&& a);
+// CHECK-FIXES: ){{.*}}noexcept{{.*}};
+};
+
+C_3::C_3(C_3&& a) = default;
+// CHECK-FIXES: ){{.*}}noexcept{{.*}} = default;
+C_3& C_3::operator=(C_3&& a) = default;
+// CHECK-FIXES: ){{.*}}noexcept{{.*}} = default;
+
+template 
+struct C_4 {
+ C_4(C_4&&) {}
+// CHECK-FIXES: ){{.*}}noexcept{{.*}} {}
+ ~C_4() {}
+ C_4& operator=(C_4&& a) = default;
+// CHECK-FIXES: ){{.*}}noexcept{{.*}} = default;
+};
+
+template 
+struct C_5 {
+ C_5(C_5&&) {}
+// CHECK-FIXES:){{.*}}noexcept{{.*}} {}
+ ~C_5() {}
+ auto operator=(C_5&& a)->C_5 = default;
+// CHECK-FIXES:){{.*}}noexcept{{.*}} = default;
+};
+
+template 
+struct C_6 {
+ C_6(C_6&&) {}
+// CHECK-FIXES:){{.*}}noexcept{{.*}} {}
+ ~C_6() {}
+ auto operator=(C_6&& a)->C_6;
+// CHECK-FIXES:){{.*}}noexcept{{.*}};
+};
+
+template 
+auto C_6::operator=(C_6&& a) -> C_6 {}
+// CHECK-FIXES: ){{.*}}noexcept{{.*}} {}
\ No newline at end of file
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45160: [clang-apply-replacements] Make clang-apply-replacements installable

2018-04-13 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

Gentle ping.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D45160



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


[PATCH] D45776: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py

2018-04-18 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis created this revision.
zinovy.nis added a project: clang-tools-extra.
Herald added subscribers: cfe-commits, xazax.hun.

The patch introduces a new command line option `-check_suffix` to allow 
multiple %check_clang_tidy% in tests.

Sample:

  // RUN: %check_clang_tidy %s misc-unused-using-decls %t 
-check_suffix=-FLAG_1--  
  // RUN: %check_clang_tidy %s misc-unused-using-decls %t -check_suffix=-FLAG_2 
--  
  ...
  +// CHECK-MESSAGES-FLAG_1: :[[@LINE-4]]:10: warning: using decl 'B' is unused 
[misc-unused-using-decls]
  +// CHECK-MESSAGES-FLAG_2: :[[@LINE-7]]:10: warning: using decl 'A' is unused 
[misc-unused-using-decls]
  +// CHECK-FIXES-FLAG_1-NOT: using a::A;$
  +// CHECK-FIXES-FLAG_2-NOT: using a::B;$


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D45776

Files:
  test/clang-tidy/check_clang_tidy.cpp
  test/clang-tidy/check_clang_tidy.py


Index: test/clang-tidy/check_clang_tidy.py
===
--- test/clang-tidy/check_clang_tidy.py
+++ test/clang-tidy/check_clang_tidy.py
@@ -42,6 +42,7 @@
   parser.add_argument('-expect-clang-tidy-error', action='store_true')
   parser.add_argument('-resource-dir')
   parser.add_argument('-assume-filename')
+  parser.add_argument('-check_suffix', default='')
   parser.add_argument('input_file_name')
   parser.add_argument('check_name')
   parser.add_argument('temp_file_name')
@@ -70,6 +71,12 @@
   clang_tidy_extra_args.extend(
   ['-fobjc-abi-version=2', '-fobjc-arc'])
 
+  if args.check_suffix and not re.match('^[A-Z0-9-_]+$', args.check_suffix):
+sys.exit('Only A..Z, 0..9, "-" and "_" are allowed in check suffix, but 
"%s" was given' % (args.check_suffix))
+
+  check_fixes_prefix = 'CHECK-FIXES' + args.check_suffix
+  check_messages_prefix = 'CHECK-MESSAGES' + args.check_suffix
+
   # Tests should not rely on STL being available, and instead provide mock
   # implementations of relevant APIs.
   clang_tidy_extra_args.append('-nostdinc++')
@@ -80,17 +87,19 @@
   with open(input_file_name, 'r') as input_file:
 input_text = input_file.read()
 
-  has_check_fixes = input_text.find('CHECK-FIXES') >= 0
-  has_check_messages = input_text.find('CHECK-MESSAGES') >= 0
+  has_check_fixes = check_fixes_prefix in input_text
+  has_check_messages = check_messages_prefix in input_text
 
   if not has_check_fixes and not has_check_messages:
-sys.exit('Neither CHECK-FIXES nor CHECK-MESSAGES found in the input')
+sys.exit('Neither %s nor %s found in the input' % (check_fixes_prefix, 
check_messages_prefix) )
 
   # Remove the contents of the CHECK lines to avoid CHECKs matching on
   # themselves.  We need to keep the comments to preserve line numbers while
   # avoiding empty lines which could potentially trigger formatting-related
   # checks.
-  cleaned_test = re.sub('// *CHECK-[A-Z-]*:[^\r\n]*', '//', input_text)
+  cleaned_test = re.sub('// *CHECK-[A-Z0-9\-_]*:[^\r\n]*', '//', input_text)
+
+  print "\n\n\n>>>",input_text, "<<-\n\n"
 
   write_file(temp_file_name, cleaned_test)
 
@@ -128,7 +137,7 @@
 try:
   subprocess.check_output(
   ['FileCheck', '-input-file=' + temp_file_name, input_file_name,
-   '-check-prefix=CHECK-FIXES', '-strict-whitespace'],
+   '-check-prefix=' + check_fixes_prefix, '-strict-whitespace'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -140,7 +149,7 @@
 try:
   subprocess.check_output(
   ['FileCheck', '-input-file=' + messages_file, input_file_name,
-   '-check-prefix=CHECK-MESSAGES',
+   '-check-prefix=' + check_messages_prefix,
'-implicit-check-not={{warning|error}}:'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
Index: test/clang-tidy/check_clang_tidy.cpp
===
--- /dev/null
+++ test/clang-tidy/check_clang_tidy.cpp
@@ -0,0 +1,15 @@
+// RUN: %check_clang_tidy %s misc-unused-using-decls %t
+// RUN: %check_clang_tidy %s misc-unused-using-decls %t -check_suffix=-FLAG -- 
-DFLAG
+namespace a { class A {}; class B {};}
+namespace b {
+#if defined(FLAG)
+using a::A;
+#else
+using a::B;
+#endif
+}
+namespace c {}
+// CHECK-MESSAGES: :[[@LINE-4]]:10: warning: using decl 'B' is unused 
[misc-unused-using-decls]
+// CHECK-MESSAGES-FLAG: :[[@LINE-7]]:10: warning: using decl 'A' is unused 
[misc-unused-using-decls]
+// CHECK-FIXES-FLAG-NOT: using a::A;$
+// CHECK-FIXES-NOT: using a::B;$
\ No newline at end of file


Index: test/clang-tidy/check_clang_tidy.py
===
--- test/clang-tidy/check_clang_tidy.py
+++ test/clang-tidy/check_clang_tidy.py
@@ -42,6 +42,7 @@
   parser.add_argument('-expect-clang-tidy-error', action='store_true')
   parser.add_argument('-resource-dir')
   parser.add_argument('-assume-fil

[PATCH] D45776: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py

2018-04-19 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 143050.
zinovy.nis marked 4 inline comments as done.
zinovy.nis added a comment.

- Fixed issues pointed by Alexander.


https://reviews.llvm.org/D45776

Files:
  test/clang-tidy/check_clang_tidy.cpp
  test/clang-tidy/check_clang_tidy.py


Index: test/clang-tidy/check_clang_tidy.py
===
--- test/clang-tidy/check_clang_tidy.py
+++ test/clang-tidy/check_clang_tidy.py
@@ -42,6 +42,7 @@
   parser.add_argument('-expect-clang-tidy-error', action='store_true')
   parser.add_argument('-resource-dir')
   parser.add_argument('-assume-filename')
+  parser.add_argument('-check-suffix', default='')
   parser.add_argument('input_file_name')
   parser.add_argument('check_name')
   parser.add_argument('temp_file_name')
@@ -70,6 +71,13 @@
   clang_tidy_extra_args.extend(
   ['-fobjc-abi-version=2', '-fobjc-arc'])
 
+  if args.check_suffix and not re.match('^[A-Z0-9\-]+$', args.check_suffix):
+sys.exit('Only A..Z, 0..9 and "-" are allowed in check suffix, but "%s" 
was given' % (args.check_suffix))
+
+  file_check_suffix = ('-' + args.check_suffix) if args.check_suffix else ''
+  check_fixes_prefix = 'CHECK-FIXES' + file_check_suffix
+  check_messages_prefix = 'CHECK-MESSAGES' + file_check_suffix
+
   # Tests should not rely on STL being available, and instead provide mock
   # implementations of relevant APIs.
   clang_tidy_extra_args.append('-nostdinc++')
@@ -80,17 +88,17 @@
   with open(input_file_name, 'r') as input_file:
 input_text = input_file.read()
 
-  has_check_fixes = input_text.find('CHECK-FIXES') >= 0
-  has_check_messages = input_text.find('CHECK-MESSAGES') >= 0
+  has_check_fixes = check_fixes_prefix in input_text
+  has_check_messages = check_messages_prefix in input_text
 
   if not has_check_fixes and not has_check_messages:
-sys.exit('Neither CHECK-FIXES nor CHECK-MESSAGES found in the input')
+sys.exit('Neither %s nor %s found in the input' % (check_fixes_prefix, 
check_messages_prefix) )
 
   # Remove the contents of the CHECK lines to avoid CHECKs matching on
   # themselves.  We need to keep the comments to preserve line numbers while
   # avoiding empty lines which could potentially trigger formatting-related
   # checks.
-  cleaned_test = re.sub('// *CHECK-[A-Z-]*:[^\r\n]*', '//', input_text)
+  cleaned_test = re.sub('// *CHECK-[A-Z0-9\-]*:[^\r\n]*', '//', input_text)
 
   write_file(temp_file_name, cleaned_test)
 
@@ -128,7 +136,7 @@
 try:
   subprocess.check_output(
   ['FileCheck', '-input-file=' + temp_file_name, input_file_name,
-   '-check-prefix=CHECK-FIXES', '-strict-whitespace'],
+   '-check-prefix=' + check_fixes_prefix, '-strict-whitespace'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -140,7 +148,7 @@
 try:
   subprocess.check_output(
   ['FileCheck', '-input-file=' + messages_file, input_file_name,
-   '-check-prefix=CHECK-MESSAGES',
+   '-check-prefix=' + check_messages_prefix,
'-implicit-check-not={{warning|error}}:'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
Index: test/clang-tidy/check_clang_tidy.cpp
===
--- test/clang-tidy/check_clang_tidy.cpp
+++ test/clang-tidy/check_clang_tidy.cpp
@@ -0,0 +1,20 @@
+// RUN: %check_clang_tidy %s misc-unused-using-decls %t -check-suffix=USING-A 
-- -DUSING_A
+// RUN: %check_clang_tidy %s misc-unused-using-decls %t -check-suffix=USING-B 
-- -DUSING_B
+// RUN: %check_clang_tidy %s misc-unused-using-decls %t
+namespace a {class A {}; class B {}; class C {}; }
+namespace b {
+#if defined(USING_A)
+using a::A;
+#elif  defined(USING_B)
+using a::B;
+#else
+using a::C;
+#endif
+}
+namespace c {}
+// CHECK-MESSAGES-USING-A: :[[@LINE-8]]:10: warning: using decl 'A' {{.*}}
+// CHECK-MESSAGES-USING-B: :[[@LINE-7]]:10: warning: using decl 'B' {{.*}}
+// CHECK-MESSAGES: :[[@LINE-6]]:10: warning: using decl 'C' {{.*}}
+// CHECK-FIXES-USING-A-NOT: using a::A;$
+// CHECK-FIXES-USING-B-NOT: using a::B;$
+// CHECK-FIXES-NOT: using a::C;$


Index: test/clang-tidy/check_clang_tidy.py
===
--- test/clang-tidy/check_clang_tidy.py
+++ test/clang-tidy/check_clang_tidy.py
@@ -42,6 +42,7 @@
   parser.add_argument('-expect-clang-tidy-error', action='store_true')
   parser.add_argument('-resource-dir')
   parser.add_argument('-assume-filename')
+  parser.add_argument('-check-suffix', default='')
   parser.add_argument('input_file_name')
   parser.add_argument('check_name')
   parser.add_argument('temp_file_name')
@@ -70,6 +71,13 @@
   clang_tidy_extra_args.extend(
   ['-fobjc-abi-version=2', '-fobjc-arc'])
 
+  if args.check_suffix and not re.match('^[A-Z0-9\-]+$', args.check_suffix):
+sys

[PATCH] D45776: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py

2018-04-19 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 143052.
zinovy.nis added a comment.

- Updated docs.


https://reviews.llvm.org/D45776

Files:
  docs/clang-tidy/index.rst
  test/clang-tidy/check_clang_tidy.cpp
  test/clang-tidy/check_clang_tidy.py

Index: test/clang-tidy/check_clang_tidy.py
===
--- test/clang-tidy/check_clang_tidy.py
+++ test/clang-tidy/check_clang_tidy.py
@@ -42,6 +42,7 @@
   parser.add_argument('-expect-clang-tidy-error', action='store_true')
   parser.add_argument('-resource-dir')
   parser.add_argument('-assume-filename')
+  parser.add_argument('-check-suffix', default='')
   parser.add_argument('input_file_name')
   parser.add_argument('check_name')
   parser.add_argument('temp_file_name')
@@ -70,6 +71,13 @@
   clang_tidy_extra_args.extend(
   ['-fobjc-abi-version=2', '-fobjc-arc'])
 
+  if args.check_suffix and not re.match('^[A-Z0-9\-]+$', args.check_suffix):
+sys.exit('Only A..Z, 0..9 and "-" are allowed in check suffix, but "%s" was given' % (args.check_suffix))
+
+  file_check_suffix = ('-' + args.check_suffix) if args.check_suffix else ''
+  check_fixes_prefix = 'CHECK-FIXES' + file_check_suffix
+  check_messages_prefix = 'CHECK-MESSAGES' + file_check_suffix
+
   # Tests should not rely on STL being available, and instead provide mock
   # implementations of relevant APIs.
   clang_tidy_extra_args.append('-nostdinc++')
@@ -80,17 +88,17 @@
   with open(input_file_name, 'r') as input_file:
 input_text = input_file.read()
 
-  has_check_fixes = input_text.find('CHECK-FIXES') >= 0
-  has_check_messages = input_text.find('CHECK-MESSAGES') >= 0
+  has_check_fixes = check_fixes_prefix in input_text
+  has_check_messages = check_messages_prefix in input_text
 
   if not has_check_fixes and not has_check_messages:
-sys.exit('Neither CHECK-FIXES nor CHECK-MESSAGES found in the input')
+sys.exit('Neither %s nor %s found in the input' % (check_fixes_prefix, check_messages_prefix) )
 
   # Remove the contents of the CHECK lines to avoid CHECKs matching on
   # themselves.  We need to keep the comments to preserve line numbers while
   # avoiding empty lines which could potentially trigger formatting-related
   # checks.
-  cleaned_test = re.sub('// *CHECK-[A-Z-]*:[^\r\n]*', '//', input_text)
+  cleaned_test = re.sub('// *CHECK-[A-Z0-9\-]*:[^\r\n]*', '//', input_text)
 
   write_file(temp_file_name, cleaned_test)
 
@@ -128,7 +136,7 @@
 try:
   subprocess.check_output(
   ['FileCheck', '-input-file=' + temp_file_name, input_file_name,
-   '-check-prefix=CHECK-FIXES', '-strict-whitespace'],
+   '-check-prefix=' + check_fixes_prefix, '-strict-whitespace'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -140,7 +148,7 @@
 try:
   subprocess.check_output(
   ['FileCheck', '-input-file=' + messages_file, input_file_name,
-   '-check-prefix=CHECK-MESSAGES',
+   '-check-prefix=' + check_messages_prefix,
'-implicit-check-not={{warning|error}}:'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
Index: test/clang-tidy/check_clang_tidy.cpp
===
--- test/clang-tidy/check_clang_tidy.cpp
+++ test/clang-tidy/check_clang_tidy.cpp
@@ -0,0 +1,20 @@
+// RUN: %check_clang_tidy %s misc-unused-using-decls %t -check-suffix=USING-A -- -DUSING_A
+// RUN: %check_clang_tidy %s misc-unused-using-decls %t -check-suffix=USING-B -- -DUSING_B
+// RUN: %check_clang_tidy %s misc-unused-using-decls %t
+namespace a {class A {}; class B {}; class C {}; }
+namespace b {
+#if defined(USING_A)
+using a::A;
+#elif  defined(USING_B)
+using a::B;
+#else
+using a::C;
+#endif
+}
+namespace c {}
+// CHECK-MESSAGES-USING-A: :[[@LINE-8]]:10: warning: using decl 'A' {{.*}}
+// CHECK-MESSAGES-USING-B: :[[@LINE-7]]:10: warning: using decl 'B' {{.*}}
+// CHECK-MESSAGES: :[[@LINE-6]]:10: warning: using decl 'C' {{.*}}
+// CHECK-FIXES-USING-A-NOT: using a::A;$
+// CHECK-FIXES-USING-B-NOT: using a::B;$
+// CHECK-FIXES-NOT: using a::C;$
Index: docs/clang-tidy/index.rst
===
--- docs/clang-tidy/index.rst
+++ docs/clang-tidy/index.rst
@@ -673,6 +673,27 @@
 // CHECK-FIXES: int b = a;
   }
 
+To check more than one scenario in the same test file use 
+``-check-suffix=SUFFIX_NAME`` on ``check_clang_tidy.py`` command line.
+With ``-check-suffix=SUFFIX_NAME`` you need to replace your ``CHECK-*`` 
+directives with ``CHECK-MESSAGES-SUFFIX-NAME`` and ``CHECK-FIXES-SUFFIX-NAME``.
+
+Here's an example:
+
+.. code-block:: c++
+
+   // RUN: %check_clang_tidy %s misc-unused-using-decls %t -check-suffix=USING-A -- -DUSING_A
+   // RUN: %check_clang_tidy %s misc-unused-using-decls %t -check-suffix=USING-B -- -DUSING_B
+   // RUN: %check_clang_tidy %

[PATCH] D45776: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py

2018-04-19 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 143053.
zinovy.nis added a comment.

- Removed exec attribute on file.


https://reviews.llvm.org/D45776

Files:
  docs/clang-tidy/index.rst
  test/clang-tidy/check_clang_tidy.cpp
  test/clang-tidy/check_clang_tidy.py

Index: test/clang-tidy/check_clang_tidy.py
===
--- test/clang-tidy/check_clang_tidy.py
+++ test/clang-tidy/check_clang_tidy.py
@@ -42,6 +42,7 @@
   parser.add_argument('-expect-clang-tidy-error', action='store_true')
   parser.add_argument('-resource-dir')
   parser.add_argument('-assume-filename')
+  parser.add_argument('-check-suffix', default='')
   parser.add_argument('input_file_name')
   parser.add_argument('check_name')
   parser.add_argument('temp_file_name')
@@ -70,6 +71,13 @@
   clang_tidy_extra_args.extend(
   ['-fobjc-abi-version=2', '-fobjc-arc'])
 
+  if args.check_suffix and not re.match('^[A-Z0-9\-]+$', args.check_suffix):
+sys.exit('Only A..Z, 0..9 and "-" are allowed in check suffix, but "%s" was given' % (args.check_suffix))
+
+  file_check_suffix = ('-' + args.check_suffix) if args.check_suffix else ''
+  check_fixes_prefix = 'CHECK-FIXES' + file_check_suffix
+  check_messages_prefix = 'CHECK-MESSAGES' + file_check_suffix
+
   # Tests should not rely on STL being available, and instead provide mock
   # implementations of relevant APIs.
   clang_tidy_extra_args.append('-nostdinc++')
@@ -80,17 +88,17 @@
   with open(input_file_name, 'r') as input_file:
 input_text = input_file.read()
 
-  has_check_fixes = input_text.find('CHECK-FIXES') >= 0
-  has_check_messages = input_text.find('CHECK-MESSAGES') >= 0
+  has_check_fixes = check_fixes_prefix in input_text
+  has_check_messages = check_messages_prefix in input_text
 
   if not has_check_fixes and not has_check_messages:
-sys.exit('Neither CHECK-FIXES nor CHECK-MESSAGES found in the input')
+sys.exit('Neither %s nor %s found in the input' % (check_fixes_prefix, check_messages_prefix) )
 
   # Remove the contents of the CHECK lines to avoid CHECKs matching on
   # themselves.  We need to keep the comments to preserve line numbers while
   # avoiding empty lines which could potentially trigger formatting-related
   # checks.
-  cleaned_test = re.sub('// *CHECK-[A-Z-]*:[^\r\n]*', '//', input_text)
+  cleaned_test = re.sub('// *CHECK-[A-Z0-9\-]*:[^\r\n]*', '//', input_text)
 
   write_file(temp_file_name, cleaned_test)
 
@@ -128,7 +136,7 @@
 try:
   subprocess.check_output(
   ['FileCheck', '-input-file=' + temp_file_name, input_file_name,
-   '-check-prefix=CHECK-FIXES', '-strict-whitespace'],
+   '-check-prefix=' + check_fixes_prefix, '-strict-whitespace'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -140,7 +148,7 @@
 try:
   subprocess.check_output(
   ['FileCheck', '-input-file=' + messages_file, input_file_name,
-   '-check-prefix=CHECK-MESSAGES',
+   '-check-prefix=' + check_messages_prefix,
'-implicit-check-not={{warning|error}}:'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
Index: test/clang-tidy/check_clang_tidy.cpp
===
--- test/clang-tidy/check_clang_tidy.cpp
+++ test/clang-tidy/check_clang_tidy.cpp
@@ -0,0 +1,20 @@
+// RUN: %check_clang_tidy %s misc-unused-using-decls %t -check-suffix=USING-A -- -DUSING_A
+// RUN: %check_clang_tidy %s misc-unused-using-decls %t -check-suffix=USING-B -- -DUSING_B
+// RUN: %check_clang_tidy %s misc-unused-using-decls %t
+namespace a {class A {}; class B {}; class C {}; }
+namespace b {
+#if defined(USING_A)
+using a::A;
+#elif  defined(USING_B)
+using a::B;
+#else
+using a::C;
+#endif
+}
+namespace c {}
+// CHECK-MESSAGES-USING-A: :[[@LINE-8]]:10: warning: using decl 'A' {{.*}}
+// CHECK-MESSAGES-USING-B: :[[@LINE-7]]:10: warning: using decl 'B' {{.*}}
+// CHECK-MESSAGES: :[[@LINE-6]]:10: warning: using decl 'C' {{.*}}
+// CHECK-FIXES-USING-A-NOT: using a::A;$
+// CHECK-FIXES-USING-B-NOT: using a::B;$
+// CHECK-FIXES-NOT: using a::C;$
Index: docs/clang-tidy/index.rst
===
--- docs/clang-tidy/index.rst
+++ docs/clang-tidy/index.rst
@@ -673,6 +673,27 @@
 // CHECK-FIXES: int b = a;
   }
 
+To check more than one scenario in the same test file use 
+``-check-suffix=SUFFIX_NAME`` on ``check_clang_tidy.py`` command line.
+With ``-check-suffix=SUFFIX_NAME`` you need to replace your ``CHECK-*`` 
+directives with ``CHECK-MESSAGES-SUFFIX-NAME`` and ``CHECK-FIXES-SUFFIX-NAME``.
+
+Here's an example:
+
+.. code-block:: c++
+
+   // RUN: %check_clang_tidy %s misc-unused-using-decls %t -check-suffix=USING-A -- -DUSING_A
+   // RUN: %check_clang_tidy %s misc-unused-using-decls %t -check-suffix=USING-B -- -DUSING_B
+   // RUN: %

[PATCH] D45776: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py

2018-04-19 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a comment.

Done.


https://reviews.llvm.org/D45776



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


[PATCH] D45776: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py

2018-04-19 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added inline comments.



Comment at: test/clang-tidy/check_clang_tidy.py:77
+
+  check_fixes_prefix = 'CHECK-FIXES' + args.check_suffix
+  check_messages_prefix = 'CHECK-MESSAGES' + args.check_suffix

alexfh wrote:
> Maybe the script should add a dash when check_suffix is not empty, so that 
> one could use -check-suffix=FLAG instead of -check-suffix=-FLAG?
OK.


https://reviews.llvm.org/D45776



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


[PATCH] D45776: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py

2018-04-20 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 143384.
zinovy.nis edited the summary of this revision.
zinovy.nis added a comment.

- Minor cosmetic fixes.


https://reviews.llvm.org/D45776

Files:
  docs/clang-tidy/index.rst
  test/clang-tidy/check_clang_tidy.cpp
  test/clang-tidy/check_clang_tidy.py

Index: test/clang-tidy/check_clang_tidy.py
===
--- test/clang-tidy/check_clang_tidy.py
+++ test/clang-tidy/check_clang_tidy.py
@@ -18,6 +18,7 @@
 Usage:
   check_clang_tidy.py [-resource-dir ] \
 [-assume-filename ] \
+[-check-suffix ] \
\
 -- [optional clang-tidy arguments]
 
@@ -42,6 +43,7 @@
   parser.add_argument('-expect-clang-tidy-error', action='store_true')
   parser.add_argument('-resource-dir')
   parser.add_argument('-assume-filename')
+  parser.add_argument('-check-suffix', default='')
   parser.add_argument('input_file_name')
   parser.add_argument('check_name')
   parser.add_argument('temp_file_name')
@@ -70,6 +72,13 @@
   clang_tidy_extra_args.extend(
   ['-fobjc-abi-version=2', '-fobjc-arc'])
 
+  if args.check_suffix and not re.match('^[A-Z0-9\-]+$', args.check_suffix):
+sys.exit('Only A..Z, 0..9 and "-" are allowed in check suffix, but "%s" was given' % (args.check_suffix))
+
+  file_check_suffix = ('-' + args.check_suffix) if args.check_suffix else ''
+  check_fixes_prefix = 'CHECK-FIXES' + file_check_suffix
+  check_messages_prefix = 'CHECK-MESSAGES' + file_check_suffix
+
   # Tests should not rely on STL being available, and instead provide mock
   # implementations of relevant APIs.
   clang_tidy_extra_args.append('-nostdinc++')
@@ -80,17 +89,17 @@
   with open(input_file_name, 'r') as input_file:
 input_text = input_file.read()
 
-  has_check_fixes = input_text.find('CHECK-FIXES') >= 0
-  has_check_messages = input_text.find('CHECK-MESSAGES') >= 0
+  has_check_fixes = check_fixes_prefix in input_text
+  has_check_messages = check_messages_prefix in input_text
 
   if not has_check_fixes and not has_check_messages:
-sys.exit('Neither CHECK-FIXES nor CHECK-MESSAGES found in the input')
+sys.exit('Neither %s nor %s found in the input' % (check_fixes_prefix, check_messages_prefix) )
 
   # Remove the contents of the CHECK lines to avoid CHECKs matching on
   # themselves.  We need to keep the comments to preserve line numbers while
   # avoiding empty lines which could potentially trigger formatting-related
   # checks.
-  cleaned_test = re.sub('// *CHECK-[A-Z-]*:[^\r\n]*', '//', input_text)
+  cleaned_test = re.sub('// *CHECK-[A-Z0-9\-]*:[^\r\n]*', '//', input_text)
 
   write_file(temp_file_name, cleaned_test)
 
@@ -128,7 +137,7 @@
 try:
   subprocess.check_output(
   ['FileCheck', '-input-file=' + temp_file_name, input_file_name,
-   '-check-prefix=CHECK-FIXES', '-strict-whitespace'],
+   '-check-prefix=' + check_fixes_prefix, '-strict-whitespace'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -140,7 +149,7 @@
 try:
   subprocess.check_output(
   ['FileCheck', '-input-file=' + messages_file, input_file_name,
-   '-check-prefix=CHECK-MESSAGES',
+   '-check-prefix=' + check_messages_prefix,
'-implicit-check-not={{warning|error}}:'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
Index: test/clang-tidy/check_clang_tidy.cpp
===
--- test/clang-tidy/check_clang_tidy.cpp
+++ test/clang-tidy/check_clang_tidy.cpp
@@ -0,0 +1,21 @@
+// RUN: %check_clang_tidy -check-suffix USING-A %s misc-unused-using-decls %t -- -- -DUSING_A
+// RUN: %check_clang_tidy -check-suffix USING-B %s misc-unused-using-decls %t -- -- -DUSING_B
+// RUN: %check_clang_tidy %s misc-unused-using-decls %t
+
+namespace a {class A {}; class B {}; class C {}; }
+namespace b {
+#if defined(USING_A)
+using a::A;
+#elif  defined(USING_B)
+using a::B;
+#else
+using a::C;
+#endif
+}
+namespace c {}
+// CHECK-MESSAGES-USING-A: :[[@LINE-8]]:10: warning: using decl 'A' {{.*}}
+// CHECK-MESSAGES-USING-B: :[[@LINE-7]]:10: warning: using decl 'B' {{.*}}
+// CHECK-MESSAGES: :[[@LINE-6]]:10: warning: using decl 'C' {{.*}}
+// CHECK-FIXES-USING-A-NOT: using a::A;$
+// CHECK-FIXES-USING-B-NOT: using a::B;$
+// CHECK-FIXES-NOT: using a::C;$
Index: docs/clang-tidy/index.rst
===
--- docs/clang-tidy/index.rst
+++ docs/clang-tidy/index.rst
@@ -673,6 +673,27 @@
 // CHECK-FIXES: int b = a;
   }
 
+To check more than one scenario in the same test file use 
+``-check-suffix=SUFFIX_NAME`` on ``check_clang_tidy.py`` command line.
+With ``-check-suffix=SUFFIX_NAME`` you need to replace your ``CHECK-*`` 
+directives with ``CHECK-MESSAGES-SUFFIX-NAME`` and ``CHECK-FIXES-SUFFIX-NAME``.
+
+Here's an example:
+
+.. code-

[PATCH] D45776: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py

2018-04-21 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis updated this revision to Diff 143436.
zinovy.nis marked 3 inline comments as done.
zinovy.nis added a comment.

- Applied the changes suggested by Alexander.


https://reviews.llvm.org/D45776

Files:
  docs/clang-tidy/index.rst
  test/clang-tidy/check_clang_tidy.cpp
  test/clang-tidy/check_clang_tidy.py

Index: test/clang-tidy/check_clang_tidy.py
===
--- test/clang-tidy/check_clang_tidy.py
+++ test/clang-tidy/check_clang_tidy.py
@@ -16,8 +16,9 @@
 This script runs clang-tidy in fix mode and verify fixes, messages or both.
 
 Usage:
-  check_clang_tidy.py [-resource-dir ] \
-[-assume-filename ] \
+  check_clang_tidy.py [-resource-dir=] \
+[-assume-filename=] \
+[-check-suffix=] \
\
 -- [optional clang-tidy arguments]
 
@@ -42,6 +43,7 @@
   parser.add_argument('-expect-clang-tidy-error', action='store_true')
   parser.add_argument('-resource-dir')
   parser.add_argument('-assume-filename')
+  parser.add_argument('-check-suffix', default='')
   parser.add_argument('input_file_name')
   parser.add_argument('check_name')
   parser.add_argument('temp_file_name')
@@ -70,6 +72,13 @@
   clang_tidy_extra_args.extend(
   ['-fobjc-abi-version=2', '-fobjc-arc'])
 
+  if args.check_suffix and not re.match('^[A-Z0-9\-]+$', args.check_suffix):
+sys.exit('Only A..Z, 0..9 and "-" are allowed in check suffix, but "%s" was given' % (args.check_suffix))
+
+  file_check_suffix = ('-' + args.check_suffix) if args.check_suffix else ''
+  check_fixes_prefix = 'CHECK-FIXES' + file_check_suffix
+  check_messages_prefix = 'CHECK-MESSAGES' + file_check_suffix
+
   # Tests should not rely on STL being available, and instead provide mock
   # implementations of relevant APIs.
   clang_tidy_extra_args.append('-nostdinc++')
@@ -80,17 +89,17 @@
   with open(input_file_name, 'r') as input_file:
 input_text = input_file.read()
 
-  has_check_fixes = input_text.find('CHECK-FIXES') >= 0
-  has_check_messages = input_text.find('CHECK-MESSAGES') >= 0
+  has_check_fixes = check_fixes_prefix in input_text
+  has_check_messages = check_messages_prefix in input_text
 
   if not has_check_fixes and not has_check_messages:
-sys.exit('Neither CHECK-FIXES nor CHECK-MESSAGES found in the input')
+sys.exit('Neither %s nor %s found in the input' % (check_fixes_prefix, check_messages_prefix) )
 
   # Remove the contents of the CHECK lines to avoid CHECKs matching on
   # themselves.  We need to keep the comments to preserve line numbers while
   # avoiding empty lines which could potentially trigger formatting-related
   # checks.
-  cleaned_test = re.sub('// *CHECK-[A-Z-]*:[^\r\n]*', '//', input_text)
+  cleaned_test = re.sub('// *CHECK-[A-Z0-9\-]*:[^\r\n]*', '//', input_text)
 
   write_file(temp_file_name, cleaned_test)
 
@@ -128,7 +137,7 @@
 try:
   subprocess.check_output(
   ['FileCheck', '-input-file=' + temp_file_name, input_file_name,
-   '-check-prefix=CHECK-FIXES', '-strict-whitespace'],
+   '-check-prefix=' + check_fixes_prefix, '-strict-whitespace'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -140,7 +149,7 @@
 try:
   subprocess.check_output(
   ['FileCheck', '-input-file=' + messages_file, input_file_name,
-   '-check-prefix=CHECK-MESSAGES',
+   '-check-prefix=' + check_messages_prefix,
'-implicit-check-not={{warning|error}}:'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
Index: test/clang-tidy/check_clang_tidy.cpp
===
--- test/clang-tidy/check_clang_tidy.cpp
+++ test/clang-tidy/check_clang_tidy.cpp
@@ -0,0 +1,21 @@
+// RUN: %check_clang_tidy -check-suffix=USING-A %s misc-unused-using-decls %t -- -- -DUSING_A
+// RUN: %check_clang_tidy -check-suffix=USING-B %s misc-unused-using-decls %t -- -- -DUSING_B
+// RUN: %check_clang_tidy %s misc-unused-using-decls %t
+
+namespace a {class A {}; class B {}; class C {}; }
+namespace b {
+#if defined(USING_A)
+using a::A;
+#elif  defined(USING_B)
+using a::B;
+#else
+using a::C;
+#endif
+}
+namespace c {}
+// CHECK-MESSAGES-USING-A: :[[@LINE-8]]:10: warning: using decl 'A' {{.*}}
+// CHECK-MESSAGES-USING-B: :[[@LINE-7]]:10: warning: using decl 'B' {{.*}}
+// CHECK-MESSAGES: :[[@LINE-6]]:10: warning: using decl 'C' {{.*}}
+// CHECK-FIXES-USING-A-NOT: using a::A;$
+// CHECK-FIXES-USING-B-NOT: using a::B;$
+// CHECK-FIXES-NOT: using a::C;$
Index: docs/clang-tidy/index.rst
===
--- docs/clang-tidy/index.rst
+++ docs/clang-tidy/index.rst
@@ -673,6 +673,27 @@
 // CHECK-FIXES: int b = a;
   }
 
+To check more than one scenario in the same test file use 
+``-check-suffix=SUFFIX-NAME`` on ``check_clang_tidy.py`` command line.
+With ``-check-suffix

[PATCH] D45160: [clang-apply-replacements] Make clang-apply-replacements installable

2018-04-21 Thread Zinovy Nis via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL330509: [clang-apply-replacements] Make 
clang-apply-replacements installable (authored by zinovy.nis, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D45160?vs=140616&id=143452#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D45160

Files:
  clang-tools-extra/trunk/clang-apply-replacements/tool/CMakeLists.txt


Index: clang-tools-extra/trunk/clang-apply-replacements/tool/CMakeLists.txt
===
--- clang-tools-extra/trunk/clang-apply-replacements/tool/CMakeLists.txt
+++ clang-tools-extra/trunk/clang-apply-replacements/tool/CMakeLists.txt
@@ -2,7 +2,7 @@
   Support
   )
 
-add_clang_executable(clang-apply-replacements
+add_clang_tool(clang-apply-replacements
   ClangApplyReplacementsMain.cpp
   )
 target_link_libraries(clang-apply-replacements


Index: clang-tools-extra/trunk/clang-apply-replacements/tool/CMakeLists.txt
===
--- clang-tools-extra/trunk/clang-apply-replacements/tool/CMakeLists.txt
+++ clang-tools-extra/trunk/clang-apply-replacements/tool/CMakeLists.txt
@@ -2,7 +2,7 @@
   Support
   )
 
-add_clang_executable(clang-apply-replacements
+add_clang_tool(clang-apply-replacements
   ClangApplyReplacementsMain.cpp
   )
 target_link_libraries(clang-apply-replacements
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45776: [clang-tidy] Customize FileCheck prefix in check_clang-tidy.py

2018-04-21 Thread Zinovy Nis via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL330511: [clang-tidy] Customize FileCheck prefix in 
check_clang-tidy.py (authored by zinovy.nis, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D45776?vs=143436&id=143453#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D45776

Files:
  clang-tools-extra/trunk/docs/clang-tidy/index.rst
  clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy.cpp
  clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy.py

Index: clang-tools-extra/trunk/docs/clang-tidy/index.rst
===
--- clang-tools-extra/trunk/docs/clang-tidy/index.rst
+++ clang-tools-extra/trunk/docs/clang-tidy/index.rst
@@ -673,6 +673,27 @@
 // CHECK-FIXES: int b = a;
   }
 
+To check more than one scenario in the same test file use 
+``-check-suffix=SUFFIX-NAME`` on ``check_clang_tidy.py`` command line.
+With ``-check-suffix=SUFFIX-NAME`` you need to replace your ``CHECK-*`` 
+directives with ``CHECK-MESSAGES-SUFFIX-NAME`` and ``CHECK-FIXES-SUFFIX-NAME``.
+
+Here's an example:
+
+.. code-block:: c++
+
+   // RUN: %check_clang_tidy -check-suffix=USING-A %s misc-unused-using-decls %t -- -- -DUSING_A
+   // RUN: %check_clang_tidy -check-suffix=USING-B %s misc-unused-using-decls %t -- -- -DUSING_B
+   // RUN: %check_clang_tidy %s misc-unused-using-decls %t
+   ...
+   // CHECK-MESSAGES-USING-A: :[[@LINE-8]]:10: warning: using decl 'A' {{.*}}
+   // CHECK-MESSAGES-USING-B: :[[@LINE-7]]:10: warning: using decl 'B' {{.*}}
+   // CHECK-MESSAGES: :[[@LINE-6]]:10: warning: using decl 'C' {{.*}}
+   // CHECK-FIXES-USING-A-NOT: using a::A;$
+   // CHECK-FIXES-USING-B-NOT: using a::B;$
+   // CHECK-FIXES-NOT: using a::C;$
+
+
 There are many dark corners in the C++ language, and it may be difficult to make
 your check work perfectly in all cases, especially if it issues fix-it hints. The
 most frequent pitfalls are macros and templates:
Index: clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy.py
===
--- clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy.py
+++ clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy.py
@@ -16,8 +16,9 @@
 This script runs clang-tidy in fix mode and verify fixes, messages or both.
 
 Usage:
-  check_clang_tidy.py [-resource-dir ] \
-[-assume-filename ] \
+  check_clang_tidy.py [-resource-dir=] \
+[-assume-filename=] \
+[-check-suffix=] \
\
 -- [optional clang-tidy arguments]
 
@@ -42,6 +43,7 @@
   parser.add_argument('-expect-clang-tidy-error', action='store_true')
   parser.add_argument('-resource-dir')
   parser.add_argument('-assume-filename')
+  parser.add_argument('-check-suffix', default='')
   parser.add_argument('input_file_name')
   parser.add_argument('check_name')
   parser.add_argument('temp_file_name')
@@ -70,6 +72,13 @@
   clang_tidy_extra_args.extend(
   ['-fobjc-abi-version=2', '-fobjc-arc'])
 
+  if args.check_suffix and not re.match('^[A-Z0-9\-]+$', args.check_suffix):
+sys.exit('Only A..Z, 0..9 and "-" are allowed in check suffix, but "%s" was given' % (args.check_suffix))
+
+  file_check_suffix = ('-' + args.check_suffix) if args.check_suffix else ''
+  check_fixes_prefix = 'CHECK-FIXES' + file_check_suffix
+  check_messages_prefix = 'CHECK-MESSAGES' + file_check_suffix
+
   # Tests should not rely on STL being available, and instead provide mock
   # implementations of relevant APIs.
   clang_tidy_extra_args.append('-nostdinc++')
@@ -80,17 +89,17 @@
   with open(input_file_name, 'r') as input_file:
 input_text = input_file.read()
 
-  has_check_fixes = input_text.find('CHECK-FIXES') >= 0
-  has_check_messages = input_text.find('CHECK-MESSAGES') >= 0
+  has_check_fixes = check_fixes_prefix in input_text
+  has_check_messages = check_messages_prefix in input_text
 
   if not has_check_fixes and not has_check_messages:
-sys.exit('Neither CHECK-FIXES nor CHECK-MESSAGES found in the input')
+sys.exit('Neither %s nor %s found in the input' % (check_fixes_prefix, check_messages_prefix) )
 
   # Remove the contents of the CHECK lines to avoid CHECKs matching on
   # themselves.  We need to keep the comments to preserve line numbers while
   # avoiding empty lines which could potentially trigger formatting-related
   # checks.
-  cleaned_test = re.sub('// *CHECK-[A-Z-]*:[^\r\n]*', '//', input_text)
+  cleaned_test = re.sub('// *CHECK-[A-Z0-9\-]*:[^\r\n]*', '//', input_text)
 
   write_file(temp_file_name, cleaned_test)
 
@@ -128,7 +137,7 @@
 try:
   subprocess.check_output(
   ['FileCheck', '-input-file=' + temp_file_name, input_file_name,
-   '-check-prefix=CHECK-FIXES', '-strict-whitespace'],
+   '-check-prefix=' + check_fixes_prefix, '-strict-whitespace'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError a

[PATCH] D45927: [clang-tidy] [modernize-use-auto] Correct way to calculate a type name length for multi-token types

2018-04-21 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis created this revision.
zinovy.nis added reviewers: malcolm.parsons, alexfh.
zinovy.nis added a project: clang-tools-extra.
Herald added subscribers: cfe-commits, xazax.hun.

This patch is a fix for https://reviews.llvm.org/D45405 where spaces were also 
considered as a part of a type name. So length("int *") was 5 instead of 3 with 
RemoveStars=0 or 4 with RemoveStars=1.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D45927

Files:
  clang-tidy/modernize/UseAutoCheck.cpp
  clang-tidy/modernize/UseAutoCheck.h
  docs/clang-tidy/checks/modernize-use-auto.rst
  test/clang-tidy/modernize-use-auto-min-type-name-length.cpp

Index: test/clang-tidy/modernize-use-auto-min-type-name-length.cpp
===
--- test/clang-tidy/modernize-use-auto-min-type-name-length.cpp
+++ test/clang-tidy/modernize-use-auto-min-type-name-length.cpp
@@ -1,29 +1,82 @@
-// RUN: %check_clang_tidy %s modernize-use-auto %t -- \
-// RUN:   -config="{CheckOptions: [{key: modernize-use-auto.MinTypeNameLength, value: '5'}]}" \
-// RUN:   -- -std=c++11 -frtti
+// RUN: %check_clang_tidy -check-suffix=0-0 %s modernize-use-auto %t  -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 0}, {key: modernize-use-auto.MinTypeNameLength, value: 0}]}" -- --std=c++11 -frtti
+// RUN: %check_clang_tidy -check-suffix=0-5 %s modernize-use-auto %t  -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 0}, {key: modernize-use-auto.MinTypeNameLength, value: 5}]}" -- --std=c++11 -frtti
+// RUN: %check_clang_tidy -check-suffix=1-0 %s modernize-use-auto %t  -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 1}, {key: modernize-use-auto.MinTypeNameLength, value: 0}]}" -- --std=c++11 -frtti
+// RUN: %check_clang_tidy -check-suffix=1-5 %s modernize-use-auto %t  -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 1}, {key: modernize-use-auto.MinTypeNameLength, value: 5}]}" -- --std=c++11 -frtti
 
-extern int foo();
-
-using VeryVeryVeryLongTypeName = int;
+template 
+extern T foo();
 
 int bar() {
-  int a = static_cast(foo());
-  // strlen('int') = 4 <  5, so skip it,
-  // even strlen('VeryVeryVeryLongTypeName') > 5.
-
-  unsigned b = static_cast(foo());
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name [modernize-use-auto]
-  // CHECK-FIXES: auto b = static_cast(foo());
-
-  bool c = static_cast(foo());
-  // strlen('bool') = 4 <  5, so skip it.
-
-  const bool c1 = static_cast(foo());
-  // strlen('bool') = 4 <  5, so skip it, even there's a 'const'.
-
-  unsigned long long ull = static_cast(foo());
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name [modernize-use-auto]
-  // CHECK-FIXES: auto ull = static_cast(foo());
+  {
+using VeryVeryVeryLongTypeName = int;
+int i = static_cast(foo());
+// CHECK-FIXES-0-0: auto i = {{.*}}
+// CHECK-FIXES-0-5: int i = {{.*}}
+// CHECK-FIXES-1-0: auto  i = {{.*}}
+// CHECK-FIXES-1-5: int i = {{.*}}
+int *pi = static_cast(foo());
+// CHECK-FIXES-0-0: auto *pi = {{.*}}
+// CHECK-FIXES-0-5: int *pi = {{.*}}
+// CHECK-FIXES-1-0: auto pi = {{.*}}
+// CHECK-FIXES-1-5: int *pi = {{.*}}
+int **ppi = static_cast(foo());
+// CHECK-FIXES-0-0: auto **ppi = {{.*}}
+// CHECK-FIXES-0-5: int **ppi = {{.*}}
+// CHECK-FIXES-1-0: auto ppi = {{.*}}
+// CHECK-FIXES-1-5: auto ppi = {{.*}}
+}
+
+  {
+bool b = static_cast(foo());
+// CHECK-FIXES-0-0: auto b = {{.*}}
+// CHECK-FIXES-0-5: bool b = {{.*}}
+// CHECK-FIXES-1-0: auto  b = {{.*}}
+// CHECK-FIXES-1-5: bool b = {{.*}}
+bool *pb = static_cast(foo());
+// CHECK-FIXES-0-0: auto *pb = {{.*}}
+// CHECK-FIXES-0-5: bool *pb = {{.*}}
+// CHECK-FIXES-1-0: auto pb = {{.*}}
+// CHECK-FIXES-1-5: auto pb = {{.*}}
+  }
+
+  {
+const bool cb = static_cast(foo());
+// CHECK-FIXES-0-0: auto cb = {{.*}}
+// CHECK-FIXES-0-5: bool cb = {{.*}}
+// CHECK-FIXES-1-0: auto  cb = {{.*}}
+// CHECK-FIXES-1-5: bool cb = {{.*}}
+const bool *pcb = static_cast(foo());
+// CHECK-FIXES-0-0: const auto *pcb = {{.*}}
+// CHECK-FIXES-0-5: const bool *pcb = {{.*}}
+// CHECK-FIXES-1-0: const auto pcb = {{.*}}
+// CHECK-FIXES-1-5: const auto pcb = {{.*}}
+  }
+
+  {
+long int li = static_cast(foo());
+// CHECK-FIXES-0-0: auto li = {{.*}}
+// CHECK-FIXES-0-5: auto li = {{.*}}
+// CHECK-FIXES-1-0: auto  li = {{.*}}
+// CHECK-FIXES-1-5: auto  li = {{.*}}
+long int *pli = static_cast(foo());
+// CHECK-FIXES-0-0: auto *pli = {{.*}}
+// CHECK-FIXES-0-5: auto *pli = {{.*}}
+// CHECK-FIXES-1-0: auto pli = {{.*}}
+// CHECK-FIXES-1-5: auto pli = {{.*}}
+  }
+
+  {
+unsigned long long ull = static_cast(foo());
+// CHECK-FIXES-0-0: auto ull = {{.*}}
+  

[PATCH] D45927: [clang-tidy] [modernize-use-auto] Correct way to calculate a type name length for multi-token types

2018-04-22 Thread Zinovy Nis via Phabricator via cfe-commits
zinovy.nis added a subscriber: malcolm.parsons.
zinovy.nis added a comment.

> I think spaces that will be removed should be counted - long long is 9.

I thought about it, but what about "long   long  int

- * * *"? Is it still 9?

I think it's a business of clang-format to remove excessive spaces, not of
clang-tidy.

вс, 22 апр. 2018 г. в 10:11, Malcolm Parsons via Phabricator <
revi...@reviews.llvm.org>:

> malcolm.parsons added a comment.
> 
> I think spaces that will be removed should be counted - long long is 9.
> 
> OTOH, MinTypeNameLength isn't likely to be set high enough for that to
>  matter.
> 
> Repository:
> 
>   rCTE Clang Tools Extra
> 
> https://reviews.llvm.org/D45927


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D45927



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


  1   2   3   >