[PATCH] D122278: [clang] Improve diagnostic for reopened inline namespace

2022-03-23 Thread Fabian Wolff via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG528e6eba2f79: [clang] Improve diagnostic for reopened inline 
namespace (authored by fwolff).

Changed prior to commit:
  https://reviews.llvm.org/D122278?vs=417455&id=417749#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D122278

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
  clang/test/SemaCXX/warn-inline-namespace-reopened-twice.cpp


Index: clang/test/SemaCXX/warn-inline-namespace-reopened-twice.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/warn-inline-namespace-reopened-twice.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -Wall -verify -std=c++11 %s
+
+// Regression test for #50794.
+
+// expected-note@+1 2 {{previous definition is here}}
+inline namespace X {}
+
+namespace X {} // expected-warning {{inline namespace reopened as a non-inline 
namespace}}
+namespace X {} // expected-warning {{inline namespace reopened as a non-inline 
namespace}}
Index: clang/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
===
--- clang/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
+++ clang/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
@@ -17,7 +17,7 @@
 // expected-warning@+2 {{inline nested namespace definition is incompatible 
with C++ standards before C++20}}
 #endif
 namespace valid1::valid2::inline valid3::inline valid4::valid5 {}
-// expected-note@-1 2 {{previous definition is here}}
+// expected-note@-1 4 {{previous definition is here}}
 
 #if __cplusplus <= 201402L
 // expected-warning@+3 {{nested namespace definition is a C++17 extension; 
define each namespace separately}}
@@ -34,7 +34,6 @@
 // expected-warning@+2 {{inline nested namespace definition is incompatible 
with C++ standards before C++20}}
 #endif
 namespace valid1::valid2::inline valid3::inline valid4::valid5 {}
-// expected-note@-1 2 {{previous definition is here}}
 
 namespace valid1 {
 namespace valid2 {
Index: clang/lib/Sema/SemaDeclCXX.cpp
===
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -11060,6 +11060,11 @@
 NamespaceDecl *PrevNS) {
   assert(*IsInline != PrevNS->isInline());
 
+  // 'inline' must appear on the original definition, but not necessarily
+  // on all extension definitions, so the note should point to the first
+  // definition to avoid confusion.
+  PrevNS = PrevNS->getFirstDecl();
+
   if (PrevNS->isInline())
 // The user probably just forgot the 'inline', so suggest that it
 // be added back.
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -83,6 +83,11 @@
 - ``-Wliteral-range`` will warn on floating-point equality comparisons with
   constants that are not representable in a casted value. For example,
   ``(float) f == 0.1`` is always false.
+- ``-Winline-namespace-reopened-noninline`` now takes into account that the
+  ``inline`` keyword must appear on the original but not necessarily all
+  extension definitions of an inline namespace and therefore points its note
+  at the original definition. This fixes `Issue 50794 (PR51452)
+  `_.
 
 Non-comprehensive list of changes in this release
 -


Index: clang/test/SemaCXX/warn-inline-namespace-reopened-twice.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/warn-inline-namespace-reopened-twice.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -Wall -verify -std=c++11 %s
+
+// Regression test for #50794.
+
+// expected-note@+1 2 {{previous definition is here}}
+inline namespace X {}
+
+namespace X {} // expected-warning {{inline namespace reopened as a non-inline namespace}}
+namespace X {} // expected-warning {{inline namespace reopened as a non-inline namespace}}
Index: clang/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
===
--- clang/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
+++ clang/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
@@ -17,7 +17,7 @@
 // expected-warning@+2 {{inline nested namespace definition is incompatible with C++ standards before C++20}}
 #endif
 namespace valid1::valid2::inline valid3::inline valid4::valid5 {}
-// expected-note@-1 2 {{previous definition is here}}
+// expected-note@-1 4 {{previous definition is here}}
 
 #if __cplusplus <= 201402L
 // expected-warning@+3 {{nested namespace definition is a C

[PATCH] D122535: [clang-tidy] Never consider assignments as equivalent in `misc-redundant-expression` check

2022-03-26 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: aaron.ballman, njames93.
fwolff added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, xazax.hun.
Herald added a project: All.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

Attempts to fix #35853 . 
This issue is about side-effectful function calls, but since almost every 
function call potentially causes side effects and would therefore prevent any 
`misc-redundant-expression` warnings, I have focused on assignments instead, 
which would also fix the example in #35853.

We already have special treatment of unary increment/decrement here 
,
 even though this can also lead to false negatives. Replacing `i++` with `i = i 
+ 1` currently changes the behavior of the `misc-redundant-expression` check, 
whereas the change proposed here prevents any warnings about redundant 
expressions if assignments are involved. This can cause false negatives, though 
(whereas the current implementation causes false positives), so let me know 
whether you think this is a sensible change to make.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D122535

Files:
  clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
@@ -831,3 +831,15 @@
 };
 
 } // namespace no_crash
+
+int TestAssignSideEffect(int i) {
+  int k = i;
+
+  if ((k = k + 1) != 1 || (k = k + 1) != 2)
+return 0;
+
+  if ((k = foo(0)) != 1 || (k = foo(0)) != 2)
+return 1;
+
+  return 2;
+}
Index: clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
@@ -134,6 +134,8 @@
 return cast(Left)->getOpcode() ==
cast(Right)->getOpcode();
   case Stmt::BinaryOperatorClass:
+if (cast(Left)->isAssignmentOp())
+  return false;
 return cast(Left)->getOpcode() ==
cast(Right)->getOpcode();
   case Stmt::UnaryExprOrTypeTraitExprClass:


Index: clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
@@ -831,3 +831,15 @@
 };
 
 } // namespace no_crash
+
+int TestAssignSideEffect(int i) {
+  int k = i;
+
+  if ((k = k + 1) != 1 || (k = k + 1) != 2)
+return 0;
+
+  if ((k = foo(0)) != 1 || (k = foo(0)) != 2)
+return 1;
+
+  return 2;
+}
Index: clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
@@ -134,6 +134,8 @@
 return cast(Left)->getOpcode() ==
cast(Right)->getOpcode();
   case Stmt::BinaryOperatorClass:
+if (cast(Left)->isAssignmentOp())
+  return false;
 return cast(Left)->getOpcode() ==
cast(Right)->getOpcode();
   case Stmt::UnaryExprOrTypeTraitExprClass:
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D122111: [clang-tidy] Fix false positives in `misc-redundant-expression` check

2022-03-20 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: alexfh, aaron.ballman, pavelkryukov.
fwolff added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, xazax.hun.
Herald added a project: All.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

It turns out that the right-hand sides of overloaded comparison operators are 
currently not checked at all in `misc-redundant-expression`, leading to such 
false positives as given in #54011 
 or here 
. This patch fixes this.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D122111

Files:
  clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
@@ -453,6 +453,11 @@
   if (s1 >= 1 || s1 <= 1) return true;
   // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always 
true
 
+  // Test for absence of false positives (issue #54011).
+  if (s1 == 1 || s1 == 2) return true;
+  if (s1 > 1 && s1 < 3) return true;
+  if (s1 >= 2 || s1 <= 0) return true;
+
   // Test for overloaded operators that may modify their params.
   S2 s2;
   if (s2 == 1 || s2 != 1) return true;
Index: clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
@@ -569,6 +569,7 @@
   std::string SwapId = (Id + "-swap").str();
   std::string NegateId = (Id + "-negate").str();
   std::string OverloadId = (Id + "-overload").str();
+  std::string ConstId = (Id + "-const").str();
 
   const auto RelationalExpr = ignoringParenImpCasts(binaryOperator(
   isComparisonOperator(), expr().bind(Id),
@@ -600,7 +601,8 @@
   cxxOperatorCallExpr(
   hasAnyOverloadedOperatorName("==", "!=", "<", "<=", ">", ">="),
   // Filter noisy false positives.
-  unless(isMacro()), unless(isInTemplateInstantiation()))
+  unless(isMacro()), unless(isInTemplateInstantiation()),
+  hasRHS(ignoringParenImpCasts(integerLiteral().bind(ConstId
   .bind(OverloadId);
 
   return anyOf(RelationalExpr, CastExpr, NegateRelationalExpr,
@@ -683,6 +685,9 @@
 OperandExpr = OverloadedOperatorExpr;
 Opcode = 
BinaryOperator::getOverloadedOpcode(OverloadedOperatorExpr->getOperator());
 
+if (!retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr))
+  return false;
+
 return BinaryOperator::isComparisonOp(Opcode);
   } else {
 return false;


Index: clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
@@ -453,6 +453,11 @@
   if (s1 >= 1 || s1 <= 1) return true;
   // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always true
 
+  // Test for absence of false positives (issue #54011).
+  if (s1 == 1 || s1 == 2) return true;
+  if (s1 > 1 && s1 < 3) return true;
+  if (s1 >= 2 || s1 <= 0) return true;
+
   // Test for overloaded operators that may modify their params.
   S2 s2;
   if (s2 == 1 || s2 != 1) return true;
Index: clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
@@ -569,6 +569,7 @@
   std::string SwapId = (Id + "-swap").str();
   std::string NegateId = (Id + "-negate").str();
   std::string OverloadId = (Id + "-overload").str();
+  std::string ConstId = (Id + "-const").str();
 
   const auto RelationalExpr = ignoringParenImpCasts(binaryOperator(
   isComparisonOperator(), expr().bind(Id),
@@ -600,7 +601,8 @@
   cxxOperatorCallExpr(
   hasAnyOverloadedOperatorName("==", "!=", "<", "<=", ">", ">="),
   // Filter noisy false positives.
-  unless(isMacro()), unless(isInTemplateInstantiation()))
+  unless(isMacro()), unless(isInTemplateInstantiation()),
+  hasRHS(ignoringParenImpCasts(integerLiteral().bind(ConstId
   .bind(OverloadId);
 
   return anyOf(RelationalExpr, CastExpr, NegateRelationalExpr,
@@ -683,6 +685,9 @@
 OperandExpr = OverloadedOperatorExpr;
 Opcode = BinaryOperator::getOverloadedOpcode(OverloadedOperatorExpr->getOperator());
 
+if (!retrieveIntegerConstantE

[PATCH] D122111: [clang-tidy] Fix false positives in `misc-redundant-expression` check

2022-03-21 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 417054.

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

https://reviews.llvm.org/D122111

Files:
  clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
@@ -369,6 +369,11 @@
 bool operator<=(const S &s, int i) { return s.x <= i; } // not modifying
 bool operator>=(const S &s, const int &i) { return s.x >= i; } // not modifying
 
+bool operator==(int i, const S &s) { return s == i; } // not modifying
+bool operator<(const int &i, const S &s) { return s > i; } // not modifying
+bool operator<=(const int &i, const S &s) { return s >= i; } // not modifying
+bool operator>(const int &i, const S &s) { return s < i; } // not modifying
+
 struct S2 {
   S2() { x = 1; }
   int x;
@@ -452,6 +457,25 @@
   // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
   if (s1 >= 1 || s1 <= 1) return true;
   // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always true
+  if (s1 >= 2 && s1 <= 0) return true;
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false
+
+  // Same test as above but with swapped LHS/RHS on one side of the logical operator.
+  if (1 == s1 && s1 == 1) return true;
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: equivalent expression on both sides of logical operator
+  if (1 == s1 || s1 != 1) return true;
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always true
+  if (1 < s1 && s1 < 1) return true;
+  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
+  if (1 <= s1 || s1 <= 1) return true;
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always true
+  if (2 < s1 && 0 > s1) return true;
+  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
+
+  // Test for absence of false positives (issue #54011).
+  if (s1 == 1 || s1 == 2) return true;
+  if (s1 > 1 && s1 < 3) return true;
+  if (s1 >= 2 || s1 <= 0) return true;
 
   // Test for overloaded operators that may modify their params.
   S2 s2;
Index: clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
@@ -569,6 +569,7 @@
   std::string SwapId = (Id + "-swap").str();
   std::string NegateId = (Id + "-negate").str();
   std::string OverloadId = (Id + "-overload").str();
+  std::string ConstId = (Id + "-const").str();
 
   const auto RelationalExpr = ignoringParenImpCasts(binaryOperator(
   isComparisonOperator(), expr().bind(Id),
@@ -600,7 +601,9 @@
   cxxOperatorCallExpr(
   hasAnyOverloadedOperatorName("==", "!=", "<", "<=", ">", ">="),
   // Filter noisy false positives.
-  unless(isMacro()), unless(isInTemplateInstantiation()))
+  unless(isMacro()), unless(isInTemplateInstantiation()),
+  anyOf(hasLHS(ignoringParenImpCasts(integerLiteral().bind(ConstId))),
+hasRHS(ignoringParenImpCasts(integerLiteral().bind(ConstId)
   .bind(OverloadId);
 
   return anyOf(RelationalExpr, CastExpr, NegateRelationalExpr,
@@ -674,16 +677,38 @@
 if (canOverloadedOperatorArgsBeModified(OverloadedOperatorExpr, false))
   return false;
 
+bool IntegerConstantIsFirstArg = false;
+
 if (const auto *Arg = OverloadedOperatorExpr->getArg(1)) {
   if (!Arg->isValueDependent() &&
-  !Arg->isIntegerConstantExpr(*Result.Context))
-return false;
-}
-Symbol = OverloadedOperatorExpr->getArg(0);
+  !Arg->isIntegerConstantExpr(*Result.Context)) {
+IntegerConstantIsFirstArg = true;
+if (const auto *Arg = OverloadedOperatorExpr->getArg(0)) {
+  if (!Arg->isValueDependent() &&
+  !Arg->isIntegerConstantExpr(*Result.Context))
+return false;
+} else
+  return false;
+  }
+} else
+  return false;
+
+Symbol = OverloadedOperatorExpr->getArg(IntegerConstantIsFirstArg ? 1 : 0);
 OperandExpr = OverloadedOperatorExpr;
 Opcode = BinaryOperator::getOverloadedOpcode(OverloadedOperatorExpr->getOperator());
 
-return BinaryOperator::isComparisonOp(Opcode);
+if (!retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr))
+  return false;
+
+if (!BinaryOperator::isComparisonOp(Opcode))
+  return false;
+
+// The call site of this function expects the constant on the RHS,
+// so change the opcode accordingly.
+if (IntegerConstantIsFirstArg)
+  

[PATCH] D122111: [clang-tidy] Fix false positives in `misc-redundant-expression` check

2022-03-21 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff marked an inline comment as done.
fwolff added a comment.

Thanks for the quick review @aaron.ballman! I think I've addressed your 
comments.




Comment at: clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp:605
+  unless(isMacro()), unless(isInTemplateInstantiation()),
+  hasRHS(ignoringParenImpCasts(integerLiteral().bind(ConstId
   .bind(OverloadId);

aaron.ballman wrote:
> This seems incorrect to me -- the LHS and RHS can be swapped along with which 
> operator is used and still achieve the same semantic results.
> 
> While playing around to test the behavior we currently have, I was a bit 
> surprised at the difference in results here: https://godbolt.org/z/hE4qfca1b.
> 
> Also, do we need to bind? Nothing seems to look at that binding that I can 
> see.
> This seems incorrect to me -- the LHS and RHS can be swapped along with which 
> operator is used and still achieve the same semantic results.

Fixed.

> While playing around to test the behavior we currently have, I was a bit 
> surprised at the difference in results here: https://godbolt.org/z/hE4qfca1b.

All four conditions get a warning with my changes. I've added your example to 
the test file.

> Also, do we need to bind? Nothing seems to look at that binding that I can 
> see.

Yes, it is hard to see, but [[ 
https://github.com/llvm/llvm-project/blob/240e06dfe77feabe38a03cbb1c94875639d0f9ff/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp#L498
 | here ]] the constant is actually read.


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

https://reviews.llvm.org/D122111

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


[PATCH] D122111: [clang-tidy] Fix false positives in `misc-redundant-expression` check

2022-03-22 Thread Fabian Wolff via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
fwolff marked an inline comment as done.
Closed by commit rG07675b0b38e9: [clang-tidy] Fix false positives in 
`misc-redundant-expression` check (authored by fwolff).

Changed prior to commit:
  https://reviews.llvm.org/D122111?vs=417054&id=417433#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D122111

Files:
  clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
@@ -369,6 +369,11 @@
 bool operator<=(const S &s, int i) { return s.x <= i; } // not modifying
 bool operator>=(const S &s, const int &i) { return s.x >= i; } // not modifying
 
+bool operator==(int i, const S &s) { return s == i; } // not modifying
+bool operator<(const int &i, const S &s) { return s > i; } // not modifying
+bool operator<=(const int &i, const S &s) { return s >= i; } // not modifying
+bool operator>(const int &i, const S &s) { return s < i; } // not modifying
+
 struct S2 {
   S2() { x = 1; }
   int x;
@@ -452,6 +457,25 @@
   // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
   if (s1 >= 1 || s1 <= 1) return true;
   // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always true
+  if (s1 >= 2 && s1 <= 0) return true;
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false
+
+  // Same test as above but with swapped LHS/RHS on one side of the logical operator.
+  if (1 == s1 && s1 == 1) return true;
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: equivalent expression on both sides of logical operator
+  if (1 == s1 || s1 != 1) return true;
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always true
+  if (1 < s1 && s1 < 1) return true;
+  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
+  if (1 <= s1 || s1 <= 1) return true;
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always true
+  if (2 < s1 && 0 > s1) return true;
+  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
+
+  // Test for absence of false positives (issue #54011).
+  if (s1 == 1 || s1 == 2) return true;
+  if (s1 > 1 && s1 < 3) return true;
+  if (s1 >= 2 || s1 <= 0) return true;
 
   // Test for overloaded operators that may modify their params.
   S2 s2;
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -116,6 +116,9 @@
   ` when a pure virtual function
   overrided has a const return type. Removed the fix for a virtual function.
 
+- Fixed a false positive in :doc:`misc-redundant-expression `
+  involving overloaded comparison operators.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
@@ -569,6 +569,7 @@
   std::string SwapId = (Id + "-swap").str();
   std::string NegateId = (Id + "-negate").str();
   std::string OverloadId = (Id + "-overload").str();
+  std::string ConstId = (Id + "-const").str();
 
   const auto RelationalExpr = ignoringParenImpCasts(binaryOperator(
   isComparisonOperator(), expr().bind(Id),
@@ -600,7 +601,9 @@
   cxxOperatorCallExpr(
   hasAnyOverloadedOperatorName("==", "!=", "<", "<=", ">", ">="),
   // Filter noisy false positives.
-  unless(isMacro()), unless(isInTemplateInstantiation()))
+  unless(isMacro()), unless(isInTemplateInstantiation()),
+  anyOf(hasLHS(ignoringParenImpCasts(integerLiteral().bind(ConstId))),
+hasRHS(ignoringParenImpCasts(integerLiteral().bind(ConstId)
   .bind(OverloadId);
 
   return anyOf(RelationalExpr, CastExpr, NegateRelationalExpr,
@@ -674,16 +677,38 @@
 if (canOverloadedOperatorArgsBeModified(OverloadedOperatorExpr, false))
   return false;
 
+bool IntegerConstantIsFirstArg = false;
+
 if (const auto *Arg = OverloadedOperatorExpr->getArg(1)) {
   if (!Arg->isValueDependent() &&
-  !Arg->isIntegerConstantExpr(*Result.Context))
-return false;
-}
-Symbol = OverloadedOperatorExpr->getArg(0);
+  !Arg->isIntegerConstantExpr(*Result.Context)) {
+IntegerConstantIsFirstArg = true;
+if (const auto *Arg =

[PATCH] D122278: [clang] Improve diagnostic for reopened inline namespace

2022-03-22 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: rsmith, cor3ntin, mizvekov.
fwolff added a project: clang.
Herald added a project: All.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

Fixes #50794 . Reopening an 
inline namespace without the `inline` keyword yields a warning:

  inline namespace abc {}
  namespace abc {}
  namespace abc {}

  :2:11: warning: inline namespace reopened as a non-inline namespace 
[-Winline-namespace-reopened-noninline]
  namespace abc {}
^
  inline 
  :1:18: note: previous definition is here
  inline namespace abc {}
   ^
  :3:11: warning: inline namespace reopened as a non-inline namespace 
[-Winline-namespace-reopened-noninline]
  namespace abc {}
^
  inline 
  :2:11: note: previous definition is here
  namespace abc {}
^

But you'll notice that the second "previous definition is here" is actually not 
helpful, because this previous definition isn't explicitly marked `inline`. I 
think that the note should point to the first definition instead, which must 
always  have the `inline` if 
the namespace is supposed to be an inline namespace.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D122278

Files:
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
  clang/test/SemaCXX/warn-inline-namespace-reopened-twice.cpp


Index: clang/test/SemaCXX/warn-inline-namespace-reopened-twice.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/warn-inline-namespace-reopened-twice.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -Wall -verify -std=c++11 %s
+
+// Regression test for #50794.
+
+// expected-note@+1 2 {{previous definition is here}}
+inline namespace X {}
+
+namespace X {} // expected-warning {{inline namespace reopened as a non-inline 
namespace}}
+namespace X {} // expected-warning {{inline namespace reopened as a non-inline 
namespace}}
Index: clang/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
===
--- clang/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
+++ clang/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
@@ -17,7 +17,7 @@
 // expected-warning@+2 {{inline nested namespace definition is incompatible 
with C++ standards before C++20}}
 #endif
 namespace valid1::valid2::inline valid3::inline valid4::valid5 {}
-// expected-note@-1 2 {{previous definition is here}}
+// expected-note@-1 4 {{previous definition is here}}
 
 #if __cplusplus <= 201402L
 // expected-warning@+3 {{nested namespace definition is a C++17 extension; 
define each namespace separately}}
@@ -34,7 +34,6 @@
 // expected-warning@+2 {{inline nested namespace definition is incompatible 
with C++ standards before C++20}}
 #endif
 namespace valid1::valid2::inline valid3::inline valid4::valid5 {}
-// expected-note@-1 2 {{previous definition is here}}
 
 namespace valid1 {
 namespace valid2 {
Index: clang/lib/Sema/SemaDeclCXX.cpp
===
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -11059,6 +11059,12 @@
 NamespaceDecl *PrevNS) {
   assert(*IsInline != PrevNS->isInline());
 
+  if (auto *FirstNS = PrevNS->getFirstDecl())
+// 'inline' must appear on the original definition, but not necessarily
+// on all extension definitions, so the note should point to the first
+// definition to avoid confusion.
+PrevNS = FirstNS;
+
   if (PrevNS->isInline())
 // The user probably just forgot the 'inline', so suggest that it
 // be added back.


Index: clang/test/SemaCXX/warn-inline-namespace-reopened-twice.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/warn-inline-namespace-reopened-twice.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -Wall -verify -std=c++11 %s
+
+// Regression test for #50794.
+
+// expected-note@+1 2 {{previous definition is here}}
+inline namespace X {}
+
+namespace X {} // expected-warning {{inline namespace reopened as a non-inline namespace}}
+namespace X {} // expected-warning {{inline namespace reopened as a non-inline namespace}}
Index: clang/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
===
--- clang/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
+++ clang/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
@@ -17,7 +17,7 @@
 // expected-warning@+2 {{inline nested namespace definition is incompatible with C++ standards before C++20}}
 #endif
 namespace valid1::valid2::inline valid3::inline valid4::valid5 {}
-// expected-note@-1 2 {{previous definition is here}}
+// expected-note@-1 4 {{

[PATCH] D122535: [clang-tidy] Never consider assignments as equivalent in `misc-redundant-expression` check

2022-04-12 Thread Fabian Wolff via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGa18634b74fc0: [clang-tidy] Never consider assignments as 
equivalent in `misc-redundant… (authored by fwolff).

Changed prior to commit:
  https://reviews.llvm.org/D122535?vs=418420&id=42#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D122535

Files:
  clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
@@ -831,3 +831,15 @@
 };
 
 } // namespace no_crash
+
+int TestAssignSideEffect(int i) {
+  int k = i;
+
+  if ((k = k + 1) != 1 || (k = k + 1) != 2)
+return 0;
+
+  if ((k = foo(0)) != 1 || (k = foo(0)) != 2)
+return 1;
+
+  return 2;
+}
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -132,7 +132,7 @@
   the vector is a member of a structure.
 
 - Fixed a false positive in :doc:`readability-non-const-parameter
-  ` when the parameter is 
referenced by an lvalue
+  ` when the parameter is 
referenced by an lvalue.
 
 - Fixed a crash in :doc:`readability-const-return-type
   ` when a pure virtual 
function
@@ -150,6 +150,9 @@
   Fixed an issue when there was already an initializer in the constructor and
   the check would try to create another initializer for the same member.
 
+- Fixed a false positive in :doc:`misc-redundant-expression 
`
+  involving assignments in conditions. This fixes `Issue 35853 
`_.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
@@ -134,6 +134,8 @@
 return cast(Left)->getOpcode() ==
cast(Right)->getOpcode();
   case Stmt::BinaryOperatorClass:
+if (cast(Left)->isAssignmentOp())
+  return false;
 return cast(Left)->getOpcode() ==
cast(Right)->getOpcode();
   case Stmt::UnaryExprOrTypeTraitExprClass:


Index: clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
@@ -831,3 +831,15 @@
 };
 
 } // namespace no_crash
+
+int TestAssignSideEffect(int i) {
+  int k = i;
+
+  if ((k = k + 1) != 1 || (k = k + 1) != 2)
+return 0;
+
+  if ((k = foo(0)) != 1 || (k = foo(0)) != 2)
+return 1;
+
+  return 2;
+}
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -132,7 +132,7 @@
   the vector is a member of a structure.
 
 - Fixed a false positive in :doc:`readability-non-const-parameter
-  ` when the parameter is referenced by an lvalue
+  ` when the parameter is referenced by an lvalue.
 
 - Fixed a crash in :doc:`readability-const-return-type
   ` when a pure virtual function
@@ -150,6 +150,9 @@
   Fixed an issue when there was already an initializer in the constructor and
   the check would try to create another initializer for the same member.
 
+- Fixed a false positive in :doc:`misc-redundant-expression `
+  involving assignments in conditions. This fixes `Issue 35853 `_.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
@@ -134,6 +134,8 @@
 return cast(Left)->getOpcode() ==
cast(Right)->getOpcode();
   case Stmt::BinaryOperatorClass:
+if (cast(Left)->isAssignmentOp())
+  return false;
 return cast(Left)->getOpcode() ==
cast(Right)->getOpcode();
   case Stmt::UnaryExprOrTypeTraitExprClass:
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D114292: [clang-tidy] Fix `altera-struct-pack-align` check for empty structs

2022-04-20 Thread Fabian Wolff via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGf25935a00091: [clang-tidy] Fix `altera-struct-pack-align` 
check for empty structs (authored by fwolff).

Changed prior to commit:
  https://reviews.llvm.org/D114292?vs=400634&id=423908#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D114292

Files:
  clang-tools-extra/clang-tidy/altera/StructPackAlignCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp
@@ -99,3 +99,22 @@
   struct bad_align3 instantiated { 'a', 0.001, 'b' };
 }
 
+// Make sure that we don't recommend aligning an empty struct to zero bytes 
(PR#51620)
+struct StructWithNoFields {};
+
+struct ContainsStructWithNoFields {
+  StructWithNoFields s;
+};
+
+// Make sure that an empty struct is treated like "char" for padding and 
alignment purposes
+struct ContainsStructWithNoFields2 {
+  StructWithNoFields s;
+  double d;
+  StructWithNoFields t;
+};
+// CHECK-MESSAGES: :[[@LINE-5]]:8: warning: accessing fields in struct 
'ContainsStructWithNoFields2' is inefficient due to padding; only needs 10 
bytes but is using 24 bytes [altera-struct-pack-align]
+// CHECK-MESSAGES: :[[@LINE-6]]:8: note: use "__attribute__((packed))" to 
reduce the amount of padding applied to struct 'ContainsStructWithNoFields2'
+// CHECK-MESSAGES: :[[@LINE-7]]:8: warning: accessing fields in struct 
'ContainsStructWithNoFields2' is inefficient due to poor alignment; currently 
aligned to 8 bytes, but recommended alignment is 16 bytes 
[altera-struct-pack-align]
+// CHECK-MESSAGES: :[[@LINE-8]]:8: note: use "__attribute__((aligned(16)))" to 
align struct 'ContainsStructWithNoFields2' to 16 bytes
+// CHECK-FIXES: __attribute__((packed))
+// CHECK-FIXES: __attribute__((aligned(16)));
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -170,6 +170,9 @@
   ` to work when
   the vector is a member of a structure.
 
+- Fixed nonsensical suggestion of :doc:`altera-struct-pack-align
+  ` check for empty structs.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/altera/StructPackAlignCheck.cpp
===
--- clang-tools-extra/clang-tidy/altera/StructPackAlignCheck.cpp
+++ clang-tools-extra/clang-tidy/altera/StructPackAlignCheck.cpp
@@ -77,7 +77,8 @@
   uint64_t CharSize = Result.Context->getCharWidth();
   CharUnits CurrSize = Result.Context->getASTRecordLayout(Struct).getSize();
   CharUnits MinByteSize =
-  CharUnits::fromQuantity(ceil((float)TotalBitSize / CharSize));
+  CharUnits::fromQuantity(std::max(
+  ceil(static_cast(TotalBitSize) / CharSize), 1));
   CharUnits MaxAlign = CharUnits::fromQuantity(
   ceil((float)Struct->getMaxAlignment() / CharSize));
   CharUnits CurrAlign =


Index: clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp
@@ -99,3 +99,22 @@
   struct bad_align3 instantiated { 'a', 0.001, 'b' };
 }
 
+// Make sure that we don't recommend aligning an empty struct to zero bytes (PR#51620)
+struct StructWithNoFields {};
+
+struct ContainsStructWithNoFields {
+  StructWithNoFields s;
+};
+
+// Make sure that an empty struct is treated like "char" for padding and alignment purposes
+struct ContainsStructWithNoFields2 {
+  StructWithNoFields s;
+  double d;
+  StructWithNoFields t;
+};
+// CHECK-MESSAGES: :[[@LINE-5]]:8: warning: accessing fields in struct 'ContainsStructWithNoFields2' is inefficient due to padding; only needs 10 bytes but is using 24 bytes [altera-struct-pack-align]
+// CHECK-MESSAGES: :[[@LINE-6]]:8: note: use "__attribute__((packed))" to reduce the amount of padding applied to struct 'ContainsStructWithNoFields2'
+// CHECK-MESSAGES: :[[@LINE-7]]:8: warning: accessing fields in struct 'ContainsStructWithNoFields2' is inefficient due to poor alignment; currently aligned to 8 bytes, but recommended alignment is 16 bytes [altera-struct-pack-align]
+// CHECK-MESSAGES: :[[@LINE-8]]:8: note: use "__attribute__((aligned(16)))" to align struct 'ContainsStructWithNoFields2' to 16 bytes
+// CHECK-FIXES: __attribute__((packed))
+// CHECK-FIXES: __attribute__((aligned(16)));
Index: clang-tools-extra/docs/ReleaseNotes.rst
==

[PATCH] D115124: [clang-tidy] Fix `readability-container-size-empty` check for smart pointers

2022-04-20 Thread Fabian Wolff via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGfb3b3f76bf75: [clang-tidy] Fix 
`readability-container-size-empty` check for smart pointers (authored by 
fwolff).
Herald added a project: All.

Changed prior to commit:
  https://reviews.llvm.org/D115124?vs=400625&id=423909#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D115124

Files:
  clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp
@@ -696,3 +696,25 @@
   instantiatedTemplateWithSizeCall();
   instantiatedTemplateWithSizeCall>();
 }
+
+namespace std {
+template 
+struct unique_ptr {
+  T *operator->() const;
+  T &operator*() const;
+};
+} // namespace std
+
+bool call_through_unique_ptr(const std::unique_ptr> &ptr) {
+  return ptr->size() > 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should be 
used
+  // CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here
+  // CHECK-FIXES: {{^  }}return !ptr->empty();
+}
+
+bool call_through_unique_ptr_deref(const std::unique_ptr> 
&ptr) {
+  return (*ptr).size() > 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should be 
used
+  // CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here
+  // CHECK-FIXES: {{^  }}return !(*ptr).empty();
+}
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -173,6 +173,9 @@
 - Fixed nonsensical suggestion of :doc:`altera-struct-pack-align
   ` check for empty structs.
 
+- Fixed incorrect suggestions for :doc:`readability-container-size-empty
+  ` when smart pointers 
are involved.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
@@ -191,10 +191,17 @@
   std::string ReplacementText = std::string(
   Lexer::getSourceText(CharSourceRange::getTokenRange(E->getSourceRange()),
*Result.SourceManager, getLangOpts()));
-  if (isBinaryOrTernary(E) || isa(E)) {
+  const auto *OpCallExpr = dyn_cast(E);
+  if (isBinaryOrTernary(E) || isa(E) ||
+  (OpCallExpr && (OpCallExpr->getOperator() == OO_Star))) {
 ReplacementText = "(" + ReplacementText + ")";
   }
-  if (E->getType()->isPointerType())
+  if (OpCallExpr &&
+  OpCallExpr->getOperator() == OverloadedOperatorKind::OO_Arrow) {
+// This can happen if the object is a smart pointer. Don't add anything
+// because a '->' is already there (PR#51776), just call the method.
+ReplacementText += "empty()";
+  } else if (E->getType()->isPointerType())
 ReplacementText += "->empty()";
   else
 ReplacementText += ".empty()";


Index: clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp
@@ -696,3 +696,25 @@
   instantiatedTemplateWithSizeCall();
   instantiatedTemplateWithSizeCall>();
 }
+
+namespace std {
+template 
+struct unique_ptr {
+  T *operator->() const;
+  T &operator*() const;
+};
+} // namespace std
+
+bool call_through_unique_ptr(const std::unique_ptr> &ptr) {
+  return ptr->size() > 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should be used
+  // CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here
+  // CHECK-FIXES: {{^  }}return !ptr->empty();
+}
+
+bool call_through_unique_ptr_deref(const std::unique_ptr> &ptr) {
+  return (*ptr).size() > 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should be used
+  // CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here
+  // CHECK-FIXES: {{^  }}return !(*ptr).empty();
+}
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -173,6 +173,9 @@
 - Fixed nonsensical suggestion of :doc:`altera-struct-pack-align
   ` check for empty structs.
 
+- Fixed incorrect suggestions f

[PATCH] D113499: [clang-tidy] Reduce false positives for `bugprone-infinite-loop` with dependent expressions

2022-04-20 Thread Fabian Wolff via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGcce79514ff40: [clang-tidy] Reduce false positives for 
`bugprone-infinite-loop` with dependent… (authored by fwolff).
Herald added a project: All.

Changed prior to commit:
  https://reviews.llvm.org/D113499?vs=386244&id=423911#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D113499

Files:
  clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp
@@ -1,5 +1,5 @@
 // RUN: %check_clang_tidy %s bugprone-infinite-loop %t \
-// RUN:   -- -- -fexceptions -fblocks
+// RUN:   -- -- -fexceptions -fblocks -fno-delayed-template-parsing
 
 void simple_infinite_loop1() {
   int i = 0;
@@ -622,3 +622,31 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (size) are updated in the loop body [bugprone-infinite-loop]
   }
 }
+
+template 
+int some_template_fn() { return 1; }
+
+template 
+void test_dependent_condition() {
+  const int error = some_template_fn();
+  do {
+  } while (false && error == 0);
+
+  const int val = some_template_fn();
+  for (; !(val == 0 || true);) {
+  }
+
+  const int val2 = some_template_fn();
+  for (; !(val2 == 0 || false);) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (val2) are updated in the loop body [bugprone-infinite-loop]
+  }
+
+  const int val3 = some_template_fn();
+  do {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (val3) are updated in the loop body [bugprone-infinite-loop]
+  } while (1, (true) && val3 == 1);
+
+  const int val4 = some_template_fn();
+  do {
+  } while (1, (false) && val4 == 1);
+}
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -176,6 +176,9 @@
 - Fixed incorrect suggestions for :doc:`readability-container-size-empty
   ` when smart pointers are involved.
 
+- Fixed some false positives in :doc:`bugprone-infinite-loop
+  ` involving dependent expressions.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
@@ -117,12 +117,32 @@
   return Result;
 }
 
-static bool isKnownFalse(const Expr &Cond, const ASTContext &Ctx) {
-  if (Cond.isValueDependent())
+static bool isKnownToHaveValue(const Expr &Cond, const ASTContext &Ctx,
+   bool ExpectedValue) {
+  if (Cond.isValueDependent()) {
+if (const auto *BinOp = dyn_cast(&Cond)) {
+  // Conjunctions (disjunctions) can still be handled if at least one
+  // conjunct (disjunct) is known to be false (true).
+  if (!ExpectedValue && BinOp->getOpcode() == BO_LAnd)
+return isKnownToHaveValue(*BinOp->getLHS(), Ctx, false) ||
+   isKnownToHaveValue(*BinOp->getRHS(), Ctx, false);
+  if (ExpectedValue && BinOp->getOpcode() == BO_LOr)
+return isKnownToHaveValue(*BinOp->getLHS(), Ctx, true) ||
+   isKnownToHaveValue(*BinOp->getRHS(), Ctx, true);
+  if (BinOp->getOpcode() == BO_Comma)
+return isKnownToHaveValue(*BinOp->getRHS(), Ctx, ExpectedValue);
+} else if (const auto *UnOp = dyn_cast(&Cond)) {
+  if (UnOp->getOpcode() == UO_LNot)
+return isKnownToHaveValue(*UnOp->getSubExpr(), Ctx, !ExpectedValue);
+} else if (const auto *Paren = dyn_cast(&Cond))
+  return isKnownToHaveValue(*Paren->getSubExpr(), Ctx, ExpectedValue);
+else if (const auto *ImplCast = dyn_cast(&Cond))
+  return isKnownToHaveValue(*ImplCast->getSubExpr(), Ctx, ExpectedValue);
 return false;
+  }
   bool Result = false;
   if (Cond.EvaluateAsBooleanCondition(Result, Ctx))
-return !Result;
+return Result == ExpectedValue;
   return false;
 }
 
@@ -144,7 +164,7 @@
   const auto *LoopStmt = Result.Nodes.getNodeAs("loop-stmt");
   const auto *Func = Result.Nodes.getNodeAs("func");
 
-  if (isKnownFalse(*Cond, *Result.Context))
+  if (isKnownToHaveValue(*Cond, *Result.Context, false))
 return;
 
   bool ShouldHaveConditionVariables = true;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
ht

[PATCH] D113804: [clang-tidy] Fix behavior of `modernize-use-using` with nested structs/unions

2022-04-20 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff added a comment.

Ping @aaron.ballman.


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

https://reviews.llvm.org/D113804

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


[PATCH] D113804: [clang-tidy] Fix behavior of `modernize-use-using` with nested structs/unions

2022-04-21 Thread Fabian Wolff via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG95d77383f2ba: [clang-tidy] Fix behavior of 
`modernize-use-using` with nested structs/unions (authored by fwolff).

Changed prior to commit:
  https://reviews.llvm.org/D113804?vs=400677&id=424172#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D113804

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

Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp
@@ -302,3 +302,15 @@
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
   // CHECK-FIXES: using b = InjectedClassNameWithUnnamedArgument;
 };
+
+typedef struct { int a; union { int b; }; } PR50990;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using PR50990 = struct { int a; union { int b; }; };
+
+typedef struct { struct { int a; struct { struct { int b; } c; int d; } e; } f; int g; } PR50990_nested;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using PR50990_nested = struct { struct { int a; struct { struct { int b; } c; int d; } e; } f; int g; };
+
+typedef struct { struct { int a; } b; union { int c; float d; struct { int e; }; }; struct { double f; } g; } PR50990_siblings;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using PR50990_siblings = struct { struct { int a; } b; union { int c; float d; struct { int e; }; }; struct { double f; } g; };
Index: clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
===
--- clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
+++ clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
@@ -23,7 +23,8 @@
 
   const bool IgnoreMacros;
   SourceLocation LastReplacementEnd;
-  SourceRange LastTagDeclRange;
+  llvm::DenseMap LastTagDeclRanges;
+
   std::string FirstTypedefType;
   std::string FirstTypedefName;
 
Index: clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
===
--- clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
@@ -16,6 +16,10 @@
 namespace tidy {
 namespace modernize {
 
+static constexpr llvm::StringLiteral ParentDeclName = "parent-decl";
+static constexpr llvm::StringLiteral TagDeclName = "tag-decl";
+static constexpr llvm::StringLiteral TypedefName = "typedef";
+
 UseUsingCheck::UseUsingCheck(StringRef Name, ClangTidyContext *Context)
 : ClangTidyCheck(Name, Context),
   IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)) {}
@@ -25,23 +29,45 @@
 }
 
 void UseUsingCheck::registerMatchers(MatchFinder *Finder) {
-  Finder->addMatcher(typedefDecl(unless(isInstantiated())).bind("typedef"),
+  Finder->addMatcher(typedefDecl(unless(isInstantiated()),
+ hasParent(decl().bind(ParentDeclName)))
+ .bind(TypedefName),
  this);
-  // This matcher used to find tag declarations in source code within typedefs.
-  // They appear in the AST just *prior* to the typedefs.
-  Finder->addMatcher(tagDecl(unless(isImplicit())).bind("tagdecl"), this);
+
+  // This matcher is used to find tag declarations in source code within
+  // typedefs. They appear in the AST just *prior* to the typedefs.
+  Finder->addMatcher(
+  tagDecl(
+  anyOf(allOf(unless(anyOf(isImplicit(),
+   classTemplateSpecializationDecl())),
+  hasParent(decl().bind(ParentDeclName))),
+// We want the parent of the ClassTemplateDecl, not the parent
+// of the specialization.
+classTemplateSpecializationDecl(hasAncestor(classTemplateDecl(
+hasParent(decl().bind(ParentDeclName)))
+  .bind(TagDeclName),
+  this);
 }
 
 void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *ParentDecl = Result.Nodes.getNodeAs(ParentDeclName);
+  if (!ParentDecl)
+return;
+
   // Match CXXRecordDecl only to store the range of the last non-implicit full
   // declaration, to later check whether it's within the typdef itself.
-  const auto *MatchedTagDecl = Result.Nodes.getNodeAs("tagdecl");
+  const auto *MatchedTagDecl = Result.Nodes.getNodeAs(TagDeclName);
   if (MatchedTagDecl) {
-LastTagDeclRange = MatchedTagDecl->getSourceRange();
+// It is not sufficient to just track the last TagDec

[PATCH] D113429: [clang-tidy] Use `hasCanonicalType()` matcher in `bugprone-unused-raii` check

2021-11-08 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: simon.giesecke, alexfh, aaron.ballman.
fwolff added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, xazax.hun.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

Fixes PR#52217.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D113429

Files:
  clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/bugprone-unused-raii.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-unused-raii.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-unused-raii.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-unused-raii.cpp
@@ -82,6 +82,28 @@
   (void)i;
 }
 
+template 
+void aliastest() {
+  using X = Foo;
+  using Y = X;
+  using Z = Y;
+  Z(42);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately 
after creation; did you mean to name the object?
+  // CHECK-FIXES: Z give_me_a_name(42);
+
+  typedef Z ZT;
+  ZT(42, 13);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately 
after creation; did you mean to name the object?
+  // CHECK-FIXES: ZT give_me_a_name(42, 13);
+
+  using TT = TCtorDefaultArg;
+  TT(42);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately 
after creation; did you mean to name the object?
+  // CHECK-FIXES: TT give_me_a_name(42);
+
+  (void)0;
+}
+
 void test() {
   Foo(42);
 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after 
creation; did you mean to name the object?
Index: clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp
@@ -29,10 +29,11 @@
   Finder->addMatcher(
   mapAnyOf(cxxConstructExpr, cxxUnresolvedConstructExpr)
   .with(hasParent(compoundStmt().bind("compound")),
-anyOf(hasType(cxxRecordDecl(hasNonTrivialDestructor())),
-  hasType(templateSpecializationType(
+anyOf(hasType(hasCanonicalType(recordType(hasDeclaration(
+  cxxRecordDecl(hasNonTrivialDestructor()),
+  hasType(hasCanonicalType(templateSpecializationType(
   hasDeclaration(classTemplateDecl(has(
-  cxxRecordDecl(hasNonTrivialDestructor()
+  cxxRecordDecl(hasNonTrivialDestructor())
   .bind("expr"),
   this);
 }


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-unused-raii.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-unused-raii.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-unused-raii.cpp
@@ -82,6 +82,28 @@
   (void)i;
 }
 
+template 
+void aliastest() {
+  using X = Foo;
+  using Y = X;
+  using Z = Y;
+  Z(42);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
+  // CHECK-FIXES: Z give_me_a_name(42);
+
+  typedef Z ZT;
+  ZT(42, 13);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
+  // CHECK-FIXES: ZT give_me_a_name(42, 13);
+
+  using TT = TCtorDefaultArg;
+  TT(42);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
+  // CHECK-FIXES: TT give_me_a_name(42);
+
+  (void)0;
+}
+
 void test() {
   Foo(42);
 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
Index: clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp
@@ -29,10 +29,11 @@
   Finder->addMatcher(
   mapAnyOf(cxxConstructExpr, cxxUnresolvedConstructExpr)
   .with(hasParent(compoundStmt().bind("compound")),
-anyOf(hasType(cxxRecordDecl(hasNonTrivialDestructor())),
-  hasType(templateSpecializationType(
+anyOf(hasType(hasCanonicalType(recordType(hasDeclaration(
+  cxxRecordDecl(hasNonTrivialDestructor()),
+  hasType(hasCanonicalType(templateSpecializationType(
   hasDeclaration(classTemplateDecl(has(
-  cxxRecordDecl(hasNonTrivialDestructor()
+  cxxRecordDecl(hasNonTrivialDestructor())
   .bind("expr"),
   this);
 }
___
cfe-commits mailing 

[PATCH] D113429: [clang-tidy] Use `hasCanonicalType()` matcher in `bugprone-unused-raii` check

2021-11-09 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff added a comment.

Thanks for reviewing this! Can you (or someone else) commit this for me? I 
don't have commit access.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D113429

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


[PATCH] D113499: [clang-tidy] Reduce false positives for `bugprone-infinite-loop` with dependent expressions

2021-11-09 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: alexfh, klimek, djasper.
fwolff added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, xazax.hun.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

Fixes PR#52081 by attempting to detect some of the "obvious" cases where a loop 
condition is known to be false despite depending on template parameters.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D113499

Files:
  clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp
@@ -622,3 +622,31 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of 
its condition variables (size) are updated in the loop body 
[bugprone-infinite-loop]
   }
 }
+
+template 
+int some_template_fn() { return 1; }
+
+template 
+void test_dependent_condition() {
+  const int error = some_template_fn();
+  do {
+  } while (false && error == 0);
+
+  const int val = some_template_fn();
+  for (; !(val == 0 || true);) {
+  }
+
+  const int val2 = some_template_fn();
+  for (; !(val2 == 0 || false);) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of 
its condition variables (val2) are updated in the loop body 
[bugprone-infinite-loop]
+  }
+
+  const int val3 = some_template_fn();
+  do {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of 
its condition variables (val3) are updated in the loop body 
[bugprone-infinite-loop]
+  } while (1, (true) && val3 == 1);
+
+  const int val4 = some_template_fn();
+  do {
+  } while (1, (false) && val4 == 1);
+}
Index: clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
@@ -117,12 +117,31 @@
   return Result;
 }
 
-static bool isKnownFalse(const Expr &Cond, const ASTContext &Ctx) {
-  if (Cond.isValueDependent())
+static bool isKnown(const Expr &Cond, const ASTContext &Ctx, const bool Value) 
{
+  if (Cond.isValueDependent()) {
+if (const auto *BinOp = dyn_cast(&Cond)) {
+  // Conjunctions (disjunctions) can still be handled if at least one
+  // conjunct (disjunct) is known to be false (true).
+  if (!Value && BinOp->getOpcode() == BO_LAnd)
+return isKnown(*BinOp->getLHS(), Ctx, false) ||
+   isKnown(*BinOp->getRHS(), Ctx, false);
+  if (Value && BinOp->getOpcode() == BO_LOr)
+return isKnown(*BinOp->getLHS(), Ctx, true) ||
+   isKnown(*BinOp->getRHS(), Ctx, true);
+  if (BinOp->getOpcode() == BO_Comma)
+return isKnown(*BinOp->getRHS(), Ctx, Value);
+} else if (const auto *UnOp = dyn_cast(&Cond)) {
+  if (UnOp->getOpcode() == UO_LNot)
+return isKnown(*UnOp->getSubExpr(), Ctx, !Value);
+} else if (const auto *Paren = dyn_cast(&Cond))
+  return isKnown(*Paren->getSubExpr(), Ctx, Value);
+else if (const auto *ImplCast = dyn_cast(&Cond))
+  return isKnown(*ImplCast->getSubExpr(), Ctx, Value);
 return false;
+  }
   bool Result = false;
   if (Cond.EvaluateAsBooleanCondition(Result, Ctx))
-return !Result;
+return Result == Value;
   return false;
 }
 
@@ -144,7 +163,7 @@
   const auto *LoopStmt = Result.Nodes.getNodeAs("loop-stmt");
   const auto *Func = Result.Nodes.getNodeAs("func");
 
-  if (isKnownFalse(*Cond, *Result.Context))
+  if (isKnown(*Cond, *Result.Context, false))
 return;
 
   bool ShouldHaveConditionVariables = true;


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp
@@ -622,3 +622,31 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (size) are updated in the loop body [bugprone-infinite-loop]
   }
 }
+
+template 
+int some_template_fn() { return 1; }
+
+template 
+void test_dependent_condition() {
+  const int error = some_template_fn();
+  do {
+  } while (false && error == 0);
+
+  const int val = some_template_fn();
+  for (; !(val == 0 || true);) {
+  }
+
+  const int val2 = some_template_fn();
+  for (; !(val2 == 0 || false);) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (val2) are updated in the loop body [bugprone-infinite-loop]
+  }
+
+  const int val3 = some_template_fn();
+  do {
+  

[PATCH] D113507: [clang-tidy] Include constructor initializers in `bugprone-exception-escape` check

2021-11-09 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: alexfh, aaron.ballman.
fwolff added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, xazax.hun.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

Fixes PR#52435.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D113507

Files:
  clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
  clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
@@ -288,6 +288,15 @@
   return recursion_helper(n);
 }
 
+struct super_throws {
+  super_throws() noexcept(false) { throw 42; }
+};
+
+struct sub_throws : super_throws {
+  sub_throws() noexcept : super_throws() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in 
function 'sub_throws' which should not throw exceptions
+};
+
 int main() {
   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in 
function 'main' which should not throw exceptions
   throw 1;
Index: clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
===
--- clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
+++ clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
@@ -119,6 +119,16 @@
 CallStack.insert(Func);
 ExceptionInfo Result =
 throwsException(Body, ExceptionInfo::Throwables(), CallStack);
+
+// For a constructor, we also have to check the initializers.
+if (const auto *Ctor = dyn_cast(Func)) {
+  for (const CXXCtorInitializer *Init : Ctor->inits()) {
+ExceptionInfo Excs = throwsException(
+Init->getInit(), ExceptionInfo::Throwables(), CallStack);
+Result.merge(Excs);
+  }
+}
+
 CallStack.erase(Func);
 return Result;
   }
@@ -195,6 +205,10 @@
   ExceptionInfo Excs = throwsException(Func, CallStack);
   Results.merge(Excs);
 }
+  } else if (const auto *Construct = dyn_cast(St)) {
+ExceptionInfo Excs =
+throwsException(Construct->getConstructor(), CallStack);
+Results.merge(Excs);
   } else {
 for (const Stmt *Child : St->children()) {
   ExceptionInfo Excs = throwsException(Child, Caught, CallStack);


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
@@ -288,6 +288,15 @@
   return recursion_helper(n);
 }
 
+struct super_throws {
+  super_throws() noexcept(false) { throw 42; }
+};
+
+struct sub_throws : super_throws {
+  sub_throws() noexcept : super_throws() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in function 'sub_throws' which should not throw exceptions
+};
+
 int main() {
   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'main' which should not throw exceptions
   throw 1;
Index: clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
===
--- clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
+++ clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
@@ -119,6 +119,16 @@
 CallStack.insert(Func);
 ExceptionInfo Result =
 throwsException(Body, ExceptionInfo::Throwables(), CallStack);
+
+// For a constructor, we also have to check the initializers.
+if (const auto *Ctor = dyn_cast(Func)) {
+  for (const CXXCtorInitializer *Init : Ctor->inits()) {
+ExceptionInfo Excs = throwsException(
+Init->getInit(), ExceptionInfo::Throwables(), CallStack);
+Result.merge(Excs);
+  }
+}
+
 CallStack.erase(Func);
 return Result;
   }
@@ -195,6 +205,10 @@
   ExceptionInfo Excs = throwsException(Func, CallStack);
   Results.merge(Excs);
 }
+  } else if (const auto *Construct = dyn_cast(St)) {
+ExceptionInfo Excs =
+throwsException(Construct->getConstructor(), CallStack);
+Results.merge(Excs);
   } else {
 for (const Stmt *Child : St->children()) {
   ExceptionInfo Excs = throwsException(Child, Caught, CallStack);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D113518: [clang] Create delegating constructors even in templates

2021-11-09 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: rsmith, dblaikie, carlosgalvezp.
fwolff added a project: clang.
Herald added subscribers: kbarton, nemanjai.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.
Herald added a project: clang-tools-extra.

This fixes a bug in clang-tidy (PR#37902), even though the code for the 
`cppcoreguidelines-pro-type-member-init` check itself is perfectly fine. It 
uses the `isDelegatingConstructor()` matcher, which does not match delegating 
constructors in templates because the AST contains incorrect information 
(constructors in templates are never marked as delegating). This patch fixes 
this behavior by constructing a correct `CXXCtorInitializer` for delegating 
constructors in templates.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D113518

Files:
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init.cpp
  clang/lib/Sema/SemaDeclCXX.cpp


Index: clang/lib/Sema/SemaDeclCXX.cpp
===
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -4496,6 +4496,8 @@
   // (broken) code in a non-template! SetCtorInitializers does not expect this.
   bool Dependent = CurContext->isDependentContext() &&
(BaseType->isDependentType() || Init->isTypeDependent());
+  bool Delegating = Context.hasSameUnqualifiedType(
+  QualType(ClassDecl->getTypeForDecl(), 0), BaseType);
 
   SourceRange InitRange = Init->getSourceRange();
   if (EllipsisLoc.isValid()) {
@@ -4519,8 +4521,7 @@
   const CXXBaseSpecifier *DirectBaseSpec = nullptr;
   const CXXBaseSpecifier *VirtualBaseSpec = nullptr;
   if (!Dependent) {
-if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0),
-   BaseType))
+if (Delegating)
   return BuildDelegatingInitializer(BaseTInfo, Init, ClassDecl);
 
 FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
@@ -4548,10 +4549,14 @@
   if (Dependent) {
 DiscardCleanupsInEvaluationContext();
 
-return new (Context) CXXCtorInitializer(Context, BaseTInfo,
-/*IsVirtual=*/false,
-InitRange.getBegin(), Init,
-InitRange.getEnd(), EllipsisLoc);
+if (!Delegating)
+  return new (Context)
+  CXXCtorInitializer(Context, BaseTInfo,
+ /*IsVirtual=*/false, InitRange.getBegin(), Init,
+ InitRange.getEnd(), EllipsisLoc);
+else
+  return new (Context) CXXCtorInitializer(
+  Context, BaseTInfo, InitRange.getBegin(), Init, InitRange.getEnd());
   }
 
   // C++ [base.class.init]p2:
@@ -5063,14 +5068,16 @@
   memcpy(initializer, &Initializer, sizeof (CXXCtorInitializer*));
   Constructor->setCtorInitializers(initializer);
 
-  if (CXXDestructorDecl *Dtor = LookupDestructor(Constructor->getParent())) {
-MarkFunctionReferenced(Initializer->getSourceLocation(), Dtor);
-DiagnoseUseOfDecl(Dtor, Initializer->getSourceLocation());
-  }
+  if (!Constructor->isDependentContext()) {
+if (CXXDestructorDecl *Dtor = LookupDestructor(Constructor->getParent())) {
+  MarkFunctionReferenced(Initializer->getSourceLocation(), Dtor);
+  DiagnoseUseOfDecl(Dtor, Initializer->getSourceLocation());
+}
 
-  DelegatingCtorDecls.push_back(Constructor);
+DelegatingCtorDecls.push_back(Constructor);
 
-  DiagnoseUninitializedFields(*this, Constructor);
+DiagnoseUninitializedFields(*this, Constructor);
+  }
 
   return false;
 }
Index: 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init.cpp
@@ -372,8 +372,6 @@
 class PositiveSelfInitialization : NegativeAggregateType
 {
   PositiveSelfInitialization() : PositiveSelfInitialization() {}
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize 
these bases: NegativeAggregateType
-  // CHECK-FIXES: PositiveSelfInitialization() : NegativeAggregateType(), 
PositiveSelfInitialization() {}
 };
 
 class PositiveIndirectMember {
@@ -552,3 +550,11 @@
   int A;
   // CHECK-FIXES-NOT: int A{};
 };
+
+// Check that a delegating constructor in a template does not trigger false 
positives (PR#37902).
+template 
+struct TemplateWithDelegatingCtor {
+  int X;
+  TemplateWithDelegatingCtor() : X{} {};
+  TemplateWithDelegatingCtor(int) : TemplateWithDelegatingCtor(){};
+};


Index: clang/lib/Sema/SemaDeclCXX.cpp
===
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -4496,6 +4496,8 @@
   // (broken) 

[PATCH] D113585: [clang-tidy] Fix false positive in `bugprone-throw-keyword-missing` check

2021-11-10 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: steveire, alexfh, Eugene.Zelenko.
fwolff added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, xazax.hun.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

Fixes PR#52400. The tests for `bugprone-throw-keyword-missing` actually already 
contain exceptions as class members, but not as members with initializers, 
which was probably just an oversight.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D113585

Files:
  clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/bugprone-throw-keyword-missing.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/bugprone-throw-keyword-missing.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/bugprone-throw-keyword-missing.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/bugprone-throw-keyword-missing.cpp
@@ -118,6 +118,7 @@
 
 class CtorInitializerListTest {
   RegularException exc;
+  RegularException exc2{};
 
   CtorInitializerListTest() : exc(RegularException()) {}
 
Index: clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp
@@ -26,7 +26,7 @@
   isSameOrDerivedFrom(matchesName("[Ee]xception|EXCEPTION",
   unless(anyOf(hasAncestor(stmt(
anyOf(cxxThrowExpr(), callExpr(), returnStmt(,
-   hasAncestor(varDecl()),
+   hasAncestor(decl(anyOf(varDecl(), fieldDecl(,
allOf(hasAncestor(CtorInitializerList),
  unless(hasAncestor(cxxCatchStmt()))
   .bind("temporary-exception-not-thrown"),


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-throw-keyword-missing.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-throw-keyword-missing.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-throw-keyword-missing.cpp
@@ -118,6 +118,7 @@
 
 class CtorInitializerListTest {
   RegularException exc;
+  RegularException exc2{};
 
   CtorInitializerListTest() : exc(RegularException()) {}
 
Index: clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp
@@ -26,7 +26,7 @@
   isSameOrDerivedFrom(matchesName("[Ee]xception|EXCEPTION",
   unless(anyOf(hasAncestor(stmt(
anyOf(cxxThrowExpr(), callExpr(), returnStmt(,
-   hasAncestor(varDecl()),
+   hasAncestor(decl(anyOf(varDecl(), fieldDecl(,
allOf(hasAncestor(CtorInitializerList),
  unless(hasAncestor(cxxCatchStmt()))
   .bind("temporary-exception-not-thrown"),
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D113499: [clang-tidy] Reduce false positives for `bugprone-infinite-loop` with dependent expressions

2021-11-10 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 386244.
fwolff added a comment.

The test failed on Windows. I don't have a machine to reproduce this, but maybe 
adding `-fno-delayed-template-parsing` helps.


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

https://reviews.llvm.org/D113499

Files:
  clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp
@@ -1,5 +1,5 @@
 // RUN: %check_clang_tidy %s bugprone-infinite-loop %t \
-// RUN:   -- -- -fexceptions -fblocks
+// RUN:   -- -- -fexceptions -fblocks 
-fno-delayed-template-parsing
 
 void simple_infinite_loop1() {
   int i = 0;
@@ -622,3 +622,31 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of 
its condition variables (size) are updated in the loop body 
[bugprone-infinite-loop]
   }
 }
+
+template 
+int some_template_fn() { return 1; }
+
+template 
+void test_dependent_condition() {
+  const int error = some_template_fn();
+  do {
+  } while (false && error == 0);
+
+  const int val = some_template_fn();
+  for (; !(val == 0 || true);) {
+  }
+
+  const int val2 = some_template_fn();
+  for (; !(val2 == 0 || false);) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of 
its condition variables (val2) are updated in the loop body 
[bugprone-infinite-loop]
+  }
+
+  const int val3 = some_template_fn();
+  do {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of 
its condition variables (val3) are updated in the loop body 
[bugprone-infinite-loop]
+  } while (1, (true) && val3 == 1);
+
+  const int val4 = some_template_fn();
+  do {
+  } while (1, (false) && val4 == 1);
+}
Index: clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
@@ -117,12 +117,31 @@
   return Result;
 }
 
-static bool isKnownFalse(const Expr &Cond, const ASTContext &Ctx) {
-  if (Cond.isValueDependent())
+static bool isKnown(const Expr &Cond, const ASTContext &Ctx, const bool Value) 
{
+  if (Cond.isValueDependent()) {
+if (const auto *BinOp = dyn_cast(&Cond)) {
+  // Conjunctions (disjunctions) can still be handled if at least one
+  // conjunct (disjunct) is known to be false (true).
+  if (!Value && BinOp->getOpcode() == BO_LAnd)
+return isKnown(*BinOp->getLHS(), Ctx, false) ||
+   isKnown(*BinOp->getRHS(), Ctx, false);
+  if (Value && BinOp->getOpcode() == BO_LOr)
+return isKnown(*BinOp->getLHS(), Ctx, true) ||
+   isKnown(*BinOp->getRHS(), Ctx, true);
+  if (BinOp->getOpcode() == BO_Comma)
+return isKnown(*BinOp->getRHS(), Ctx, Value);
+} else if (const auto *UnOp = dyn_cast(&Cond)) {
+  if (UnOp->getOpcode() == UO_LNot)
+return isKnown(*UnOp->getSubExpr(), Ctx, !Value);
+} else if (const auto *Paren = dyn_cast(&Cond))
+  return isKnown(*Paren->getSubExpr(), Ctx, Value);
+else if (const auto *ImplCast = dyn_cast(&Cond))
+  return isKnown(*ImplCast->getSubExpr(), Ctx, Value);
 return false;
+  }
   bool Result = false;
   if (Cond.EvaluateAsBooleanCondition(Result, Ctx))
-return !Result;
+return Result == Value;
   return false;
 }
 
@@ -144,7 +163,7 @@
   const auto *LoopStmt = Result.Nodes.getNodeAs("loop-stmt");
   const auto *Func = Result.Nodes.getNodeAs("func");
 
-  if (isKnownFalse(*Cond, *Result.Context))
+  if (isKnown(*Cond, *Result.Context, false))
 return;
 
   bool ShouldHaveConditionVariables = true;


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp
@@ -1,5 +1,5 @@
 // RUN: %check_clang_tidy %s bugprone-infinite-loop %t \
-// RUN:   -- -- -fexceptions -fblocks
+// RUN:   -- -- -fexceptions -fblocks -fno-delayed-template-parsing
 
 void simple_infinite_loop1() {
   int i = 0;
@@ -622,3 +622,31 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (size) are updated in the loop body [bugprone-infinite-loop]
   }
 }
+
+template 
+int some_template_fn() { return 1; }
+
+template 
+void test_dependent_condition() {
+  const int error = some_template_fn();
+  do {
+  } while (false && error == 0);
+
+  const int val = some_template_fn();
+

[PATCH] D113518: [clang] Create delegating constructors even in templates

2021-11-10 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 386297.

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

https://reviews.llvm.org/D113518

Files:
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init.cpp
  clang/lib/Sema/SemaDeclCXX.cpp


Index: clang/lib/Sema/SemaDeclCXX.cpp
===
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -4496,6 +4496,8 @@
   // (broken) code in a non-template! SetCtorInitializers does not expect this.
   bool Dependent = CurContext->isDependentContext() &&
(BaseType->isDependentType() || Init->isTypeDependent());
+  bool Delegating = Context.hasSameUnqualifiedType(
+  QualType(ClassDecl->getTypeForDecl(), 0), BaseType);
 
   SourceRange InitRange = Init->getSourceRange();
   if (EllipsisLoc.isValid()) {
@@ -4519,8 +4521,7 @@
   const CXXBaseSpecifier *DirectBaseSpec = nullptr;
   const CXXBaseSpecifier *VirtualBaseSpec = nullptr;
   if (!Dependent) {
-if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0),
-   BaseType))
+if (Delegating)
   return BuildDelegatingInitializer(BaseTInfo, Init, ClassDecl);
 
 FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
@@ -4548,10 +4549,14 @@
   if (Dependent) {
 DiscardCleanupsInEvaluationContext();
 
-return new (Context) CXXCtorInitializer(Context, BaseTInfo,
-/*IsVirtual=*/false,
-InitRange.getBegin(), Init,
-InitRange.getEnd(), EllipsisLoc);
+if (!Delegating)
+  return new (Context)
+  CXXCtorInitializer(Context, BaseTInfo,
+ /*IsVirtual=*/false, InitRange.getBegin(), Init,
+ InitRange.getEnd(), EllipsisLoc);
+else
+  return new (Context) CXXCtorInitializer(
+  Context, BaseTInfo, InitRange.getBegin(), Init, InitRange.getEnd());
   }
 
   // C++ [base.class.init]p2:
@@ -5063,14 +5068,16 @@
   memcpy(initializer, &Initializer, sizeof (CXXCtorInitializer*));
   Constructor->setCtorInitializers(initializer);
 
-  if (CXXDestructorDecl *Dtor = LookupDestructor(Constructor->getParent())) {
-MarkFunctionReferenced(Initializer->getSourceLocation(), Dtor);
-DiagnoseUseOfDecl(Dtor, Initializer->getSourceLocation());
-  }
+  if (!Constructor->isDependentContext()) {
+if (CXXDestructorDecl *Dtor = LookupDestructor(Constructor->getParent())) {
+  MarkFunctionReferenced(Initializer->getSourceLocation(), Dtor);
+  DiagnoseUseOfDecl(Dtor, Initializer->getSourceLocation());
+}
 
-  DelegatingCtorDecls.push_back(Constructor);
+DelegatingCtorDecls.push_back(Constructor);
 
-  DiagnoseUninitializedFields(*this, Constructor);
+DiagnoseUninitializedFields(*this, Constructor);
+  }
 
   return false;
 }
Index: 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init.cpp
@@ -372,8 +372,6 @@
 class PositiveSelfInitialization : NegativeAggregateType
 {
   PositiveSelfInitialization() : PositiveSelfInitialization() {}
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize 
these bases: NegativeAggregateType
-  // CHECK-FIXES: PositiveSelfInitialization() : NegativeAggregateType(), 
PositiveSelfInitialization() {}
 };
 
 class PositiveIndirectMember {
@@ -552,3 +550,18 @@
   int A;
   // CHECK-FIXES-NOT: int A{};
 };
+
+// Check that a delegating constructor in a template does not trigger false 
positives (PR#37902).
+template 
+struct TemplateWithDelegatingCtor {
+  int X;
+  TemplateWithDelegatingCtor() : X{} {};
+  TemplateWithDelegatingCtor(int) : TemplateWithDelegatingCtor(){};
+};
+
+template 
+struct TemplateWithDelegatingCtorNSDMI {
+  int X{};
+  TemplateWithDelegatingCtorNSDMI() = default;
+  TemplateWithDelegatingCtorNSDMI(int) : TemplateWithDelegatingCtorNSDMI() {}
+};


Index: clang/lib/Sema/SemaDeclCXX.cpp
===
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -4496,6 +4496,8 @@
   // (broken) code in a non-template! SetCtorInitializers does not expect this.
   bool Dependent = CurContext->isDependentContext() &&
(BaseType->isDependentType() || Init->isTypeDependent());
+  bool Delegating = Context.hasSameUnqualifiedType(
+  QualType(ClassDecl->getTypeForDecl(), 0), BaseType);
 
   SourceRange InitRange = Init->getSourceRange();
   if (EllipsisLoc.isValid()) {
@@ -4519,8 +4521,7 @@
   const CXXBaseSpecifier *DirectBaseSpec = nullptr;
   const CXXBaseSpecifier *Virt

[PATCH] D113518: [clang] Create delegating constructors even in templates

2021-11-10 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff marked 2 inline comments as done.
fwolff added a comment.

Thanks for your review @carlosgalvezp! I have addressed your inline comments. 
I'm not sure about the failing test, but it looks like a regression test 
internal to libFuzzer? Maybe it goes away with the rebuild.




Comment at: 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init.cpp:374
 {
   PositiveSelfInitialization() : PositiveSelfInitialization() {}
 };

carlosgalvezp wrote:
> Not really sure what this test is meant to do. Why would it call the 
> destructor of the own class in it's own constructor? Looks very strange to me.
> 
> If anything, the constructor should call the constructor of the base:
> 
> PositiveSelfInitialization() : NegativeAggregateType()
> 
> What do you think?
The comment above talks about a "pathological template", so my guess is that 
this checks that clang-tidy doesn't crash for this input. The only reason why I 
had to touch this test at all is that the constructor is now treated as a 
delegating constructor, which suppresses the warning.


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

https://reviews.llvm.org/D113518

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


[PATCH] D113518: [clang] Create delegating constructors even in templates

2021-11-11 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 386620.

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

https://reviews.llvm.org/D113518

Files:
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init.cpp
  clang/lib/Sema/SemaDeclCXX.cpp

Index: clang/lib/Sema/SemaDeclCXX.cpp
===
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -4496,6 +4496,8 @@
   // (broken) code in a non-template! SetCtorInitializers does not expect this.
   bool Dependent = CurContext->isDependentContext() &&
(BaseType->isDependentType() || Init->isTypeDependent());
+  bool Delegating = Context.hasSameUnqualifiedType(
+  QualType(ClassDecl->getTypeForDecl(), 0), BaseType);
 
   SourceRange InitRange = Init->getSourceRange();
   if (EllipsisLoc.isValid()) {
@@ -4519,8 +4521,7 @@
   const CXXBaseSpecifier *DirectBaseSpec = nullptr;
   const CXXBaseSpecifier *VirtualBaseSpec = nullptr;
   if (!Dependent) {
-if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0),
-   BaseType))
+if (Delegating)
   return BuildDelegatingInitializer(BaseTInfo, Init, ClassDecl);
 
 FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
@@ -4548,10 +4549,14 @@
   if (Dependent) {
 DiscardCleanupsInEvaluationContext();
 
-return new (Context) CXXCtorInitializer(Context, BaseTInfo,
-/*IsVirtual=*/false,
-InitRange.getBegin(), Init,
-InitRange.getEnd(), EllipsisLoc);
+if (!Delegating)
+  return new (Context)
+  CXXCtorInitializer(Context, BaseTInfo,
+ /*IsVirtual=*/false, InitRange.getBegin(), Init,
+ InitRange.getEnd(), EllipsisLoc);
+else
+  return new (Context) CXXCtorInitializer(
+  Context, BaseTInfo, InitRange.getBegin(), Init, InitRange.getEnd());
   }
 
   // C++ [base.class.init]p2:
@@ -5063,14 +5068,16 @@
   memcpy(initializer, &Initializer, sizeof (CXXCtorInitializer*));
   Constructor->setCtorInitializers(initializer);
 
-  if (CXXDestructorDecl *Dtor = LookupDestructor(Constructor->getParent())) {
-MarkFunctionReferenced(Initializer->getSourceLocation(), Dtor);
-DiagnoseUseOfDecl(Dtor, Initializer->getSourceLocation());
-  }
+  if (!Constructor->isDependentContext()) {
+if (CXXDestructorDecl *Dtor = LookupDestructor(Constructor->getParent())) {
+  MarkFunctionReferenced(Initializer->getSourceLocation(), Dtor);
+  DiagnoseUseOfDecl(Dtor, Initializer->getSourceLocation());
+}
 
-  DelegatingCtorDecls.push_back(Constructor);
+DelegatingCtorDecls.push_back(Constructor);
 
-  DiagnoseUninitializedFields(*this, Constructor);
+DiagnoseUninitializedFields(*this, Constructor);
+  }
 
   return false;
 }
Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init.cpp
@@ -372,8 +372,6 @@
 class PositiveSelfInitialization : NegativeAggregateType
 {
   PositiveSelfInitialization() : PositiveSelfInitialization() {}
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these bases: NegativeAggregateType
-  // CHECK-FIXES: PositiveSelfInitialization() : NegativeAggregateType(), PositiveSelfInitialization() {}
 };
 
 class PositiveIndirectMember {
@@ -552,3 +550,27 @@
   int A;
   // CHECK-FIXES-NOT: int A{};
 };
+
+// Check that a delegating constructor in a template does not trigger false positives (PR#37902).
+template 
+struct TemplateWithDelegatingCtor {
+  int X;
+  TemplateWithDelegatingCtor() : X{} {};
+  TemplateWithDelegatingCtor(int) : TemplateWithDelegatingCtor(){};
+};
+
+template 
+struct TemplateWithDelegatingCtorNSDMI {
+  int X{};
+  TemplateWithDelegatingCtorNSDMI() = default;
+  TemplateWithDelegatingCtorNSDMI(int) : TemplateWithDelegatingCtorNSDMI() {}
+};
+
+template 
+class TemplateDoesNotInitializeBase : NegativeAggregateType {
+  int X;
+  TemplateDoesNotInitializeBase() : X(42) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these bases: NegativeAggregateType
+
+  TemplateDoesNotInitializeBase(double) : TemplateDoesNotInitializeBase() {}
+};
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D113518: [clang] Create delegating constructors even in templates

2021-11-11 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff added inline comments.



Comment at: 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init.cpp:374
 {
   PositiveSelfInitialization() : PositiveSelfInitialization() {}
 };

carlosgalvezp wrote:
> fwolff wrote:
> > carlosgalvezp wrote:
> > > Not really sure what this test is meant to do. Why would it call the 
> > > destructor of the own class in it's own constructor? Looks very strange 
> > > to me.
> > > 
> > > If anything, the constructor should call the constructor of the base:
> > > 
> > > PositiveSelfInitialization() : NegativeAggregateType()
> > > 
> > > What do you think?
> > The comment above talks about a "pathological template", so my guess is 
> > that this checks that clang-tidy doesn't crash for this input. The only 
> > reason why I had to touch this test at all is that the constructor is now 
> > treated as a delegating constructor, which suppresses the warning.
> Hmm, I see. I would like to make sure we still catch the failure mode "this 
> constructor does not initialize these base classes" for class templates.
> 
> I don't see such test existing (only for non-template classes), maybe you can 
> add that too?
Good point, done now.


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

https://reviews.llvm.org/D113518

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


[PATCH] D113708: [clang-tidy] Fix `bugprone-use-after-move` check to also consider moves in constructor initializers

2021-11-11 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: alexfh, carlosgalvezp.
fwolff added a project: clang-tools-extra.
Herald added a subscriber: xazax.hun.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

Fixes PR#38187. Constructors are actually already checked, but only as 
functions, i.e. the check only looks at the constructor body and not at the 
initializers, which misses the (common) case where constructor parameters are 
moved as part of an initializer expression.

One remaining false negative is when both the move //and// the use-after-move 
occur in constructor initializers. This is a lot more difficult to handle, 
though, because the `bugprone-use-after-move` check is currently based on a CFG 
that only takes the body into account, not the initializers, so e.g. 
initialization order would have to manually be considered. I will file a 
follow-up issue for this once PR#38187 is closed.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D113708

Files:
  clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/bugprone-use-after-move.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-use-after-move.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-use-after-move.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-use-after-move.cpp
@@ -1338,3 +1338,26 @@
   Foo Other{std::move(Bar)};
 }
 } // namespace UnevalContext
+
+class PR38187 {
+public:
+  PR38187(std::string val) : val_(std::move(val)) {
+val.empty();
+// CHECK-NOTES: [[@LINE-1]]:5: warning: 'val' used after it was moved
+// CHECK-NOTES: [[@LINE-3]]:30: note: move occurred here
+  }
+
+private:
+  std::string val_;
+};
+
+class UseAfterMoveInCtorInit {
+public:
+  // TODO: warn here
+  UseAfterMoveInCtorInit(std::string val) : s(std::move(val)), b(val.empty()) {
+  }
+
+private:
+  std::string s;
+  bool b;
+};
Index: clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -129,8 +129,12 @@
   Visited.clear();
 
   const CFGBlock *Block = BlockMap->blockContainingStmt(MovingCall);
-  if (!Block)
-return false;
+  if (!Block) {
+// This can happen if MovingCall is in a constructor initializer, which is
+// not included in the CFG because the CFG is built only from the function
+// body.
+Block = &TheCFG->getEntry();
+  }
 
   return findInternal(Block, MovingCall, MovedVariable, TheUseAfterMove);
 }


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-use-after-move.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-use-after-move.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-use-after-move.cpp
@@ -1338,3 +1338,26 @@
   Foo Other{std::move(Bar)};
 }
 } // namespace UnevalContext
+
+class PR38187 {
+public:
+  PR38187(std::string val) : val_(std::move(val)) {
+val.empty();
+// CHECK-NOTES: [[@LINE-1]]:5: warning: 'val' used after it was moved
+// CHECK-NOTES: [[@LINE-3]]:30: note: move occurred here
+  }
+
+private:
+  std::string val_;
+};
+
+class UseAfterMoveInCtorInit {
+public:
+  // TODO: warn here
+  UseAfterMoveInCtorInit(std::string val) : s(std::move(val)), b(val.empty()) {
+  }
+
+private:
+  std::string s;
+  bool b;
+};
Index: clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -129,8 +129,12 @@
   Visited.clear();
 
   const CFGBlock *Block = BlockMap->blockContainingStmt(MovingCall);
-  if (!Block)
-return false;
+  if (!Block) {
+// This can happen if MovingCall is in a constructor initializer, which is
+// not included in the CFG because the CFG is built only from the function
+// body.
+Block = &TheCFG->getEntry();
+  }
 
   return findInternal(Block, MovingCall, MovedVariable, TheUseAfterMove);
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D113804: [clang-tidy] Fix behavior of `modernize-use-using` with nested structs/unions

2021-11-12 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: alexfh, whisperity.
fwolff added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, rnkovacs, xazax.hun.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

Fixes PR#50990.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D113804

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

Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp
@@ -302,3 +302,7 @@
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
   // CHECK-FIXES: using b = InjectedClassNameWithUnnamedArgument;
 };
+
+typedef struct { int a; union { int b; }; } PR50990;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using PR50990 = struct { int a; union { int b; }; };
Index: clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
===
--- clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
+++ clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
@@ -10,6 +10,7 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_USING_H
 
 #include "../ClangTidyCheck.h"
+#include 
 
 namespace clang {
 namespace tidy {
@@ -23,7 +24,8 @@
 
   const bool IgnoreMacros;
   SourceLocation LastReplacementEnd;
-  SourceRange LastTagDeclRange;
+  std::map LastTagDeclRanges;
+
   std::string FirstTypedefType;
   std::string FirstTypedefName;
 
Index: clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
===
--- clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
@@ -25,19 +25,42 @@
 }
 
 void UseUsingCheck::registerMatchers(MatchFinder *Finder) {
-  Finder->addMatcher(typedefDecl(unless(isInstantiated())).bind("typedef"),
+  Finder->addMatcher(typedefDecl(unless(isInstantiated()),
+ hasParent(decl().bind("parent-decl")))
+ .bind("typedef"),
  this);
-  // This matcher used to find tag declarations in source code within typedefs.
-  // They appear in the AST just *prior* to the typedefs.
-  Finder->addMatcher(tagDecl(unless(isImplicit())).bind("tagdecl"), this);
+
+  // This matcher is used to find tag declarations in source code within
+  // typedefs. They appear in the AST just *prior* to the typedefs.
+  Finder->addMatcher(
+  tagDecl(
+  anyOf(allOf(unless(anyOf(isImplicit(),
+   classTemplateSpecializationDecl())),
+  hasParent(decl().bind("parent-decl"))),
+// We want the parent of the ClassTemplateDecl, not the parent
+// of the specialization.
+classTemplateSpecializationDecl(hasAncestor(
+classTemplateDecl(hasParent(decl().bind("parent-decl")))
+  .bind("tagdecl"),
+  this);
 }
 
 void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *ParentDecl = Result.Nodes.getNodeAs("parent-decl");
+  if (!ParentDecl) {
+return;
+  }
+
   // Match CXXRecordDecl only to store the range of the last non-implicit full
   // declaration, to later check whether it's within the typdef itself.
   const auto *MatchedTagDecl = Result.Nodes.getNodeAs("tagdecl");
   if (MatchedTagDecl) {
-LastTagDeclRange = MatchedTagDecl->getSourceRange();
+// It is not sufficient to just track the last TagDecl that we've seen,
+// because if one struct or union is nested inside another, the last TagDecl
+// before the typedef will be the nested one (PR#50990). Therefore, we also
+// keep track of the parent declaration, so that we can look up the last
+// TagDecl that is a sibling of the typedef in the AST.
+LastTagDeclRanges[ParentDecl] = MatchedTagDecl->getSourceRange();
 return;
   }
 
@@ -102,12 +125,14 @@
   auto Diag = diag(ReplaceRange.getBegin(), UseUsingWarning);
 
   // If typedef contains a full tag declaration, extract its full text.
-  if (LastTagDeclRange.isValid() &&
-  ReplaceRange.fullyContains(LastTagDeclRange)) {
+  auto LastTagDeclRange = LastTagDeclRanges.find(ParentDecl);
+  if (LastTagDeclRange != LastTagDeclRanges.end() &&
+  LastTagDeclRange->second.isValid() &&
+  ReplaceRange.fullyContains(LastTagDeclRange->second)) {
 bool Invalid;
-Type = std::string(
-Lexer::getSourceText(CharSourceRange::getTokenRange(LastTagDeclRange),
- *Result.SourceManager, getLangOpts(), &Invalid));
+  

[PATCH] D113828: [clang-tidy] Fix false positives in `fuchsia-trailing-return` check involving deduction guides

2021-11-13 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: alexfh, aaron.ballman, mizvekov.
fwolff added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, abrachet, phosek, xazax.hun.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

Fixes PR#47614. Deduction guides, implicit or user-defined, look like function 
declarations in the AST. They aren't really functions, though, and they always 
have a trailing return type, so it doesn't make sense to issue this warning for 
them.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D113828

Files:
  clang-tools-extra/clang-tidy/fuchsia/TrailingReturnCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/fuchsia-trailing-return.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/fuchsia-trailing-return.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/fuchsia-trailing-return.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/fuchsia-trailing-return.cpp
@@ -1,9 +1,9 @@
-// RUN: %check_clang_tidy %s fuchsia-trailing-return %t
+// RUN: %check_clang_tidy -std=c++17-or-later %s fuchsia-trailing-return %t
 
 int add_one(const int arg) { return arg; }
 
 auto get_add_one() -> int (*)(const int) {
-  // CHECK-MESSAGES: [[@LINE-1]]:1: warning: a trailing return type is 
disallowed for this type of declaration
+  // CHECK-MESSAGES: [[@LINE-1]]:1: warning: a trailing return type is 
disallowed for this function declaration
   // CHECK-NEXT: auto get_add_one() -> int (*)(const int) {
   return add_one;
 }
@@ -21,3 +21,31 @@
 auto fn(const T1 &lhs, const T2 &rhs) -> decltype(lhs + rhs) {
   return lhs + rhs;
 }
+
+// Now check that implicit and explicit C++17 deduction guides don't trigger 
this warning (PR#47614).
+
+template 
+struct ImplicitDeductionGuides {
+  ImplicitDeductionGuides(const T &);
+};
+
+template 
+struct pair {
+  A first;
+  B second;
+};
+
+template 
+struct UserDefinedDeductionGuides {
+  UserDefinedDeductionGuides(T);
+  template 
+  UserDefinedDeductionGuides(T1, T2);
+};
+
+template 
+UserDefinedDeductionGuides(T1, T2) -> UserDefinedDeductionGuides>;
+
+void foo() {
+  ImplicitDeductionGuides X(42);
+  UserDefinedDeductionGuides s(1, "abc");
+}
Index: clang-tools-extra/clang-tidy/fuchsia/TrailingReturnCheck.cpp
===
--- clang-tools-extra/clang-tidy/fuchsia/TrailingReturnCheck.cpp
+++ clang-tools-extra/clang-tidy/fuchsia/TrailingReturnCheck.cpp
@@ -17,12 +17,6 @@
 namespace tidy {
 namespace fuchsia {
 
-namespace {
-AST_MATCHER(FunctionDecl, hasTrailingReturn) {
-  return Node.getType()->castAs()->hasTrailingReturn();
-}
-} // namespace
-
 void TrailingReturnCheck::registerMatchers(MatchFinder *Finder) {
   // Functions that have trailing returns are disallowed, except for those
   // using decltype specifiers and lambda with otherwise unutterable
@@ -30,15 +24,16 @@
   Finder->addMatcher(
   functionDecl(hasTrailingReturn(),
unless(anyOf(returns(decltypeType()),
-hasParent(cxxRecordDecl(isLambda())
+hasParent(cxxRecordDecl(isLambda())),
+cxxDeductionGuideDecl(
   .bind("decl"),
   this);
 }
 
 void TrailingReturnCheck::check(const MatchFinder::MatchResult &Result) {
-  if (const auto *D = Result.Nodes.getNodeAs("decl"))
+  if (const auto *D = Result.Nodes.getNodeAs("decl"))
 diag(D->getBeginLoc(),
- "a trailing return type is disallowed for this type of declaration");
+ "a trailing return type is disallowed for this function declaration");
 }
 
 } // namespace fuchsia


Index: clang-tools-extra/test/clang-tidy/checkers/fuchsia-trailing-return.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/fuchsia-trailing-return.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/fuchsia-trailing-return.cpp
@@ -1,9 +1,9 @@
-// RUN: %check_clang_tidy %s fuchsia-trailing-return %t
+// RUN: %check_clang_tidy -std=c++17-or-later %s fuchsia-trailing-return %t
 
 int add_one(const int arg) { return arg; }
 
 auto get_add_one() -> int (*)(const int) {
-  // CHECK-MESSAGES: [[@LINE-1]]:1: warning: a trailing return type is disallowed for this type of declaration
+  // CHECK-MESSAGES: [[@LINE-1]]:1: warning: a trailing return type is disallowed for this function declaration
   // CHECK-NEXT: auto get_add_one() -> int (*)(const int) {
   return add_one;
 }
@@ -21,3 +21,31 @@
 auto fn(const T1 &lhs, const T2 &rhs) -> decltype(lhs + rhs) {
   return lhs + rhs;
 }
+
+// Now check that implicit and explicit C++17 deduction guides don't trigger this warning (PR#47614).
+
+template 
+struct ImplicitDeductionGuides {
+  ImplicitDeductionGuides(const T &);
+};
+
+template 
+struct pair {
+  A first;
+  B second;
+};
+
+template 
+struct UserDefinedDeductionGuid

[PATCH] D113830: [clang-tidy] Fix false positive in `readability-identifier-naming` check involving `override` attribute

2021-11-13 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: alexfh, salman-javed-nz.
fwolff added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, xazax.hun.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

Fixes part of PR#45815. Overriding methods should not get a 
`readability-identifier-naming` warning because the issue can only be fixed in 
the base class; but the current check for whether a method is overriding does 
not take the `override` attribute into account, which makes a difference for 
dependent base classes.

The other issue mentioned in PR#45815 is not solved by this patch: Applying the 
fix provided by `readability-identifier-naming` only changes the name in the 
base class, not in the derived class(es) or at any call sites. This is 
difficult to fix, because in addition to the template base class, there could 
be specializations of the base class that also contain the overridden method, 
which is why applying the fix from the base class in the derived class in 
general would not lead to correct code.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D113830

Files:
  clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp
@@ -305,9 +305,29 @@
   }
 };
 
-void VirtualCall(AOverridden &a_vItem) {
+template
+class ATOverridden {
+public:
+  virtual void BadBaseMethod() = 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for virtual 
method 'BadBaseMethod'
+  // CHECK-FIXES: {{^}}  virtual void v_Bad_Base_Method() = 0;
+};
+
+template
+class CTOverriding : public ATOverridden {
+  // Overriding a badly-named base isn't a new violation.
+  // FIXME: The fixes from the base class should be propagated to the derived 
class here
+  //(note that there could be specializations of the template base 
class, though)
+  void BadBaseMethod() override{}
+};
+
+template
+void VirtualCall(AOverridden &a_vItem, ATOverridden &a_vTitem) {
   a_vItem.BadBaseMethod();
   // CHECK-FIXES: {{^}}  a_vItem.v_Bad_Base_Method();
+
+  // FIXME: The fixes from ATOverridden should be propagated to the following 
call
+  a_vTitem.BadBaseMethod();
 }
 
 template 
Index: clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
@@ -1257,7 +1257,7 @@
 
   if (const auto *Decl = dyn_cast(D)) {
 if (Decl->isMain() || !Decl->isUserProvided() ||
-Decl->size_overridden_methods() > 0)
+Decl->size_overridden_methods() > 0 || Decl->hasAttr())
   return SK_Invalid;
 
 // If this method has the same name as any base method, this is likely


Index: clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp
@@ -305,9 +305,29 @@
   }
 };
 
-void VirtualCall(AOverridden &a_vItem) {
+template
+class ATOverridden {
+public:
+  virtual void BadBaseMethod() = 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for virtual method 'BadBaseMethod'
+  // CHECK-FIXES: {{^}}  virtual void v_Bad_Base_Method() = 0;
+};
+
+template
+class CTOverriding : public ATOverridden {
+  // Overriding a badly-named base isn't a new violation.
+  // FIXME: The fixes from the base class should be propagated to the derived class here
+  //(note that there could be specializations of the template base class, though)
+  void BadBaseMethod() override{}
+};
+
+template
+void VirtualCall(AOverridden &a_vItem, ATOverridden &a_vTitem) {
   a_vItem.BadBaseMethod();
   // CHECK-FIXES: {{^}}  a_vItem.v_Bad_Base_Method();
+
+  // FIXME: The fixes from ATOverridden should be propagated to the following call
+  a_vTitem.BadBaseMethod();
 }
 
 template 
Index: clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
@@ -1257,7 +1257,7 @@
 
   if (const auto *Decl = dyn_cast(D)) {
 if (Decl->isMain() || !Decl->isUserProvided() ||
-Decl->size_overridden_methods() > 0)
+Decl->size_overridden_methods() > 0 || Decl->hasAttr())
   return SK_I

[PATCH] D113708: [clang-tidy] Fix `bugprone-use-after-move` check to also consider moves in constructor initializers

2021-11-14 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 387116.
fwolff added a comment.

Thanks for reviewing this @carlosgalvezp! I have removed the "dead" test and 
put it into a follow-up issue (PR#52502).

If you are otherwise happy with the changes, could you commit them for me?


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

https://reviews.llvm.org/D113708

Files:
  clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/bugprone-use-after-move.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-use-after-move.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-use-after-move.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-use-after-move.cpp
@@ -1338,3 +1338,15 @@
   Foo Other{std::move(Bar)};
 }
 } // namespace UnevalContext
+
+class PR38187 {
+public:
+  PR38187(std::string val) : val_(std::move(val)) {
+val.empty();
+// CHECK-NOTES: [[@LINE-1]]:5: warning: 'val' used after it was moved
+// CHECK-NOTES: [[@LINE-3]]:30: note: move occurred here
+  }
+
+private:
+  std::string val_;
+};
Index: clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -129,8 +129,12 @@
   Visited.clear();
 
   const CFGBlock *Block = BlockMap->blockContainingStmt(MovingCall);
-  if (!Block)
-return false;
+  if (!Block) {
+// This can happen if MovingCall is in a constructor initializer, which is
+// not included in the CFG because the CFG is built only from the function
+// body.
+Block = &TheCFG->getEntry();
+  }
 
   return findInternal(Block, MovingCall, MovedVariable, TheUseAfterMove);
 }


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-use-after-move.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-use-after-move.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-use-after-move.cpp
@@ -1338,3 +1338,15 @@
   Foo Other{std::move(Bar)};
 }
 } // namespace UnevalContext
+
+class PR38187 {
+public:
+  PR38187(std::string val) : val_(std::move(val)) {
+val.empty();
+// CHECK-NOTES: [[@LINE-1]]:5: warning: 'val' used after it was moved
+// CHECK-NOTES: [[@LINE-3]]:30: note: move occurred here
+  }
+
+private:
+  std::string val_;
+};
Index: clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -129,8 +129,12 @@
   Visited.clear();
 
   const CFGBlock *Block = BlockMap->blockContainingStmt(MovingCall);
-  if (!Block)
-return false;
+  if (!Block) {
+// This can happen if MovingCall is in a constructor initializer, which is
+// not included in the CFG because the CFG is built only from the function
+// body.
+Block = &TheCFG->getEntry();
+  }
 
   return findInternal(Block, MovingCall, MovedVariable, TheUseAfterMove);
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D113830: [clang-tidy] Fix false positive in `readability-identifier-naming` check involving `override` attribute

2021-11-14 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 387121.
fwolff added a comment.

Thanks for your comments @salman-javed-nz! I have expanded the tests now 
according to your suggestions.


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

https://reviews.llvm.org/D113830

Files:
  clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp
@@ -285,6 +285,10 @@
   virtual void BadBaseMethod() = 0;
   // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for virtual method 'BadBaseMethod'
   // CHECK-FIXES: {{^}}  virtual void v_Bad_Base_Method() = 0;
+
+  virtual void BadBaseMethodNoAttr() = 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for virtual method 'BadBaseMethodNoAttr'
+  // CHECK-FIXES: {{^}}  virtual void v_Bad_Base_Method_No_Attr() = 0;
 };
 
 class COverriding : public AOverridden {
@@ -292,6 +296,8 @@
   // Overriding a badly-named base isn't a new violation.
   void BadBaseMethod() override {}
   // CHECK-FIXES: {{^}}  void v_Bad_Base_Method() override {}
+  void BadBaseMethodNoAttr() {}
+  // CHECK-FIXES: {{^}}  void v_Bad_Base_Method_No_Attr() {}
 
   void foo() {
 BadBaseMethod();
@@ -302,14 +308,66 @@
 // CHECK-FIXES: {{^}}AOverridden::v_Bad_Base_Method();
 COverriding::BadBaseMethod();
 // CHECK-FIXES: {{^}}COverriding::v_Bad_Base_Method();
+
+BadBaseMethodNoAttr();
+// CHECK-FIXES: {{^}}v_Bad_Base_Method_No_Attr();
   }
 };
 
-void VirtualCall(AOverridden &a_vItem) {
+// Same test as above, now with a dependent base class.
+template
+class ATOverridden {
+public:
+  virtual void BadBaseMethod() = 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for virtual method 'BadBaseMethod'
+  // CHECK-FIXES: {{^}}  virtual void v_Bad_Base_Method() = 0;
+
+  virtual void BadBaseMethodNoAttr() = 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for virtual method 'BadBaseMethodNoAttr'
+  // CHECK-FIXES: {{^}}  virtual void v_Bad_Base_Method_No_Attr() = 0;
+};
+
+template
+class CTOverriding : public ATOverridden {
+  // Overriding a badly-named base isn't a new violation.
+  // FIXME: The fixes from the base class should be propagated to the derived class here
+  //(note that there could be specializations of the template base class, though)
+  void BadBaseMethod() override{}
+
+  // Without the "override" attribute, and due to the dependent base class, it is not
+  // known whether this method overrides anything, so we get the warning here.
+  virtual void BadBaseMethodNoAttr() {};
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for virtual method 'BadBaseMethodNoAttr'
+  // CHECK-FIXES: {{^}}  virtual void v_Bad_Base_Method_No_Attr() {};
+};
+
+template
+void VirtualCall(AOverridden &a_vItem, ATOverridden &a_vTitem) {
   a_vItem.BadBaseMethod();
   // CHECK-FIXES: {{^}}  a_vItem.v_Bad_Base_Method();
+
+  // FIXME: The fixes from ATOverridden should be propagated to the following call
+  a_vTitem.BadBaseMethod();
 }
 
+// Same test as above, now with a dependent base class that is instantiated below.
+template
+class ATIOverridden {
+public:
+  virtual void BadBaseMethod() = 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for virtual method 'BadBaseMethod'
+  // CHECK-FIXES: {{^}}  virtual void v_Bad_Base_Method() = 0;
+};
+
+template
+class CTIOverriding : public ATIOverridden {
+  // Overriding a badly-named base isn't a new violation.
+  void BadBaseMethod() override{}
+  // CHECK-FIXES: {{^}}  void v_Bad_Base_Method() override{}
+};
+
+template class CTIOverriding;
+
 template 
 class CRTPBase {
 public:
Index: clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
@@ -1257,7 +1257,7 @@
 
   if (const auto *Decl = dyn_cast(D)) {
 if (Decl->isMain() || !Decl->isUserProvided() ||
-Decl->size_overridden_methods() > 0)
+Decl->size_overridden_methods() > 0 || Decl->hasAttr())
   return SK_Invalid;
 
 // If this method has the same name as any base method, this is likely
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D113863: [clang-tidy] Make `readability-container-data-pointer` more robust

2021-11-14 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: compnerd, alexfh, aaron.ballman.
fwolff added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, xazax.hun.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

Fixes PR#52245. I've also added a few test cases beyond PR#52245 that would 
also fail with the current implementation, which is quite brittle in many 
respects (e.g. it uses the `hasDescendant()` matcher to find the container that 
is being accessed, which is very easy to trick, as in the example in PR#52245).

I have not been able to reproduce the second issue mentioned in PR#52245 
(namely that using the `data()` member function is suggested even for 
containers that don't have it), but I've added a test case for it to be sure.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D113863

Files:
  clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
@@ -109,3 +109,38 @@
   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
   // CHECK-FIXES: {{^  }}return v.data();{{$}}
 }
+
+template 
+struct container_without_data {
+  using size_type = size_t;
+  T &operator[](size_type);
+  const T &operator[](size_type) const;
+};
+
+template 
+const T *n(const container_without_data &c) {
+  // c has no "data" member function, so there should not be a warning here:
+  return &c[0];
+}
+
+const int *o(const std::vector>> &v, const size_t idx1, const size_t idx2) {
+  return &v[idx1][idx2][0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return v[idx1][idx2].data();{{$}}
+}
+
+std::vector &select(std::vector &u, std::vector &v) {
+  return v;
+}
+
+int *p(std::vector &v1, std::vector &v2) {
+  return &select(*&v1, v2)[0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return select(*&v1, v2).data();{{$}}
+}
+
+int *q(std::vector ***v) {
+  return &(***v)[0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return (**v)->data();{{$}}
+}
Index: clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
@@ -16,6 +16,12 @@
 namespace clang {
 namespace tidy {
 namespace readability {
+
+static const char ContainerExprName[] = "container-expr";
+static const char DerefContainerExprName[] = "deref-container-expr";
+static const char AddrofContainerExprName[] = "addrof-container-expr";
+static const char AddressOfName[] = "address-of";
+
 ContainerDataPointerCheck::ContainerDataPointerCheck(StringRef Name,
  ClangTidyContext *Context)
 : ClangTidyCheck(Name, Context) {}
@@ -38,69 +44,69 @@
   const auto Container =
   qualType(anyOf(NonTemplateContainerType, TemplateContainerType));
 
+  const auto ContainerExpr = anyOf(
+  declRefExpr(
+  to(varDecl(anyOf(hasType(Container), hasType(pointsTo(Container)),
+   hasType(references(Container))
+  .bind(ContainerExprName),
+  unaryOperator(
+  hasOperatorName("*"),
+  hasUnaryOperand(
+  expr(hasType(pointsTo(Container))).bind(DerefContainerExprName)))
+  .bind(ContainerExprName),
+  unaryOperator(hasOperatorName("&"),
+hasUnaryOperand(expr(anyOf(hasType(Container),
+   hasType(references(Container
+.bind(AddrofContainerExprName)))
+  .bind(ContainerExprName),
+  expr(anyOf(hasType(Container), hasType(pointsTo(Container)),
+ hasType(references(Container
+  .bind(ContainerExprName));
+
+  const auto Zero = ignoringParens(integerLiteral(equals(0)));
+
+  const auto SubscriptOperator = callee(cxxMethodDecl(hasName("operator[]")));
+
   Finde

[PATCH] D113863: [clang-tidy] Make `readability-container-data-pointer` more robust

2021-11-14 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 387132.

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

https://reviews.llvm.org/D113863

Files:
  clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
@@ -109,3 +109,38 @@
   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
   // CHECK-FIXES: {{^  }}return v.data();{{$}}
 }
+
+template 
+struct container_without_data {
+  using size_type = size_t;
+  T &operator[](size_type);
+  const T &operator[](size_type) const;
+};
+
+template 
+const T *n(const container_without_data &c) {
+  // c has no "data" member function, so there should not be a warning here:
+  return &c[0];
+}
+
+const int *o(const std::vector>> &v, const size_t idx1, const size_t idx2) {
+  return &v[idx1][idx2][0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return v[idx1][idx2].data();{{$}}
+}
+
+std::vector &select(std::vector &u, std::vector &v) {
+  return v;
+}
+
+int *p(std::vector &v1, std::vector &v2) {
+  return &select(*&v1, v2)[0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return select(*&v1, v2).data();{{$}}
+}
+
+int *q(std::vector ***v) {
+  return &(***v)[0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return (**v)->data();{{$}}
+}
Index: clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
@@ -16,6 +16,12 @@
 namespace clang {
 namespace tidy {
 namespace readability {
+
+static const char ContainerExprName[] = "container-expr";
+static const char DerefContainerExprName[] = "deref-container-expr";
+static const char AddrofContainerExprName[] = "addrof-container-expr";
+static const char AddressOfName[] = "address-of";
+
 ContainerDataPointerCheck::ContainerDataPointerCheck(StringRef Name,
  ClangTidyContext *Context)
 : ClangTidyCheck(Name, Context) {}
@@ -38,69 +44,65 @@
   const auto Container =
   qualType(anyOf(NonTemplateContainerType, TemplateContainerType));
 
+  const auto ContainerExpr = anyOf(
+  unaryOperator(
+  hasOperatorName("*"),
+  hasUnaryOperand(
+  expr(hasType(pointsTo(Container))).bind(DerefContainerExprName)))
+  .bind(ContainerExprName),
+  unaryOperator(hasOperatorName("&"),
+hasUnaryOperand(expr(anyOf(hasType(Container),
+   hasType(references(Container
+.bind(AddrofContainerExprName)))
+  .bind(ContainerExprName),
+  expr(anyOf(hasType(Container), hasType(pointsTo(Container)),
+ hasType(references(Container
+  .bind(ContainerExprName));
+
+  const auto Zero = ignoringParens(integerLiteral(equals(0)));
+
+  const auto SubscriptOperator = callee(cxxMethodDecl(hasName("operator[]")));
+
   Finder->addMatcher(
   unaryOperator(
   unless(isExpansionInSystemHeader()), hasOperatorName("&"),
-  hasUnaryOperand(anyOf(
-  ignoringParenImpCasts(
-  cxxOperatorCallExpr(
-  callee(cxxMethodDecl(hasName("operator[]"))
- .bind("operator[]")),
-  argumentCountIs(2),
-  hasArgument(
-  0,
-  anyOf(ignoringParenImpCasts(
-declRefExpr(
-to(varDecl(anyOf(
-hasType(Container),
-hasType(references(Container))
-.bind("var")),
-ignoringParenImpCasts(hasDescendant(
-decl

[PATCH] D113863: [clang-tidy] Make `readability-container-data-pointer` more robust

2021-11-14 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 387133.

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

https://reviews.llvm.org/D113863

Files:
  clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
@@ -109,3 +109,38 @@
   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
   // CHECK-FIXES: {{^  }}return v.data();{{$}}
 }
+
+template 
+struct container_without_data {
+  using size_type = size_t;
+  T &operator[](size_type);
+  const T &operator[](size_type) const;
+};
+
+template 
+const T *n(const container_without_data &c) {
+  // c has no "data" member function, so there should not be a warning here:
+  return &c[0];
+}
+
+const int *o(const std::vector>> &v, const size_t idx1, const size_t idx2) {
+  return &v[idx1][idx2][0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return v[idx1][idx2].data();{{$}}
+}
+
+std::vector &select(std::vector &u, std::vector &v) {
+  return v;
+}
+
+int *p(std::vector &v1, std::vector &v2) {
+  return &select(*&v1, v2)[0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return select(*&v1, v2).data();{{$}}
+}
+
+int *q(std::vector ***v) {
+  return &(***v)[0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return (**v)->data();{{$}}
+}
Index: clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
@@ -16,6 +16,12 @@
 namespace clang {
 namespace tidy {
 namespace readability {
+
+static const char ContainerExprName[] = "container-expr";
+static const char DerefContainerExprName[] = "deref-container-expr";
+static const char AddrofContainerExprName[] = "addrof-container-expr";
+static const char AddressOfName[] = "address-of";
+
 ContainerDataPointerCheck::ContainerDataPointerCheck(StringRef Name,
  ClangTidyContext *Context)
 : ClangTidyCheck(Name, Context) {}
@@ -38,69 +44,65 @@
   const auto Container =
   qualType(anyOf(NonTemplateContainerType, TemplateContainerType));
 
+  const auto ContainerExpr = anyOf(
+  unaryOperator(
+  hasOperatorName("*"),
+  hasUnaryOperand(
+  expr(hasType(pointsTo(Container))).bind(DerefContainerExprName)))
+  .bind(ContainerExprName),
+  unaryOperator(hasOperatorName("&"),
+hasUnaryOperand(expr(anyOf(hasType(Container),
+   hasType(references(Container
+.bind(AddrofContainerExprName)))
+  .bind(ContainerExprName),
+  expr(anyOf(hasType(Container), hasType(pointsTo(Container)),
+ hasType(references(Container
+  .bind(ContainerExprName));
+
+  const auto Zero = integerLiteral(equals(0));
+
+  const auto SubscriptOperator = callee(cxxMethodDecl(hasName("operator[]")));
+
   Finder->addMatcher(
   unaryOperator(
   unless(isExpansionInSystemHeader()), hasOperatorName("&"),
-  hasUnaryOperand(anyOf(
-  ignoringParenImpCasts(
-  cxxOperatorCallExpr(
-  callee(cxxMethodDecl(hasName("operator[]"))
- .bind("operator[]")),
-  argumentCountIs(2),
-  hasArgument(
-  0,
-  anyOf(ignoringParenImpCasts(
-declRefExpr(
-to(varDecl(anyOf(
-hasType(Container),
-hasType(references(Container))
-.bind("var")),
-ignoringParenImpCasts(hasDescendant(
-declRefExpr(
-  

[PATCH] D113804: [clang-tidy] Fix behavior of `modernize-use-using` with nested structs/unions

2021-11-15 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 387377.
fwolff added a comment.

Thanks for your suggestions @whisperity! I have fixed both of them now.


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

https://reviews.llvm.org/D113804

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

Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp
@@ -302,3 +302,15 @@
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
   // CHECK-FIXES: using b = InjectedClassNameWithUnnamedArgument;
 };
+
+typedef struct { int a; union { int b; }; } PR50990;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using PR50990 = struct { int a; union { int b; }; };
+
+typedef struct { struct { int a; struct { struct { int b; } c; int d; } e; } f; int g; } PR50990_nested;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using PR50990_nested = struct { struct { int a; struct { struct { int b; } c; int d; } e; } f; int g; };
+
+typedef struct { struct { int a; } b; union { int c; float d; struct { int e; }; }; struct { double f; } g; } PR50990_siblings;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using PR50990_siblings = struct { struct { int a; } b; union { int c; float d; struct { int e; }; }; struct { double f; } g; };
Index: clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
===
--- clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
+++ clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
@@ -23,7 +23,8 @@
 
   const bool IgnoreMacros;
   SourceLocation LastReplacementEnd;
-  SourceRange LastTagDeclRange;
+  llvm::DenseMap LastTagDeclRanges;
+
   std::string FirstTypedefType;
   std::string FirstTypedefName;
 
Index: clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
===
--- clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
@@ -25,19 +25,42 @@
 }
 
 void UseUsingCheck::registerMatchers(MatchFinder *Finder) {
-  Finder->addMatcher(typedefDecl(unless(isInstantiated())).bind("typedef"),
+  Finder->addMatcher(typedefDecl(unless(isInstantiated()),
+ hasParent(decl().bind("parent-decl")))
+ .bind("typedef"),
  this);
-  // This matcher used to find tag declarations in source code within typedefs.
-  // They appear in the AST just *prior* to the typedefs.
-  Finder->addMatcher(tagDecl(unless(isImplicit())).bind("tagdecl"), this);
+
+  // This matcher is used to find tag declarations in source code within
+  // typedefs. They appear in the AST just *prior* to the typedefs.
+  Finder->addMatcher(
+  tagDecl(
+  anyOf(allOf(unless(anyOf(isImplicit(),
+   classTemplateSpecializationDecl())),
+  hasParent(decl().bind("parent-decl"))),
+// We want the parent of the ClassTemplateDecl, not the parent
+// of the specialization.
+classTemplateSpecializationDecl(hasAncestor(
+classTemplateDecl(hasParent(decl().bind("parent-decl")))
+  .bind("tagdecl"),
+  this);
 }
 
 void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *ParentDecl = Result.Nodes.getNodeAs("parent-decl");
+  if (!ParentDecl) {
+return;
+  }
+
   // Match CXXRecordDecl only to store the range of the last non-implicit full
   // declaration, to later check whether it's within the typdef itself.
   const auto *MatchedTagDecl = Result.Nodes.getNodeAs("tagdecl");
   if (MatchedTagDecl) {
-LastTagDeclRange = MatchedTagDecl->getSourceRange();
+// It is not sufficient to just track the last TagDecl that we've seen,
+// because if one struct or union is nested inside another, the last TagDecl
+// before the typedef will be the nested one (PR#50990). Therefore, we also
+// keep track of the parent declaration, so that we can look up the last
+// TagDecl that is a sibling of the typedef in the AST.
+LastTagDeclRanges[ParentDecl] = MatchedTagDecl->getSourceRange();
 return;
   }
 
@@ -102,12 +125,14 @@
   auto Diag = diag(ReplaceRange.getBegin(), UseUsingWarning);
 
   // If typedef contains a full tag declaration, extract its full text.
-  if (LastTagDeclRange.isValid() &&
-  ReplaceRange.fullyContains(LastTagDeclRange)) {
+  auto LastTagDeclRange = LastTagDecl

[PATCH] D113585: [clang-tidy] Fix false positive in `bugprone-throw-keyword-missing` check

2021-11-15 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff added a comment.

Thanks for reviewing this! Can you also commit it for me?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D113585

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


[PATCH] D113863: [clang-tidy] Make `readability-container-data-pointer` more robust

2021-11-15 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 387384.

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

https://reviews.llvm.org/D113863

Files:
  clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
@@ -109,3 +109,38 @@
   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
   // CHECK-FIXES: {{^  }}return v.data();{{$}}
 }
+
+template 
+struct container_without_data {
+  using size_type = size_t;
+  T &operator[](size_type);
+  const T &operator[](size_type) const;
+};
+
+template 
+const T *n(const container_without_data &c) {
+  // c has no "data" member function, so there should not be a warning here:
+  return &c[0];
+}
+
+const int *o(const std::vector>> &v, const size_t idx1, const size_t idx2) {
+  return &v[idx1][idx2][0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return v[idx1][idx2].data();{{$}}
+}
+
+std::vector &select(std::vector &u, std::vector &v) {
+  return v;
+}
+
+int *p(std::vector &v1, std::vector &v2) {
+  return &select(*&v1, v2)[0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return select(*&v1, v2).data();{{$}}
+}
+
+int *q(std::vector ***v) {
+  return &(***v)[0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return (**v)->data();{{$}}
+}
Index: clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
@@ -16,6 +16,12 @@
 namespace clang {
 namespace tidy {
 namespace readability {
+
+constexpr llvm::StringLiteral ContainerExprName = "container-expr";
+constexpr llvm::StringLiteral DerefContainerExprName = "deref-container-expr";
+constexpr llvm::StringLiteral AddrofContainerExprName = "addrof-container-expr";
+constexpr llvm::StringLiteral AddressOfName = "address-of";
+
 ContainerDataPointerCheck::ContainerDataPointerCheck(StringRef Name,
  ClangTidyContext *Context)
 : ClangTidyCheck(Name, Context) {}
@@ -38,69 +44,65 @@
   const auto Container =
   qualType(anyOf(NonTemplateContainerType, TemplateContainerType));
 
+  const auto ContainerExpr = anyOf(
+  unaryOperator(
+  hasOperatorName("*"),
+  hasUnaryOperand(
+  expr(hasType(pointsTo(Container))).bind(DerefContainerExprName)))
+  .bind(ContainerExprName),
+  unaryOperator(hasOperatorName("&"),
+hasUnaryOperand(expr(anyOf(hasType(Container),
+   hasType(references(Container
+.bind(AddrofContainerExprName)))
+  .bind(ContainerExprName),
+  expr(anyOf(hasType(Container), hasType(pointsTo(Container)),
+ hasType(references(Container
+  .bind(ContainerExprName));
+
+  const auto Zero = integerLiteral(equals(0));
+
+  const auto SubscriptOperator = callee(cxxMethodDecl(hasName("operator[]")));
+
   Finder->addMatcher(
   unaryOperator(
   unless(isExpansionInSystemHeader()), hasOperatorName("&"),
-  hasUnaryOperand(anyOf(
-  ignoringParenImpCasts(
-  cxxOperatorCallExpr(
-  callee(cxxMethodDecl(hasName("operator[]"))
- .bind("operator[]")),
-  argumentCountIs(2),
-  hasArgument(
-  0,
-  anyOf(ignoringParenImpCasts(
-declRefExpr(
-to(varDecl(anyOf(
-hasType(Container),
-hasType(references(Container))
-.bind("var")),
-ignoringParenImpCasts(hasDescendant(
-

[PATCH] D113863: [clang-tidy] Make `readability-container-data-pointer` more robust

2021-11-15 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff marked an inline comment as done.
fwolff added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp:20-23
+static const char ContainerExprName[] = "container-expr";
+static const char DerefContainerExprName[] = "deref-container-expr";
+static const char AddrofContainerExprName[] = "addrof-container-expr";
+static const char AddressOfName[] = "address-of";

whisperity wrote:
> Perhaps we could use `constexpr llvm::StringLiteral`?
Fixed.


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

https://reviews.llvm.org/D113863

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


[PATCH] D113585: [clang-tidy] Fix false positive in `bugprone-throw-keyword-missing` check

2021-11-15 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff added a comment.

In D113585#3132810 , @aaron.ballman 
wrote:

> In D113585#3132793 , @fwolff wrote:
>
>> Thanks for reviewing this! Can you also commit it for me?
>
> Sure can! What name and email address would you like used for patch 
> attribution? I'm in C standards meetings all this week so if someone else is 
> able to land this before I get to it, I will not be hurt. :-)

Thanks! You can use the same name and email as in commit 
`c3e3c762098e8d425731bb40f3b8b04dac1013f3`.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D113585

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


[PATCH] D113830: [clang-tidy] Fix false positive in `readability-identifier-naming` check involving `override` attribute

2021-11-15 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 387401.
fwolff added a comment.

Thanks again for your feedback @salman-javed-nz! I think I've addressed all of 
your comments now.


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

https://reviews.llvm.org/D113830

Files:
  clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp
@@ -285,6 +285,10 @@
   virtual void BadBaseMethod() = 0;
   // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for virtual method 'BadBaseMethod'
   // CHECK-FIXES: {{^}}  virtual void v_Bad_Base_Method() = 0;
+
+  virtual void BadBaseMethodNoAttr() = 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for virtual method 'BadBaseMethodNoAttr'
+  // CHECK-FIXES: {{^}}  virtual void v_Bad_Base_Method_No_Attr() = 0;
 };
 
 class COverriding : public AOverridden {
@@ -293,6 +297,9 @@
   void BadBaseMethod() override {}
   // CHECK-FIXES: {{^}}  void v_Bad_Base_Method() override {}
 
+  void BadBaseMethodNoAttr() /* override */ {}
+  // CHECK-FIXES: {{^}}  void v_Bad_Base_Method_No_Attr() /* override */ {}
+
   void foo() {
 BadBaseMethod();
 // CHECK-FIXES: {{^}}v_Bad_Base_Method();
@@ -302,12 +309,79 @@
 // CHECK-FIXES: {{^}}AOverridden::v_Bad_Base_Method();
 COverriding::BadBaseMethod();
 // CHECK-FIXES: {{^}}COverriding::v_Bad_Base_Method();
+
+BadBaseMethodNoAttr();
+// CHECK-FIXES: {{^}}v_Bad_Base_Method_No_Attr();
+this->BadBaseMethodNoAttr();
+// CHECK-FIXES: {{^}}this->v_Bad_Base_Method_No_Attr();
+AOverridden::BadBaseMethodNoAttr();
+// CHECK-FIXES: {{^}}AOverridden::v_Bad_Base_Method_No_Attr();
+COverriding::BadBaseMethodNoAttr();
+// CHECK-FIXES: {{^}}COverriding::v_Bad_Base_Method_No_Attr();
   }
 };
 
-void VirtualCall(AOverridden &a_vItem) {
+// Same test as above, now with a dependent base class.
+template
+class ATOverridden {
+public:
+  virtual void BadBaseMethod() = 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for virtual method 'BadBaseMethod'
+  // CHECK-FIXES: {{^}}  virtual void v_Bad_Base_Method() = 0;
+
+  virtual void BadBaseMethodNoAttr() = 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for virtual method 'BadBaseMethodNoAttr'
+  // CHECK-FIXES: {{^}}  virtual void v_Bad_Base_Method_No_Attr() = 0;
+};
+
+template
+class CTOverriding : public ATOverridden {
+  // Overriding a badly-named base isn't a new violation.
+  // FIXME: The fixes from the base class should be propagated to the derived class here
+  //(note that there could be specializations of the template base class, though)
+  void BadBaseMethod() override {}
+
+  // Without the "override" attribute, and due to the dependent base class, it is not
+  // known whether this method overrides anything, so we get the warning here.
+  virtual void BadBaseMethodNoAttr() {};
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for virtual method 'BadBaseMethodNoAttr'
+  // CHECK-FIXES: {{^}}  virtual void v_Bad_Base_Method_No_Attr() {};
+};
+
+template
+void VirtualCall(AOverridden &a_vItem, ATOverridden &a_vTitem) {
+  a_vItem.BadBaseMethod();
+  // CHECK-FIXES: {{^}}  a_vItem.v_Bad_Base_Method();
+
+  // FIXME: The fixes from ATOverridden should be propagated to the following call
+  a_vTitem.BadBaseMethod();
+}
+
+// Same test as above, now with a dependent base class that is instantiated below.
+template
+class ATIOverridden {
+public:
+  virtual void BadBaseMethod() = 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for virtual method 'BadBaseMethod'
+  // CHECK-FIXES: {{^}}  virtual void v_Bad_Base_Method() = 0;
+};
+
+template
+class CTIOverriding : public ATIOverridden {
+public:
+  // Overriding a badly-named base isn't a new violation.
+  void BadBaseMethod() override {}
+  // CHECK-FIXES: {{^}}  void v_Bad_Base_Method() override {}
+};
+
+template class CTIOverriding;
+
+void VirtualCallI(ATIOverridden& a_vItem, CTIOverriding& a_vCitem) {
   a_vItem.BadBaseMethod();
   // CHECK-FIXES: {{^}}  a_vItem.v_Bad_Base_Method();
+
+  a_vCitem.BadBaseMethod();
+  // CHECK-FIXES: {{^}}  a_vCitem.v_Bad_Base_Method();
 }
 
 template 
Index: clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
@@ -1257,7 +1257,7 @@
 
   if (const auto *Decl = dyn_cast(D)) {
 if (Decl->isMain() || !Decl

[PATCH] D114197: [clang-tidy] Fix false positives involving type aliases in `misc-unconventional-assign-operator` check

2021-11-18 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: aaron.ballman, alexfh, whisperity, mizvekov.
fwolff added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, jeroen.dobbelaere, rnkovacs, xazax.hun.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

clang-tidy currently reports false positives even for simple cases such as:

  struct S {
  using X = S;
  X &operator=(const X&) { return *this; }
  };

This is due to the fact that the `misc-unconventional-assign-operator` check 
fails to look at the //canonical// types. This patch fixes this behavior.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D114197

Files:
  clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp
@@ -127,3 +127,26 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: operator=() should always 
return '*this'
   }
 };
+
+// Check that no false positives are issued when using type aliases
+struct TypeAlias {
+  using Alias = TypeAlias;
+  // This is correct and should not produce any warnings:
+  Alias &operator=(const Alias &) { return *this; }
+
+  using AliasRef = Alias &;
+  // So is this:
+  AliasRef operator=(int) { return *this; }
+};
+
+// Same check as above for a template class
+template 
+struct TemplateTypeAlias {
+  using Alias1 = TemplateTypeAlias &;
+  using Alias2 = TemplateTypeAlias const &;
+  Alias1 operator=(Alias2) { return *this; }
+
+  template 
+  using Alias3 = TemplateTypeAlias;
+  Alias3 &operator=(int) { return *this; }
+};
Index: clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp
@@ -18,13 +18,14 @@
 
 void UnconventionalAssignOperatorCheck::registerMatchers(
 ast_matchers::MatchFinder *Finder) {
-  const auto HasGoodReturnType = cxxMethodDecl(returns(lValueReferenceType(
-  pointee(unless(isConstQualified()),
-  anyOf(autoType(), hasDeclaration(equalsBoundNode("class")));
+  const auto HasGoodReturnType =
+  cxxMethodDecl(returns(hasCanonicalType(lValueReferenceType(pointee(
+  unless(isConstQualified()),
+  anyOf(autoType(), hasDeclaration(equalsBoundNode("class";
 
-  const auto IsSelf = qualType(
+  const auto IsSelf = qualType(hasCanonicalType(
   anyOf(hasDeclaration(equalsBoundNode("class")),
-referenceType(pointee(hasDeclaration(equalsBoundNode("class"));
+
referenceType(pointee(hasDeclaration(equalsBoundNode("class")));
   const auto IsAssign =
   cxxMethodDecl(unless(anyOf(isDeleted(), isPrivate(), isImplicit())),
 hasName("operator="), ofClass(recordDecl().bind("class")))
@@ -37,9 +38,9 @@
   cxxMethodDecl(IsAssign, unless(HasGoodReturnType)).bind("ReturnType"),
   this);
 
-  const auto BadSelf = referenceType(
+  const auto BadSelf = qualType(hasCanonicalType(referenceType(
   anyOf(lValueReferenceType(pointee(unless(isConstQualified(,
-rValueReferenceType(pointee(isConstQualified();
+rValueReferenceType(pointee(isConstQualified()));
 
   Finder->addMatcher(
   cxxMethodDecl(IsSelfAssign,


Index: clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp
@@ -127,3 +127,26 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: operator=() should always return '*this'
   }
 };
+
+// Check that no false positives are issued when using type aliases
+struct TypeAlias {
+  using Alias = TypeAlias;
+  // This is correct and should not produce any warnings:
+  Alias &operator=(const Alias &) { return *this; }
+
+  using AliasRef = Alias &;
+  // So is this:
+  AliasRef operator=(int) { return *this; }
+};
+
+// Same check as above for a template class
+template 
+struct TemplateTypeAlias {
+  using Alias1 = TemplateTypeAlias &;
+  using Alias2 = TemplateTypeAlias const &;
+  Alias1 operator=(Alias2) { return *this; }
+
+  template 
+  using Alias3 = TemplateTypeAlias;
+  Alias3 &operator=(int) { return *this; }
+};
Index: clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp
=

[PATCH] D114197: [clang-tidy] Fix false positives involving type aliases in `misc-unconventional-assign-operator` check

2021-11-18 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff added a comment.

Thanks for the quick review! Can you also commit it for me? You can use name 
and email as in commit `738e7f1231949ec248c1d8d154783338215613d1`. Thank you!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D114197

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


[PATCH] D114292: [clang-tidy] Fix `altera-struct-pack-align` check for empty structs

2021-11-19 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: alexfh, whisperity, hokein.
fwolff added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, rnkovacs, xazax.hun.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

Fixes PR#51620 .


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D114292

Files:
  clang-tools-extra/clang-tidy/altera/StructPackAlignCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp
@@ -99,3 +99,22 @@
   struct bad_align3 instantiated { 'a', 0.001, 'b' };
 }
 
+// Make sure that we don't recommend aligning an empty struct to zero bytes 
(PR#51620)
+struct StructWithNoFields {};
+
+struct ContainsStructWithNoFields {
+  StructWithNoFields s;
+};
+
+// Make sure that an empty struct is treated like "char" for padding and 
alignment purposes
+struct ContainsStructWithNoFields2 {
+  StructWithNoFields s;
+  double d;
+  StructWithNoFields t;
+};
+// CHECK-MESSAGES: :[[@LINE-5]]:8: warning: accessing fields in struct 
'ContainsStructWithNoFields2' is inefficient due to padding; only needs 10 
bytes but is using 24 bytes [altera-struct-pack-align]
+// CHECK-MESSAGES: :[[@LINE-6]]:8: note: use "__attribute__((packed))" to 
reduce the amount of padding applied to struct 'ContainsStructWithNoFields2'
+// CHECK-MESSAGES: :[[@LINE-7]]:8: warning: accessing fields in struct 
'ContainsStructWithNoFields2' is inefficient due to poor alignment; currently 
aligned to 8 bytes, but recommended alignment is 16 bytes 
[altera-struct-pack-align]
+// CHECK-MESSAGES: :[[@LINE-8]]:8: note: use "__attribute__((aligned(16)))" to 
align struct 'ContainsStructWithNoFields2' to 16 bytes
+// CHECK-FIXES: __attribute__((packed))
+// CHECK-FIXES: __attribute__((aligned(16)));
Index: clang-tools-extra/clang-tidy/altera/StructPackAlignCheck.cpp
===
--- clang-tools-extra/clang-tidy/altera/StructPackAlignCheck.cpp
+++ clang-tools-extra/clang-tidy/altera/StructPackAlignCheck.cpp
@@ -73,7 +73,8 @@
   uint64_t CharSize = Result.Context->getCharWidth();
   CharUnits CurrSize = Result.Context->getASTRecordLayout(Struct).getSize();
   CharUnits MinByteSize =
-  CharUnits::fromQuantity(ceil((float)TotalBitSize / CharSize));
+  CharUnits::fromQuantity(std::max(
+  ceil((float)TotalBitSize / CharSize), 1));
   CharUnits MaxAlign = CharUnits::fromQuantity(
   ceil((float)Struct->getMaxAlignment() / CharSize));
   CharUnits CurrAlign =


Index: clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp
@@ -99,3 +99,22 @@
   struct bad_align3 instantiated { 'a', 0.001, 'b' };
 }
 
+// Make sure that we don't recommend aligning an empty struct to zero bytes (PR#51620)
+struct StructWithNoFields {};
+
+struct ContainsStructWithNoFields {
+  StructWithNoFields s;
+};
+
+// Make sure that an empty struct is treated like "char" for padding and alignment purposes
+struct ContainsStructWithNoFields2 {
+  StructWithNoFields s;
+  double d;
+  StructWithNoFields t;
+};
+// CHECK-MESSAGES: :[[@LINE-5]]:8: warning: accessing fields in struct 'ContainsStructWithNoFields2' is inefficient due to padding; only needs 10 bytes but is using 24 bytes [altera-struct-pack-align]
+// CHECK-MESSAGES: :[[@LINE-6]]:8: note: use "__attribute__((packed))" to reduce the amount of padding applied to struct 'ContainsStructWithNoFields2'
+// CHECK-MESSAGES: :[[@LINE-7]]:8: warning: accessing fields in struct 'ContainsStructWithNoFields2' is inefficient due to poor alignment; currently aligned to 8 bytes, but recommended alignment is 16 bytes [altera-struct-pack-align]
+// CHECK-MESSAGES: :[[@LINE-8]]:8: note: use "__attribute__((aligned(16)))" to align struct 'ContainsStructWithNoFields2' to 16 bytes
+// CHECK-FIXES: __attribute__((packed))
+// CHECK-FIXES: __attribute__((aligned(16)));
Index: clang-tools-extra/clang-tidy/altera/StructPackAlignCheck.cpp
===
--- clang-tools-extra/clang-tidy/altera/StructPackAlignCheck.cpp
+++ clang-tools-extra/clang-tidy/altera/StructPackAlignCheck.cpp
@@ -73,7 +73,8 @@
   uint64_t CharSize = Result.Context->getCharWidth();
   CharUnits CurrSize = Result.Context->getASTRecordLayout(Struct).getSize();
   CharUnits MinByteSize =
-  CharUnits::fromQuantity(ceil((float)TotalBitSize / CharSize));
+  CharUnits::fromQua

[PATCH] D114299: [clang-tidy] Fix `readability-redundant-declaration` false positive for template friend declaration

2021-11-19 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: Eugene.Zelenko, alexfh, Szelethus.
fwolff added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, xazax.hun.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

Fixes PR#48086 . The problem is 
that the current matcher uses `hasParent()` to detect friend declarations, but 
for a template friend declaration, the immediate parent of the `FunctionDecl` 
is a `FunctionTemplateDecl`, not the `FriendDecl`. Therefore, I have replaced 
the matcher with `hasAncestor()`.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D114299

Files:
  clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
@@ -66,8 +66,14 @@
 struct Friendly {
   friend void best_friend();
   friend void enemy();
+
+  template 
+  friend void generic_friend();
 };
 
+template 
+void generic_friend() {}
+
 void enemy();
 
 namespace macros {
Index: clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
@@ -37,7 +37,7 @@
   functionDecl(unless(anyOf(
   isDefinition(), isDefaulted(),
   doesDeclarationForceExternallyVisibleDefinition(),
-  hasParent(friendDecl()))
+  hasAncestor(friendDecl()))
   .bind("Decl"),
   this);
 }


Index: clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
@@ -66,8 +66,14 @@
 struct Friendly {
   friend void best_friend();
   friend void enemy();
+
+  template 
+  friend void generic_friend();
 };
 
+template 
+void generic_friend() {}
+
 void enemy();
 
 namespace macros {
Index: clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
@@ -37,7 +37,7 @@
   functionDecl(unless(anyOf(
   isDefinition(), isDefaulted(),
   doesDeclarationForceExternallyVisibleDefinition(),
-  hasParent(friendDecl()))
+  hasAncestor(friendDecl()))
   .bind("Decl"),
   this);
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D113828: [clang-tidy] Fix false positives in `fuchsia-trailing-return` check involving deduction guides

2021-12-01 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 391102.
fwolff added a comment.

In D113828#3164016 , @aaron.ballman 
wrote:

> LGTM! Can you add a release note about the bug fix?

Done. Thank you for the review! Can you also commit it for me? You can use name 
and email as in `6259016361345e09f0607ef4e037e00bcbe4bd40`. Thanks!


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

https://reviews.llvm.org/D113828

Files:
  clang-tools-extra/clang-tidy/fuchsia/TrailingReturnCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/test/clang-tidy/checkers/fuchsia-trailing-return.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/fuchsia-trailing-return.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/fuchsia-trailing-return.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/fuchsia-trailing-return.cpp
@@ -1,9 +1,9 @@
-// RUN: %check_clang_tidy %s fuchsia-trailing-return %t
+// RUN: %check_clang_tidy -std=c++17-or-later %s fuchsia-trailing-return %t
 
 int add_one(const int arg) { return arg; }
 
 auto get_add_one() -> int (*)(const int) {
-  // CHECK-MESSAGES: [[@LINE-1]]:1: warning: a trailing return type is 
disallowed for this type of declaration
+  // CHECK-MESSAGES: [[@LINE-1]]:1: warning: a trailing return type is 
disallowed for this function declaration
   // CHECK-NEXT: auto get_add_one() -> int (*)(const int) {
   return add_one;
 }
@@ -21,3 +21,31 @@
 auto fn(const T1 &lhs, const T2 &rhs) -> decltype(lhs + rhs) {
   return lhs + rhs;
 }
+
+// Now check that implicit and explicit C++17 deduction guides don't trigger 
this warning (PR#47614).
+
+template 
+struct ImplicitDeductionGuides {
+  ImplicitDeductionGuides(const T &);
+};
+
+template 
+struct pair {
+  A first;
+  B second;
+};
+
+template 
+struct UserDefinedDeductionGuides {
+  UserDefinedDeductionGuides(T);
+  template 
+  UserDefinedDeductionGuides(T1, T2);
+};
+
+template 
+UserDefinedDeductionGuides(T1, T2) -> UserDefinedDeductionGuides>;
+
+void foo() {
+  ImplicitDeductionGuides X(42);
+  UserDefinedDeductionGuides s(1, "abc");
+}
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -140,6 +140,9 @@
   ` to diagnose and fix 
functional
   casts, to achieve feature parity with the corresponding ``cpplint.py`` check.
 
+- Fixed a false positive in :doc:`fuchsia-trailing-return
+  ` for C++17 deduction guides.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/fuchsia/TrailingReturnCheck.cpp
===
--- clang-tools-extra/clang-tidy/fuchsia/TrailingReturnCheck.cpp
+++ clang-tools-extra/clang-tidy/fuchsia/TrailingReturnCheck.cpp
@@ -17,12 +17,6 @@
 namespace tidy {
 namespace fuchsia {
 
-namespace {
-AST_MATCHER(FunctionDecl, hasTrailingReturn) {
-  return Node.getType()->castAs()->hasTrailingReturn();
-}
-} // namespace
-
 void TrailingReturnCheck::registerMatchers(MatchFinder *Finder) {
   // Functions that have trailing returns are disallowed, except for those
   // using decltype specifiers and lambda with otherwise unutterable
@@ -30,15 +24,16 @@
   Finder->addMatcher(
   functionDecl(hasTrailingReturn(),
unless(anyOf(returns(decltypeType()),
-hasParent(cxxRecordDecl(isLambda())
+hasParent(cxxRecordDecl(isLambda())),
+cxxDeductionGuideDecl(
   .bind("decl"),
   this);
 }
 
 void TrailingReturnCheck::check(const MatchFinder::MatchResult &Result) {
-  if (const auto *D = Result.Nodes.getNodeAs("decl"))
+  if (const auto *D = Result.Nodes.getNodeAs("decl"))
 diag(D->getBeginLoc(),
- "a trailing return type is disallowed for this type of declaration");
+ "a trailing return type is disallowed for this function declaration");
 }
 
 } // namespace fuchsia


Index: clang-tools-extra/test/clang-tidy/checkers/fuchsia-trailing-return.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/fuchsia-trailing-return.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/fuchsia-trailing-return.cpp
@@ -1,9 +1,9 @@
-// RUN: %check_clang_tidy %s fuchsia-trailing-return %t
+// RUN: %check_clang_tidy -std=c++17-or-later %s fuchsia-trailing-return %t
 
 int add_one(const int arg) { return arg; }
 
 auto get_add_one() -> int (*)(const int) {
-  // CHECK-MESSAGES: [[@LINE-1]]:1: warning: a trailing return type is disallowed for this type of declaration
+  // CHECK-MESSAGES: [[@LINE-1]]:1: warning: a trailing return type is disallowed for this function declaration
   // CHECK-NEXT: auto get_add_one() -> int (*)(const int) {
   return add_one;
 }
@@ -21,3 +21,31 @@
 auto fn(cons

[PATCH] D114299: [clang-tidy] Fix `readability-redundant-declaration` false positive for template friend declaration

2021-12-01 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 391163.

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

https://reviews.llvm.org/D114299

Files:
  clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
@@ -70,6 +70,32 @@
 
 void enemy();
 
+template 
+struct TemplateFriendly {
+  template 
+  friend void generic_friend();
+};
+
+template 
+void generic_friend() {}
+
+TemplateFriendly template_friendly;
+
+template 
+struct TemplateFriendly2 {
+  template 
+  friend void generic_friend2() {}
+};
+
+template 
+void generic_friend2();
+
+void generic_friend_caller() {
+  TemplateFriendly2 f;
+  generic_friend2();
+}
+
+
 namespace macros {
 #define DECLARE(x) extern int x
 #define DEFINE(x) extern int x; int x = 42
Index: clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
@@ -37,7 +37,7 @@
   functionDecl(unless(anyOf(
   isDefinition(), isDefaulted(),
   doesDeclarationForceExternallyVisibleDefinition(),
-  hasParent(friendDecl()))
+  hasAncestor(friendDecl()))
   .bind("Decl"),
   this);
 }


Index: clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
@@ -70,6 +70,32 @@
 
 void enemy();
 
+template 
+struct TemplateFriendly {
+  template 
+  friend void generic_friend();
+};
+
+template 
+void generic_friend() {}
+
+TemplateFriendly template_friendly;
+
+template 
+struct TemplateFriendly2 {
+  template 
+  friend void generic_friend2() {}
+};
+
+template 
+void generic_friend2();
+
+void generic_friend_caller() {
+  TemplateFriendly2 f;
+  generic_friend2();
+}
+
+
 namespace macros {
 #define DECLARE(x) extern int x
 #define DEFINE(x) extern int x; int x = 42
Index: clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
@@ -37,7 +37,7 @@
   functionDecl(unless(anyOf(
   isDefinition(), isDefaulted(),
   doesDeclarationForceExternallyVisibleDefinition(),
-  hasParent(friendDecl()))
+  hasAncestor(friendDecl()))
   .bind("Decl"),
   this);
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D114299: [clang-tidy] Fix `readability-redundant-declaration` false positive for template friend declaration

2021-12-01 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff added a comment.

In D114299#3164127 , @aaron.ballman 
wrote:

> Hmm, the test case you added passes without the patch applied: 
> https://godbolt.org/z/T9TerMYGz

You are right; I have fixed the test now, and I've also added your other 
example as a second test.


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

https://reviews.llvm.org/D114299

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


[PATCH] D113429: [clang-tidy] Use `hasCanonicalType()` matcher in `bugprone-unused-raii` check

2021-12-01 Thread Fabian Wolff via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG987a21522f2c: [clang-tidy] Use `hasCanonicalType()` matcher 
in `bugprone-unused-raii` check (authored by fwolff).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D113429

Files:
  clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/bugprone-unused-raii.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-unused-raii.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-unused-raii.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-unused-raii.cpp
@@ -82,6 +82,28 @@
   (void)i;
 }
 
+template 
+void aliastest() {
+  using X = Foo;
+  using Y = X;
+  using Z = Y;
+  Z(42);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately 
after creation; did you mean to name the object?
+  // CHECK-FIXES: Z give_me_a_name(42);
+
+  typedef Z ZT;
+  ZT(42, 13);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately 
after creation; did you mean to name the object?
+  // CHECK-FIXES: ZT give_me_a_name(42, 13);
+
+  using TT = TCtorDefaultArg;
+  TT(42);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately 
after creation; did you mean to name the object?
+  // CHECK-FIXES: TT give_me_a_name(42);
+
+  (void)0;
+}
+
 void test() {
   Foo(42);
 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after 
creation; did you mean to name the object?
Index: clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp
@@ -29,10 +29,11 @@
   Finder->addMatcher(
   mapAnyOf(cxxConstructExpr, cxxUnresolvedConstructExpr)
   .with(hasParent(compoundStmt().bind("compound")),
-anyOf(hasType(cxxRecordDecl(hasNonTrivialDestructor())),
-  hasType(templateSpecializationType(
+anyOf(hasType(hasCanonicalType(recordType(hasDeclaration(
+  cxxRecordDecl(hasNonTrivialDestructor()),
+  hasType(hasCanonicalType(templateSpecializationType(
   hasDeclaration(classTemplateDecl(has(
-  cxxRecordDecl(hasNonTrivialDestructor()
+  cxxRecordDecl(hasNonTrivialDestructor())
   .bind("expr"),
   this);
 }


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-unused-raii.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-unused-raii.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-unused-raii.cpp
@@ -82,6 +82,28 @@
   (void)i;
 }
 
+template 
+void aliastest() {
+  using X = Foo;
+  using Y = X;
+  using Z = Y;
+  Z(42);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
+  // CHECK-FIXES: Z give_me_a_name(42);
+
+  typedef Z ZT;
+  ZT(42, 13);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
+  // CHECK-FIXES: ZT give_me_a_name(42, 13);
+
+  using TT = TCtorDefaultArg;
+  TT(42);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
+  // CHECK-FIXES: TT give_me_a_name(42);
+
+  (void)0;
+}
+
 void test() {
   Foo(42);
 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
Index: clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp
@@ -29,10 +29,11 @@
   Finder->addMatcher(
   mapAnyOf(cxxConstructExpr, cxxUnresolvedConstructExpr)
   .with(hasParent(compoundStmt().bind("compound")),
-anyOf(hasType(cxxRecordDecl(hasNonTrivialDestructor())),
-  hasType(templateSpecializationType(
+anyOf(hasType(hasCanonicalType(recordType(hasDeclaration(
+  cxxRecordDecl(hasNonTrivialDestructor()),
+  hasType(hasCanonicalType(templateSpecializationType(
   hasDeclaration(classTemplateDecl(has(
-  cxxRecordDecl(hasNonTrivialDestructor()
+  cxxRecordDecl(hasNonTrivialDestructor())
   .bind("expr"),
   this);
 }
___
cfe-commits mailing list
cfe-comm

[PATCH] D113518: [clang][Sema] Create delegating constructors even in templates

2021-12-04 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff marked 2 inline comments as done.
fwolff added inline comments.



Comment at: clang/lib/Sema/SemaDeclCXX.cpp:4524-4525
   if (!Dependent) {
-if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0),
-   BaseType))
+if (Delegating)
   return BuildDelegatingInitializer(BaseTInfo, Init, ClassDecl);
 

aaron.ballman wrote:
> Looking at the source for `BuildDelegatingInitializer()`, it looks like we 
> should still be able to call this in a dependent context. In fact, it has a 
> fixme comment specifically about that:
> ```
> // If we are in a dependent context, template instantiation will
> // perform this type-checking again. Just save the arguments that we
> // received in a ParenListExpr.
> // FIXME: This isn't quite ideal, since our ASTs don't capture all
> // of the information that we have about the base
> // initializer. However, deconstructing the ASTs is a dicey process,
> // and this approach is far more likely to get the corner cases right.
> ```
> I'm wondering if the better fix here is to hoist the delegation check out of 
> the `if (!Dependent)`. Did you try that and run into issues?
Yes, I have tried this, and it leads to a crash [[ 
https://github.com/llvm/llvm-project/blob/ca2f53897a2f2a60d8cb1538d5fcf930d814e9f5/clang/lib/Sema/SemaDeclCXX.cpp#L
 | here ]] (because the cast fails). Apparently, this code path in 
`BuildDelegatingInitializer()` is never exercised for dependent contexts, 
despite the comment, and therefore doesn't work.



Comment at: clang/lib/Sema/SemaDeclCXX.cpp:5071
 
-  if (CXXDestructorDecl *Dtor = LookupDestructor(Constructor->getParent())) {
-MarkFunctionReferenced(Initializer->getSourceLocation(), Dtor);
-DiagnoseUseOfDecl(Dtor, Initializer->getSourceLocation());
-  }
+  if (!Constructor->isDependentContext()) {
+if (CXXDestructorDecl *Dtor = LookupDestructor(Constructor->getParent())) {

aaron.ballman wrote:
> Can you explain why this change was needed?
Without this, clang crashes because `LookupDestructor()` calls 
`LookupSpecialMember()`, which then runs into [[ 
https://github.com/llvm/llvm-project/blob/ca2f53897a2f2a60d8cb1538d5fcf930d814e9f5/clang/lib/Sema/SemaLookup.cpp#L3064-L3065
 | this assertion ]]:
```
clang-14: /[...]/llvm-project/clang/lib/Sema/SemaLookup.cpp:3064: 
clang::Sema::SpecialMemberOverloadResult 
clang::Sema::LookupSpecialMember(clang::CXXRecordDecl*, 
clang::Sema::CXXSpecialMember, bool, bool, bool, bool, bool): Assertion 
`CanDeclareSpecialMemberFunction(RD) && "doing special member lookup into 
record that isn't fully complete"' failed.
```
Previously, this wasn't necessary because no delegating constructors would be 
generated for templates, and so this function wasn't ever called in a dependent 
context.


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

https://reviews.llvm.org/D113518

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


[PATCH] D114197: [clang-tidy] Fix false positives involving type aliases in `misc-unconventional-assign-operator` check

2021-12-04 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 391850.

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

https://reviews.llvm.org/D114197

Files:
  clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp
  
clang-tools-extra/docs/clang-tidy/checks/misc-unconventional-assign-operator.rst
  
clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp
@@ -127,3 +127,30 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: operator=() should always 
return '*this'
   }
 };
+
+// Check that no false positives are issued when using type aliases
+struct TypeAlias {
+  using Alias = TypeAlias;
+  // This is correct and should not produce any warnings:
+  Alias &operator=(const Alias &) { return *this; }
+
+  using AliasRef = Alias &;
+  // So is this (assignments from other types are fine):
+  AliasRef operator=(int) { return *this; }
+};
+
+// Same check as above for a template class
+template 
+struct TemplateTypeAlias {
+  using Alias1 = TemplateTypeAlias &;
+  using Alias2 = TemplateTypeAlias const &;
+  Alias1 operator=(Alias2) { return *this; }
+
+  template 
+  using Alias3 = TemplateTypeAlias;
+  Alias3 &operator=(int) { return *this; }
+
+  // Using a different type parameter in the return type should give a warning
+  Alias3& operator=(double) { return *this; }
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 
'TemplateTypeAlias&' [misc-unconventional-assign-operator]
+};
Index: 
clang-tools-extra/docs/clang-tidy/checks/misc-unconventional-assign-operator.rst
===
--- 
clang-tools-extra/docs/clang-tidy/checks/misc-unconventional-assign-operator.rst
+++ 
clang-tools-extra/docs/clang-tidy/checks/misc-unconventional-assign-operator.rst
@@ -8,6 +8,8 @@
 types and definitions with good return type but wrong ``return`` statements.
 
   * The return type must be ``Class&``.
-  * Works with move-assign and assign by value.
+  * The assignment may be from the class type by value, const lvalue
+reference, or non-const rvalue reference, or from a completely different
+type (e.g. ``int``).
   * Private and deleted operators are ignored.
   * The operator must always return ``*this``.
Index: clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp
@@ -18,13 +18,14 @@
 
 void UnconventionalAssignOperatorCheck::registerMatchers(
 ast_matchers::MatchFinder *Finder) {
-  const auto HasGoodReturnType = cxxMethodDecl(returns(lValueReferenceType(
-  pointee(unless(isConstQualified()),
-  anyOf(autoType(), hasDeclaration(equalsBoundNode("class")));
+  const auto HasGoodReturnType =
+  cxxMethodDecl(returns(hasCanonicalType(lValueReferenceType(pointee(
+  unless(isConstQualified()),
+  anyOf(autoType(), hasDeclaration(equalsBoundNode("class";
 
-  const auto IsSelf = qualType(
+  const auto IsSelf = qualType(hasCanonicalType(
   anyOf(hasDeclaration(equalsBoundNode("class")),
-referenceType(pointee(hasDeclaration(equalsBoundNode("class"));
+
referenceType(pointee(hasDeclaration(equalsBoundNode("class")));
   const auto IsAssign =
   cxxMethodDecl(unless(anyOf(isDeleted(), isPrivate(), isImplicit())),
 hasName("operator="), ofClass(recordDecl().bind("class")))
@@ -37,9 +38,9 @@
   cxxMethodDecl(IsAssign, unless(HasGoodReturnType)).bind("ReturnType"),
   this);
 
-  const auto BadSelf = referenceType(
+  const auto BadSelf = qualType(hasCanonicalType(referenceType(
   anyOf(lValueReferenceType(pointee(unless(isConstQualified(,
-rValueReferenceType(pointee(isConstQualified();
+rValueReferenceType(pointee(isConstQualified()));
 
   Finder->addMatcher(
   cxxMethodDecl(IsSelfAssign,


Index: clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp
@@ -127,3 +127,30 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: operator=() should always return '*this'
   }
 };
+
+// Check that no false positives are issued when using type aliases
+struct TypeAlias {
+  using Alias = TypeAlias;
+  // This is correct and s

[PATCH] D114197: [clang-tidy] Fix false positives involving type aliases in `misc-unconventional-assign-operator` check

2021-12-04 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff marked 2 inline comments as done.
fwolff added a comment.

Thanks for your comments @whisperity. I think I've addressed them, could you 
have another look?




Comment at: 
clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp:151
+  using Alias3 = TemplateTypeAlias;
+  Alias3 &operator=(int) { return *this; }
+};

whisperity wrote:
> This is a no-warn due to the parameter being a completely unrelated type, 
> right? Might worth a comment. I don't see at first glance why a warning 
> should not happen here.
Exactly. I've added a comment in the `TypeAlias` struct above, because that one 
comes first. I've also updated the documentation for this check to make this 
clearer.



Comment at: 
clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp:152
+  Alias3 &operator=(int) { return *this; }
+};

whisperity wrote:
> What about `Alias3& operator =(const Alias1&) { return 
> *this; }`? That should trigger a warning as it is an unrelated type, right?
Yes, I've added a test for this (but with `double` as the argument type, 
because `const Alias1&` gives a warning:
```
warning: 'const' qualifier on reference type 'TemplateTypeAlias::Alias1' (aka 
'TemplateTypeAlias &') has no effect [-Wignored-qualifiers]
```


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

https://reviews.llvm.org/D114197

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


[PATCH] D113804: [clang-tidy] Fix behavior of `modernize-use-using` with nested structs/unions

2021-12-04 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 391852.
fwolff added a comment.

Thanks for your comments @whisperity! They should all be fixed now.


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

https://reviews.llvm.org/D113804

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

Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp
@@ -302,3 +302,15 @@
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
   // CHECK-FIXES: using b = InjectedClassNameWithUnnamedArgument;
 };
+
+typedef struct { int a; union { int b; }; } PR50990;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using PR50990 = struct { int a; union { int b; }; };
+
+typedef struct { struct { int a; struct { struct { int b; } c; int d; } e; } f; int g; } PR50990_nested;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using PR50990_nested = struct { struct { int a; struct { struct { int b; } c; int d; } e; } f; int g; };
+
+typedef struct { struct { int a; } b; union { int c; float d; struct { int e; }; }; struct { double f; } g; } PR50990_siblings;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using PR50990_siblings = struct { struct { int a; } b; union { int c; float d; struct { int e; }; }; struct { double f; } g; };
Index: clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
===
--- clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
+++ clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
@@ -23,7 +23,8 @@
 
   const bool IgnoreMacros;
   SourceLocation LastReplacementEnd;
-  SourceRange LastTagDeclRange;
+  llvm::DenseMap LastTagDeclRanges;
+
   std::string FirstTypedefType;
   std::string FirstTypedefName;
 
Index: clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
===
--- clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
@@ -16,6 +16,10 @@
 namespace tidy {
 namespace modernize {
 
+static constexpr llvm::StringLiteral ParentDeclName = "parent-decl";
+static constexpr llvm::StringLiteral TagDeclName = "tag-decl";
+static constexpr llvm::StringLiteral TypedefName = "typedef";
+
 UseUsingCheck::UseUsingCheck(StringRef Name, ClangTidyContext *Context)
 : ClangTidyCheck(Name, Context),
   IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)) {}
@@ -25,23 +29,45 @@
 }
 
 void UseUsingCheck::registerMatchers(MatchFinder *Finder) {
-  Finder->addMatcher(typedefDecl(unless(isInstantiated())).bind("typedef"),
+  Finder->addMatcher(typedefDecl(unless(isInstantiated()),
+ hasParent(decl().bind(ParentDeclName)))
+ .bind(TypedefName),
  this);
-  // This matcher used to find tag declarations in source code within typedefs.
-  // They appear in the AST just *prior* to the typedefs.
-  Finder->addMatcher(tagDecl(unless(isImplicit())).bind("tagdecl"), this);
+
+  // This matcher is used to find tag declarations in source code within
+  // typedefs. They appear in the AST just *prior* to the typedefs.
+  Finder->addMatcher(
+  tagDecl(
+  anyOf(allOf(unless(anyOf(isImplicit(),
+   classTemplateSpecializationDecl())),
+  hasParent(decl().bind(ParentDeclName))),
+// We want the parent of the ClassTemplateDecl, not the parent
+// of the specialization.
+classTemplateSpecializationDecl(hasAncestor(
+classTemplateDecl(hasParent(decl().bind(ParentDeclName)))
+  .bind(TagDeclName),
+  this);
 }
 
 void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *ParentDecl = Result.Nodes.getNodeAs(ParentDeclName);
+  if (!ParentDecl)
+return;
+
   // Match CXXRecordDecl only to store the range of the last non-implicit full
   // declaration, to later check whether it's within the typdef itself.
-  const auto *MatchedTagDecl = Result.Nodes.getNodeAs("tagdecl");
+  const auto *MatchedTagDecl = Result.Nodes.getNodeAs(TagDeclName);
   if (MatchedTagDecl) {
-LastTagDeclRange = MatchedTagDecl->getSourceRange();
+// It is not sufficient to just track the last TagDecl that we've seen,
+// because if one struct or union is nested inside another, the last TagDecl
+// before the typedef will be the nested one (PR#50990). Therefore, we also
+// kee

[PATCH] D113863: [clang-tidy] Make `readability-container-data-pointer` more robust

2021-12-04 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 391869.
fwolff marked an inline comment as done.

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

https://reviews.llvm.org/D113863

Files:
  clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
@@ -109,3 +109,38 @@
   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
   // CHECK-FIXES: {{^  }}return v.data();{{$}}
 }
+
+template 
+struct container_without_data {
+  using size_type = size_t;
+  T &operator[](size_type);
+  const T &operator[](size_type) const;
+};
+
+template 
+const T *n(const container_without_data &c) {
+  // c has no "data" member function, so there should not be a warning here:
+  return &c[0];
+}
+
+const int *o(const std::vector>> &v, const size_t idx1, const size_t idx2) {
+  return &v[idx1][idx2][0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return v[idx1][idx2].data();{{$}}
+}
+
+std::vector &select(std::vector &u, std::vector &v) {
+  return v;
+}
+
+int *p(std::vector &v1, std::vector &v2) {
+  return &select(*&v1, v2)[0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return select(*&v1, v2).data();{{$}}
+}
+
+int *q(std::vector ***v) {
+  return &(***v)[0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return (**v)->data();{{$}}
+}
Index: clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
@@ -16,6 +16,12 @@
 namespace clang {
 namespace tidy {
 namespace readability {
+
+constexpr llvm::StringLiteral ContainerExprName = "container-expr";
+constexpr llvm::StringLiteral DerefContainerExprName = "deref-container-expr";
+constexpr llvm::StringLiteral AddrOfContainerExprName = "addr-of-container-expr";
+constexpr llvm::StringLiteral AddressOfName = "address-of";
+
 ContainerDataPointerCheck::ContainerDataPointerCheck(StringRef Name,
  ClangTidyContext *Context)
 : ClangTidyCheck(Name, Context) {}
@@ -38,69 +44,65 @@
   const auto Container =
   qualType(anyOf(NonTemplateContainerType, TemplateContainerType));
 
+  const auto ContainerExpr = anyOf(
+  unaryOperator(
+  hasOperatorName("*"),
+  hasUnaryOperand(
+  expr(hasType(pointsTo(Container))).bind(DerefContainerExprName)))
+  .bind(ContainerExprName),
+  unaryOperator(hasOperatorName("&"),
+hasUnaryOperand(expr(anyOf(hasType(Container),
+   hasType(references(Container
+.bind(AddrOfContainerExprName)))
+  .bind(ContainerExprName),
+  expr(anyOf(hasType(Container), hasType(pointsTo(Container)),
+ hasType(references(Container
+  .bind(ContainerExprName));
+
+  const auto Zero = integerLiteral(equals(0));
+
+  const auto SubscriptOperator = callee(cxxMethodDecl(hasName("operator[]")));
+
   Finder->addMatcher(
   unaryOperator(
   unless(isExpansionInSystemHeader()), hasOperatorName("&"),
-  hasUnaryOperand(anyOf(
-  ignoringParenImpCasts(
-  cxxOperatorCallExpr(
-  callee(cxxMethodDecl(hasName("operator[]"))
- .bind("operator[]")),
-  argumentCountIs(2),
-  hasArgument(
-  0,
-  anyOf(ignoringParenImpCasts(
-declRefExpr(
-to(varDecl(anyOf(
-hasType(Container),
-hasType(references(Container))
-.bind("var")),
-ignoringPare

[PATCH] D113863: [clang-tidy] Make `readability-container-data-pointer` more robust

2021-12-04 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff marked 3 inline comments as done.
fwolff added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp:76
+arraySubscriptExpr(hasLHS(ContainerExpr), hasRHS(Zero))
+  .bind(AddressOfName),
   this);

compnerd wrote:
> Nice, I do like this, it is quite a bit more succinct.  One thing that is a 
> bit less clear to me is that the previous expression was a bit more 
> restrictive in the parameter types to certain expressions, is there a reason 
> that you don't expect that to matter much in practice?  If a malformed input 
> is provided, we could now match certain things that we didn't previously, or 
> am I not matching up the conditions carefully enough?
I have indeed changed things slightly to make everything more consistent. For 
instance, calling `&vp->operator[](0)` currently does not yield a warning ([[ 
https://godbolt.org/z/M1hGvGdWr | Godbolt link ]]), but `&v.operator[](0)` 
does, because the old check allowed a pointer to a container for a 
`cxxOperatorCallExpr()` (line 62 on the left) but not for 
`cxxMemberCallExpr()`. I think this was simply an oversight because the check 
was written in such a redundant way; my version covers both.

So yes, I have made some checks a bit less restrictive, but I think that's an 
improvement. Or which cases were you thinking of exactly?



Comment at: 
clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp:99
+  Lexer::getSourceText(CharSourceRange::getTokenRange(SourceRange),
+   *Result.SourceManager, getLangOpts()));
+

compnerd wrote:
> The diff shows up odd here, is there a hard tab or is that just the rendering?
I think this is Phabricator's way of saying that the only thing that was 
changed in this line is the indentation. I haven't used any tabs.


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

https://reviews.llvm.org/D113863

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


[PATCH] D113863: [clang-tidy] Make `readability-container-data-pointer` more robust

2021-12-04 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 391871.

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

https://reviews.llvm.org/D113863

Files:
  clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
@@ -109,3 +109,38 @@
   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
   // CHECK-FIXES: {{^  }}return v.data();{{$}}
 }
+
+template 
+struct container_without_data {
+  using size_type = size_t;
+  T &operator[](size_type);
+  const T &operator[](size_type) const;
+};
+
+template 
+const T *n(const container_without_data &c) {
+  // c has no "data" member function, so there should not be a warning here:
+  return &c[0];
+}
+
+const int *o(const std::vector>> &v, const size_t idx1, const size_t idx2) {
+  return &v[idx1][idx2][0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return v[idx1][idx2].data();{{$}}
+}
+
+std::vector &select(std::vector &u, std::vector &v) {
+  return v;
+}
+
+int *p(std::vector &v1, std::vector &v2) {
+  return &select(*&v1, v2)[0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return select(*&v1, v2).data();{{$}}
+}
+
+int *q(std::vector ***v) {
+  return &(***v)[0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return (**v)->data();{{$}}
+}
Index: clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
@@ -16,6 +16,13 @@
 namespace clang {
 namespace tidy {
 namespace readability {
+
+constexpr llvm::StringLiteral ContainerExprName = "container-expr";
+constexpr llvm::StringLiteral DerefContainerExprName = "deref-container-expr";
+constexpr llvm::StringLiteral AddrOfContainerExprName =
+"addr-of-container-expr";
+constexpr llvm::StringLiteral AddressOfName = "address-of";
+
 ContainerDataPointerCheck::ContainerDataPointerCheck(StringRef Name,
  ClangTidyContext *Context)
 : ClangTidyCheck(Name, Context) {}
@@ -38,69 +45,65 @@
   const auto Container =
   qualType(anyOf(NonTemplateContainerType, TemplateContainerType));
 
+  const auto ContainerExpr = anyOf(
+  unaryOperator(
+  hasOperatorName("*"),
+  hasUnaryOperand(
+  expr(hasType(pointsTo(Container))).bind(DerefContainerExprName)))
+  .bind(ContainerExprName),
+  unaryOperator(hasOperatorName("&"),
+hasUnaryOperand(expr(anyOf(hasType(Container),
+   hasType(references(Container
+.bind(AddrOfContainerExprName)))
+  .bind(ContainerExprName),
+  expr(anyOf(hasType(Container), hasType(pointsTo(Container)),
+ hasType(references(Container
+  .bind(ContainerExprName));
+
+  const auto Zero = integerLiteral(equals(0));
+
+  const auto SubscriptOperator = callee(cxxMethodDecl(hasName("operator[]")));
+
   Finder->addMatcher(
   unaryOperator(
   unless(isExpansionInSystemHeader()), hasOperatorName("&"),
-  hasUnaryOperand(anyOf(
-  ignoringParenImpCasts(
-  cxxOperatorCallExpr(
-  callee(cxxMethodDecl(hasName("operator[]"))
- .bind("operator[]")),
-  argumentCountIs(2),
-  hasArgument(
-  0,
-  anyOf(ignoringParenImpCasts(
-declRefExpr(
-to(varDecl(anyOf(
-hasType(Container),
-hasType(references(Container))
-.bind("var")),
-ignoringParenImpCasts(hasDescendant(
-  

[PATCH] D115106: [clang-tidy] Fix `readability-static-accessed-through-instance` false negative for static methods

2021-12-04 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: aaron.ballman, simon.giesecke, jcking1034.
fwolff added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, xazax.hun.
fwolff requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Fixes PR#52519 . The problem 
actually has nothing to do with the out-of-line definition being `inline`; the 
problem is that `hasDeclaration()` of the `memberExpr()` will match the 
out-of-line definition, which obviously isn't marked `static`, so 
`isStaticStorageClass()` won't match. To find out whether a member function is 
`static`, one needs to look at the //canonical// declaration, but there doesn't 
seem to be a matcher for that yet, so I've added an `isStatic()` narrowing 
matcher for `CXXMethodDecl`s, similar to the `isConst()` matcher that already 
exists.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D115106

Files:
  
clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-static-accessed-through-instance.cpp
  clang/docs/LibASTMatchersReference.html
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/lib/ASTMatchers/Dynamic/Registry.cpp
  clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2017,6 +2017,17 @@
   notMatches("struct A { void foo(); };", cxxMethodDecl(isConst(;
 }
 
+TEST_P(ASTMatchersTest, IsStatic) {
+  if (!GetParam().isCXX()) {
+return;
+  }
+
+  EXPECT_TRUE(
+  matches("struct A { static void foo(); };", cxxMethodDecl(isStatic(;
+  EXPECT_TRUE(
+  notMatches("struct A { void foo(); };", cxxMethodDecl(isStatic(;
+}
+
 TEST_P(ASTMatchersTest, IsOverride) {
   if (!GetParam().isCXX()) {
 return;
Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -451,6 +451,7 @@
   REGISTER_MATCHER(isSharedKind);
   REGISTER_MATCHER(isSignedInteger);
   REGISTER_MATCHER(isStandaloneDirective);
+  REGISTER_MATCHER(isStatic);
   REGISTER_MATCHER(isStaticLocal);
   REGISTER_MATCHER(isStaticStorageClass);
   REGISTER_MATCHER(isStruct);
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -6003,6 +6003,19 @@
   return Node.isConst();
 }
 
+/// Matches if the given method declaration is static.
+///
+/// Given
+/// \code
+/// struct A {
+///   static void foo();
+///   void bar();
+/// };
+/// \endcode
+///
+/// cxxMethodDecl(isStatic()) matches A::foo() but not A::bar()
+AST_MATCHER(CXXMethodDecl, isStatic) { return Node.isStatic(); }
+
 /// Matches if the given method declaration declares a copy assignment
 /// operator.
 ///
Index: clang/docs/LibASTMatchersReference.html
===
--- clang/docs/LibASTMatchersReference.html
+++ clang/docs/LibASTMatchersReference.html
@@ -3322,6 +3322,19 @@
 
 
 
+MatcherCXXMethodDecl>isStatic
+Matches if the given method declaration is static.
+
+Given
+struct A {
+  static void foo();
+  void bar();
+};
+
+cxxMethodDecl(isStatic()) matches A::foo() but not A::bar()
+
+
+
 MatcherCXXMethodDecl>isCopyAssignmentOperator
 Matches if the given method declaration declares a copy assignment
 operator.
Index: clang-tools-extra/test/clang-tidy/checkers/readability-static-accessed-through-instance.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-static-accessed-through-instance.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-static-accessed-through-instance.cpp
@@ -263,3 +263,20 @@
 // CHECK-MESSAGES-NOT: :[[@LINE-1]]:10: warning: static member
 
 } // namespace Bugzilla_48758
+
+// https://bugs.llvm.org/show_bug.cgi?id=52519
+struct PR52519 {
+  static PR52519 &getInstance();
+  static int getInt();
+};
+
+int PR52519::getInt() {
+  return 42;
+}
+
+int PR52519_bar() {
+  auto &foo = PR52519::getInstance();
+  return foo.getInt();
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: static member accessed through instance [readability-static-accessed-through-instance]
+  // CHECK-FIXES: {{^}}  return PR52519::getInt();{{$}}
+}
Index: clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
==

[PATCH] D115118: [clang-tidy] Assume that `noexcept` functions won't throw anything in `bugprone-exception-escape` check

2021-12-05 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: aaron.ballman, JonasToth, lebedev.ri.
fwolff added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, xazax.hun.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

Fixes PR#52254 . The 
`ExceptionAnalyzer` currently recursively checks called functions, but this 
does not make sense if the called function is marked as `noexcept`. If it does 
throw, there should be a warning //for that function,// but not for every 
caller. In particular, this can lead to false positives if the called 
`noexcept` function calls other, potentially throwing, functions, in a way that 
ensures they will never actually throw.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D115118

Files:
  clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
  clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
@@ -288,6 +288,29 @@
   return recursion_helper(n);
 }
 
+// The following functions all incorrectly throw exceptions, *but* calling them
+// should not yield a warning because they are marked as noexcept (or similar).
+void est_dynamic_none() throw() { throw 42; }
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in 
function 'est_dynamic_none' which should not throw exceptions
+void est_basic_noexcept() noexcept { throw 42; }
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in 
function 'est_basic_noexcept' which should not throw exceptions
+void est_noexcept_true() noexcept(true) { throw 42; }
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in 
function 'est_noexcept_true' which should not throw exceptions
+template 
+void est_dependent_noexcept() noexcept(T::should_throw) { throw 42; }
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in 
function 'est_dependent_noexcept>' which should not throw 
exceptions
+template 
+struct ShouldThrow {
+  static const bool should_throw = B;
+};
+
+void only_calls_non_throwing() noexcept {
+  est_dynamic_none();
+  est_basic_noexcept();
+  est_noexcept_true();
+  est_dependent_noexcept>();
+}
+
 int main() {
   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in 
function 'main' which should not throw exceptions
   throw 1;
Index: clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
===
--- clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
+++ clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
@@ -192,8 +192,27 @@
 Results.merge(Uncaught);
   } else if (const auto *Call = dyn_cast(St)) {
 if (const FunctionDecl *Func = Call->getDirectCallee()) {
-  ExceptionInfo Excs = throwsException(Func, CallStack);
-  Results.merge(Excs);
+  bool MightThrow;
+
+  switch (Func->getExceptionSpecType()) {
+  case EST_DynamicNone:
+  case EST_NoThrow:
+  case EST_BasicNoexcept:
+  case EST_DependentNoexcept: // Let's be optimistic here (necessary e.g.
+  // for variant assignment; see PR#52254)
+  case EST_NoexceptTrue:
+MightThrow = false;
+break;
+
+  default:
+MightThrow = true;
+break;
+  }
+
+  if (MightThrow) {
+ExceptionInfo Excs = throwsException(Func, CallStack);
+Results.merge(Excs);
+  }
 }
   } else {
 for (const Stmt *Child : St->children()) {


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
@@ -288,6 +288,29 @@
   return recursion_helper(n);
 }
 
+// The following functions all incorrectly throw exceptions, *but* calling them
+// should not yield a warning because they are marked as noexcept (or similar).
+void est_dynamic_none() throw() { throw 42; }
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'est_dynamic_none' which should not throw exceptions
+void est_basic_noexcept() noexcept { throw 42; }
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'est_basic_noexcept' which should not throw exceptions
+void est_noexcept_true() noexcept(true) { throw 42; }
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'est_noexcept_true' which should not throw exceptions
+template 
+void est_dependent_noexcept() noexcept(T::should_throw) 

[PATCH] D115124: [clang-tidy] Fix `readability-container-size-empty` check for smart pointers

2021-12-05 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: mizvekov, compnerd.
fwolff added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, xazax.hun.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

Fixes PR#51776 . If the object on 
which `size()` is called has an overloaded `operator->`, the span for `E` will 
include the `->`, and since the return type of `operator->` is a pointer, 
`readability-container-size-empty` will try to add another arrow, leading to 
the nonsensical `vp->->empty()` suggestion. This patch fixes this behavior.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D115124

Files:
  clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp
@@ -696,3 +696,17 @@
   instantiatedTemplateWithSizeCall();
   instantiatedTemplateWithSizeCall>();
 }
+
+namespace std {
+template 
+struct unique_ptr {
+  T *operator->() const;
+};
+} // namespace std
+
+bool call_through_unique_ptr(const std::unique_ptr> &ptr) {
+  return ptr->size() > 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should be 
used
+  // CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here
+  // CHECK-FIXES: {{^  }}return !ptr->empty();
+}
Index: clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
@@ -194,7 +194,13 @@
   if (isBinaryOrTernary(E) || isa(E)) {
 ReplacementText = "(" + ReplacementText + ")";
   }
-  if (E->getType()->isPointerType())
+  const auto *OpCallExpr = dyn_cast(E);
+  if (OpCallExpr &&
+  OpCallExpr->getOperator() == OverloadedOperatorKind::OO_Arrow) {
+// This can happen if the object is a smart pointer. Don't add anything
+// because a '->' is already there (PR#51776), just call the method.
+ReplacementText += "empty()";
+  } else if (E->getType()->isPointerType())
 ReplacementText += "->empty()";
   else
 ReplacementText += ".empty()";


Index: clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp
@@ -696,3 +696,17 @@
   instantiatedTemplateWithSizeCall();
   instantiatedTemplateWithSizeCall>();
 }
+
+namespace std {
+template 
+struct unique_ptr {
+  T *operator->() const;
+};
+} // namespace std
+
+bool call_through_unique_ptr(const std::unique_ptr> &ptr) {
+  return ptr->size() > 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should be used
+  // CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here
+  // CHECK-FIXES: {{^  }}return !ptr->empty();
+}
Index: clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
@@ -194,7 +194,13 @@
   if (isBinaryOrTernary(E) || isa(E)) {
 ReplacementText = "(" + ReplacementText + ")";
   }
-  if (E->getType()->isPointerType())
+  const auto *OpCallExpr = dyn_cast(E);
+  if (OpCallExpr &&
+  OpCallExpr->getOperator() == OverloadedOperatorKind::OO_Arrow) {
+// This can happen if the object is a smart pointer. Don't add anything
+// because a '->' is already there (PR#51776), just call the method.
+ReplacementText += "empty()";
+  } else if (E->getType()->isPointerType())
 ReplacementText += "->empty()";
   else
 ReplacementText += ".empty()";
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D133244: [clang-tidy] Readability-container-data-pointer adds new option to ignore Containers

2022-10-21 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff added a comment.

I suppose it sounds sensible to have the option of ignoring certain containers 
in this check; though I haven't needed it myself so far, which is also why I'm 
leaning against ignoring `std::array` by default. But I do not claim ultimate 
authority on this question, of course.




Comment at: 
clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp:26
 constexpr llvm::StringLiteral AddressOfName = "address-of";
+const auto DefaultIgnoredContainers = "::std::array";
 

This is, of course, debatable, but I think I would prefer not to ignore 
`std::array` by default. Note the documentation (emphasis mine):

> This **also** ensures that in the case that the container is empty, the data 
> pointer access does not perform an errant memory access.

i.e. while you are correct that the danger of accessing an empty container does 
not apply to an array of non-zero size (though you aren't checking anywhere 
that the size is not zero AFAICS), this is not the **only** purpose of this 
check, which explains why this check is found in the "readability" category 
(instead of, say, "bugprone"). Therefore, I think the check is useful even for 
`std::array`, and not ignoring it by default would be the conservative choice 
here because that's what the check is currently doing.



Comment at: clang-tools-extra/docs/ReleaseNotes.rst:146
+
+  The check now skips containers that are defined in the option 
`IgnoredContainers`.  The default value is `::std::array`.
+

I think you should also update the documentation for this check in 
`clang-tools-extra/docs/clang-tidy/checks/readability/container-data-pointer.rst`
 and list the new option there.



Comment at: 
clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp:59
 #define z (0)
 
 void g(size_t s) {

Regardless of whether or not `std::array` should be ignored by default, I think 
it wouldn't hurt to add a test case for it somewhere in this file, given that 
it was the impetus for this change, no?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D133244

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


[PATCH] D127036: [clang-tidy] Warn about arrays in `bugprone-undefined-memory-manipulation`

2022-06-03 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: aaron.ballman, njames93, alexfh.
fwolff added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, xazax.hun.
Herald added a project: All.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

Fixes issue #55579 .


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D127036

Files:
  clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/bugprone-undefined-memory-manipulation.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/bugprone-undefined-memory-manipulation.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/bugprone-undefined-memory-manipulation.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/bugprone-undefined-memory-manipulation.cpp
@@ -126,6 +126,12 @@
   ::memmove(&p, &vb, sizeof(int));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source 
object type 'types::VirtualBase'
 
+  types::Copy ca[10];
+  memset(ca, 0, sizeof(ca));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination 
object type 'types::Copy[10]'
+  memset(&ca, 0, sizeof(ca));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination 
object type 'types::Copy[10]'
+
 #define MEMSET memset(&vf, 0, sizeof(int));
   MEMSET
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination 
object type 'types::VirtualFunc'
@@ -159,6 +165,13 @@
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination 
object type 'aliases::Copy2'
   memset(pc3, 0, sizeof(int));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination 
object type 'Copy3'
+
+  using Copy3Arr = Copy3[5];
+  Copy3Arr c3a;
+  memset(c3a, 0, sizeof(c3a));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination 
object type 'Copy3Arr'
+  memset(&c3a, 0, sizeof(c3a));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination 
object type 'Copy3Arr'
 }
 
 void triviallyCopyable() {
Index: 
clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.cpp
@@ -24,9 +24,13 @@
 } // namespace
 
 void UndefinedMemoryManipulationCheck::registerMatchers(MatchFinder *Finder) {
-  const auto NotTriviallyCopyableObject =
-  hasType(ast_matchers::hasCanonicalType(
-  pointsTo(cxxRecordDecl(isNotTriviallyCopyable();
+  const auto ArrayOfNotTriviallyCopyable = arrayType(
+  hasElementType(hasDeclaration(cxxRecordDecl(isNotTriviallyCopyable();
+  const auto NotTriviallyCopyableObject = hasType(hasCanonicalType(
+  anyOf(pointsTo(qualType(
+anyOf(hasDeclaration(cxxRecordDecl(isNotTriviallyCopyable())),
+  ArrayOfNotTriviallyCopyable))),
+ArrayOfNotTriviallyCopyable)));
 
   // Check whether destination object is not TriviallyCopyable.
   // Applicable to all three memory manipulation functions.


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-undefined-memory-manipulation.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-undefined-memory-manipulation.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-undefined-memory-manipulation.cpp
@@ -126,6 +126,12 @@
   ::memmove(&p, &vb, sizeof(int));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualBase'
 
+  types::Copy ca[10];
+  memset(ca, 0, sizeof(ca));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Copy[10]'
+  memset(&ca, 0, sizeof(ca));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Copy[10]'
+
 #define MEMSET memset(&vf, 0, sizeof(int));
   MEMSET
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc'
@@ -159,6 +165,13 @@
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'aliases::Copy2'
   memset(pc3, 0, sizeof(int));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3'
+
+  using Copy3Arr = Copy3[5];
+  Copy3Arr c3a;
+  memset(c3a, 0, sizeof(c3a));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3Arr'
+  memset(&c3a, 0, sizeof(c3a));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3Arr'
 }
 
 void triviallyCopyable() {
Index: clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipul

[PATCH] D127036: [clang-tidy] Warn about arrays in `bugprone-undefined-memory-manipulation`

2022-06-04 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 434283.

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

https://reviews.llvm.org/D127036

Files:
  clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/bugprone-undefined-memory-manipulation.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/bugprone-undefined-memory-manipulation.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/bugprone-undefined-memory-manipulation.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/bugprone-undefined-memory-manipulation.cpp
@@ -126,6 +126,12 @@
   ::memmove(&p, &vb, sizeof(int));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source 
object type 'types::VirtualBase'
 
+  types::Copy ca[10];
+  memset(ca, 0, sizeof(ca));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination 
object type 'types::Copy[10]'
+  memset(&ca, 0, sizeof(ca));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination 
object type 'types::Copy[10]'
+
 #define MEMSET memset(&vf, 0, sizeof(int));
   MEMSET
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination 
object type 'types::VirtualFunc'
@@ -159,6 +165,18 @@
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination 
object type 'aliases::Copy2'
   memset(pc3, 0, sizeof(int));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination 
object type 'Copy3'
+
+  using Copy3Arr = Copy3[5];
+  Copy3Arr c3a;
+  memset(c3a, 0, sizeof(c3a));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination 
object type 'Copy3Arr'
+  memset(&c3a, 0, sizeof(c3a));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination 
object type 'Copy3Arr'
+
+  typedef Copy3 Copy3Arr2[5];
+  Copy3Arr2 c3a2;
+  memset(c3a2, 0, sizeof(c3a2));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination 
object type 'Copy3Arr2'
 }
 
 void triviallyCopyable() {
Index: 
clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.cpp
@@ -24,9 +24,14 @@
 } // namespace
 
 void UndefinedMemoryManipulationCheck::registerMatchers(MatchFinder *Finder) {
-  const auto NotTriviallyCopyableObject =
-  hasType(ast_matchers::hasCanonicalType(
-  pointsTo(cxxRecordDecl(isNotTriviallyCopyable();
+  const auto HasNotTriviallyCopyableDecl =
+  hasDeclaration(cxxRecordDecl(isNotTriviallyCopyable()));
+  const auto ArrayOfNotTriviallyCopyable =
+  arrayType(hasElementType(HasNotTriviallyCopyableDecl));
+  const auto NotTriviallyCopyableObject = hasType(hasCanonicalType(
+  anyOf(pointsTo(qualType(anyOf(HasNotTriviallyCopyableDecl,
+ArrayOfNotTriviallyCopyable))),
+ArrayOfNotTriviallyCopyable)));
 
   // Check whether destination object is not TriviallyCopyable.
   // Applicable to all three memory manipulation functions.


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-undefined-memory-manipulation.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-undefined-memory-manipulation.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-undefined-memory-manipulation.cpp
@@ -126,6 +126,12 @@
   ::memmove(&p, &vb, sizeof(int));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualBase'
 
+  types::Copy ca[10];
+  memset(ca, 0, sizeof(ca));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Copy[10]'
+  memset(&ca, 0, sizeof(ca));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Copy[10]'
+
 #define MEMSET memset(&vf, 0, sizeof(int));
   MEMSET
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc'
@@ -159,6 +165,18 @@
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'aliases::Copy2'
   memset(pc3, 0, sizeof(int));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3'
+
+  using Copy3Arr = Copy3[5];
+  Copy3Arr c3a;
+  memset(c3a, 0, sizeof(c3a));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3Arr'
+  memset(&c3a, 0, sizeof(c3a));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3Arr'
+
+  typedef Copy3 Copy3Arr2[5];
+  Copy3Arr2 c3a2;
+  memset(c3a2, 0, sizeof(c3a2));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, dest

[PATCH] D157428: [clang-tidy] `readability-implicit-bool-conversion.AllowIntegerConditions` ignores `DoStmt`s

2023-08-08 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: PiotrZSL, aaron.ballman.
fwolff added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, xazax.hun.
Herald added a reviewer: njames93.
Herald added a project: All.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

Fixes a simple oversight which currently causes the `AllowIntegerConditions` 
option of the `readability-implicit-bool-conversion` check to not apply to 
do-while loop conditions, for no apparent reason.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D157428

Files:
  clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
@@ -38,6 +38,9 @@
   while (functionReturningInt()) {}
   while (functionReturningPointer()) {}
   while (functionReturningInt() && !functionReturningPointer() || 
(!functionReturningInt() && functionReturningPointer())) {}
+  do {} while (functionReturningInt());
+  do {} while (functionReturningPointer());
+  do {} while (functionReturningInt() && !functionReturningPointer() || 
(!functionReturningInt() && functionReturningPointer()));
   int value1 = functionReturningInt() ? 1 : 2;
   int value2 = !functionReturningInt() ? 1 : 2;
   int value3 = (functionReturningInt() && functionReturningPointer() || 
!functionReturningInt()) ? 1 : 2;
Index: clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
@@ -228,7 +228,8 @@
   if (!S)
 return false;
   if (isa(S) || isa(S) || isa(S) ||
-  isa(S) || isa(S))
+  isa(S) || isa(S) ||
+  isa(S))
 return true;
   if (isa(S) || isa(S) ||
   isUnaryLogicalNotOperator(S) ||


Index: clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
@@ -38,6 +38,9 @@
   while (functionReturningInt()) {}
   while (functionReturningPointer()) {}
   while (functionReturningInt() && !functionReturningPointer() || (!functionReturningInt() && functionReturningPointer())) {}
+  do {} while (functionReturningInt());
+  do {} while (functionReturningPointer());
+  do {} while (functionReturningInt() && !functionReturningPointer() || (!functionReturningInt() && functionReturningPointer()));
   int value1 = functionReturningInt() ? 1 : 2;
   int value2 = !functionReturningInt() ? 1 : 2;
   int value3 = (functionReturningInt() && functionReturningPointer() || !functionReturningInt()) ? 1 : 2;
Index: clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
@@ -228,7 +228,8 @@
   if (!S)
 return false;
   if (isa(S) || isa(S) || isa(S) ||
-  isa(S) || isa(S))
+  isa(S) || isa(S) ||
+  isa(S))
 return true;
   if (isa(S) || isa(S) ||
   isUnaryLogicalNotOperator(S) ||
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D157436: [clang-tidy] `performance-faster-string-find` generates incorrect fixes for single quote character literals

2023-08-08 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff created this revision.
fwolff added reviewers: PiotrZSL, carlosgalvezp.
fwolff added a project: clang-tools-extra.
Herald added a subscriber: xazax.hun.
Herald added a reviewer: njames93.
Herald added a project: All.
fwolff requested review of this revision.
Herald added a subscriber: cfe-commits.

`"'"` is turned into `'''` but should be turned into `'\''`.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D157436

Files:
  clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp
@@ -56,13 +56,21 @@
   // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string 
literal
   // CHECK-FIXES: Str.find('a', 1);
 
-  // Doens't work with strings smaller or larger than 1 char.
+  // Doesn't work with strings smaller or larger than 1 char.
   Str.find("");
   Str.find("ab");
 
   // Doesn't do anything with the 3 argument overload.
   Str.find("a", 1, 1);
 
+  // Single quotes are escaped properly
+  Str.find("'");
+  // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string 
literal
+  // CHECK-FIXES: Str.find('\'');
+  Str.find("\'");
+  // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string 
literal
+  // CHECK-FIXES: Str.find('\'');
+
   // Other methods that can also be replaced
   Str.rfind("a");
   // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'rfind' called with a string 
literal
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -196,6 +196,10 @@
   ` check to emit proper
   warnings when a type forward declaration precedes its definition.
 
+- Fixed a bug in :doc:`performance-faster-string-find
+  ` which generated incorrect fixes by not
+  escaping single quotes properly.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp
===
--- clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp
+++ clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp
@@ -26,14 +26,20 @@
 Literal->outputString(OS);
   }
   // Now replace the " with '.
-  auto Pos = Result.find_first_of('"');
-  if (Pos == Result.npos)
+  auto OpenPos = Result.find_first_of('"');
+  if (OpenPos == Result.npos)
 return std::nullopt;
-  Result[Pos] = '\'';
-  Pos = Result.find_last_of('"');
-  if (Pos == Result.npos)
+  Result[OpenPos] = '\'';
+
+  auto ClosePos = Result.find_last_of('"');
+  if (ClosePos == Result.npos)
 return std::nullopt;
-  Result[Pos] = '\'';
+  Result[ClosePos] = '\'';
+
+  // "'" is OK, but ''' is not, so add a backslash
+  if (ClosePos - OpenPos == 2 && Result[OpenPos + 1] == '\'')
+Result.replace(OpenPos + 1, 1, "\\'");
+
   return Result;
 }
 


Index: clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp
@@ -56,13 +56,21 @@
   // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal
   // CHECK-FIXES: Str.find('a', 1);
 
-  // Doens't work with strings smaller or larger than 1 char.
+  // Doesn't work with strings smaller or larger than 1 char.
   Str.find("");
   Str.find("ab");
 
   // Doesn't do anything with the 3 argument overload.
   Str.find("a", 1, 1);
 
+  // Single quotes are escaped properly
+  Str.find("'");
+  // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal
+  // CHECK-FIXES: Str.find('\'');
+  Str.find("\'");
+  // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal
+  // CHECK-FIXES: Str.find('\'');
+
   // Other methods that can also be replaced
   Str.rfind("a");
   // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'rfind' called with a string literal
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -196,6 +196,10 @@
   ` check to emit proper
   warnings when a type forward declaration precedes its definition.
 
+- Fixed a bug in :doc:`performance-faster-string-find
+  ` which generated incorrect fixes by not
+  escaping single quotes properly.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/c

[PATCH] D157428: [clang-tidy] `readability-implicit-bool-conversion.AllowIntegerConditions` ignores `DoStmt`s

2023-08-08 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 548334.
fwolff added a comment.

Mention this change in the release notes


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157428

Files:
  clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
@@ -38,6 +38,9 @@
   while (functionReturningInt()) {}
   while (functionReturningPointer()) {}
   while (functionReturningInt() && !functionReturningPointer() || 
(!functionReturningInt() && functionReturningPointer())) {}
+  do {} while (functionReturningInt());
+  do {} while (functionReturningPointer());
+  do {} while (functionReturningInt() && !functionReturningPointer() || 
(!functionReturningInt() && functionReturningPointer()));
   int value1 = functionReturningInt() ? 1 : 2;
   int value2 = !functionReturningInt() ? 1 : 2;
   int value3 = (functionReturningInt() && functionReturningPointer() || 
!functionReturningInt()) ? 1 : 2;
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -196,6 +196,11 @@
   ` check to emit proper
   warnings when a type forward declaration precedes its definition.
 
+- Improved :doc:`readability-implicit-bool-conversion
+  ` check to take do-while loops into
+  account for the ``AllowIntegerConditions`` and ``AllowPointerConditions``
+  options.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
@@ -228,7 +228,8 @@
   if (!S)
 return false;
   if (isa(S) || isa(S) || isa(S) ||
-  isa(S) || isa(S))
+  isa(S) || isa(S) ||
+  isa(S))
 return true;
   if (isa(S) || isa(S) ||
   isUnaryLogicalNotOperator(S) ||


Index: clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
@@ -38,6 +38,9 @@
   while (functionReturningInt()) {}
   while (functionReturningPointer()) {}
   while (functionReturningInt() && !functionReturningPointer() || (!functionReturningInt() && functionReturningPointer())) {}
+  do {} while (functionReturningInt());
+  do {} while (functionReturningPointer());
+  do {} while (functionReturningInt() && !functionReturningPointer() || (!functionReturningInt() && functionReturningPointer()));
   int value1 = functionReturningInt() ? 1 : 2;
   int value2 = !functionReturningInt() ? 1 : 2;
   int value3 = (functionReturningInt() && functionReturningPointer() || !functionReturningInt()) ? 1 : 2;
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -196,6 +196,11 @@
   ` check to emit proper
   warnings when a type forward declaration precedes its definition.
 
+- Improved :doc:`readability-implicit-bool-conversion
+  ` check to take do-while loops into
+  account for the ``AllowIntegerConditions`` and ``AllowPointerConditions``
+  options.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
@@ -228,7 +228,8 @@
   if (!S)
 return false;
   if (isa(S) || isa(S) || isa(S) ||
-  isa(S) || isa(S))
+  isa(S) || isa(S) ||
+  isa(S))
 return true;
   if (isa(S) || isa(S) ||
   isUnaryLogicalNotOperator(S) ||
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D157428: [clang-tidy] `readability-implicit-bool-conversion.AllowIntegerConditions` ignores `DoStmt`s

2023-08-08 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 548342.

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157428

Files:
  clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
@@ -38,6 +38,9 @@
   while (functionReturningInt()) {}
   while (functionReturningPointer()) {}
   while (functionReturningInt() && !functionReturningPointer() || 
(!functionReturningInt() && functionReturningPointer())) {}
+  do {} while (functionReturningInt());
+  do {} while (functionReturningPointer());
+  do {} while (functionReturningInt() && !functionReturningPointer() || 
(!functionReturningInt() && functionReturningPointer()));
   int value1 = functionReturningInt() ? 1 : 2;
   int value2 = !functionReturningInt() ? 1 : 2;
   int value3 = (functionReturningInt() && functionReturningPointer() || 
!functionReturningInt()) ? 1 : 2;
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -196,6 +196,11 @@
   ` check to emit proper
   warnings when a type forward declaration precedes its definition.
 
+- Improved :doc:`readability-implicit-bool-conversion
+  ` check to take
+  do-while loops into account for the `AllowIntegerConditions` and
+  `AllowPointerConditions` options.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
@@ -228,7 +228,8 @@
   if (!S)
 return false;
   if (isa(S) || isa(S) || isa(S) ||
-  isa(S) || isa(S))
+  isa(S) || isa(S) ||
+  isa(S))
 return true;
   if (isa(S) || isa(S) ||
   isUnaryLogicalNotOperator(S) ||


Index: clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
@@ -38,6 +38,9 @@
   while (functionReturningInt()) {}
   while (functionReturningPointer()) {}
   while (functionReturningInt() && !functionReturningPointer() || (!functionReturningInt() && functionReturningPointer())) {}
+  do {} while (functionReturningInt());
+  do {} while (functionReturningPointer());
+  do {} while (functionReturningInt() && !functionReturningPointer() || (!functionReturningInt() && functionReturningPointer()));
   int value1 = functionReturningInt() ? 1 : 2;
   int value2 = !functionReturningInt() ? 1 : 2;
   int value3 = (functionReturningInt() && functionReturningPointer() || !functionReturningInt()) ? 1 : 2;
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -196,6 +196,11 @@
   ` check to emit proper
   warnings when a type forward declaration precedes its definition.
 
+- Improved :doc:`readability-implicit-bool-conversion
+  ` check to take
+  do-while loops into account for the `AllowIntegerConditions` and
+  `AllowPointerConditions` options.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
@@ -228,7 +228,8 @@
   if (!S)
 return false;
   if (isa(S) || isa(S) || isa(S) ||
-  isa(S) || isa(S))
+  isa(S) || isa(S) ||
+  isa(S))
 return true;
   if (isa(S) || isa(S) ||
   isUnaryLogicalNotOperator(S) ||
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D157428: [clang-tidy] `readability-implicit-bool-conversion.AllowIntegerConditions` ignores `DoStmt`s

2023-08-08 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff marked an inline comment as done.
fwolff added a comment.

Thanks for reviewing this @PiotrZSL!

In D157428#4570497 , @PiotrZSL wrote:

> What about switchStmt ?

The `AllowIntegerConditions` and `AllowPointerConditions` options only apply to 
`int -> bool` conversions, whereas switch statements have integral conditions.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157428

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


[PATCH] D157436: [clang-tidy] `performance-faster-string-find` generates incorrect fixes for single quote character literals

2023-08-08 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 548347.

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157436

Files:
  clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp
@@ -56,13 +56,21 @@
   // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string 
literal
   // CHECK-FIXES: Str.find('a', 1);
 
-  // Doens't work with strings smaller or larger than 1 char.
+  // Doesn't work with strings smaller or larger than 1 char.
   Str.find("");
   Str.find("ab");
 
   // Doesn't do anything with the 3 argument overload.
   Str.find("a", 1, 1);
 
+  // Single quotes are escaped properly
+  Str.find("'");
+  // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string 
literal
+  // CHECK-FIXES: Str.find('\'');
+  Str.find("\'");
+  // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string 
literal
+  // CHECK-FIXES: Str.find('\'');
+
   // Other methods that can also be replaced
   Str.rfind("a");
   // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'rfind' called with a string 
literal
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -188,6 +188,10 @@
   ` to support for-loops with
   iterators initialized by free functions like ``begin``, ``end``, or ``size``.
 
+- Improved :doc:`performance-faster-string-find
+  ` check to properly escape
+  single quotes.
+
 - Improved :doc:`performanc-noexcept-swap
   ` check to enforce a stricter
   match with the swap function signature, eliminating false-positives.
Index: clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp
===
--- clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp
+++ clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp
@@ -26,14 +26,20 @@
 Literal->outputString(OS);
   }
   // Now replace the " with '.
-  auto Pos = Result.find_first_of('"');
-  if (Pos == Result.npos)
+  auto OpenPos = Result.find_first_of('"');
+  if (OpenPos == Result.npos)
 return std::nullopt;
-  Result[Pos] = '\'';
-  Pos = Result.find_last_of('"');
-  if (Pos == Result.npos)
+  Result[OpenPos] = '\'';
+
+  auto ClosePos = Result.find_last_of('"');
+  if (ClosePos == Result.npos)
 return std::nullopt;
-  Result[Pos] = '\'';
+  Result[ClosePos] = '\'';
+
+  // "'" is OK, but ''' is not, so add a backslash
+  if ((ClosePos - OpenPos) == 2 && Result[OpenPos + 1] == '\'')
+Result.replace(OpenPos + 1, 1, "\\'");
+
   return Result;
 }
 


Index: clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp
@@ -56,13 +56,21 @@
   // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal
   // CHECK-FIXES: Str.find('a', 1);
 
-  // Doens't work with strings smaller or larger than 1 char.
+  // Doesn't work with strings smaller or larger than 1 char.
   Str.find("");
   Str.find("ab");
 
   // Doesn't do anything with the 3 argument overload.
   Str.find("a", 1, 1);
 
+  // Single quotes are escaped properly
+  Str.find("'");
+  // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal
+  // CHECK-FIXES: Str.find('\'');
+  Str.find("\'");
+  // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal
+  // CHECK-FIXES: Str.find('\'');
+
   // Other methods that can also be replaced
   Str.rfind("a");
   // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'rfind' called with a string literal
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -188,6 +188,10 @@
   ` to support for-loops with
   iterators initialized by free functions like ``begin``, ``end``, or ``size``.
 
+- Improved :doc:`performance-faster-string-find
+  ` check to properly escape
+  single quotes.
+
 - Improved :doc:`performanc-noexcept-swap
   ` check to enforce a stricter
   match with the swap function signature, eliminating false-positives.
Index: clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp
=

[PATCH] D157428: [clang-tidy] `readability-implicit-bool-conversion.AllowIntegerConditions` ignores `DoStmt`s

2023-08-08 Thread Fabian Wolff via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGf263f45ba649: [clang-tidy] 
`readability-implicit-bool-conversion.AllowIntegerConditions`… (authored by 
fwolff).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157428

Files:
  clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
@@ -38,6 +38,9 @@
   while (functionReturningInt()) {}
   while (functionReturningPointer()) {}
   while (functionReturningInt() && !functionReturningPointer() || 
(!functionReturningInt() && functionReturningPointer())) {}
+  do {} while (functionReturningInt());
+  do {} while (functionReturningPointer());
+  do {} while (functionReturningInt() && !functionReturningPointer() || 
(!functionReturningInt() && functionReturningPointer()));
   int value1 = functionReturningInt() ? 1 : 2;
   int value2 = !functionReturningInt() ? 1 : 2;
   int value3 = (functionReturningInt() && functionReturningPointer() || 
!functionReturningInt()) ? 1 : 2;
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -196,6 +196,11 @@
   ` check to emit proper
   warnings when a type forward declaration precedes its definition.
 
+- Improved :doc:`readability-implicit-bool-conversion
+  ` check to take
+  do-while loops into account for the `AllowIntegerConditions` and
+  `AllowPointerConditions` options.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
@@ -228,7 +228,8 @@
   if (!S)
 return false;
   if (isa(S) || isa(S) || isa(S) ||
-  isa(S) || isa(S))
+  isa(S) || isa(S) ||
+  isa(S))
 return true;
   if (isa(S) || isa(S) ||
   isUnaryLogicalNotOperator(S) ||


Index: clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp
@@ -38,6 +38,9 @@
   while (functionReturningInt()) {}
   while (functionReturningPointer()) {}
   while (functionReturningInt() && !functionReturningPointer() || (!functionReturningInt() && functionReturningPointer())) {}
+  do {} while (functionReturningInt());
+  do {} while (functionReturningPointer());
+  do {} while (functionReturningInt() && !functionReturningPointer() || (!functionReturningInt() && functionReturningPointer()));
   int value1 = functionReturningInt() ? 1 : 2;
   int value2 = !functionReturningInt() ? 1 : 2;
   int value3 = (functionReturningInt() && functionReturningPointer() || !functionReturningInt()) ? 1 : 2;
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -196,6 +196,11 @@
   ` check to emit proper
   warnings when a type forward declaration precedes its definition.
 
+- Improved :doc:`readability-implicit-bool-conversion
+  ` check to take
+  do-while loops into account for the `AllowIntegerConditions` and
+  `AllowPointerConditions` options.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
@@ -228,7 +228,8 @@
   if (!S)
 return false;
   if (isa(S) || isa(S) || isa(S) ||
-  isa(S) || isa(S))
+  isa(S) || isa(S) ||
+  isa(S))
 return true;
   if (isa(S) || isa(S) ||
   isUnaryLogicalNotOperator(S) ||
___
cfe-

[PATCH] D157436: [clang-tidy] `performance-faster-string-find` generates incorrect fixes for single quote character literals

2023-08-08 Thread Fabian Wolff via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG5b95d17da1f0: [clang-tidy] `performance-faster-string-find` 
generates incorrect fixes for… (authored by fwolff).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157436

Files:
  clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp
@@ -56,13 +56,21 @@
   // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string 
literal
   // CHECK-FIXES: Str.find('a', 1);
 
-  // Doens't work with strings smaller or larger than 1 char.
+  // Doesn't work with strings smaller or larger than 1 char.
   Str.find("");
   Str.find("ab");
 
   // Doesn't do anything with the 3 argument overload.
   Str.find("a", 1, 1);
 
+  // Single quotes are escaped properly
+  Str.find("'");
+  // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string 
literal
+  // CHECK-FIXES: Str.find('\'');
+  Str.find("\'");
+  // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string 
literal
+  // CHECK-FIXES: Str.find('\'');
+
   // Other methods that can also be replaced
   Str.rfind("a");
   // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'rfind' called with a string 
literal
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -188,6 +188,10 @@
   ` to support for-loops with
   iterators initialized by free functions like ``begin``, ``end``, or ``size``.
 
+- Improved :doc:`performance-faster-string-find
+  ` check to properly escape
+  single quotes.
+
 - Improved :doc:`performanc-noexcept-swap
   ` check to enforce a stricter
   match with the swap function signature, eliminating false-positives.
Index: clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp
===
--- clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp
+++ clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp
@@ -26,14 +26,20 @@
 Literal->outputString(OS);
   }
   // Now replace the " with '.
-  auto Pos = Result.find_first_of('"');
-  if (Pos == Result.npos)
+  auto OpenPos = Result.find_first_of('"');
+  if (OpenPos == Result.npos)
 return std::nullopt;
-  Result[Pos] = '\'';
-  Pos = Result.find_last_of('"');
-  if (Pos == Result.npos)
+  Result[OpenPos] = '\'';
+
+  auto ClosePos = Result.find_last_of('"');
+  if (ClosePos == Result.npos)
 return std::nullopt;
-  Result[Pos] = '\'';
+  Result[ClosePos] = '\'';
+
+  // "'" is OK, but ''' is not, so add a backslash
+  if ((ClosePos - OpenPos) == 2 && Result[OpenPos + 1] == '\'')
+Result.replace(OpenPos + 1, 1, "\\'");
+
   return Result;
 }
 


Index: clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp
@@ -56,13 +56,21 @@
   // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal
   // CHECK-FIXES: Str.find('a', 1);
 
-  // Doens't work with strings smaller or larger than 1 char.
+  // Doesn't work with strings smaller or larger than 1 char.
   Str.find("");
   Str.find("ab");
 
   // Doesn't do anything with the 3 argument overload.
   Str.find("a", 1, 1);
 
+  // Single quotes are escaped properly
+  Str.find("'");
+  // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal
+  // CHECK-FIXES: Str.find('\'');
+  Str.find("\'");
+  // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal
+  // CHECK-FIXES: Str.find('\'');
+
   // Other methods that can also be replaced
   Str.rfind("a");
   // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'rfind' called with a string literal
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -188,6 +188,10 @@
   ` to support for-loops with
   iterators initialized by free functions like ``begin``, ``end``, or ``size``.
 
+- Improved :doc:`performance-faster-string-find
+  ` check to properly escape
+  single quotes.
+
 - Improved :doc:`perform

[PATCH] D113863: [clang-tidy] Make `readability-container-data-pointer` more robust

2022-01-18 Thread Fabian Wolff via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGf7b7138a6264: [clang-tidy] Make 
`readability-container-data-pointer` more robust (authored by fwolff).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D113863

Files:
  clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
@@ -109,3 +109,38 @@
   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
   // CHECK-FIXES: {{^  }}return v.data();{{$}}
 }
+
+template 
+struct container_without_data {
+  using size_type = size_t;
+  T &operator[](size_type);
+  const T &operator[](size_type) const;
+};
+
+template 
+const T *n(const container_without_data &c) {
+  // c has no "data" member function, so there should not be a warning here:
+  return &c[0];
+}
+
+const int *o(const std::vector>> &v, const size_t idx1, const size_t idx2) {
+  return &v[idx1][idx2][0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return v[idx1][idx2].data();{{$}}
+}
+
+std::vector &select(std::vector &u, std::vector &v) {
+  return v;
+}
+
+int *p(std::vector &v1, std::vector &v2) {
+  return &select(*&v1, v2)[0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return select(*&v1, v2).data();{{$}}
+}
+
+int *q(std::vector ***v) {
+  return &(***v)[0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return (**v)->data();{{$}}
+}
Index: clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
@@ -16,6 +16,13 @@
 namespace clang {
 namespace tidy {
 namespace readability {
+
+constexpr llvm::StringLiteral ContainerExprName = "container-expr";
+constexpr llvm::StringLiteral DerefContainerExprName = "deref-container-expr";
+constexpr llvm::StringLiteral AddrOfContainerExprName =
+"addr-of-container-expr";
+constexpr llvm::StringLiteral AddressOfName = "address-of";
+
 ContainerDataPointerCheck::ContainerDataPointerCheck(StringRef Name,
  ClangTidyContext *Context)
 : ClangTidyCheck(Name, Context) {}
@@ -38,69 +45,63 @@
   const auto Container =
   qualType(anyOf(NonTemplateContainerType, TemplateContainerType));
 
+  const auto ContainerExpr = anyOf(
+  unaryOperator(
+  hasOperatorName("*"),
+  hasUnaryOperand(
+  expr(hasType(pointsTo(Container))).bind(DerefContainerExprName)))
+  .bind(ContainerExprName),
+  unaryOperator(hasOperatorName("&"),
+hasUnaryOperand(expr(anyOf(hasType(Container),
+   hasType(references(Container
+.bind(AddrOfContainerExprName)))
+  .bind(ContainerExprName),
+  expr(anyOf(hasType(Container), hasType(pointsTo(Container)),
+ hasType(references(Container
+  .bind(ContainerExprName));
+
+  const auto Zero = integerLiteral(equals(0));
+
+  const auto SubscriptOperator = callee(cxxMethodDecl(hasName("operator[]")));
+
   Finder->addMatcher(
   unaryOperator(
   unless(isExpansionInSystemHeader()), hasOperatorName("&"),
-  hasUnaryOperand(anyOf(
-  ignoringParenImpCasts(
-  cxxOperatorCallExpr(
-  callee(cxxMethodDecl(hasName("operator[]"))
- .bind("operator[]")),
-  argumentCountIs(2),
-  hasArgument(
-  0,
-  anyOf(ignoringParenImpCasts(
-declRefExpr(
-to(varDecl(anyOf(
-hasType(Container),
- 

[PATCH] D113507: [clang-tidy] Include constructor initializers in `bugprone-exception-escape` check

2022-01-20 Thread Fabian Wolff via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
fwolff marked an inline comment as done.
Closed by commit rGd3b188a2d72f: [clang-tidy] Include constructor initializers 
in `bugprone-exception-escape`… (authored by fwolff).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D113507

Files:
  clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
  clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
@@ -288,6 +288,49 @@
   return recursion_helper(n);
 }
 
+struct super_throws {
+  super_throws() noexcept(false) { throw 42; }
+};
+
+struct sub_throws : super_throws {
+  sub_throws() noexcept : super_throws() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in 
function 'sub_throws' which should not throw exceptions
+};
+
+struct super_throws_again {
+  super_throws_again() throw(int);
+};
+
+struct sub_throws_again : super_throws_again {
+  sub_throws_again() noexcept : super_throws_again() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in 
function 'sub_throws_again' which should not throw exceptions
+};
+
+struct init_member_throws {
+  super_throws s;
+
+  init_member_throws() noexcept : s() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in 
function 'init_member_throws' which should not throw exceptions
+};
+
+struct implicit_init_member_throws {
+  super_throws s;
+
+  implicit_init_member_throws() noexcept {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in 
function 'implicit_init_member_throws' which should not throw exceptions
+};
+
+struct init {
+  explicit init(int, int) noexcept(false) { throw 42; }
+};
+
+struct in_class_init_throws {
+  init i{1, 2};
+
+  in_class_init_throws() noexcept {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in 
function 'in_class_init_throws' which should not throw exceptions
+};
+
 int main() {
   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in 
function 'main' which should not throw exceptions
   throw 1;
Index: clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
===
--- clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
+++ clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
@@ -119,6 +119,16 @@
 CallStack.insert(Func);
 ExceptionInfo Result =
 throwsException(Body, ExceptionInfo::Throwables(), CallStack);
+
+// For a constructor, we also have to check the initializers.
+if (const auto *Ctor = dyn_cast(Func)) {
+  for (const CXXCtorInitializer *Init : Ctor->inits()) {
+ExceptionInfo Excs = throwsException(
+Init->getInit(), ExceptionInfo::Throwables(), CallStack);
+Result.merge(Excs);
+  }
+}
+
 CallStack.erase(Func);
 return Result;
   }
@@ -195,6 +205,14 @@
   ExceptionInfo Excs = throwsException(Func, CallStack);
   Results.merge(Excs);
 }
+  } else if (const auto *Construct = dyn_cast(St)) {
+ExceptionInfo Excs =
+throwsException(Construct->getConstructor(), CallStack);
+Results.merge(Excs);
+  } else if (const auto *DefaultInit = dyn_cast(St)) {
+ExceptionInfo Excs =
+throwsException(DefaultInit->getExpr(), Caught, CallStack);
+Results.merge(Excs);
   } else {
 for (const Stmt *Child : St->children()) {
   ExceptionInfo Excs = throwsException(Child, Caught, CallStack);


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
@@ -288,6 +288,49 @@
   return recursion_helper(n);
 }
 
+struct super_throws {
+  super_throws() noexcept(false) { throw 42; }
+};
+
+struct sub_throws : super_throws {
+  sub_throws() noexcept : super_throws() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in function 'sub_throws' which should not throw exceptions
+};
+
+struct super_throws_again {
+  super_throws_again() throw(int);
+};
+
+struct sub_throws_again : super_throws_again {
+  sub_throws_again() noexcept : super_throws_again() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in function 'sub_throws_again' which should not throw exceptions
+};
+
+struct init_member_throws {
+  super_throws s;
+
+  init_member_throws() noexcept : s() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: a

[PATCH] D114299: [clang-tidy] Fix `readability-redundant-declaration` false positive for template friend declaration

2022-01-17 Thread Fabian Wolff via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG42bc3275d368: [clang-tidy] Fix 
`readability-redundant-declaration` false positive for… (authored by fwolff).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D114299

Files:
  clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
@@ -70,6 +70,32 @@
 
 void enemy();
 
+template 
+struct TemplateFriendly {
+  template 
+  friend void generic_friend();
+};
+
+template 
+void generic_friend() {}
+
+TemplateFriendly template_friendly;
+
+template 
+struct TemplateFriendly2 {
+  template 
+  friend void generic_friend2() {}
+};
+
+template 
+void generic_friend2();
+
+void generic_friend_caller() {
+  TemplateFriendly2 f;
+  generic_friend2();
+}
+
+
 namespace macros {
 #define DECLARE(x) extern int x
 #define DEFINE(x) extern int x; int x = 42
Index: clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
@@ -37,7 +37,7 @@
   functionDecl(unless(anyOf(
   isDefinition(), isDefaulted(),
   doesDeclarationForceExternallyVisibleDefinition(),
-  hasParent(friendDecl()))
+  hasAncestor(friendDecl()))
   .bind("Decl"),
   this);
 }


Index: clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-redundant-declaration.cpp
@@ -70,6 +70,32 @@
 
 void enemy();
 
+template 
+struct TemplateFriendly {
+  template 
+  friend void generic_friend();
+};
+
+template 
+void generic_friend() {}
+
+TemplateFriendly template_friendly;
+
+template 
+struct TemplateFriendly2 {
+  template 
+  friend void generic_friend2() {}
+};
+
+template 
+void generic_friend2();
+
+void generic_friend_caller() {
+  TemplateFriendly2 f;
+  generic_friend2();
+}
+
+
 namespace macros {
 #define DECLARE(x) extern int x
 #define DEFINE(x) extern int x; int x = 42
Index: clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
@@ -37,7 +37,7 @@
   functionDecl(unless(anyOf(
   isDefinition(), isDefaulted(),
   doesDeclarationForceExternallyVisibleDefinition(),
-  hasParent(friendDecl()))
+  hasAncestor(friendDecl()))
   .bind("Decl"),
   this);
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D114197: [clang-tidy] Fix false positives involving type aliases in `misc-unconventional-assign-operator` check

2022-01-17 Thread Fabian Wolff via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG2cd2accc61ea: [clang-tidy] Fix false positives involving 
type aliases in `misc-unconventional… (authored by fwolff).

Changed prior to commit:
  https://reviews.llvm.org/D114197?vs=391850&id=400618#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D114197

Files:
  clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp
  
clang-tools-extra/docs/clang-tidy/checks/misc-unconventional-assign-operator.rst
  
clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp
@@ -127,3 +127,39 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: operator=() should always 
return '*this'
   }
 };
+
+// Check that no false positives are issued when using type aliases.
+struct TypeAlias {
+  using Alias = TypeAlias;
+  // This is correct and should not produce any warnings:
+  Alias &operator=(const Alias &) { return *this; }
+
+  using AliasRef = Alias &;
+  // So is this (assignments from other types are fine):
+  AliasRef operator=(int) { return *this; }
+};
+
+// Same check as above with typedef instead of using
+struct TypeAliasTypedef {
+  typedef TypeAliasTypedef Alias;
+  Alias &operator=(const Alias &) { return *this; }
+
+  typedef Alias &AliasRef;
+  AliasRef operator=(int) { return *this; }
+};
+
+// Same check as above for a template class
+template 
+struct TemplateTypeAlias {
+  using Alias1 = TemplateTypeAlias &;
+  using Alias2 = TemplateTypeAlias const &;
+  Alias1 operator=(Alias2) { return *this; }
+
+  template 
+  using Alias3 = TemplateTypeAlias;
+  Alias3 &operator=(int) { return *this; }
+
+  // Using a different type parameter in the return type should give a warning
+  Alias3 &operator=(double) { return *this; }
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 
'TemplateTypeAlias&' [misc-unconventional-assign-operator]
+};
Index: 
clang-tools-extra/docs/clang-tidy/checks/misc-unconventional-assign-operator.rst
===
--- 
clang-tools-extra/docs/clang-tidy/checks/misc-unconventional-assign-operator.rst
+++ 
clang-tools-extra/docs/clang-tidy/checks/misc-unconventional-assign-operator.rst
@@ -8,6 +8,8 @@
 types and definitions with good return type but wrong ``return`` statements.
 
   * The return type must be ``Class&``.
-  * Works with move-assign and assign by value.
+  * The assignment may be from the class type by value, const lvalue
+reference, non-const rvalue reference, or from a completely different
+type (e.g. ``int``).
   * Private and deleted operators are ignored.
   * The operator must always return ``*this``.
Index: clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp
@@ -18,13 +18,14 @@
 
 void UnconventionalAssignOperatorCheck::registerMatchers(
 ast_matchers::MatchFinder *Finder) {
-  const auto HasGoodReturnType = cxxMethodDecl(returns(lValueReferenceType(
-  pointee(unless(isConstQualified()),
-  anyOf(autoType(), hasDeclaration(equalsBoundNode("class")));
+  const auto HasGoodReturnType =
+  cxxMethodDecl(returns(hasCanonicalType(lValueReferenceType(pointee(
+  unless(isConstQualified()),
+  anyOf(autoType(), hasDeclaration(equalsBoundNode("class";
 
-  const auto IsSelf = qualType(
+  const auto IsSelf = qualType(hasCanonicalType(
   anyOf(hasDeclaration(equalsBoundNode("class")),
-referenceType(pointee(hasDeclaration(equalsBoundNode("class"));
+
referenceType(pointee(hasDeclaration(equalsBoundNode("class")));
   const auto IsAssign =
   cxxMethodDecl(unless(anyOf(isDeleted(), isPrivate(), isImplicit())),
 hasName("operator="), ofClass(recordDecl().bind("class")))
@@ -37,9 +38,9 @@
   cxxMethodDecl(IsAssign, unless(HasGoodReturnType)).bind("ReturnType"),
   this);
 
-  const auto BadSelf = referenceType(
+  const auto BadSelf = qualType(hasCanonicalType(referenceType(
   anyOf(lValueReferenceType(pointee(unless(isConstQualified(,
-rValueReferenceType(pointee(isConstQualified();
+rValueReferenceType(pointee(isConstQualified()));
 
   Finder->addMatcher(
   cxxMethodDecl(IsSelfAssign,


Index: clang-tools-extra/test/clang-tidy/checkers/misc-uncon

[PATCH] D115124: [clang-tidy] Fix `readability-container-size-empty` check for smart pointers

2022-01-17 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 400625.
fwolff added a comment.

In D115124#3209199 , @Sockke wrote:

> Could you please add a test case where the smart pointer object is 
> dereferenced before calling `size()`? E.g. `return (*ptr).size() == 0;`. I 
> think this change doesn't work on this test case.

This is not entirely true; what you're seeing is an existing, unrelated bug: 
https://godbolt.org/z/9zEfdrPW8

In any case, I've fixed it, added a test for it, and added a bullet point to 
the release notes.


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

https://reviews.llvm.org/D115124

Files:
  clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp
@@ -696,3 +696,25 @@
   instantiatedTemplateWithSizeCall();
   instantiatedTemplateWithSizeCall>();
 }
+
+namespace std {
+template 
+struct unique_ptr {
+  T *operator->() const;
+  T &operator*() const;
+};
+} // namespace std
+
+bool call_through_unique_ptr(const std::unique_ptr> &ptr) {
+  return ptr->size() > 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should be 
used
+  // CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here
+  // CHECK-FIXES: {{^  }}return !ptr->empty();
+}
+
+bool call_through_unique_ptr_deref(const std::unique_ptr> 
&ptr) {
+  return (*ptr).size() > 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should be 
used
+  // CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here
+  // CHECK-FIXES: {{^  }}return !(*ptr).empty();
+}
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -83,6 +83,9 @@
 - Generalized the `modernize-use-default-member-init` check to handle 
non-default
   constructors.
 
+- Fixed incorrect suggestions for `readability-container-size-empty` when
+  smart pointers are involved.
+
 New checks
 ^^
 
Index: clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
@@ -191,10 +191,17 @@
   std::string ReplacementText = std::string(
   Lexer::getSourceText(CharSourceRange::getTokenRange(E->getSourceRange()),
*Result.SourceManager, getLangOpts()));
-  if (isBinaryOrTernary(E) || isa(E)) {
+  const auto *OpCallExpr = dyn_cast(E);
+  if (isBinaryOrTernary(E) || isa(E) ||
+  (OpCallExpr && (OpCallExpr->getOperator() == OO_Star))) {
 ReplacementText = "(" + ReplacementText + ")";
   }
-  if (E->getType()->isPointerType())
+  if (OpCallExpr &&
+  OpCallExpr->getOperator() == OverloadedOperatorKind::OO_Arrow) {
+// This can happen if the object is a smart pointer. Don't add anything
+// because a '->' is already there (PR#51776), just call the method.
+ReplacementText += "empty()";
+  } else if (E->getType()->isPointerType())
 ReplacementText += "->empty()";
   else
 ReplacementText += ".empty()";


Index: clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp
@@ -696,3 +696,25 @@
   instantiatedTemplateWithSizeCall();
   instantiatedTemplateWithSizeCall>();
 }
+
+namespace std {
+template 
+struct unique_ptr {
+  T *operator->() const;
+  T &operator*() const;
+};
+} // namespace std
+
+bool call_through_unique_ptr(const std::unique_ptr> &ptr) {
+  return ptr->size() > 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should be used
+  // CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here
+  // CHECK-FIXES: {{^  }}return !ptr->empty();
+}
+
+bool call_through_unique_ptr_deref(const std::unique_ptr> &ptr) {
+  return (*ptr).size() > 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should be used
+  // CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here
+  // CHECK-FIXES: {{^  }}return !(*ptr).empty();
+}
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clan

[PATCH] D114292: [clang-tidy] Fix `altera-struct-pack-align` check for empty structs

2022-01-17 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 400634.
fwolff added a comment.

I've added the `static_cast` and an entry in the release notes. I'm not sure 
how to handle `[[no_unique_address]]`, so I'd rather leave this to future work.


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

https://reviews.llvm.org/D114292

Files:
  clang-tools-extra/clang-tidy/altera/StructPackAlignCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp
@@ -99,3 +99,22 @@
   struct bad_align3 instantiated { 'a', 0.001, 'b' };
 }
 
+// Make sure that we don't recommend aligning an empty struct to zero bytes 
(PR#51620)
+struct StructWithNoFields {};
+
+struct ContainsStructWithNoFields {
+  StructWithNoFields s;
+};
+
+// Make sure that an empty struct is treated like "char" for padding and 
alignment purposes
+struct ContainsStructWithNoFields2 {
+  StructWithNoFields s;
+  double d;
+  StructWithNoFields t;
+};
+// CHECK-MESSAGES: :[[@LINE-5]]:8: warning: accessing fields in struct 
'ContainsStructWithNoFields2' is inefficient due to padding; only needs 10 
bytes but is using 24 bytes [altera-struct-pack-align]
+// CHECK-MESSAGES: :[[@LINE-6]]:8: note: use "__attribute__((packed))" to 
reduce the amount of padding applied to struct 'ContainsStructWithNoFields2'
+// CHECK-MESSAGES: :[[@LINE-7]]:8: warning: accessing fields in struct 
'ContainsStructWithNoFields2' is inefficient due to poor alignment; currently 
aligned to 8 bytes, but recommended alignment is 16 bytes 
[altera-struct-pack-align]
+// CHECK-MESSAGES: :[[@LINE-8]]:8: note: use "__attribute__((aligned(16)))" to 
align struct 'ContainsStructWithNoFields2' to 16 bytes
+// CHECK-FIXES: __attribute__((packed))
+// CHECK-FIXES: __attribute__((aligned(16)));
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -83,6 +83,9 @@
 - Generalized the `modernize-use-default-member-init` check to handle 
non-default
   constructors.
 
+- Fixed nonsensical suggestion of `altera-struct-pack-align` check for empty
+  structs.
+
 New checks
 ^^
 
Index: clang-tools-extra/clang-tidy/altera/StructPackAlignCheck.cpp
===
--- clang-tools-extra/clang-tidy/altera/StructPackAlignCheck.cpp
+++ clang-tools-extra/clang-tidy/altera/StructPackAlignCheck.cpp
@@ -77,7 +77,8 @@
   uint64_t CharSize = Result.Context->getCharWidth();
   CharUnits CurrSize = Result.Context->getASTRecordLayout(Struct).getSize();
   CharUnits MinByteSize =
-  CharUnits::fromQuantity(ceil((float)TotalBitSize / CharSize));
+  CharUnits::fromQuantity(std::max(
+  ceil(static_cast(TotalBitSize) / CharSize), 1));
   CharUnits MaxAlign = CharUnits::fromQuantity(
   ceil((float)Struct->getMaxAlignment() / CharSize));
   CharUnits CurrAlign =


Index: clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/altera-struct-pack-align.cpp
@@ -99,3 +99,22 @@
   struct bad_align3 instantiated { 'a', 0.001, 'b' };
 }
 
+// Make sure that we don't recommend aligning an empty struct to zero bytes (PR#51620)
+struct StructWithNoFields {};
+
+struct ContainsStructWithNoFields {
+  StructWithNoFields s;
+};
+
+// Make sure that an empty struct is treated like "char" for padding and alignment purposes
+struct ContainsStructWithNoFields2 {
+  StructWithNoFields s;
+  double d;
+  StructWithNoFields t;
+};
+// CHECK-MESSAGES: :[[@LINE-5]]:8: warning: accessing fields in struct 'ContainsStructWithNoFields2' is inefficient due to padding; only needs 10 bytes but is using 24 bytes [altera-struct-pack-align]
+// CHECK-MESSAGES: :[[@LINE-6]]:8: note: use "__attribute__((packed))" to reduce the amount of padding applied to struct 'ContainsStructWithNoFields2'
+// CHECK-MESSAGES: :[[@LINE-7]]:8: warning: accessing fields in struct 'ContainsStructWithNoFields2' is inefficient due to poor alignment; currently aligned to 8 bytes, but recommended alignment is 16 bytes [altera-struct-pack-align]
+// CHECK-MESSAGES: :[[@LINE-8]]:8: note: use "__attribute__((aligned(16)))" to align struct 'ContainsStructWithNoFields2' to 16 bytes
+// CHECK-FIXES: __attribute__((packed))
+// CHECK-FIXES: __attribute__((aligned(16)));
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-

[PATCH] D113507: [clang-tidy] Include constructor initializers in `bugprone-exception-escape` check

2022-01-17 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 400668.

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

https://reviews.llvm.org/D113507

Files:
  clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
  clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
@@ -288,6 +288,49 @@
   return recursion_helper(n);
 }
 
+struct super_throws {
+  super_throws() noexcept(false) { throw 42; }
+};
+
+struct sub_throws : super_throws {
+  sub_throws() noexcept : super_throws() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in 
function 'sub_throws' which should not throw exceptions
+};
+
+struct super_throws_again {
+  super_throws_again() throw(int);
+};
+
+struct sub_throws_again : super_throws_again {
+  sub_throws_again() noexcept : super_throws_again() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in 
function 'sub_throws_again' which should not throw exceptions
+};
+
+struct init_member_throws {
+  super_throws s;
+
+  init_member_throws() noexcept : s() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in 
function 'init_member_throws' which should not throw exceptions
+};
+
+struct implicit_init_member_throws {
+  super_throws s;
+
+  implicit_init_member_throws() noexcept {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in 
function 'implicit_init_member_throws' which should not throw exceptions
+};
+
+struct init {
+  explicit init(int, int) noexcept(false) { throw 42; }
+};
+
+struct in_class_init_throws {
+  init i{1, 2};
+
+  in_class_init_throws() noexcept {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in 
function 'in_class_init_throws' which should not throw exceptions
+};
+
 int main() {
   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in 
function 'main' which should not throw exceptions
   throw 1;
Index: clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
===
--- clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
+++ clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
@@ -119,6 +119,16 @@
 CallStack.insert(Func);
 ExceptionInfo Result =
 throwsException(Body, ExceptionInfo::Throwables(), CallStack);
+
+// For a constructor, we also have to check the initializers.
+if (const auto *Ctor = dyn_cast(Func)) {
+  for (const CXXCtorInitializer *Init : Ctor->inits()) {
+ExceptionInfo Excs = throwsException(
+Init->getInit(), ExceptionInfo::Throwables(), CallStack);
+Result.merge(Excs);
+  }
+}
+
 CallStack.erase(Func);
 return Result;
   }
@@ -195,6 +205,14 @@
   ExceptionInfo Excs = throwsException(Func, CallStack);
   Results.merge(Excs);
 }
+  } else if (const auto *Construct = dyn_cast(St)) {
+ExceptionInfo Excs =
+throwsException(Construct->getConstructor(), CallStack);
+Results.merge(Excs);
+  } else if (const auto *DefaultInit = dyn_cast(St)) {
+ExceptionInfo Excs =
+throwsException(DefaultInit->getExpr(), Caught, CallStack);
+Results.merge(Excs);
   } else {
 for (const Stmt *Child : St->children()) {
   ExceptionInfo Excs = throwsException(Child, Caught, CallStack);


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp
@@ -288,6 +288,49 @@
   return recursion_helper(n);
 }
 
+struct super_throws {
+  super_throws() noexcept(false) { throw 42; }
+};
+
+struct sub_throws : super_throws {
+  sub_throws() noexcept : super_throws() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in function 'sub_throws' which should not throw exceptions
+};
+
+struct super_throws_again {
+  super_throws_again() throw(int);
+};
+
+struct sub_throws_again : super_throws_again {
+  sub_throws_again() noexcept : super_throws_again() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in function 'sub_throws_again' which should not throw exceptions
+};
+
+struct init_member_throws {
+  super_throws s;
+
+  init_member_throws() noexcept : s() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in function 'init_member_throws' which should not throw exceptions
+};
+
+struct implicit_init_member_throws {
+  super_throws s;
+
+  implicit_init_member_throws() noexcept {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: wa

[PATCH] D113507: [clang-tidy] Include constructor initializers in `bugprone-exception-escape` check

2022-01-17 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff marked an inline comment as done.
fwolff added inline comments.



Comment at: 
clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp:291-293
+struct super_throws {
+  super_throws() noexcept(false) { throw 42; }
+};

aaron.ballman wrote:
> I think this needs additional test coverage.
> 
> Dynamic exception specifications:
> ```
> struct super_throws_again {
>   super_throws_again() throw(int);
> };
> 
> struct sub_throws_again : super_throws_again {
>   sub_throws_again() noexcept : super_throws_again() {}
> };
> ```
> Non-base class explicit inits:
> ```
> struct init_member_throws {
>   super_throws s;
> 
>   init_member_throws() noexcept : s() {}
> };
> ```
> Non-base class implicit inits:
> ```
> struct init_member_throws {
>   super_throws s;
> 
>   init_member_throws() noexcept {}
> };
> ```
> In-class initializers (IIRC those are modeled as a ctor init):
> ```
> struct init {
>   explicit init(int, int) noexcept(false);
> };
> 
> struct in_class_init_throws {
>   init i{1, 2};
> };
> ```
> I *think* all of these will wind up being covered by the code changes, but we 
> should test them to be sure.
Thanks a lot for your suggestions! I have added these tests, as well as some 
special handling for `CXXDefaultInitExpr`, which was necessary to get the last 
one to pass.


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

https://reviews.llvm.org/D113507

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


[PATCH] D113518: [clang][Sema] Create delegating constructors even in templates

2022-01-17 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff added a comment.

@aaron.ballman Ping? I think I've responded to all comments so far; let me know 
if you still have concerns.


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

https://reviews.llvm.org/D113518

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


[PATCH] D113804: [clang-tidy] Fix behavior of `modernize-use-using` with nested structs/unions

2022-01-17 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 400677.
fwolff added a comment.

Rebased and ping @whisperity


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

https://reviews.llvm.org/D113804

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

Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp
@@ -302,3 +302,19 @@
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
   // CHECK-FIXES: using b = InjectedClassNameWithUnnamedArgument;
 };
+
+// clang-format off
+
+typedef struct { int a; union { int b; }; } PR50990;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using PR50990 = struct { int a; union { int b; }; };
+
+typedef struct { struct { int a; struct { struct { int b; } c; int d; } e; } f; int g; } PR50990_nested;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using PR50990_nested = struct { struct { int a; struct { struct { int b; } c; int d; } e; } f; int g; };
+
+typedef struct { struct { int a; } b; union { int c; float d; struct { int e; }; }; struct { double f; } g; } PR50990_siblings;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using PR50990_siblings = struct { struct { int a; } b; union { int c; float d; struct { int e; }; }; struct { double f; } g; };
+
+// clang-format on
Index: clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
===
--- clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
+++ clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
@@ -23,7 +23,8 @@
 
   const bool IgnoreMacros;
   SourceLocation LastReplacementEnd;
-  SourceRange LastTagDeclRange;
+  llvm::DenseMap LastTagDeclRanges;
+
   std::string FirstTypedefType;
   std::string FirstTypedefName;
 
Index: clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
===
--- clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
@@ -16,6 +16,10 @@
 namespace tidy {
 namespace modernize {
 
+static constexpr llvm::StringLiteral ParentDeclName = "parent-decl";
+static constexpr llvm::StringLiteral TagDeclName = "tag-decl";
+static constexpr llvm::StringLiteral TypedefName = "typedef";
+
 UseUsingCheck::UseUsingCheck(StringRef Name, ClangTidyContext *Context)
 : ClangTidyCheck(Name, Context),
   IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)) {}
@@ -25,23 +29,45 @@
 }
 
 void UseUsingCheck::registerMatchers(MatchFinder *Finder) {
-  Finder->addMatcher(typedefDecl(unless(isInstantiated())).bind("typedef"),
+  Finder->addMatcher(typedefDecl(unless(isInstantiated()),
+ hasParent(decl().bind(ParentDeclName)))
+ .bind(TypedefName),
  this);
-  // This matcher used to find tag declarations in source code within typedefs.
-  // They appear in the AST just *prior* to the typedefs.
-  Finder->addMatcher(tagDecl(unless(isImplicit())).bind("tagdecl"), this);
+
+  // This matcher is used to find tag declarations in source code within
+  // typedefs. They appear in the AST just *prior* to the typedefs.
+  Finder->addMatcher(
+  tagDecl(
+  anyOf(allOf(unless(anyOf(isImplicit(),
+   classTemplateSpecializationDecl())),
+  hasParent(decl().bind(ParentDeclName))),
+// We want the parent of the ClassTemplateDecl, not the parent
+// of the specialization.
+classTemplateSpecializationDecl(hasAncestor(classTemplateDecl(
+hasParent(decl().bind(ParentDeclName)))
+  .bind(TagDeclName),
+  this);
 }
 
 void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *ParentDecl = Result.Nodes.getNodeAs(ParentDeclName);
+  if (!ParentDecl)
+return;
+
   // Match CXXRecordDecl only to store the range of the last non-implicit full
   // declaration, to later check whether it's within the typdef itself.
-  const auto *MatchedTagDecl = Result.Nodes.getNodeAs("tagdecl");
+  const auto *MatchedTagDecl = Result.Nodes.getNodeAs(TagDeclName);
   if (MatchedTagDecl) {
-LastTagDeclRange = MatchedTagDecl->getSourceRange();
+// It is not sufficient to just track the last TagDecl that we've seen,
+// because if one struct or union is nested inside another, the last TagDecl
+// before the typedef will be the nested one (PR#50990). Therefore, we also
+

[PATCH] D113863: [clang-tidy] Make `readability-container-data-pointer` more robust

2022-01-17 Thread Fabian Wolff via Phabricator via cfe-commits
fwolff updated this revision to Diff 400680.
fwolff added a comment.

Fixed the nits. Thanks for the review @aaron.ballman!


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

https://reviews.llvm.org/D113863

Files:
  clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-container-data-pointer.cpp
@@ -109,3 +109,38 @@
   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
   // CHECK-FIXES: {{^  }}return v.data();{{$}}
 }
+
+template 
+struct container_without_data {
+  using size_type = size_t;
+  T &operator[](size_type);
+  const T &operator[](size_type) const;
+};
+
+template 
+const T *n(const container_without_data &c) {
+  // c has no "data" member function, so there should not be a warning here:
+  return &c[0];
+}
+
+const int *o(const std::vector>> &v, const size_t idx1, const size_t idx2) {
+  return &v[idx1][idx2][0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return v[idx1][idx2].data();{{$}}
+}
+
+std::vector &select(std::vector &u, std::vector &v) {
+  return v;
+}
+
+int *p(std::vector &v1, std::vector &v2) {
+  return &select(*&v1, v2)[0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return select(*&v1, v2).data();{{$}}
+}
+
+int *q(std::vector ***v) {
+  return &(***v)[0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
+  // CHECK-FIXES: {{^  }}return (**v)->data();{{$}}
+}
Index: clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp
@@ -16,6 +16,13 @@
 namespace clang {
 namespace tidy {
 namespace readability {
+
+constexpr llvm::StringLiteral ContainerExprName = "container-expr";
+constexpr llvm::StringLiteral DerefContainerExprName = "deref-container-expr";
+constexpr llvm::StringLiteral AddrOfContainerExprName =
+"addr-of-container-expr";
+constexpr llvm::StringLiteral AddressOfName = "address-of";
+
 ContainerDataPointerCheck::ContainerDataPointerCheck(StringRef Name,
  ClangTidyContext *Context)
 : ClangTidyCheck(Name, Context) {}
@@ -38,69 +45,63 @@
   const auto Container =
   qualType(anyOf(NonTemplateContainerType, TemplateContainerType));
 
+  const auto ContainerExpr = anyOf(
+  unaryOperator(
+  hasOperatorName("*"),
+  hasUnaryOperand(
+  expr(hasType(pointsTo(Container))).bind(DerefContainerExprName)))
+  .bind(ContainerExprName),
+  unaryOperator(hasOperatorName("&"),
+hasUnaryOperand(expr(anyOf(hasType(Container),
+   hasType(references(Container
+.bind(AddrOfContainerExprName)))
+  .bind(ContainerExprName),
+  expr(anyOf(hasType(Container), hasType(pointsTo(Container)),
+ hasType(references(Container
+  .bind(ContainerExprName));
+
+  const auto Zero = integerLiteral(equals(0));
+
+  const auto SubscriptOperator = callee(cxxMethodDecl(hasName("operator[]")));
+
   Finder->addMatcher(
   unaryOperator(
   unless(isExpansionInSystemHeader()), hasOperatorName("&"),
-  hasUnaryOperand(anyOf(
-  ignoringParenImpCasts(
-  cxxOperatorCallExpr(
-  callee(cxxMethodDecl(hasName("operator[]"))
- .bind("operator[]")),
-  argumentCountIs(2),
-  hasArgument(
-  0,
-  anyOf(ignoringParenImpCasts(
-declRefExpr(
-to(varDecl(anyOf(
-hasType(Container),
-hasType(references(Container))
-.bind("var")),
-