[PATCH] D52315: [clang-tidy] Fix for performance-unnecessary-value-param, performance-unnecessary-copy-initialization and performance-for-range-copy

2018-09-20 Thread Felix Berger via Phabricator via cfe-commits
flx added inline comments.



Comment at: clang-tidy/utils/TypeTraits.cpp:49
+  if (Context.getTypeSize(Type) <= Context.getTypeSize(Context.VoidPtrTy))
+return false;
+

This early return now ignores the fact that the type has non-trivial copy 
constructors, virtual destructors etc which makes the type expensive to copy. 
Could we achieve the same desired outcome by adding a blacklist that allows 
users exclude types they deem to be not expensive?

This way they would get a warning the first time they run the check and then 
could disable such types. 


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D52315



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


[PATCH] D52360: [clang-tidy] Fix for performance-unnecessary-value-param, performance-unnecessary-copy-initialization and performance-for-range-copy

2018-09-26 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

In https://reviews.llvm.org/D52360#1246472, @baloghadamsoftware wrote:

> In https://reviews.llvm.org/D52360#1246443, @danilaml wrote:
>
> > Would that also skip checks for something like `shared_ptr`?
>
>
> Yes, everything ending on `pointer`, `ptr`, `reference` or `ref`, first 
> letter case insensitive.


std::shared_ptr should not be blacklisted. It is not free to copy it: It incurs 
two atomic operations and two branches.

Users should blacklist it if they know they don't care about this or not use 
the check.

While it looks weird for the check to suggest to pass std::shared_ptr by 
reference it is correct. A better change would be to just pass the raw pointer 
in this case:

std::shared_ptr p;
PassByRawPointer(p.get());

But this would require function signature change that breaks callers outside of 
the translation unit.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D52360



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


[PATCH] D79440: Fix ForRangeCopyCheck not triggering on iterators returning elements by value in C++17.

2020-05-05 Thread Felix Berger via Phabricator via cfe-commits
flx created this revision.
flx added a reviewer: gribozavr2.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

The AST is different in C++17 in that there is no MaterializeTemporaryExpr for 
in the AST for a loop variable that is initialized from an iterator that 
returns its elements by value.

Account for this by checking that the variable is not initialized by an 
operator* call that returns a value type.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D79440

Files:
  clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
@@ -28,6 +28,7 @@
 };
 template 
 struct View {
+  View() = default;
   T begin() { return T(); }
   T begin() const { return T(); }
   T end() { return T(); }
@@ -270,3 +271,27 @@
   for (auto _ : View>()) {
   }
 }
+
+template  struct ValueReturningIterator {
+  void operator++() {}
+  T operator*() { return T(); }
+  bool operator!=(const ValueReturningIterator &) { return false; }
+  typedef const T &const_reference;
+};
+
+void negativeValueIterator() {
+  // Check does not trigger for iterators that return elements by value.
+  for (const S SS : View>()) {
+  }
+}
+
+View> createView(S) { return View>(); }
+
+void positiveValueIteratorUsedElseWhere() {
+  for (const S SS : createView(*ValueReturningIterator())) {
+// CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is not
+// a reference type; this creates a copy in each iteration; consider making
+// this a reference [performance-for-range-copy] CHECK-FIXES: for (const S&
+// SS : createView(*ValueReturningIterator())) {
+  }
+}
Index: clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
===
--- clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
+++ clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
@@ -37,12 +37,18 @@
   // Match loop variables that are not references or pointers or are already
   // initialized through MaterializeTemporaryExpr which indicates a type
   // conversion.
-  auto LoopVar = varDecl(
-  hasType(qualType(
-  unless(anyOf(hasCanonicalType(anyOf(referenceType(), pointerType())),
-   hasDeclaration(namedDecl(
-   matchers::matchesAnyListedName(AllowedTypes))),
-  unless(hasInitializer(expr(hasDescendant(materializeTemporaryExpr());
+  auto HasReferenceOrPointerTypeOrIsAllowed = hasType(qualType(
+  unless(anyOf(hasCanonicalType(anyOf(referenceType(), pointerType())),
+   hasDeclaration(namedDecl(
+   matchers::matchesAnyListedName(AllowedTypes)));
+  auto IteratorReturnsValueType = cxxOperatorCallExpr(
+  hasOverloadedOperatorName("*"),
+  callee(
+  cxxMethodDecl(returns(unless(hasCanonicalType(referenceType()));
+  auto LoopVar =
+  varDecl(HasReferenceOrPointerTypeOrIsAllowed,
+  unless(hasInitializer(expr(hasDescendant(expr(anyOf(
+  materializeTemporaryExpr(), IteratorReturnsValueType)));
   Finder->addMatcher(cxxForRangeStmt(hasLoopVariable(LoopVar.bind("loopVar")))
  .bind("forRange"),
  this);


Index: clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
@@ -28,6 +28,7 @@
 };
 template 
 struct View {
+  View() = default;
   T begin() { return T(); }
   T begin() const { return T(); }
   T end() { return T(); }
@@ -270,3 +271,27 @@
   for (auto _ : View>()) {
   }
 }
+
+template  struct ValueReturningIterator {
+  void operator++() {}
+  T operator*() { return T(); }
+  bool operator!=(const ValueReturningIterator &) { return false; }
+  typedef const T &const_reference;
+};
+
+void negativeValueIterator() {
+  // Check does not trigger for iterators that return elements by value.
+  for (const S SS : View>()) {
+  }
+}
+
+View> createView(S) { return View>(); }
+
+void positiveValueIteratorUsedElseWhere() {
+  for (const S SS : createView(*ValueReturningIterator())) {
+// CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is not
+// a reference type; this creates a copy in each iteration; consider making
+// this a reference [performance-for-range-copy] CHECK-FIXES: for (const S&
+// SS : createView(*ValueReturningIterator())) {
+  }
+}
Index: clang-tools-extra/cla

[PATCH] D106173: [clang-tidy] performance-unnecessary-copy-initialization: Create option to exclude container types from triggering the check.

2021-07-16 Thread Felix Berger via Phabricator via cfe-commits
flx created this revision.
flx added reviewers: aaron.ballman, ymandel, gribozavr2.
Herald added a subscriber: xazax.hun.
flx requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

Add string list option of type names analagous to `AllowedTypes` which lets
users specify a list of ExcludedContainerTypes.

Types matching this list will not trigger the check when an expensive variable
is copy initialized from a const accessor method they provide, i.e.:

  ExcludedContainerTypes = 'ExcludedType'
  
  void foo() {
ExcludedType Container;
const ExpensiveToCopy NecessaryCopy = Container.get();
  }

Even though an expensive to copy variable is copy initialized the check does not
trigger because the container type is excluded.

This is useful for container types that don't own their data, such as view types
where modification of the returned references in other places cannot be reliably
tracked, or const incorrect types.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D106173

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
  
clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst

Index: clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
===
--- clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
+++ clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
@@ -47,3 +47,15 @@
is empty. If a name in the list contains the sequence `::` it is matched
against the qualified typename (i.e. `namespace::Type`, otherwise it is
matched against only the type name (i.e. `Type`).
+
+.. option:: ExcludedContainerTypes
+
+   A semicolon-separated list of names of types whose methods are not allowed to
+   return the const reference the variable is copied from. When an expensive to
+   copy variable is copy initialized by the return value from a type on this
+   list the check does not trigger. This can be used to exclude types known to
+   be const incorrect or where the lifetime or immutability of returned
+   references is not tied to mutations of the container. An example are view
+   types that don't own the underlying data. As for `AllowedTypes` above regular
+   expressions are accepted and the inclusion of `::` determines whether the
+   qualified typename is matched or not.
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
@@ -43,6 +43,7 @@
   const Stmt &BlockStmt, const DeclStmt &Stmt,
   bool IssueFix, ASTContext &Context);
   const std::vector AllowedTypes;
+  const std::vector ExcludedContainerTypes;
 };
 
 } // namespace performance
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -73,7 +73,8 @@
   }
 }
 
-AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningMethodCall) {
+AST_MATCHER_FUNCTION_P(StatementMatcher, isConstRefReturningMethodCall,
+   std::vector, ExcludedContainerTypes) {
   // Match method call expressions where the `this` argument is only used as
   // const, this will be checked in `check()` part. This returned const
   // reference is highly likely to outlive the local const reference of the
@@ -82,7 +83,11 @@
   // called object.
   return cxxMemberCallExpr(
   callee(cxxMethodDecl(returns(matchers::isReferenceToConst(,
-  on(declRefExpr(to(varDecl().bind(ObjectArgId);
+  on(declRefExpr(to(
+  varDecl(
+  unless(hasType(qualType(hasCanonicalType(hasDeclaration(namedDecl(
+  matchers::matchesAnyListedName(ExcludedContainerTypes
+  .bind(ObjectArgId);
 }
 
 AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningFunctionCall) {
@@ -94,11 +99,13 @@
   .bind(InitFunctionCallId);
 }
 
-AST_MATCHER_FUNCTION(StatementMatcher, initializerReturnsReferenceToConst) {
+AST_MATCHER_FUNCTION_P(StatementMatcher, initializerReturnsReferenceToConst,
+   std::vector, ExcludedContainerTypes) {
   auto OldVarDeclRef =
   declRefExpr(to(varDecl(hasLocalStorage()).bind(OldVarDeclId)));
   return expr(
-  anyOf(isConstRefReturningFunctionCall(), isConstRefReturningMethodCall(),
+  anyOf(isConstRefReturningFunct

[PATCH] D106173: [clang-tidy] performance-unnecessary-copy-initialization: Create option to exclude container types from triggering the check.

2021-07-22 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 360865.
flx added a comment.

Add test file for the new option.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D106173

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
  
clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
@@ -0,0 +1,60 @@
+// RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t -- -config="{CheckOptions: [{key: performance-unnecessary-copy-initialization.ExcludedContainerTypes, value: 'ns::ViewType$;::ConstInCorrectType$'}]}" --
+
+namespace ns {
+template 
+struct ViewType {
+  ViewType(const T &);
+  const T &view() const;
+};
+} // namespace ns
+
+template 
+struct ViewType {
+  ViewType(const T &);
+  const T &view() const;
+};
+
+struct ExpensiveToCopy {
+  ~ExpensiveToCopy();
+  void constMethod() const;
+};
+
+struct ConstInCorrectType {
+  const ExpensiveToCopy &secretlyMutates() const;
+};
+
+using NSVTE = ns::ViewType;
+typedef ns::ViewType FewType;
+
+void positiveViewType() {
+  ExpensiveToCopy E;
+  ViewType V(E);
+  const auto O = V.view();
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'O' is copy-constructed
+  // CHECK-FIXES: const auto& O = V.view();
+  O.constMethod();
+}
+
+void excludedViewTypeInNamespace() {
+  ExpensiveToCopy E;
+  ns::ViewType V(E);
+  const auto O = V.view();
+  O.constMethod();
+}
+
+void excludedViewTypeAliased() {
+  ExpensiveToCopy E;
+  NSVTE V(E);
+  const auto O = V.view();
+  O.constMethod();
+
+  FewType F(E);
+  const auto P = F.view();
+  P.constMethod();
+}
+
+void excludedConstIncorrectType() {
+  ConstInCorrectType C;
+  const auto E = C.secretlyMutates();
+  E.constMethod();
+}
Index: clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
===
--- clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
+++ clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
@@ -47,3 +47,15 @@
is empty. If a name in the list contains the sequence `::` it is matched
against the qualified typename (i.e. `namespace::Type`, otherwise it is
matched against only the type name (i.e. `Type`).
+
+.. option:: ExcludedContainerTypes
+
+   A semicolon-separated list of names of types whose methods are allowed to
+   return the const reference the variable is copied from. When an expensive to
+   copy variable is copy initialized by the return value from a type on this
+   list the check does not trigger. This can be used to exclude types known to
+   be const incorrect or where the lifetime or immutability of returned
+   references is not tied to mutations of the container. An example are view
+   types that don't own the underlying data. Like for `AllowedTypes` above,
+   regular expressions are accepted and the inclusion of `::` determines whether
+   the qualified typename is matched or not.
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
@@ -43,6 +43,7 @@
   const Stmt &BlockStmt, const DeclStmt &Stmt,
   bool IssueFix, ASTContext &Context);
   const std::vector AllowedTypes;
+  const std::vector ExcludedContainerTypes;
 };
 
 } // namespace performance
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -73,7 +73,8 @@
   }
 }
 
-AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningMethodCall) {
+AST_MATCHER_FUNCTION_P(StatementMatcher, isConstRefReturningMethodCall,
+   std::vector, ExcludedContainerTypes) {
   // Match method call expressions where the `this` argument is only used as
   // const, this will be checked in `check()` part. This returned const
   // reference is highly likely to outlive the local const reference of the
@@ -82,7 +83,11 @@

[PATCH] D106173: [clang-tidy] performance-unnecessary-copy-initialization: Create option to exclude container types from triggering the check.

2021-07-22 Thread Felix Berger via Phabricator via cfe-commits
flx marked an inline comment as done.
flx added a comment.

I also added a file testing the new option.




Comment at: 
clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst:53
+
+   A semicolon-separated list of names of types whose methods are not allowed 
to
+   return the const reference the variable is copied from. When an expensive to

ymandel wrote:
> should this "not" be here?
Yeah, that makes it more clear. Done.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D106173

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


[PATCH] D106011: [clang-tidy] performance-unnecessary-copy-initialization: Disable check when variable and initializer have different replaced template param types.

2021-07-22 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 360868.
flx added a comment.

Addressed review feedback.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D106011

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -17,6 +17,9 @@
   Iterator end() const;
   void nonConstMethod();
   bool constMethod() const;
+  template 
+  const A &templatedAccessor() const;
+  operator int() const; // Implicit conversion to int.
 };
 
 struct TrivialToCopyType {
@@ -659,3 +662,54 @@
   C.constMethod();
   D.constMethod();
 }
+
+template 
+const A &templatedReference();
+
+template 
+void negativeTemplateTypes() {
+  A Orig;
+  // Different replaced template type params do not trigger the check. In some
+  // template instantiation this might not be a copy but an implicit
+  // conversion, so converting this to a reference might not work.
+  B AmbiguousCopy = Orig;
+  // CHECK-NOT-FIXES: B AmbiguousCopy = Orig;
+
+  B NecessaryCopy = templatedReference();
+  // CHECK-NOT-FIXES: B NecessaryCopy = templatedReference();
+
+  B NecessaryCopy2 = Orig.template templatedAccessor();
+
+  // Non-dependent types in template still trigger the check.
+  const auto UnnecessaryCopy = ExpensiveTypeReference();
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' is copy-constructed
+  // CHECK-FIXES: const auto& UnnecessaryCopy = ExpensiveTypeReference();
+  UnnecessaryCopy.constMethod();
+}
+
+void instantiateNegativeTemplateTypes() {
+  negativeTemplateTypes();
+  // This template instantiation would not compile if the `AmbiguousCopy` above was made a reference.
+  negativeTemplateTypes();
+}
+
+template 
+void positiveSingleTemplateType() {
+  A Orig;
+  A SingleTmplParmTypeCopy = Orig;
+  // CHECK-MESSAGES: [[@LINE-1]]:5: warning: local copy 'SingleTmplParmTypeCopy' of the variable 'Orig' is never modified
+  // CHECK-FIXES: const A& SingleTmplParmTypeCopy = Orig;
+  SingleTmplParmTypeCopy.constMethod();
+
+  A UnnecessaryCopy2 = templatedReference();
+  // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the variable 'UnnecessaryCopy2' is copy-constructed from a const reference
+  // CHECK-FIXES: const A& UnnecessaryCopy2 = templatedReference();
+  UnnecessaryCopy2.constMethod();
+
+  A UnnecessaryCopy3 = Orig.template templatedAccessor();
+  // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the variable 'UnnecessaryCopy3' is copy-constructed from a const reference
+  // CHECK-FIXES: const A& UnnecessaryCopy3 = Orig.template templatedAccessor();
+  UnnecessaryCopy3.constMethod();
+}
+
+void instantiatePositiveSingleTemplateType() { positiveSingleTemplateType(); }
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -27,6 +27,8 @@
 
 static constexpr StringRef ObjectArgId = "objectArg";
 static constexpr StringRef InitFunctionCallId = "initFunctionCall";
+static constexpr StringRef MethodDeclId = "methodDecl";
+static constexpr StringRef FunctionDeclId = "functionDecl";
 static constexpr StringRef OldVarDeclId = "oldVarDecl";
 
 void recordFixes(const VarDecl &Var, ASTContext &Context,
@@ -81,7 +83,8 @@
   // returned either points to a global static variable or to a member of the
   // called object.
   return cxxMemberCallExpr(
-  callee(cxxMethodDecl(returns(matchers::isReferenceToConst(,
+  callee(cxxMethodDecl(returns(matchers::isReferenceToConst()))
+ .bind(MethodDeclId)),
   on(declRefExpr(to(varDecl().bind(ObjectArgId);
 }
 
@@ -89,7 +92,8 @@
   // Only allow initialization of a const reference from a free function if it
   // has no arguments. Otherwise it could return an alias to one of its
   // arguments and the arguments need to be checked for const use as well.
-  return callExpr(callee(functionDecl(returns(matchers::isReferenceToConst(,
+  return callExpr(callee(functionDecl(returns(matchers::isReferenceToConst()))
+ .bind(FunctionDeclId)),
   argumentCountIs(0), unless(callee(cxxMethodDecl(
   .bind(InitFunctionCallId);
 }
@@ -155,6 +159,45 @@
   return allDeclRefExprs(Var, BlockStmt, Context).empty();
 }
 
+const SubstTemplateTypeParmType *getSubstitutedType(const QualType &Type,
+  

[PATCH] D106011: [clang-tidy] performance-unnecessary-copy-initialization: Disable check when variable and initializer have different replaced template param types.

2021-07-22 Thread Felix Berger via Phabricator via cfe-commits
flx added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp:178-183
+  if (VarTmplType->getReplacedParameter()->desugar().getCanonicalType() !=
+  InitializerTmplType->getReplacedParameter()
+  ->desugar()
+  .getCanonicalType()) {
+return true;
+  }

ymandel wrote:
> nit: maybe just return the condition (instead of using if(...) return true)? 
> that is
> return VarTmpType->... != ...
Done. Was left over from when there were debug statements there ;)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D106011

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


[PATCH] D106011: [clang-tidy] performance-unnecessary-copy-initialization: Disable check when variable and initializer have different replaced template param types.

2021-07-22 Thread Felix Berger via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG00edae9203c9: [clang-tidy] 
performance-unnecessary-copy-initialization: Disable check when… (authored by 
flx).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D106011

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -17,6 +17,9 @@
   Iterator end() const;
   void nonConstMethod();
   bool constMethod() const;
+  template 
+  const A &templatedAccessor() const;
+  operator int() const; // Implicit conversion to int.
 };
 
 struct TrivialToCopyType {
@@ -659,3 +662,54 @@
   C.constMethod();
   D.constMethod();
 }
+
+template 
+const A &templatedReference();
+
+template 
+void negativeTemplateTypes() {
+  A Orig;
+  // Different replaced template type params do not trigger the check. In some
+  // template instantiation this might not be a copy but an implicit
+  // conversion, so converting this to a reference might not work.
+  B AmbiguousCopy = Orig;
+  // CHECK-NOT-FIXES: B AmbiguousCopy = Orig;
+
+  B NecessaryCopy = templatedReference();
+  // CHECK-NOT-FIXES: B NecessaryCopy = templatedReference();
+
+  B NecessaryCopy2 = Orig.template templatedAccessor();
+
+  // Non-dependent types in template still trigger the check.
+  const auto UnnecessaryCopy = ExpensiveTypeReference();
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' is copy-constructed
+  // CHECK-FIXES: const auto& UnnecessaryCopy = ExpensiveTypeReference();
+  UnnecessaryCopy.constMethod();
+}
+
+void instantiateNegativeTemplateTypes() {
+  negativeTemplateTypes();
+  // This template instantiation would not compile if the `AmbiguousCopy` above was made a reference.
+  negativeTemplateTypes();
+}
+
+template 
+void positiveSingleTemplateType() {
+  A Orig;
+  A SingleTmplParmTypeCopy = Orig;
+  // CHECK-MESSAGES: [[@LINE-1]]:5: warning: local copy 'SingleTmplParmTypeCopy' of the variable 'Orig' is never modified
+  // CHECK-FIXES: const A& SingleTmplParmTypeCopy = Orig;
+  SingleTmplParmTypeCopy.constMethod();
+
+  A UnnecessaryCopy2 = templatedReference();
+  // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the variable 'UnnecessaryCopy2' is copy-constructed from a const reference
+  // CHECK-FIXES: const A& UnnecessaryCopy2 = templatedReference();
+  UnnecessaryCopy2.constMethod();
+
+  A UnnecessaryCopy3 = Orig.template templatedAccessor();
+  // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the variable 'UnnecessaryCopy3' is copy-constructed from a const reference
+  // CHECK-FIXES: const A& UnnecessaryCopy3 = Orig.template templatedAccessor();
+  UnnecessaryCopy3.constMethod();
+}
+
+void instantiatePositiveSingleTemplateType() { positiveSingleTemplateType(); }
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -27,6 +27,8 @@
 
 static constexpr StringRef ObjectArgId = "objectArg";
 static constexpr StringRef InitFunctionCallId = "initFunctionCall";
+static constexpr StringRef MethodDeclId = "methodDecl";
+static constexpr StringRef FunctionDeclId = "functionDecl";
 static constexpr StringRef OldVarDeclId = "oldVarDecl";
 
 void recordFixes(const VarDecl &Var, ASTContext &Context,
@@ -81,7 +83,8 @@
   // returned either points to a global static variable or to a member of the
   // called object.
   return cxxMemberCallExpr(
-  callee(cxxMethodDecl(returns(matchers::isReferenceToConst(,
+  callee(cxxMethodDecl(returns(matchers::isReferenceToConst()))
+ .bind(MethodDeclId)),
   on(declRefExpr(to(varDecl().bind(ObjectArgId);
 }
 
@@ -89,7 +92,8 @@
   // Only allow initialization of a const reference from a free function if it
   // has no arguments. Otherwise it could return an alias to one of its
   // arguments and the arguments need to be checked for const use as well.
-  return callExpr(callee(functionDecl(returns(matchers::isReferenceToConst(,
+  return callExpr(callee(functionDecl(returns(matchers::isReferenceToConst()))
+ .bind(FunctionDeclId)),
   argumentCountIs(0), unless(callee(cxxMethodDecl(
   .bind(InitFunctionCallId);
 }
@@ -155,6 +159,45 @@
   return allDeclRefExprs(Var, BlockStmt, Context

[PATCH] D106173: [clang-tidy] performance-unnecessary-copy-initialization: Create option to exclude container types from triggering the check.

2021-07-22 Thread Felix Berger via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
flx marked an inline comment as done.
Closed by commit rGcb4c12b6117a: [clang-tidy] 
performance-unnecessary-copy-initialization: Create option to… (authored by 
flx).

Changed prior to commit:
  https://reviews.llvm.org/D106173?vs=360865&id=360951#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D106173

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
  
clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
@@ -0,0 +1,60 @@
+// RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t -- -config="{CheckOptions: [{key: performance-unnecessary-copy-initialization.ExcludedContainerTypes, value: 'ns::ViewType$;::ConstInCorrectType$'}]}" --
+
+namespace ns {
+template 
+struct ViewType {
+  ViewType(const T &);
+  const T &view() const;
+};
+} // namespace ns
+
+template 
+struct ViewType {
+  ViewType(const T &);
+  const T &view() const;
+};
+
+struct ExpensiveToCopy {
+  ~ExpensiveToCopy();
+  void constMethod() const;
+};
+
+struct ConstInCorrectType {
+  const ExpensiveToCopy &secretlyMutates() const;
+};
+
+using NSVTE = ns::ViewType;
+typedef ns::ViewType FewType;
+
+void positiveViewType() {
+  ExpensiveToCopy E;
+  ViewType V(E);
+  const auto O = V.view();
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'O' is copy-constructed
+  // CHECK-FIXES: const auto& O = V.view();
+  O.constMethod();
+}
+
+void excludedViewTypeInNamespace() {
+  ExpensiveToCopy E;
+  ns::ViewType V(E);
+  const auto O = V.view();
+  O.constMethod();
+}
+
+void excludedViewTypeAliased() {
+  ExpensiveToCopy E;
+  NSVTE V(E);
+  const auto O = V.view();
+  O.constMethod();
+
+  FewType F(E);
+  const auto P = F.view();
+  P.constMethod();
+}
+
+void excludedConstIncorrectType() {
+  ConstInCorrectType C;
+  const auto E = C.secretlyMutates();
+  E.constMethod();
+}
Index: clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
===
--- clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
+++ clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
@@ -47,3 +47,15 @@
is empty. If a name in the list contains the sequence `::` it is matched
against the qualified typename (i.e. `namespace::Type`, otherwise it is
matched against only the type name (i.e. `Type`).
+
+.. option:: ExcludedContainerTypes
+
+   A semicolon-separated list of names of types whose methods are allowed to
+   return the const reference the variable is copied from. When an expensive to
+   copy variable is copy initialized by the return value from a type on this
+   list the check does not trigger. This can be used to exclude types known to
+   be const incorrect or where the lifetime or immutability of returned
+   references is not tied to mutations of the container. An example are view
+   types that don't own the underlying data. Like for `AllowedTypes` above,
+   regular expressions are accepted and the inclusion of `::` determines whether
+   the qualified typename is matched or not.
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
@@ -43,6 +43,7 @@
   const Stmt &BlockStmt, const DeclStmt &Stmt,
   bool IssueFix, ASTContext &Context);
   const std::vector AllowedTypes;
+  const std::vector ExcludedContainerTypes;
 };
 
 } // namespace performance
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -75,7 +75,8 @@
   }
 }
 
-AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningMethodCall) {
+AST_MATCHER_FUNCTION_P(StatementMatcher, isConstRefReturningMethodCall,
+   std::vector, ExcludedContainerTypes) {
   // Match method 

[PATCH] D116593: Fix `performance-unnecessary-value-param` for template specialization

2022-05-20 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

I don't have access to Windows, perhaps rebase and try again? It looks like the 
template specialization related tests are failing there though.


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

https://reviews.llvm.org/D116593

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


[PATCH] D87455: [clang-tidy] performance-unnecessary-copy-initialization: Restrict UnnecessaryCopyInitialization check to variables initialized from free functions without arguments

2020-09-14 Thread Felix Berger via Phabricator via cfe-commits
flx added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp:126
   if (OldVar == nullptr) {
+// Only allow initialization of a const reference from a free function if 
it
+// has no arguments or only default arguments. Otherwise it could return

aaron.ballman wrote:
> I'm not certain I agree with this change, but I'm also not certain I disagree 
> with it. There are more ways to alias than just default arguments (global 
> variables, etc) and the presence of a default argument is not really an 
> indication about its return value in this case. e.g.,
> ```
> const ExpensiveToCopyType &freeFunctionWithDefaultArg(int i = 12);
> ```
> (I don't see a reason why `= 12` should impact whether use of this function 
> diagnoses or not.)
> 
> Perhaps if this was tightened up a bit to care about the type of the default 
> argument it might make sense, but even that gets tricky when you consider 
> base classes, template types, etc. and doesn't cover all of the aliasing 
> cases anyway. Is there an important use case for this behavior?
This was mostly following the logic already applied to the copy constructor 
where the existing code also allowed default arguments. The idea is to not 
disallow functions with default arguments that are not overridden. 

I'll switch to not allowing any arguments. This will just exclude a few more 
cases, but better to be safe, until we might be able to verify the constness of 
all function arguments as well.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87455

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


[PATCH] D87455: [clang-tidy] performance-unnecessary-copy-initialization: Restrict UnnecessaryCopyInitialization check to variables initialized from free functions without arguments

2020-09-14 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 291584.
flx edited the summary of this revision.

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

https://reviews.llvm.org/D87455

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -23,6 +23,9 @@
 ExpensiveToCopyType global_expensive_to_copy_type;
 
 const ExpensiveToCopyType &ExpensiveTypeReference();
+const ExpensiveToCopyType &freeFunctionWithArg(const ExpensiveToCopyType &);
+const ExpensiveToCopyType &freeFunctionWithDefaultArg(
+const ExpensiveToCopyType *arg = nullptr);
 const TrivialToCopyType &TrivialTypeReference();
 
 void mutate(ExpensiveToCopyType &);
@@ -387,3 +390,18 @@
   for (const Element &E : Container()) {
   }
 }
+
+// This should not trigger the check as the argument could introduce an alias.
+void negativeInitializedFromFreeFunctionWithArg() {
+  ExpensiveToCopyType Orig;
+  const ExpensiveToCopyType Copy = freeFunctionWithArg(Orig);
+}
+
+void negativeInitializedFromFreeFunctionWithDefaultArg() {
+  const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg();
+}
+
+void negativeInitialzedFromFreeFunctionWithNonDefaultArg() {
+  ExpensiveToCopyType Orig;
+  const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig);
+}
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -29,6 +29,14 @@
   }
 }
 
+template 
+bool hasNonDefaultArgs(const Call &CallExpr, unsigned int StartIndex = 0) {
+  for (unsigned int I = StartIndex; I < CallExpr.getNumArgs(); ++I)
+if (!CallExpr.getArg(I)->isDefaultArgument())
+  return true;
+  return false;
+}
+
 } // namespace
 
 using namespace ::clang::ast_matchers;
@@ -54,7 +62,8 @@
 on(declRefExpr(to(varDecl().bind("objectArg");
   auto ConstRefReturningFunctionCall =
   callExpr(callee(functionDecl(returns(ConstReference))),
-   unless(callee(cxxMethodDecl(;
+   unless(callee(cxxMethodDecl(
+  .bind("initFunctionCall");
 
   auto localVarCopiedFrom = [this](const internal::Matcher &CopyCtorArg) {
 return compoundStmt(
@@ -96,6 +105,8 @@
   const auto *ObjectArg = Result.Nodes.getNodeAs("objectArg");
   const auto *BlockStmt = Result.Nodes.getNodeAs("blockStmt");
   const auto *CtorCall = Result.Nodes.getNodeAs("ctorCall");
+  const auto *InitFunctionCall =
+  Result.Nodes.getNodeAs("initFunctionCall");
 
   TraversalKindScope RAII(*Result.Context, ast_type_traits::TK_AsIs);
 
@@ -108,11 +119,15 @@
   // A constructor that looks like T(const T& t, bool arg = false) counts as a
   // copy only when it is called with default arguments for the arguments after
   // the first.
-  for (unsigned int i = 1; i < CtorCall->getNumArgs(); ++i)
-if (!CtorCall->getArg(i)->isDefaultArgument())
-  return;
+  if (hasNonDefaultArgs(*CtorCall, 1))
+return;
 
   if (OldVar == nullptr) {
+// Only allow initialization of a const reference from a free function if it
+// has no arguments. Otherwise it could return an alias to one of its
+// arguments and the arguments need to be checked for const use as well.
+if (InitFunctionCall != nullptr && InitFunctionCall->getNumArgs() > 0)
+  return;
 handleCopyFromMethodReturn(*NewVar, *BlockStmt, IssueFix, ObjectArg,
*Result.Context);
   } else {
@@ -127,10 +142,10 @@
   bool IsConstQualified = Var.getType().isConstQualified();
   if (!IsConstQualified && !isOnlyUsedAsConst(Var, BlockStmt, Context))
 return;
+
   if (ObjectArg != nullptr &&
   !isOnlyUsedAsConst(*ObjectArg, BlockStmt, Context))
 return;
-
   auto Diagnostic =
   diag(Var.getLocation(),
IsConstQualified ? "the const qualified variable %0 is "
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D87455: [clang-tidy] performance-unnecessary-copy-initialization: Restrict UnnecessaryCopyInitialization check to variables initialized from free functions without arguments

2020-09-14 Thread Felix Berger via Phabricator via cfe-commits
flx added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp:126
   if (OldVar == nullptr) {
+// Only allow initialization of a const reference from a free function if 
it
+// has no arguments or only default arguments. Otherwise it could return

flx wrote:
> aaron.ballman wrote:
> > I'm not certain I agree with this change, but I'm also not certain I 
> > disagree with it. There are more ways to alias than just default arguments 
> > (global variables, etc) and the presence of a default argument is not 
> > really an indication about its return value in this case. e.g.,
> > ```
> > const ExpensiveToCopyType &freeFunctionWithDefaultArg(int i = 12);
> > ```
> > (I don't see a reason why `= 12` should impact whether use of this function 
> > diagnoses or not.)
> > 
> > Perhaps if this was tightened up a bit to care about the type of the 
> > default argument it might make sense, but even that gets tricky when you 
> > consider base classes, template types, etc. and doesn't cover all of the 
> > aliasing cases anyway. Is there an important use case for this behavior?
> This was mostly following the logic already applied to the copy constructor 
> where the existing code also allowed default arguments. The idea is to not 
> disallow functions with default arguments that are not overridden. 
> 
> I'll switch to not allowing any arguments. This will just exclude a few more 
> cases, but better to be safe, until we might be able to verify the constness 
> of all function arguments as well.
This is done now.


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

https://reviews.llvm.org/D87455

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


[PATCH] D87455: [clang-tidy] performance-unnecessary-copy-initialization: Restrict UnnecessaryCopyInitialization check to variables initialized from free functions without arguments

2020-09-14 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 291610.
flx marked an inline comment as done.

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

https://reviews.llvm.org/D87455

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -23,6 +23,9 @@
 ExpensiveToCopyType global_expensive_to_copy_type;
 
 const ExpensiveToCopyType &ExpensiveTypeReference();
+const ExpensiveToCopyType &freeFunctionWithArg(const ExpensiveToCopyType &);
+const ExpensiveToCopyType &freeFunctionWithDefaultArg(
+const ExpensiveToCopyType *arg = nullptr);
 const TrivialToCopyType &TrivialTypeReference();
 
 void mutate(ExpensiveToCopyType &);
@@ -387,3 +390,18 @@
   for (const Element &E : Container()) {
   }
 }
+
+// This should not trigger the check as the argument could introduce an alias.
+void negativeInitializedFromFreeFunctionWithArg() {
+  ExpensiveToCopyType Orig;
+  const ExpensiveToCopyType Copy = freeFunctionWithArg(Orig);
+}
+
+void negativeInitializedFromFreeFunctionWithDefaultArg() {
+  const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg();
+}
+
+void negativeInitialzedFromFreeFunctionWithNonDefaultArg() {
+  ExpensiveToCopyType Orig;
+  const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig);
+}
Index: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -54,7 +54,8 @@
 on(declRefExpr(to(varDecl().bind("objectArg");
   auto ConstRefReturningFunctionCall =
   callExpr(callee(functionDecl(returns(ConstReference))),
-   unless(callee(cxxMethodDecl(;
+   unless(callee(cxxMethodDecl(
+  .bind("initFunctionCall");
 
   auto localVarCopiedFrom = [this](const internal::Matcher &CopyCtorArg) 
{
 return compoundStmt(
@@ -96,6 +97,8 @@
   const auto *ObjectArg = Result.Nodes.getNodeAs("objectArg");
   const auto *BlockStmt = Result.Nodes.getNodeAs("blockStmt");
   const auto *CtorCall = Result.Nodes.getNodeAs("ctorCall");
+  const auto *InitFunctionCall =
+  Result.Nodes.getNodeAs("initFunctionCall");
 
   TraversalKindScope RAII(*Result.Context, ast_type_traits::TK_AsIs);
 
@@ -113,6 +116,11 @@
   return;
 
   if (OldVar == nullptr) {
+// Only allow initialization of a const reference from a free function if 
it
+// has no arguments. Otherwise it could return an alias to one of its
+// arguments and the arguments need to be checked for const use as well.
+if (InitFunctionCall != nullptr && InitFunctionCall->getNumArgs() > 0)
+  return;
 handleCopyFromMethodReturn(*NewVar, *BlockStmt, IssueFix, ObjectArg,
*Result.Context);
   } else {


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -23,6 +23,9 @@
 ExpensiveToCopyType global_expensive_to_copy_type;
 
 const ExpensiveToCopyType &ExpensiveTypeReference();
+const ExpensiveToCopyType &freeFunctionWithArg(const ExpensiveToCopyType &);
+const ExpensiveToCopyType &freeFunctionWithDefaultArg(
+const ExpensiveToCopyType *arg = nullptr);
 const TrivialToCopyType &TrivialTypeReference();
 
 void mutate(ExpensiveToCopyType &);
@@ -387,3 +390,18 @@
   for (const Element &E : Container()) {
   }
 }
+
+// This should not trigger the check as the argument could introduce an alias.
+void negativeInitializedFromFreeFunctionWithArg() {
+  ExpensiveToCopyType Orig;
+  const ExpensiveToCopyType Copy = freeFunctionWithArg(Orig);
+}
+
+void negativeInitializedFromFreeFunctionWithDefaultArg() {
+  const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg();
+}
+
+void negativeInitialzedFromFreeFunctionWithNonDefaultArg() {
+  ExpensiveToCopyType Orig;
+  const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig);
+}
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/Unnecessary

[PATCH] D87455: [clang-tidy] performance-unnecessary-copy-initialization: Restrict UnnecessaryCopyInitialization check to variables initialized from free functions without arguments

2020-09-14 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

Thank you for the review, Aaron!

I don't have have commit access. Would you mind submitting it?


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

https://reviews.llvm.org/D87455

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


[PATCH] D87455: Restrict UnnecessaryCopyInitialization check to variables initialized from methods/functions without arguments

2020-09-10 Thread Felix Berger via Phabricator via cfe-commits
flx created this revision.
flx added reviewers: alexfh, sbenza.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
flx requested review of this revision.

This restriction avoids cases where an alias is returned to an argument and 
which could lead to to a false positive change. Example:

  struct S {
S(const S&);
void modify();
  };
  
  const S& alias(const S& a) {
return a;
  }
  
  void f(S a) {
const S c = alias(a);
a.modify();
  }

Taking a const reference of the return value of alias would not be safe since a 
is modified.

Still allow methods and functions with default arguments if they are called 
with their default arguments.

A more involved alternative approach would be to inspect each argument passed 
to these functions for its constness, but this can get complex quickly.

As I'm writing this I'm realizing though that this precludes catching repeated 
protobuff messages:

  Message m;
  const auto field = m.repeated_field(0);

Maybe this approach should be refined to allowing functions and methods that 
take all parameters by value?


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D87455

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -6,6 +6,8 @@
   const ExpensiveToCopyType &reference() const;
   void nonConstMethod();
   bool constMethod() const;
+  const ExpensiveToCopyType &methodWithArg(const ExpensiveToCopyType &) const;
+  const ExpensiveToCopyType &methodWithDefaultArg(int arg = 0) const;
 };
 
 struct TrivialToCopyType {
@@ -23,6 +25,9 @@
 ExpensiveToCopyType global_expensive_to_copy_type;
 
 const ExpensiveToCopyType &ExpensiveTypeReference();
+const ExpensiveToCopyType &freeFunctionWithArg(const ExpensiveToCopyType &);
+const ExpensiveToCopyType &freeFunctionWithDefaultArg(
+const ExpensiveToCopyType *arg = nullptr);
 const TrivialToCopyType &TrivialTypeReference();
 
 void mutate(ExpensiveToCopyType &);
@@ -387,3 +392,38 @@
   for (const Element &E : Container()) {
   }
 }
+
+// This should not trigger the check as the argument could introduce an alias.
+void negativeInitializedFromMethodWithArg() {
+  ExpensiveToCopyType Orig;
+  const ExpensiveToCopyType Copy = Orig.methodWithArg(Orig);
+}
+
+// This should not trigger the check as the argument could introduce an alias.
+void negativeInitializedFromFreeFunctionWithArg() {
+  ExpensiveToCopyType Orig;
+  const ExpensiveToCopyType Copy = freeFunctionWithArg(Orig);
+}
+
+void positiveInitializedFromMethodWithDefaultArg() {
+  ExpensiveToCopyType Orig;
+  const ExpensiveToCopyType Copy = Orig.methodWithDefaultArg();
+  // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'Copy'
+  // CHECK-FIXES: const ExpensiveToCopyType& Copy = Orig.methodWithDefaultArg();
+}
+
+void negativeInitializedFromMethodWithNonDefaultArg() {
+  ExpensiveToCopyType Orig;
+  const ExpensiveToCopyType Copy = Orig.methodWithDefaultArg(5);
+}
+
+void positiveInitializedFromFreeFunctionWithDefaultArg() {
+  const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg();
+  // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'Copy'
+  // CHECK-FIXES: const ExpensiveToCopyType& Copy = freeFunctionWithDefaultArg();
+}
+
+void negativeInitialzedFromFreeFunctionWithNonDefaultArg() {
+  ExpensiveToCopyType Orig;
+  const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig);
+}
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
@@ -36,6 +36,7 @@
 private:
   void handleCopyFromMethodReturn(const VarDecl &Var, const Stmt &BlockStmt,
   bool IssueFix, const VarDecl *ObjectArg,
+  const CallExpr *InitCallExpr,
   ASTContext &Context);
   void handleCopyFromLocalVar(const VarDecl &NewVar, const VarDecl &OldVar,
   const Stmt &BlockStmt, bool IssueFix,
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitial

[PATCH] D87455: [clang-tidy] performance-unnecessary-copy-initialization: Restrict UnnecessaryCopyInitialization check to variables initialized from methods/functions without arguments

2020-09-10 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

The motivating false positive was the free functions `std::min`. To not limit 
the usefulness of the check I'll only disable arguments for free functions for 
now. Updated change coming.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87455

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


[PATCH] D87455: [clang-tidy] performance-unnecessary-copy-initialization: Restrict UnnecessaryCopyInitialization check to variables initialized from free functions without arguments

2020-09-10 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 291030.
flx retitled this revision from "[clang-tidy] 
performance-unnecessary-copy-initialization: Restrict 
UnnecessaryCopyInitialization check to variables initialized from 
methods/functions without arguments " to "[clang-tidy] 
performance-unnecessary-copy-initialization: Restrict 
UnnecessaryCopyInitialization check to variables initialized from free 
functions without arguments ".
flx edited the summary of this revision.

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

https://reviews.llvm.org/D87455

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -23,6 +23,9 @@
 ExpensiveToCopyType global_expensive_to_copy_type;
 
 const ExpensiveToCopyType &ExpensiveTypeReference();
+const ExpensiveToCopyType &freeFunctionWithArg(const ExpensiveToCopyType &);
+const ExpensiveToCopyType &freeFunctionWithDefaultArg(
+const ExpensiveToCopyType *arg = nullptr);
 const TrivialToCopyType &TrivialTypeReference();
 
 void mutate(ExpensiveToCopyType &);
@@ -387,3 +390,20 @@
   for (const Element &E : Container()) {
   }
 }
+
+// This should not trigger the check as the argument could introduce an alias.
+void negativeInitializedFromFreeFunctionWithArg() {
+  ExpensiveToCopyType Orig;
+  const ExpensiveToCopyType Copy = freeFunctionWithArg(Orig);
+}
+
+void positiveInitializedFromFreeFunctionWithDefaultArg() {
+  const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg();
+  // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'Copy'
+  // CHECK-FIXES: const ExpensiveToCopyType& Copy = freeFunctionWithDefaultArg();
+}
+
+void negativeInitialzedFromFreeFunctionWithNonDefaultArg() {
+  ExpensiveToCopyType Orig;
+  const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig);
+}
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -29,6 +29,14 @@
   }
 }
 
+template 
+bool hasNonDefaultArgs(const Call &CallExpr, unsigned int StartIndex = 0) {
+  for (unsigned int I = StartIndex; I < CallExpr.getNumArgs(); ++I)
+if (!CallExpr.getArg(I)->isDefaultArgument())
+  return true;
+  return false;
+}
+
 } // namespace
 
 using namespace ::clang::ast_matchers;
@@ -54,7 +62,8 @@
 on(declRefExpr(to(varDecl().bind("objectArg");
   auto ConstRefReturningFunctionCall =
   callExpr(callee(functionDecl(returns(ConstReference))),
-   unless(callee(cxxMethodDecl(;
+   unless(callee(cxxMethodDecl(
+  .bind("initFunctionCall");
 
   auto localVarCopiedFrom = [this](const internal::Matcher &CopyCtorArg) {
 return compoundStmt(
@@ -96,6 +105,8 @@
   const auto *ObjectArg = Result.Nodes.getNodeAs("objectArg");
   const auto *BlockStmt = Result.Nodes.getNodeAs("blockStmt");
   const auto *CtorCall = Result.Nodes.getNodeAs("ctorCall");
+  const auto *InitFunctionCall =
+  Result.Nodes.getNodeAs("initFunctionCall");
 
   TraversalKindScope RAII(*Result.Context, ast_type_traits::TK_AsIs);
 
@@ -108,11 +119,16 @@
   // A constructor that looks like T(const T& t, bool arg = false) counts as a
   // copy only when it is called with default arguments for the arguments after
   // the first.
-  for (unsigned int i = 1; i < CtorCall->getNumArgs(); ++i)
-if (!CtorCall->getArg(i)->isDefaultArgument())
-  return;
+  if (hasNonDefaultArgs(*CtorCall, 1))
+return;
 
   if (OldVar == nullptr) {
+// Only allow initialization of a const reference from a free function if it
+// has no arguments or only default arguments. Otherwise it could return
+// an alias to one of its arguments and the arguments need to be checked for
+// const use as well.
+if (InitFunctionCall != nullptr && hasNonDefaultArgs(*InitFunctionCall))
+  return;
 handleCopyFromMethodReturn(*NewVar, *BlockStmt, IssueFix, ObjectArg,
*Result.Context);
   } else {
@@ -127,10 +143,10 @@
   bool IsConstQualified = Var.getType().isConstQualified();
   if (!IsConstQualified && !isOnlyUsedAsConst(Var, BlockStmt, Context))
 return;
+
   if (ObjectArg != nullptr &&
   !isOnlyUsedAsConst(*ObjectArg, BlockStmt, Context))
 return;
-
   auto Diagnostic =
   diag(Var.getLocation(),
IsConstQualified ? "the const quali

[PATCH] D91893: [clang-tidy] performance-unnecessary-copy-initialization: Prevent false positives when dependent variable is modified.

2020-12-08 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 310285.
flx marked 5 inline comments as done.
flx added a comment.

Address review comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D91893

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
  clang-tools-extra/clang-tidy/utils/Matchers.h
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -476,3 +476,17 @@
   auto Copy = Orig.reference();
   Update(Copy);
 }
+
+void negativeCopiedFromReferenceToModifiedVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig;
+  const auto NecessaryCopy = Ref;
+  Orig.nonConstMethod();
+}
+
+void negativeCopiedFromGetterOfReferenceToModifiedVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig.reference();
+  const auto NecessaryCopy = Ref.reference();
+  Orig.nonConstMethod();
+}
Index: clang-tools-extra/clang-tidy/utils/Matchers.h
===
--- clang-tools-extra/clang-tidy/utils/Matchers.h
+++ clang-tools-extra/clang-tidy/utils/Matchers.h
@@ -43,6 +43,12 @@
   return referenceType(pointee(qualType(isConstQualified(;
 }
 
+// Returns QualType matcher for pointers to const.
+AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isPointerToConst) {
+  using namespace ast_matchers;
+  return pointerType(pointee(qualType(isConstQualified(;
+}
+
 AST_MATCHER_P(NamedDecl, matchesAnyListedName, std::vector,
   NameList) {
   return llvm::any_of(NameList, [&Node](const std::string &Name) {
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -58,7 +58,7 @@
   SmallPtrSet DeclRefs;
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
-  qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
+  qualType(anyOf(matchers::isReferenceToConst(),
  unless(anyOf(referenceType(), pointerType(),
   substTemplateTypeParmType();
   auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
@@ -71,6 +71,20 @@
   Matches =
   match(findAll(cxxConstructExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
+  // References and pointers to const assignments.
+  Matches =
+  match(findAll(declStmt(
+has(varDecl(hasType(qualType(matchers::isReferenceToConst())),
+hasInitializer(ignoringImpCasts(DeclRefToVar)),
+Stmt, Context);
+  extractNodesByIdTo(Matches, "declRef", DeclRefs);
+  Matches =
+  match(findAll(declStmt(has(varDecl(
+hasType(qualType(matchers::isPointerToConst())),
+hasInitializer(ignoringImpCasts(unaryOperator(
+hasOperatorName("&"), hasUnaryOperand(DeclRefToVar,
+Stmt, Context);
+  extractNodesByIdTo(Matches, "declRef", DeclRefs);
   return DeclRefs;
 }
 
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -19,6 +19,14 @@
 namespace performance {
 namespace {
 
+using namespace ::clang::ast_matchers;
+using llvm::StringRef;
+using utils::decl_ref_expr::isOnlyUsedAsConst;
+
+static constexpr StringRef ObjectArgId = "objectArg";
+static constexpr StringRef InitFunctionCallId = "initFunctionCall";
+static constexpr StringRef OldVarDeclId = "oldVarDecl";
+
 void recordFixes(const VarDecl &Var, ASTContext &Context,
  DiagnosticBuilder &Diagnostic) {
   Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context);
@@ -29,10 +37,88 @@
   }
 }
 
-} // namespace
+AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningMethodCall) {
+  // Match method call expressions where the `this` argument is only used as
+  // const, this will be checked in `check()` part. This returned const
+  // reference is highly likely to outlive the local const reference of the
+  // variable being declared. The assumption is that the const reference being
+  // returned either points to a global static variable or to a member of the
+  // called object.

[PATCH] D91893: [clang-tidy] performance-unnecessary-copy-initialization: Prevent false positives when dependent variable is modified.

2020-12-08 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

Thanks for the review, Aaron! I appreciate it. Please let me know if you have 
any questions about the test cases.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D91893

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


[PATCH] D91893: [clang-tidy] performance-unnecessary-copy-initialization: Prevent false positives when dependent variable is modified.

2020-12-10 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 310888.
flx added a comment.

Added positive variants of new tests.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D91893

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
  clang-tools-extra/clang-tidy/utils/Matchers.h
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -476,3 +476,35 @@
   auto Copy = Orig.reference();
   Update(Copy);
 }
+
+void negativeCopiedFromReferenceToModifiedVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig;
+  const auto NecessaryCopy = Ref;
+  Orig.nonConstMethod();
+}
+
+void positiveCopiedFromReferenceToConstVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig;
+  const auto UnnecessaryCopy = Ref;
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: local copy 'UnnecessaryCopy' of
+  // CHECK-FIXES: const auto& UnnecessaryCopy = Ref;
+  Orig.constMethod();
+}
+
+void negativeCopiedFromGetterOfReferenceToModifiedVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig.reference();
+  const auto NecessaryCopy = Ref.reference();
+  Orig.nonConstMethod();
+}
+
+void positiveCopiedFromGetterOfReferenceToConstVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig.reference();
+  auto UnnecessaryCopy = Ref.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'UnnecessaryCopy' is
+  // CHECK-FIXES: const auto& UnnecessaryCopy = Ref.reference();
+  Orig.constMethod();
+}
Index: clang-tools-extra/clang-tidy/utils/Matchers.h
===
--- clang-tools-extra/clang-tidy/utils/Matchers.h
+++ clang-tools-extra/clang-tidy/utils/Matchers.h
@@ -43,6 +43,12 @@
   return referenceType(pointee(qualType(isConstQualified(;
 }
 
+// Returns QualType matcher for pointers to const.
+AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isPointerToConst) {
+  using namespace ast_matchers;
+  return pointerType(pointee(qualType(isConstQualified(;
+}
+
 AST_MATCHER_P(NamedDecl, matchesAnyListedName, std::vector,
   NameList) {
   return llvm::any_of(NameList, [&Node](const std::string &Name) {
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -58,7 +58,7 @@
   SmallPtrSet DeclRefs;
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
-  qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
+  qualType(anyOf(matchers::isReferenceToConst(),
  unless(anyOf(referenceType(), pointerType(),
   substTemplateTypeParmType();
   auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
@@ -71,6 +71,20 @@
   Matches =
   match(findAll(cxxConstructExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
+  // References and pointers to const assignments.
+  Matches =
+  match(findAll(declStmt(
+has(varDecl(hasType(qualType(matchers::isReferenceToConst())),
+hasInitializer(ignoringImpCasts(DeclRefToVar)),
+Stmt, Context);
+  extractNodesByIdTo(Matches, "declRef", DeclRefs);
+  Matches =
+  match(findAll(declStmt(has(varDecl(
+hasType(qualType(matchers::isPointerToConst())),
+hasInitializer(ignoringImpCasts(unaryOperator(
+hasOperatorName("&"), hasUnaryOperand(DeclRefToVar,
+Stmt, Context);
+  extractNodesByIdTo(Matches, "declRef", DeclRefs);
   return DeclRefs;
 }
 
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -19,6 +19,14 @@
 namespace performance {
 namespace {
 
+using namespace ::clang::ast_matchers;
+using llvm::StringRef;
+using utils::decl_ref_expr::isOnlyUsedAsConst;
+
+static constexpr StringRef ObjectArgId = "objectArg";
+static constexpr StringRef InitFunctionCallId = "initFunctionCall";
+static constexpr StringRef OldVarDeclId = "oldVarDecl";
+
 void recordFixes(const VarDecl &Var, ASTContext &Context,
  DiagnosticBu

[PATCH] D91893: [clang-tidy] performance-unnecessary-copy-initialization: Prevent false positives when dependent variable is modified.

2020-12-10 Thread Felix Berger via Phabricator via cfe-commits
flx marked an inline comment as done.
flx added inline comments.



Comment at: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp:492
+  Orig.nonConstMethod();
+}

aaron.ballman wrote:
> Making sure I understand properly, if you were calling `Orig.constMethod()` 
> then the diagnostic should be triggered, correct? Assuming so, having those 
> test cases would be useful.
Your understanding is correct. I validated the positive cases with the existing 
tests from lines 104 and 112, but those didn't have any further references to 
the original variable. I agree it's easier to understand when the negative and 
positive cases are grouped together.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D91893

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


[PATCH] D91893: [clang-tidy] performance-unnecessary-copy-initialization: Prevent false positives when dependent variable is modified.

2020-12-10 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 310997.
flx marked an inline comment as done.
flx added a comment.

Shortened isa<> expression.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D91893

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
  clang-tools-extra/clang-tidy/utils/Matchers.h
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -476,3 +476,35 @@
   auto Copy = Orig.reference();
   Update(Copy);
 }
+
+void negativeCopiedFromReferenceToModifiedVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig;
+  const auto NecessaryCopy = Ref;
+  Orig.nonConstMethod();
+}
+
+void positiveCopiedFromReferenceToConstVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig;
+  const auto UnnecessaryCopy = Ref;
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: local copy 'UnnecessaryCopy' of
+  // CHECK-FIXES: const auto& UnnecessaryCopy = Ref;
+  Orig.constMethod();
+}
+
+void negativeCopiedFromGetterOfReferenceToModifiedVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig.reference();
+  const auto NecessaryCopy = Ref.reference();
+  Orig.nonConstMethod();
+}
+
+void positiveCopiedFromGetterOfReferenceToConstVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig.reference();
+  auto UnnecessaryCopy = Ref.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'UnnecessaryCopy' is
+  // CHECK-FIXES: const auto& UnnecessaryCopy = Ref.reference();
+  Orig.constMethod();
+}
Index: clang-tools-extra/clang-tidy/utils/Matchers.h
===
--- clang-tools-extra/clang-tidy/utils/Matchers.h
+++ clang-tools-extra/clang-tidy/utils/Matchers.h
@@ -43,6 +43,12 @@
   return referenceType(pointee(qualType(isConstQualified(;
 }
 
+// Returns QualType matcher for pointers to const.
+AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isPointerToConst) {
+  using namespace ast_matchers;
+  return pointerType(pointee(qualType(isConstQualified(;
+}
+
 AST_MATCHER_P(NamedDecl, matchesAnyListedName, std::vector,
   NameList) {
   return llvm::any_of(NameList, [&Node](const std::string &Name) {
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -58,7 +58,7 @@
   SmallPtrSet DeclRefs;
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
-  qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
+  qualType(anyOf(matchers::isReferenceToConst(),
  unless(anyOf(referenceType(), pointerType(),
   substTemplateTypeParmType();
   auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
@@ -71,6 +71,20 @@
   Matches =
   match(findAll(cxxConstructExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
+  // References and pointers to const assignments.
+  Matches =
+  match(findAll(declStmt(
+has(varDecl(hasType(qualType(matchers::isReferenceToConst())),
+hasInitializer(ignoringImpCasts(DeclRefToVar)),
+Stmt, Context);
+  extractNodesByIdTo(Matches, "declRef", DeclRefs);
+  Matches =
+  match(findAll(declStmt(has(varDecl(
+hasType(qualType(matchers::isPointerToConst())),
+hasInitializer(ignoringImpCasts(unaryOperator(
+hasOperatorName("&"), hasUnaryOperand(DeclRefToVar,
+Stmt, Context);
+  extractNodesByIdTo(Matches, "declRef", DeclRefs);
   return DeclRefs;
 }
 
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -19,6 +19,14 @@
 namespace performance {
 namespace {
 
+using namespace ::clang::ast_matchers;
+using llvm::StringRef;
+using utils::decl_ref_expr::isOnlyUsedAsConst;
+
+static constexpr StringRef ObjectArgId = "objectArg";
+static constexpr StringRef InitFunctionCallId = "initFunctionCall";
+static constexpr StringRef OldVarDeclId = "oldVarDecl";
+
 void recordFixes(const VarDecl &Var, ASTContext &Context,
  

[PATCH] D91893: [clang-tidy] performance-unnecessary-copy-initialization: Prevent false positives when dependent variable is modified.

2020-12-10 Thread Felix Berger 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 rG671ad580610a: [clang-tidy] 
performance-unnecessary-copy-initialization: Prevent false… (authored by flx).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D91893

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
  clang-tools-extra/clang-tidy/utils/Matchers.h
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -476,3 +476,35 @@
   auto Copy = Orig.reference();
   Update(Copy);
 }
+
+void negativeCopiedFromReferenceToModifiedVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig;
+  const auto NecessaryCopy = Ref;
+  Orig.nonConstMethod();
+}
+
+void positiveCopiedFromReferenceToConstVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig;
+  const auto UnnecessaryCopy = Ref;
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: local copy 'UnnecessaryCopy' of
+  // CHECK-FIXES: const auto& UnnecessaryCopy = Ref;
+  Orig.constMethod();
+}
+
+void negativeCopiedFromGetterOfReferenceToModifiedVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig.reference();
+  const auto NecessaryCopy = Ref.reference();
+  Orig.nonConstMethod();
+}
+
+void positiveCopiedFromGetterOfReferenceToConstVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig.reference();
+  auto UnnecessaryCopy = Ref.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'UnnecessaryCopy' is
+  // CHECK-FIXES: const auto& UnnecessaryCopy = Ref.reference();
+  Orig.constMethod();
+}
Index: clang-tools-extra/clang-tidy/utils/Matchers.h
===
--- clang-tools-extra/clang-tidy/utils/Matchers.h
+++ clang-tools-extra/clang-tidy/utils/Matchers.h
@@ -43,6 +43,12 @@
   return referenceType(pointee(qualType(isConstQualified(;
 }
 
+// Returns QualType matcher for pointers to const.
+AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isPointerToConst) {
+  using namespace ast_matchers;
+  return pointerType(pointee(qualType(isConstQualified(;
+}
+
 AST_MATCHER_P(NamedDecl, matchesAnyListedName, std::vector,
   NameList) {
   return llvm::any_of(NameList, [&Node](const std::string &Name) {
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -58,7 +58,7 @@
   SmallPtrSet DeclRefs;
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
-  qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
+  qualType(anyOf(matchers::isReferenceToConst(),
  unless(anyOf(referenceType(), pointerType(),
   substTemplateTypeParmType();
   auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
@@ -71,6 +71,20 @@
   Matches =
   match(findAll(cxxConstructExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
+  // References and pointers to const assignments.
+  Matches =
+  match(findAll(declStmt(
+has(varDecl(hasType(qualType(matchers::isReferenceToConst())),
+hasInitializer(ignoringImpCasts(DeclRefToVar)),
+Stmt, Context);
+  extractNodesByIdTo(Matches, "declRef", DeclRefs);
+  Matches =
+  match(findAll(declStmt(has(varDecl(
+hasType(qualType(matchers::isPointerToConst())),
+hasInitializer(ignoringImpCasts(unaryOperator(
+hasOperatorName("&"), hasUnaryOperand(DeclRefToVar,
+Stmt, Context);
+  extractNodesByIdTo(Matches, "declRef", DeclRefs);
   return DeclRefs;
 }
 
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -19,6 +19,14 @@
 namespace performance {
 namespace {
 
+using namespace ::clang::ast_matchers;
+using llvm::StringRef;
+using utils::decl_ref_expr::isOnlyUsedAsConst;
+
+static constexpr StringRef ObjectArgId = "objectArg";
+static constexpr StringRef InitFunctionCallId = "initFunctionCa

[PATCH] D90042: [clang-tidy] performance-unnecessary-copy-initialization: Check for const reference arguments that are replaced template parameter type.

2020-11-11 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

In D90042#2368219 , @aaron.ballman 
wrote:

> In D90042#2360042 , @flx wrote:
>
>> In D90042#2357078 , @aaron.ballman 
>> wrote:
>>
>>> In D90042#2356265 , @flx wrote:
>>>
 In D90042#2356180 , 
 @aaron.ballman wrote:

> In D90042#2350035 , @flx wrote:
>
>> I should note that I was only able to reproduce the false positive with 
>> the actual implementation std::function and not our fake version here.
>
> Any reason not to lift enough of the actual definition to be able to 
> reproduce the issue in your test cases? Does the change in definitions 
> break other tests?

 I poured over the actual definition and couldn't find any difference wrt 
 the call operator that would explain it. I would also think that:

   template 
   void foo(T&& t) {
 std::forward(t).modify();
   }

 would be a simpler case that should trigger replacement, but it doesn't. 
 Do you have any idea what I could be missing?
>>>
>>> Perhaps silly question, but are you instantiating `foo()`?
>>
>> I think I added a full implementation of foo now, reverted the change, but 
>> am still not getting the negative case to fail. Can you spot an issue with 
>> the code?
>
> I can't, but to be honest, I'm not certain I understand how that false 
> positive could happen in the first place. That's why I was hoping to see the 
> original case -- one thing you could try is with the original code, pass `-E` 
> to preprocess to a file, and then try reducing the test case from that output 
> (either by hand or by using a tool like creduce), or did you already give 
> that a shot?

Thanks for the suggestion, I had never hear of creduce! After a bit of trial an 
error I seem to have found a more minimal example:

  namespace std {   
   
  template  class function;   
   
  template  class function {
   
  public:   
   
void operator()(b...);  
   
  };
   
  } // namespace std
   
  struct c {
   
c();
   
c(const c &);   
   
  };
   
  std::function f;   
   
  void d() {
   
c Orig; 
   
c Copy = Orig;  
   
f(Copy);
   
  }  

To be frank I can't spot a meaningful difference to the std::function copy we 
already have.

Here's also the test script I used for posterity:

  #!/bin/bash   
   

   
  trap 'exit 1' ERR 
   
  out=$(tempfile)   
   
  clang-tidy  --checks=-*,performance-unnecessary-copy-initialization 
--extra-arg=-std=c++17 full.cc > $out 
  grep "warning: local copy.*Copy" $out 
  

[PATCH] D90042: [clang-tidy] performance-unnecessary-copy-initialization: Check for const reference arguments that are replaced template parameter type.

2020-11-12 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 304831.
flx added a comment.

Fixed definition of fake std::function which now makes the bug fixed by this 
change reproducible.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D90042

Files:
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -411,14 +411,37 @@
 
 template 
 class function;
-template 
-class function {
+template 
+class function {
 public:
   function();
-  function(const function &other);
-  R operator()(Args &&...args) const;
+  function(const function &Other);
+  R operator()(ArgTypes... Args) const;
+};
+
+template 
+struct remove_reference;
+
+template 
+struct remove_reference {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &> {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &&> {
+  typedef _Tp type;
 };
 
+template 
+constexpr _Tp &&forward(typename remove_reference<_Tp>::type &__t) noexcept {
+  return static_cast<_Tp &&>(__t);
+}
+
 } // namespace __1
 } // namespace std
 
@@ -460,3 +483,19 @@
 }
 
 } // namespace fake
+
+void positiveInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is 
copy-constructed from a const reference
+  // CHECK-FIXES: const auto& Copy = Orig.reference();
+  Update(Copy);
+}
+
+void negativeInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  Update(Copy);
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -59,9 +59,13 @@
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
   qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
- unless(anyOf(referenceType(), pointerType();
+ unless(anyOf(referenceType(), pointerType(),
+  substTemplateTypeParmType();
+  auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
+  ConstReferenceOrValue,
+  substTemplateTypeParmType(hasReplacementType(ConstReferenceOrValue;
   auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
-  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue)));
+  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValueOrReplaced)));
   Matches = match(findAll(callExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   Matches =


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -411,14 +411,37 @@
 
 template 
 class function;
-template 
-class function {
+template 
+class function {
 public:
   function();
-  function(const function &other);
-  R operator()(Args &&...args) const;
+  function(const function &Other);
+  R operator()(ArgTypes... Args) const;
+};
+
+template 
+struct remove_reference;
+
+template 
+struct remove_reference {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &> {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &&> {
+  typedef _Tp type;
 };
 
+template 
+constexpr _Tp &&forward(typename remove_reference<_Tp>::type &__t) noexcept {
+  return static_cast<_Tp &&>(__t);
+}
+
 } // namespace __1
 } // namespace std
 
@@ -460,3 +483,19 @@
 }
 
 } // namespace fake
+
+void positiveInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is copy-constructed from a const reference
+  // CHECK-FIXES: const auto& Copy = Orig.reference();
+  Update(Copy);
+}
+
+void negativeInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  Update(Copy);
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprU

[PATCH] D90042: [clang-tidy] performance-unnecessary-copy-initialization: Check for const reference arguments that are replaced template parameter type.

2020-11-12 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 304833.
flx added a comment.

Remove unnecessary test code that is not needed.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D90042

Files:
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -411,12 +411,12 @@
 
 template 
 class function;
-template 
-class function {
+template 
+class function {
 public:
   function();
-  function(const function &other);
-  R operator()(Args &&...args) const;
+  function(const function &Other);
+  R operator()(ArgTypes... Args) const;
 };
 
 } // namespace __1
@@ -460,3 +460,19 @@
 }
 
 } // namespace fake
+
+void positiveInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is 
copy-constructed from a const reference
+  // CHECK-FIXES: const auto& Copy = Orig.reference();
+  Update(Copy);
+}
+
+void negativeInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  Update(Copy);
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -59,9 +59,13 @@
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
   qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
- unless(anyOf(referenceType(), pointerType();
+ unless(anyOf(referenceType(), pointerType(),
+  substTemplateTypeParmType();
+  auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
+  ConstReferenceOrValue,
+  substTemplateTypeParmType(hasReplacementType(ConstReferenceOrValue;
   auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
-  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue)));
+  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValueOrReplaced)));
   Matches = match(findAll(callExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   Matches =


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -411,12 +411,12 @@
 
 template 
 class function;
-template 
-class function {
+template 
+class function {
 public:
   function();
-  function(const function &other);
-  R operator()(Args &&...args) const;
+  function(const function &Other);
+  R operator()(ArgTypes... Args) const;
 };
 
 } // namespace __1
@@ -460,3 +460,19 @@
 }
 
 } // namespace fake
+
+void positiveInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is copy-constructed from a const reference
+  // CHECK-FIXES: const auto& Copy = Orig.reference();
+  Update(Copy);
+}
+
+void negativeInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  Update(Copy);
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -59,9 +59,13 @@
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
   qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
- unless(anyOf(referenceType(), pointerType();
+ unless(anyOf(referenceType(), pointerType(),
+  substTemplateTypeParmType();
+  auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
+  ConstReferenceOrValue,
+  substTemplateTypeParmType(hasReplacementType(ConstReferenceOrValue;
   auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
-  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue)));
+  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValueOrReplaced)));
   Matches = match(findAll(

[PATCH] D90042: [clang-tidy] performance-unnecessary-copy-initialization: Check for const reference arguments that are replaced template parameter type.

2020-11-12 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

In D90042#2391246 , @aaron.ballman 
wrote:

> In D90042#2390203 , @flx wrote:
>
>> Thanks for the suggestion, I had never hear of creduce!
>
> Glad to have introduced you to it -- it's a great tool!
>
>> After a bit of trial an error I seem to have found a more minimal example:
>>
>>   namespace std {
>>   
>>   template  class function;
>>   
>>   template  class function { 
>>   
>>   public:
>>   
>> void operator()(b...);   
>>   
>>   }; 
>>   
>>   } // namespace std 
>>   
>>   struct c { 
>>   
>> c(); 
>>   
>> c(const c &);
>>   
>>   }; 
>>   
>>   std::function f;
>>   
>>   void d() { 
>>   
>> c Orig;  
>>   
>> c Copy = Orig;   
>>   
>> f(Copy); 
>>   
>>   }  
>>
>>
>> To be frank I can't spot a meaningful difference to the std::function copy 
>> we already have.
>
> Aha, I may have spotted it. The call operators have subtly different 
> signatures and the signature we have in our test file is wrong. Note the `&&` 
> in our test file compared to what the standard defines: 
> http://eel.is/c++draft/func.wrap.func#inv which is what's causing the 
> difference here: https://godbolt.org/z/hxfM7P

Ah! That is subtle and surprising, but makes sense. I confirmed that the new 
test cases fail now before the fix is put in place. Thanks for your help!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D90042

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


[PATCH] D90042: [clang-tidy] performance-unnecessary-copy-initialization: Check for const reference arguments that are replaced template parameter type.

2020-11-12 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 304834.
flx added a comment.

Updated change description.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D90042

Files:
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -411,12 +411,12 @@
 
 template 
 class function;
-template 
-class function {
+template 
+class function {
 public:
   function();
-  function(const function &other);
-  R operator()(Args &&...args) const;
+  function(const function &Other);
+  R operator()(ArgTypes... Args) const;
 };
 
 } // namespace __1
@@ -460,3 +460,19 @@
 }
 
 } // namespace fake
+
+void positiveInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is 
copy-constructed from a const reference
+  // CHECK-FIXES: const auto& Copy = Orig.reference();
+  Update(Copy);
+}
+
+void negativeInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  Update(Copy);
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -59,9 +59,13 @@
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
   qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
- unless(anyOf(referenceType(), pointerType();
+ unless(anyOf(referenceType(), pointerType(),
+  substTemplateTypeParmType();
+  auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
+  ConstReferenceOrValue,
+  substTemplateTypeParmType(hasReplacementType(ConstReferenceOrValue;
   auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
-  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue)));
+  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValueOrReplaced)));
   Matches = match(findAll(callExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   Matches =


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -411,12 +411,12 @@
 
 template 
 class function;
-template 
-class function {
+template 
+class function {
 public:
   function();
-  function(const function &other);
-  R operator()(Args &&...args) const;
+  function(const function &Other);
+  R operator()(ArgTypes... Args) const;
 };
 
 } // namespace __1
@@ -460,3 +460,19 @@
 }
 
 } // namespace fake
+
+void positiveInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is copy-constructed from a const reference
+  // CHECK-FIXES: const auto& Copy = Orig.reference();
+  Update(Copy);
+}
+
+void negativeInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  Update(Copy);
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -59,9 +59,13 @@
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
   qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
- unless(anyOf(referenceType(), pointerType();
+ unless(anyOf(referenceType(), pointerType(),
+  substTemplateTypeParmType();
+  auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
+  ConstReferenceOrValue,
+  substTemplateTypeParmType(hasReplacementType(ConstReferenceOrValue;
   auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
-  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue)));
+  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValueOrReplaced)));
   Matches = match(findAll(callExpr(UsedAsConstR

[PATCH] D90042: [clang-tidy] performance-unnecessary-copy-initialization: Check for const reference arguments that are replaced template parameter type.

2020-11-16 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

In D90042#2397885 , @aaron.ballman 
wrote:

> LGTM, thank you for the fix!

Thanks for helping track down the difference in our definition of std::function 
:)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D90042

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


[PATCH] D90042: [clang-tidy] performance-unnecessary-copy-initialization: Check for const reference arguments that are replaced template parameter type.

2020-11-16 Thread Felix Berger via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGace9653c11c6: [clang-tidy] 
performance-unnecessary-copy-initialization: Check for const… (authored by flx).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D90042

Files:
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -411,12 +411,12 @@
 
 template 
 class function;
-template 
-class function {
+template 
+class function {
 public:
   function();
-  function(const function &other);
-  R operator()(Args &&...args) const;
+  function(const function &Other);
+  R operator()(ArgTypes... Args) const;
 };
 
 } // namespace __1
@@ -460,3 +460,19 @@
 }
 
 } // namespace fake
+
+void positiveInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is 
copy-constructed from a const reference
+  // CHECK-FIXES: const auto& Copy = Orig.reference();
+  Update(Copy);
+}
+
+void negativeInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  Update(Copy);
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -59,9 +59,13 @@
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
   qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
- unless(anyOf(referenceType(), pointerType();
+ unless(anyOf(referenceType(), pointerType(),
+  substTemplateTypeParmType();
+  auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
+  ConstReferenceOrValue,
+  substTemplateTypeParmType(hasReplacementType(ConstReferenceOrValue;
   auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
-  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue)));
+  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValueOrReplaced)));
   Matches = match(findAll(callExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   Matches =


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -411,12 +411,12 @@
 
 template 
 class function;
-template 
-class function {
+template 
+class function {
 public:
   function();
-  function(const function &other);
-  R operator()(Args &&...args) const;
+  function(const function &Other);
+  R operator()(ArgTypes... Args) const;
 };
 
 } // namespace __1
@@ -460,3 +460,19 @@
 }
 
 } // namespace fake
+
+void positiveInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is copy-constructed from a const reference
+  // CHECK-FIXES: const auto& Copy = Orig.reference();
+  Update(Copy);
+}
+
+void negativeInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  Update(Copy);
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -59,9 +59,13 @@
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
   qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
- unless(anyOf(referenceType(), pointerType();
+ unless(anyOf(referenceType(), pointerType(),
+  substTemplateTypeParmType();
+  auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
+  ConstReferenceOrValue,
+  substTemplateTypeParmType(hasReplacementType(ConstReferenceOrValue;
   auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
-  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue)));
+  DeclRefTo

[PATCH] D89332: Always allow std::function to be copied.

2020-10-13 Thread Felix Berger via Phabricator via cfe-commits
flx created this revision.
flx added a reviewer: aaron.ballman.
Herald added a project: clang.
flx requested review of this revision.

Since its call operator is const but can modify the state of its underlying
functor we cannot tell whether the copy is necessary or not.

This avoids false positives.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D89332

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -405,3 +405,23 @@
   ExpensiveToCopyType Orig;
   const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig);
 }
+
+namespace std {
+
+template 
+class function;
+template 
+class function {
+public:
+  function();
+  function(const function &other);
+  R operator()(Args... args) const;
+};
+
+} // namespace std
+
+void negativeStdFunction() {
+  std::function Orig;
+  std::function Copy = Orig;
+  int i = Orig();
+}
Index: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -19,6 +19,10 @@
 namespace performance {
 namespace {
 
+using namespace ::clang::ast_matchers;
+using ::clang::ast_matchers::internal::Matcher;
+using utils::decl_ref_expr::isOnlyUsedAsConst;
+
 void recordFixes(const VarDecl &Var, ASTContext &Context,
  DiagnosticBuilder &Diagnostic) {
   Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context);
@@ -29,10 +33,17 @@
   }
 }
 
-} // namespace
+// Always allow std::function to be copied. Since its call operator is const 
but
+// can modify the state of the underlying functor we cannot ell whether the 
copy
+// is unnecessary.
+AST_MATCHER(NamedDecl, isStdFunction) {
+  // First use the fast getName() method to avoid unnecessary calls to the
+  // slow getQualifiedNameAsString().
+  return Node.getName() == "function" &&
+ Node.getQualifiedNameAsString() == "std::function";
+}
 
-using namespace ::clang::ast_matchers;
-using utils::decl_ref_expr::isOnlyUsedAsConst;
+} // namespace
 
 UnnecessaryCopyInitialization::UnnecessaryCopyInitialization(
 StringRef Name, ClangTidyContext *Context)
@@ -57,7 +68,7 @@
unless(callee(cxxMethodDecl(
   .bind("initFunctionCall");
 
-  auto localVarCopiedFrom = [this](const internal::Matcher &CopyCtorArg) 
{
+  auto localVarCopiedFrom = [this](const Matcher &CopyCtorArg) {
 return compoundStmt(
forEachDescendant(
declStmt(
@@ -66,8 +77,9 @@
hasCanonicalType(
matchers::isExpensiveToCopy()),
unless(hasDeclaration(namedDecl(
-   matchers::matchesAnyListedName(
-   AllowedTypes)),
+   
anyOf(matchers::matchesAnyListedName(
+ AllowedTypes),
+ isStdFunction())),
unless(isImplicit()),
hasInitializer(traverse(
ast_type_traits::TK_AsIs,


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -405,3 +405,23 @@
   ExpensiveToCopyType Orig;
   const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig);
 }
+
+namespace std {
+
+template 
+class function;
+template 
+class function {
+public:
+  function();
+  function(const function &other);
+  R operator()(Args... args) const;
+};
+
+} // namespace std
+
+void negativeStdFunction() {
+  std::function Orig;
+  std::function Copy = Orig;
+  int i = Orig();
+}
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -19,6 +19,10 @@
 namespace pe

[PATCH] D89332: [clang-tidy] performance-unnecessary-copy-initialization: Always allow std::function to be copied.

2020-10-13 Thread Felix Berger via Phabricator via cfe-commits
flx added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp:52
   AllowedTypes(
   utils::options::parseStringList(Options.get("AllowedTypes", ""))) {}
 

lebedev.ri wrote:
> Just put it here?
I tried this first, but this list  is substring matched against only on the 
non-qualified type name, so std::function would not match anything and if we 
added "function" here it would match many other types that contain the word 
function.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D89332

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


[PATCH] D91893: [clang-tidy] performance-unnecessary-copy-initialization: Prevent false positives when dependent variable is modified.

2020-11-20 Thread Felix Berger via Phabricator via cfe-commits
flx created this revision.
flx added reviewers: aaron.ballman, hokein.
Herald added subscribers: cfe-commits, xazax.hun.
Herald added a project: clang.
flx requested review of this revision.

Extend the check to not only look at the variable the unnecessarily copied
variable is initialized from, but also ensure that any variable the old variable
references is not modified.

Extend DeclRefExprUtils to also count references and pointers to const assigned
from the DeclRef we check for const usages.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D91893

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
  clang-tools-extra/clang-tidy/utils/Matchers.h
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -476,3 +476,17 @@
   auto Copy = Orig.reference();
   Update(Copy);
 }
+
+void negativeCopiedFromReferenceToModifiedVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig;
+  const auto NecessaryCopy = Ref;
+  Orig.nonConstMethod();
+}
+
+void negativeCopiedFromGetterOfReferenceToModifiedVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig.reference();
+  const auto NecessaryCopy = Ref.reference();
+  Orig.nonConstMethod();
+}
Index: clang-tools-extra/clang-tidy/utils/Matchers.h
===
--- clang-tools-extra/clang-tidy/utils/Matchers.h
+++ clang-tools-extra/clang-tidy/utils/Matchers.h
@@ -43,6 +43,12 @@
   return referenceType(pointee(qualType(isConstQualified(;
 }
 
+// Returns QualType matcher for pointers to const.
+AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isPointerToConst) {
+  using namespace ast_matchers;
+  return pointerType(pointee(qualType(isConstQualified(;
+}
+
 AST_MATCHER_P(NamedDecl, matchesAnyListedName, std::vector,
   NameList) {
   return llvm::any_of(NameList, [&Node](const std::string &Name) {
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -58,7 +58,7 @@
   SmallPtrSet DeclRefs;
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
-  qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
+  qualType(anyOf(matchers::isReferenceToConst(),
  unless(anyOf(referenceType(), pointerType(),
   substTemplateTypeParmType();
   auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
@@ -71,6 +71,20 @@
   Matches =
   match(findAll(cxxConstructExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
+  // References and pointers to const assignments.
+  Matches =
+  match(findAll(declStmt(
+has(varDecl(hasType(qualType(matchers::isReferenceToConst())),
+hasInitializer(ignoringImpCasts(DeclRefToVar)),
+Stmt, Context);
+  extractNodesByIdTo(Matches, "declRef", DeclRefs);
+  Matches =
+  match(findAll(declStmt(has(varDecl(
+hasType(qualType(matchers::isPointerToConst())),
+hasInitializer(ignoringImpCasts(unaryOperator(
+hasOperatorName("&"), hasUnaryOperand(DeclRefToVar,
+Stmt, Context);
+  extractNodesByIdTo(Matches, "declRef", DeclRefs);
   return DeclRefs;
 }
 
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -7,7 +7,6 @@
 //===--===//
 
 #include "UnnecessaryCopyInitialization.h"
-
 #include "../utils/DeclRefExprUtils.h"
 #include "../utils/FixItHintUtils.h"
 #include "../utils/Matchers.h"
@@ -19,6 +18,14 @@
 namespace performance {
 namespace {
 
+using namespace ::clang::ast_matchers;
+using llvm::StringRef;
+using utils::decl_ref_expr::isOnlyUsedAsConst;
+
+static constexpr StringRef kObjectArg = "objectArg";
+static constexpr StringRef kInitFunctionCall = "initFunctionCall";
+static constexpr StringRef kOldVarDecl = "oldVarDecl";
+
 void recordFixes(const VarDecl &Var, ASTContext &Context,
  DiagnosticBuilder &Diagnostic) {
   Diagnostic << utils::fixit::chang

[PATCH] D91893: [clang-tidy] performance-unnecessary-copy-initialization: Prevent false positives when dependent variable is modified.

2020-11-20 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 306773.
flx added a comment.

Fix formatting and comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D91893

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
  clang-tools-extra/clang-tidy/utils/Matchers.h
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -476,3 +476,17 @@
   auto Copy = Orig.reference();
   Update(Copy);
 }
+
+void negativeCopiedFromReferenceToModifiedVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig;
+  const auto NecessaryCopy = Ref;
+  Orig.nonConstMethod();
+}
+
+void negativeCopiedFromGetterOfReferenceToModifiedVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig.reference();
+  const auto NecessaryCopy = Ref.reference();
+  Orig.nonConstMethod();
+}
Index: clang-tools-extra/clang-tidy/utils/Matchers.h
===
--- clang-tools-extra/clang-tidy/utils/Matchers.h
+++ clang-tools-extra/clang-tidy/utils/Matchers.h
@@ -43,6 +43,12 @@
   return referenceType(pointee(qualType(isConstQualified(;
 }
 
+// Returns QualType matcher for pointers to const.
+AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isPointerToConst) {
+  using namespace ast_matchers;
+  return pointerType(pointee(qualType(isConstQualified(;
+}
+
 AST_MATCHER_P(NamedDecl, matchesAnyListedName, std::vector,
   NameList) {
   return llvm::any_of(NameList, [&Node](const std::string &Name) {
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -58,7 +58,7 @@
   SmallPtrSet DeclRefs;
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
-  qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
+  qualType(anyOf(matchers::isReferenceToConst(),
  unless(anyOf(referenceType(), pointerType(),
   substTemplateTypeParmType();
   auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
@@ -71,6 +71,20 @@
   Matches =
   match(findAll(cxxConstructExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
+  // References and pointers to const assignments.
+  Matches =
+  match(findAll(declStmt(
+has(varDecl(hasType(qualType(matchers::isReferenceToConst())),
+hasInitializer(ignoringImpCasts(DeclRefToVar)),
+Stmt, Context);
+  extractNodesByIdTo(Matches, "declRef", DeclRefs);
+  Matches =
+  match(findAll(declStmt(has(varDecl(
+hasType(qualType(matchers::isPointerToConst())),
+hasInitializer(ignoringImpCasts(unaryOperator(
+hasOperatorName("&"), hasUnaryOperand(DeclRefToVar,
+Stmt, Context);
+  extractNodesByIdTo(Matches, "declRef", DeclRefs);
   return DeclRefs;
 }
 
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -19,6 +19,14 @@
 namespace performance {
 namespace {
 
+using namespace ::clang::ast_matchers;
+using llvm::StringRef;
+using utils::decl_ref_expr::isOnlyUsedAsConst;
+
+static constexpr StringRef kObjectArg = "objectArg";
+static constexpr StringRef kInitFunctionCall = "initFunctionCall";
+static constexpr StringRef kOldVarDecl = "oldVarDecl";
+
 void recordFixes(const VarDecl &Var, ASTContext &Context,
  DiagnosticBuilder &Diagnostic) {
   Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context);
@@ -29,10 +37,91 @@
   }
 }
 
-} // namespace
+AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningMethodCall) {
+  // Match method call expressions where the `this` argument is only used as
+  // const, this will be checked in `check()` part. This returned const
+  // reference is highly likely to outlive the local const reference of the
+  // variable being declared. The assumption is that the const reference being
+  // returned either points to a global static variable or to a member of the
+  // called object.
+  return cxxMemberCallExpr(
+  

[PATCH] D91893: [clang-tidy] performance-unnecessary-copy-initialization: Prevent false positives when dependent variable is modified.

2020-12-03 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 309361.
flx added a comment.

Fixed clang tidy warnings.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D91893

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
  clang-tools-extra/clang-tidy/utils/Matchers.h
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -476,3 +476,17 @@
   auto Copy = Orig.reference();
   Update(Copy);
 }
+
+void negativeCopiedFromReferenceToModifiedVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig;
+  const auto NecessaryCopy = Ref;
+  Orig.nonConstMethod();
+}
+
+void negativeCopiedFromGetterOfReferenceToModifiedVar() {
+  ExpensiveToCopyType Orig;
+  const auto &Ref = Orig.reference();
+  const auto NecessaryCopy = Ref.reference();
+  Orig.nonConstMethod();
+}
Index: clang-tools-extra/clang-tidy/utils/Matchers.h
===
--- clang-tools-extra/clang-tidy/utils/Matchers.h
+++ clang-tools-extra/clang-tidy/utils/Matchers.h
@@ -43,6 +43,12 @@
   return referenceType(pointee(qualType(isConstQualified(;
 }
 
+// Returns QualType matcher for pointers to const.
+AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isPointerToConst) {
+  using namespace ast_matchers;
+  return pointerType(pointee(qualType(isConstQualified(;
+}
+
 AST_MATCHER_P(NamedDecl, matchesAnyListedName, std::vector,
   NameList) {
   return llvm::any_of(NameList, [&Node](const std::string &Name) {
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -58,7 +58,7 @@
   SmallPtrSet DeclRefs;
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
-  qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
+  qualType(anyOf(matchers::isReferenceToConst(),
  unless(anyOf(referenceType(), pointerType(),
   substTemplateTypeParmType();
   auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
@@ -71,6 +71,20 @@
   Matches =
   match(findAll(cxxConstructExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
+  // References and pointers to const assignments.
+  Matches =
+  match(findAll(declStmt(
+has(varDecl(hasType(qualType(matchers::isReferenceToConst())),
+hasInitializer(ignoringImpCasts(DeclRefToVar)),
+Stmt, Context);
+  extractNodesByIdTo(Matches, "declRef", DeclRefs);
+  Matches =
+  match(findAll(declStmt(has(varDecl(
+hasType(qualType(matchers::isPointerToConst())),
+hasInitializer(ignoringImpCasts(unaryOperator(
+hasOperatorName("&"), hasUnaryOperand(DeclRefToVar,
+Stmt, Context);
+  extractNodesByIdTo(Matches, "declRef", DeclRefs);
   return DeclRefs;
 }
 
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -19,6 +19,14 @@
 namespace performance {
 namespace {
 
+using namespace ::clang::ast_matchers;
+using llvm::StringRef;
+using utils::decl_ref_expr::isOnlyUsedAsConst;
+
+static constexpr StringRef ObjectArgId = "objectArg";
+static constexpr StringRef InitFunctionCallId = "initFunctionCall";
+static constexpr StringRef OldVarDeclId = "oldVarDecl";
+
 void recordFixes(const VarDecl &Var, ASTContext &Context,
  DiagnosticBuilder &Diagnostic) {
   Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context);
@@ -29,10 +37,90 @@
   }
 }
 
-} // namespace
+AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningMethodCall) {
+  // Match method call expressions where the `this` argument is only used as
+  // const, this will be checked in `check()` part. This returned const
+  // reference is highly likely to outlive the local const reference of the
+  // variable being declared. The assumption is that the const reference being
+  // returned either points to a global static variable or to a member of the
+  // called object.
+  return cxxMemberCallExpr(
+ 

[PATCH] D91893: [clang-tidy] performance-unnecessary-copy-initialization: Prevent false positives when dependent variable is modified.

2020-12-07 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

Could someone take a first pass at this change? It would be great progress on 
this as this is the last currently known case that generates false positives.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D91893

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


[PATCH] D89332: [clang-tidy] performance-unnecessary-copy-initialization: Always allow std::function to be copied.

2020-10-16 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 298745.
flx added a comment.

Add more complete fake version of std::function.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D89332

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -405,3 +405,36 @@
   ExpensiveToCopyType Orig;
   const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig);
 }
+
+// Let's fake a minimal std::function-like facility.
+namespace std {
+template 
+_Tp declval();
+
+template 
+struct __res {
+  template 
+  static decltype(declval<_Functor>()(_Args()...)) _S_test(int);
+
+  template 
+  static void _S_test(...);
+
+  using type = decltype(_S_test<_ArgTypes...>(0));
+};
+
+template 
+struct function;
+
+template 
+struct function {
+  template ::type>
+  function(_Functor) {}
+};
+} // namespace std
+
+void negativeStdFunction() {
+  std::function Orig;
+  std::function Copy = Orig;
+  int i = Orig();
+}
Index: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -19,6 +19,10 @@
 namespace performance {
 namespace {
 
+using namespace ::clang::ast_matchers;
+using ::clang::ast_matchers::internal::Matcher;
+using utils::decl_ref_expr::isOnlyUsedAsConst;
+
 void recordFixes(const VarDecl &Var, ASTContext &Context,
  DiagnosticBuilder &Diagnostic) {
   Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context);
@@ -29,10 +33,17 @@
   }
 }
 
-} // namespace
+// Always allow std::function to be copied. Since its call operator is const 
but
+// can modify the state of the underlying functor we cannot ell whether the 
copy
+// is unnecessary.
+AST_MATCHER(NamedDecl, isStdFunction) {
+  // First use the fast getName() method to avoid unnecessary calls to the
+  // slow getQualifiedNameAsString().
+  return Node.getName() == "function" &&
+ Node.getQualifiedNameAsString() == "std::function";
+}
 
-using namespace ::clang::ast_matchers;
-using utils::decl_ref_expr::isOnlyUsedAsConst;
+} // namespace
 
 UnnecessaryCopyInitialization::UnnecessaryCopyInitialization(
 StringRef Name, ClangTidyContext *Context)
@@ -57,7 +68,7 @@
unless(callee(cxxMethodDecl(
   .bind("initFunctionCall");
 
-  auto localVarCopiedFrom = [this](const internal::Matcher &CopyCtorArg) 
{
+  auto localVarCopiedFrom = [this](const Matcher &CopyCtorArg) {
 return compoundStmt(
forEachDescendant(
declStmt(
@@ -66,8 +77,9 @@
hasCanonicalType(
matchers::isExpensiveToCopy()),
unless(hasDeclaration(namedDecl(
-   matchers::matchesAnyListedName(
-   AllowedTypes)),
+   
anyOf(matchers::matchesAnyListedName(
+ AllowedTypes),
+ isStdFunction())),
unless(isImplicit()),
hasInitializer(traverse(
ast_type_traits::TK_AsIs,


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -405,3 +405,36 @@
   ExpensiveToCopyType Orig;
   const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig);
 }
+
+// Let's fake a minimal std::function-like facility.
+namespace std {
+template 
+_Tp declval();
+
+template 
+struct __res {
+  template 
+  static decltype(declval<_Functor>()(_Args()...)) _S_test(int);
+
+  template 
+  static void _S_test(...);
+
+  using type = decltype(_S_test<_ArgTypes...>(0));
+};
+
+template 
+struct function;
+
+template 
+struct function {
+  template ::type>
+  function(_Functor) {}
+};
+} // namespace std
+
+void negativeStdFunction() {
+  std::function Orig;
+  std::function Copy = Orig;
+  

[PATCH] D89332: [clang-tidy] performance-unnecessary-copy-initialization: Always allow std::function to be copied.

2020-10-16 Thread Felix Berger via Phabricator via cfe-commits
flx added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp:52
   AllowedTypes(
   utils::options::parseStringList(Options.get("AllowedTypes", ""))) {}
 

lebedev.ri wrote:
> flx wrote:
> > lebedev.ri wrote:
> > > Just put it here?
> > I tried this first, but this list  is substring matched against only on the 
> > non-qualified type name, so std::function would not match anything and if 
> > we added "function" here it would match many other types that contain the 
> > word function.
> I would personally say it's a bug, especially because i personally don't like 
> hardcoded "choices" that are impossible to change.
> 
Are you referring to how the matching of "AllowedTypes" works or the fact that 
std::function causes false positives?

The latter is currently a bug and by excluding it now its severity is 
downgraded from bug to missing feature. Is your concern that you would like to 
have std::function be matched even if it is a false positive?

Regarding "AllowedTypes" matching I'm also surprised to find it matches 
substrings without namespaces as the name doesn't communicate this and makes it 
an imprecise net to cast. Changing it could break existing users that have type 
substrings configured though.



Comment at: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp:409
+
+namespace std {
+

gribozavr2 wrote:
> Could you add a nested inline namespace to better imitate what declarations 
> look like in libc++?
I'm not sure I follow.  I looked through the other tests that declare a std 
function and copied the declaration from modernize-avoid-bind.cpp.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D89332

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


[PATCH] D89332: [clang-tidy] performance-unnecessary-copy-initialization: Always allow std::function to be copied.

2020-10-20 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 299471.
flx added a comment.

Use hasName matcher on the declaration of the canonical type.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D89332

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -405,3 +405,41 @@
   ExpensiveToCopyType Orig;
   const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig);
 }
+
+namespace std {
+inline namespace __1 {
+
+template 
+class function;
+template 
+class function {
+public:
+  function();
+  function(const function &other);
+  R operator()(Args &&...args) const;
+};
+
+} // namespace __1
+} // namespace std
+
+void negativeStdFunction() {
+  std::function Orig;
+  std::function Copy = Orig;
+  int i = Orig();
+}
+
+using Functor = std::function;
+
+void negativeAliasedStdFunction() {
+  Functor Orig;
+  Functor Copy = Orig;
+  int i = Orig();
+}
+
+typedef std::function TypedefFunc;
+
+void negativeTypedefedStdFunction() {
+  TypedefFunc Orig;
+  TypedefFunc Copy = Orig;
+  int i = Orig();
+}
Index: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -40,7 +40,8 @@
   AllowedTypes(
   utils::options::parseStringList(Options.get("AllowedTypes", ""))) {}
 
-void UnnecessaryCopyInitialization::registerMatchers(MatchFinder *Finder) {
+void UnnecessaryCopyInitialization::registerMatchers(
+internal::MatchFinder *Finder) {
   auto ConstReference = referenceType(pointee(qualType(isConstQualified(;
 
   // Match method call expressions where the `this` argument is only used as
@@ -57,17 +58,20 @@
unless(callee(cxxMethodDecl(
   .bind("initFunctionCall");
 
-  auto localVarCopiedFrom = [this](const internal::Matcher &CopyCtorArg) 
{
+  auto localVarCopiedFrom = [this](const Matcher &CopyCtorArg) {
 return compoundStmt(
forEachDescendant(
declStmt(
has(varDecl(hasLocalStorage(),
hasType(qualType(
-   hasCanonicalType(
-   matchers::isExpensiveToCopy()),
+   hasCanonicalType(allOf(
+   matchers::isExpensiveToCopy(),
+   unless(hasDeclaration(namedDecl(
+   hasName("::std::function")),
unless(hasDeclaration(namedDecl(
-   matchers::matchesAnyListedName(
-   AllowedTypes)),
+   
anyOf(matchers::matchesAnyListedName(
+ AllowedTypes),
+ isStdFunction())),
unless(isImplicit()),
hasInitializer(traverse(
ast_type_traits::TK_AsIs,


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -405,3 +405,41 @@
   ExpensiveToCopyType Orig;
   const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig);
 }
+
+namespace std {
+inline namespace __1 {
+
+template 
+class function;
+template 
+class function {
+public:
+  function();
+  function(const function &other);
+  R operator()(Args &&...args) const;
+};
+
+} // namespace __1
+} // namespace std
+
+void negativeStdFunction() {
+  std::function Orig;
+  std::function Copy = Orig;
+  int i = Orig();
+}
+
+using Functor = std::function;
+
+void negativeAliasedStdFunction() {
+  Functor Orig;
+  Functor Copy = Orig;
+  int i = Orig();
+}
+
+typedef std::function TypedefFunc;
+
+void negativeTypedefedStdFunction() {
+  TypedefFunc Orig;
+  TypedefFunc Copy = Orig;
+  int i = Orig();
+}
Index: clang-tools-extra/clang-tidy/per

[PATCH] D89332: [clang-tidy] performance-unnecessary-copy-initialization: Always allow std::function to be copied.

2020-10-20 Thread Felix Berger via Phabricator via cfe-commits
flx marked 2 inline comments as done.
flx added a comment.

Thank you all for the input!

In D89332#2336566 , @njames93 wrote:

> How does this type alias and typedef, In theory that should also be handled.
>
>   using Functor = std::function<...>;
>   Functor Copy = Orig; // No warning.

Good point. I added test cases that cover this and motivated the use of the 
`hasName()` matcher on the canonical type.

In D89332#2338319 , @njames93 wrote:

> Come to think of it, this is a pretty illogical way to solve this problem, 
> just append `::std::function` to the AllowedTypes vector in 
> `registerMatchers` and be do with it. Will require dropping the const 
> Qualifier on AllowedTypes, but aside from that it is a much simpler fix.
> The has(Any)Name matcher has logic for skipping inline namespaces.

`AllowedTypes` is currently matched using a regular expression on only the not 
fully qualified name of the NamedDecl:

https://github.com/llvm/llvm-project/blob/343410d1cc154db99b7858e0a9c3ffd86ad94e45/clang-tools-extra/clang-tidy/utils/Matchers.h#L49

This is why this approach didn't work.




Comment at: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp:39-44
+AST_MATCHER(NamedDecl, isStdFunction) {
+  // First use the fast getName() method to avoid unnecessary calls to the
+  // slow getQualifiedNameAsString().
+  return Node.getName() == "function" &&
+ Node.getQualifiedNameAsString() == "std::function";
+}

aaron.ballman wrote:
> njames93 wrote:
> > It's better to use `node.isInStdNamespace()` instead of checking the 
> > qualified name as its designed for that very purpose. Is should probably 
> > take a `CXXRecordDecl` instead of a `NamedDecl` aswell.
> There's no need for this matcher -- `hasName("::std::function")` is the 
> correct way to test for this.
hasName() on the canonical type worked and handled type aliases as well.



Comment at: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp:409
+
+namespace std {
+

njames93 wrote:
> gribozavr2 wrote:
> > flx wrote:
> > > gribozavr2 wrote:
> > > > Could you add a nested inline namespace to better imitate what 
> > > > declarations look like in libc++?
> > > I'm not sure I follow.  I looked through the other tests that declare a 
> > > std function and copied the declaration from modernize-avoid-bind.cpp.
> > libc++ declarations look like this:
> > 
> > ```
> > namespace std {
> > inline namespace __1 {
> > template<...> struct function...
> > } // __1
> > } // std
> > ```
> > 
> > The inline namespace in the middle often trips up declaration matching in 
> > checkers. And yes, many other tests don't imitate this pattern, and are 
> > often broken with libc++. Those tests should be improved.
> @flx Thats the reason why its advisable to use `Decl::isInStdNamespace` as it 
> will handle inline namespaces.
Thanks for the extra explanation and sample code. This is done now and works.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D89332

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


[PATCH] D89332: [clang-tidy] performance-unnecessary-copy-initialization: Always allow std::function to be copied.

2020-10-21 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 299684.
flx added a comment.

Fix compile errors.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D89332

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -405,3 +405,41 @@
   ExpensiveToCopyType Orig;
   const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig);
 }
+
+namespace std {
+inline namespace __1 {
+
+template 
+class function;
+template 
+class function {
+public:
+  function();
+  function(const function &other);
+  R operator()(Args &&...args) const;
+};
+
+} // namespace __1
+} // namespace std
+
+void negativeStdFunction() {
+  std::function Orig;
+  std::function Copy = Orig;
+  int i = Orig();
+}
+
+using Functor = std::function;
+
+void negativeAliasedStdFunction() {
+  Functor Orig;
+  Functor Copy = Orig;
+  int i = Orig();
+}
+
+typedef std::function TypedefFunc;
+
+void negativeTypedefedStdFunction() {
+  TypedefFunc Orig;
+  TypedefFunc Copy = Orig;
+  int i = Orig();
+}
Index: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -63,8 +63,10 @@
declStmt(
has(varDecl(hasLocalStorage(),
hasType(qualType(
-   hasCanonicalType(
-   matchers::isExpensiveToCopy()),
+   hasCanonicalType(allOf(
+   matchers::isExpensiveToCopy(),
+   unless(hasDeclaration(namedDecl(
+   hasName("::std::function")),
unless(hasDeclaration(namedDecl(
matchers::matchesAnyListedName(
AllowedTypes)),


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -405,3 +405,41 @@
   ExpensiveToCopyType Orig;
   const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig);
 }
+
+namespace std {
+inline namespace __1 {
+
+template 
+class function;
+template 
+class function {
+public:
+  function();
+  function(const function &other);
+  R operator()(Args &&...args) const;
+};
+
+} // namespace __1
+} // namespace std
+
+void negativeStdFunction() {
+  std::function Orig;
+  std::function Copy = Orig;
+  int i = Orig();
+}
+
+using Functor = std::function;
+
+void negativeAliasedStdFunction() {
+  Functor Orig;
+  Functor Copy = Orig;
+  int i = Orig();
+}
+
+typedef std::function TypedefFunc;
+
+void negativeTypedefedStdFunction() {
+  TypedefFunc Orig;
+  TypedefFunc Copy = Orig;
+  int i = Orig();
+}
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -63,8 +63,10 @@
declStmt(
has(varDecl(hasLocalStorage(),
hasType(qualType(
-   hasCanonicalType(
-   matchers::isExpensiveToCopy()),
+   hasCanonicalType(allOf(
+   matchers::isExpensiveToCopy(),
+   unless(hasDeclaration(namedDecl(
+   hasName("::std::function")),
unless(hasDeclaration(namedDecl(
matchers::matchesAnyListedName(
AllowedTypes)),
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.or

[PATCH] D89332: [clang-tidy] performance-unnecessary-copy-initialization: Always allow std::function to be copied.

2020-10-21 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 299794.
flx added a comment.

Add fake std function to ensure it is still matched.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D89332

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -405,3 +405,58 @@
   ExpensiveToCopyType Orig;
   const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig);
 }
+
+namespace std {
+inline namespace __1 {
+
+template 
+class function;
+template 
+class function {
+public:
+  function();
+  function(const function &other);
+  R operator()(Args &&...args) const;
+};
+
+} // namespace __1
+} // namespace std
+
+void negativeStdFunction() {
+  std::function Orig;
+  std::function Copy = Orig;
+  int i = Orig();
+}
+
+using Functor = std::function;
+
+void negativeAliasedStdFunction() {
+  Functor Orig;
+  Functor Copy = Orig;
+  int i = Orig();
+}
+
+typedef std::function TypedefFunc;
+
+void negativeTypedefedStdFunction() {
+  TypedefFunc Orig;
+  TypedefFunc Copy = Orig;
+  int i = Orig();
+}
+
+namespace fake {
+namespace std {
+template 
+struct function {
+  // Custom copy constructor makes it expensive to copy;
+  function(const function &);
+};
+} // namespace std
+
+void positiveFakeStdFunction(std::function F) {
+  auto Copy = F;
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: local copy 'Copy' of the variable 
'F' is never modified;
+  // CHECK-FIXES: const auto& Copy = F;
+}
+
+} // namespace fake
Index: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -63,8 +63,10 @@
declStmt(
has(varDecl(hasLocalStorage(),
hasType(qualType(
-   hasCanonicalType(
-   matchers::isExpensiveToCopy()),
+   hasCanonicalType(allOf(
+   matchers::isExpensiveToCopy(),
+   unless(hasDeclaration(namedDecl(
+   hasName("::std::function")),
unless(hasDeclaration(namedDecl(
matchers::matchesAnyListedName(
AllowedTypes)),


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -405,3 +405,58 @@
   ExpensiveToCopyType Orig;
   const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig);
 }
+
+namespace std {
+inline namespace __1 {
+
+template 
+class function;
+template 
+class function {
+public:
+  function();
+  function(const function &other);
+  R operator()(Args &&...args) const;
+};
+
+} // namespace __1
+} // namespace std
+
+void negativeStdFunction() {
+  std::function Orig;
+  std::function Copy = Orig;
+  int i = Orig();
+}
+
+using Functor = std::function;
+
+void negativeAliasedStdFunction() {
+  Functor Orig;
+  Functor Copy = Orig;
+  int i = Orig();
+}
+
+typedef std::function TypedefFunc;
+
+void negativeTypedefedStdFunction() {
+  TypedefFunc Orig;
+  TypedefFunc Copy = Orig;
+  int i = Orig();
+}
+
+namespace fake {
+namespace std {
+template 
+struct function {
+  // Custom copy constructor makes it expensive to copy;
+  function(const function &);
+};
+} // namespace std
+
+void positiveFakeStdFunction(std::function F) {
+  auto Copy = F;
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: local copy 'Copy' of the variable 'F' is never modified;
+  // CHECK-FIXES: const auto& Copy = F;
+}
+
+} // namespace fake
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -63,8 +63,10 @@
declStmt(
  

[PATCH] D89332: [clang-tidy] performance-unnecessary-copy-initialization: Always allow std::function to be copied.

2020-10-21 Thread Felix Berger via Phabricator via cfe-commits
flx marked an inline comment as done.
flx added a comment.

Added a fake std function that still triggers the check.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D89332

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


[PATCH] D89332: [clang-tidy] performance-unnecessary-copy-initialization: Always allow std::function to be copied.

2020-10-21 Thread Felix Berger via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG1c1f794c2b64: Always allow std::function to be copied. 
(authored by flx).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D89332

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -405,3 +405,58 @@
   ExpensiveToCopyType Orig;
   const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig);
 }
+
+namespace std {
+inline namespace __1 {
+
+template 
+class function;
+template 
+class function {
+public:
+  function();
+  function(const function &other);
+  R operator()(Args &&...args) const;
+};
+
+} // namespace __1
+} // namespace std
+
+void negativeStdFunction() {
+  std::function Orig;
+  std::function Copy = Orig;
+  int i = Orig();
+}
+
+using Functor = std::function;
+
+void negativeAliasedStdFunction() {
+  Functor Orig;
+  Functor Copy = Orig;
+  int i = Orig();
+}
+
+typedef std::function TypedefFunc;
+
+void negativeTypedefedStdFunction() {
+  TypedefFunc Orig;
+  TypedefFunc Copy = Orig;
+  int i = Orig();
+}
+
+namespace fake {
+namespace std {
+template 
+struct function {
+  // Custom copy constructor makes it expensive to copy;
+  function(const function &);
+};
+} // namespace std
+
+void positiveFakeStdFunction(std::function F) {
+  auto Copy = F;
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: local copy 'Copy' of the variable 
'F' is never modified;
+  // CHECK-FIXES: const auto& Copy = F;
+}
+
+} // namespace fake
Index: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -63,8 +63,10 @@
declStmt(
has(varDecl(hasLocalStorage(),
hasType(qualType(
-   hasCanonicalType(
-   matchers::isExpensiveToCopy()),
+   hasCanonicalType(allOf(
+   matchers::isExpensiveToCopy(),
+   unless(hasDeclaration(namedDecl(
+   hasName("::std::function")),
unless(hasDeclaration(namedDecl(
matchers::matchesAnyListedName(
AllowedTypes)),


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -405,3 +405,58 @@
   ExpensiveToCopyType Orig;
   const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig);
 }
+
+namespace std {
+inline namespace __1 {
+
+template 
+class function;
+template 
+class function {
+public:
+  function();
+  function(const function &other);
+  R operator()(Args &&...args) const;
+};
+
+} // namespace __1
+} // namespace std
+
+void negativeStdFunction() {
+  std::function Orig;
+  std::function Copy = Orig;
+  int i = Orig();
+}
+
+using Functor = std::function;
+
+void negativeAliasedStdFunction() {
+  Functor Orig;
+  Functor Copy = Orig;
+  int i = Orig();
+}
+
+typedef std::function TypedefFunc;
+
+void negativeTypedefedStdFunction() {
+  TypedefFunc Orig;
+  TypedefFunc Copy = Orig;
+  int i = Orig();
+}
+
+namespace fake {
+namespace std {
+template 
+struct function {
+  // Custom copy constructor makes it expensive to copy;
+  function(const function &);
+};
+} // namespace std
+
+void positiveFakeStdFunction(std::function F) {
+  auto Copy = F;
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: local copy 'Copy' of the variable 'F' is never modified;
+  // CHECK-FIXES: const auto& Copy = F;
+}
+
+} // namespace fake
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -6

[PATCH] D90042: [clang-tidy] performance-unnecessary-copy-initialization: Check for const reference arguments that are replaced template parameter type.

2020-10-23 Thread Felix Berger via Phabricator via cfe-commits
flx created this revision.
flx added reviewers: aaron.ballman, gribozavr2.
Herald added subscribers: cfe-commits, xazax.hun.
Herald added a project: clang.
flx requested review of this revision.

This fixes false positive cases where a non-const reference is passed to a
std::function but interpreted as a const reference.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D90042

Files:
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t
+// RUN: %check_clang_tidy -std=c++17 %s 
performance-unnecessary-copy-initialization %t
 
 struct ExpensiveToCopyType {
   ExpensiveToCopyType();
@@ -411,12 +411,12 @@
 
 template 
 class function;
-template 
-class function {
+template 
+class function {
 public:
   function();
-  function(const function &other);
-  R operator()(Args &&...args) const;
+  function(const function &Other);
+  R operator()(ArgTypes &&...Args) const;
 };
 
 } // namespace __1
@@ -460,3 +460,19 @@
 }
 
 } // namespace fake
+
+void positiveInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is 
copy-constructed from a const reference
+  // CHECK-FIXES: const auto& Copy = Orig.reference();
+  Update(Copy);
+}
+
+void negativeInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  Update(Copy);
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -57,11 +57,15 @@
   Stmt, Context);
   SmallPtrSet DeclRefs;
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
-  auto ConstReferenceOrValue =
-  qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
- unless(anyOf(referenceType(), pointerType();
+  auto ConstReferenceOrValue = qualType(
+  anyOf(referenceType(pointee(qualType(isConstQualified(,
+unless(anyOf(referenceType(),
+ pointerType() /*, substTemplateTypeParmType()*/;
+  auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
+  ConstReferenceOrValue,
+  substTemplateTypeParmType(hasReplacementType(ConstReferenceOrValue;
   auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
-  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue)));
+  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValueOrReplaced)));
   Matches = match(findAll(callExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   Matches =


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t
+// RUN: %check_clang_tidy -std=c++17 %s performance-unnecessary-copy-initialization %t
 
 struct ExpensiveToCopyType {
   ExpensiveToCopyType();
@@ -411,12 +411,12 @@
 
 template 
 class function;
-template 
-class function {
+template 
+class function {
 public:
   function();
-  function(const function &other);
-  R operator()(Args &&...args) const;
+  function(const function &Other);
+  R operator()(ArgTypes &&...Args) const;
 };
 
 } // namespace __1
@@ -460,3 +460,19 @@
 }
 
 } // namespace fake
+
+void positiveInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is copy-constructed from a const reference
+  // CHECK-FIXES: const auto& Copy = Orig.reference();
+  Update(Copy);
+}
+
+void negativeInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  Update(Copy);
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -57,11 +57

[PATCH] D90042: [clang-tidy] performance-unnecessary-copy-initialization: Check for const reference arguments that are replaced template parameter type.

2020-10-23 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 300274.
flx added a comment.

Remove code comment.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D90042

Files:
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t
+// RUN: %check_clang_tidy -std=c++17 %s 
performance-unnecessary-copy-initialization %t
 
 struct ExpensiveToCopyType {
   ExpensiveToCopyType();
@@ -411,12 +411,12 @@
 
 template 
 class function;
-template 
-class function {
+template 
+class function {
 public:
   function();
-  function(const function &other);
-  R operator()(Args &&...args) const;
+  function(const function &Other);
+  R operator()(ArgTypes &&...Args) const;
 };
 
 } // namespace __1
@@ -460,3 +460,19 @@
 }
 
 } // namespace fake
+
+void positiveInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is 
copy-constructed from a const reference
+  // CHECK-FIXES: const auto& Copy = Orig.reference();
+  Update(Copy);
+}
+
+void negativeInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  Update(Copy);
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -59,9 +59,13 @@
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
   qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
- unless(anyOf(referenceType(), pointerType();
+ unless(anyOf(referenceType(), pointerType(),
+  substTemplateTypeParmType();
+  auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
+  ConstReferenceOrValue,
+  substTemplateTypeParmType(hasReplacementType(ConstReferenceOrValue;
   auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
-  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue)));
+  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValueOrReplaced)));
   Matches = match(findAll(callExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   Matches =


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t
+// RUN: %check_clang_tidy -std=c++17 %s performance-unnecessary-copy-initialization %t
 
 struct ExpensiveToCopyType {
   ExpensiveToCopyType();
@@ -411,12 +411,12 @@
 
 template 
 class function;
-template 
-class function {
+template 
+class function {
 public:
   function();
-  function(const function &other);
-  R operator()(Args &&...args) const;
+  function(const function &Other);
+  R operator()(ArgTypes &&...Args) const;
 };
 
 } // namespace __1
@@ -460,3 +460,19 @@
 }
 
 } // namespace fake
+
+void positiveInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is copy-constructed from a const reference
+  // CHECK-FIXES: const auto& Copy = Orig.reference();
+  Update(Copy);
+}
+
+void negativeInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  Update(Copy);
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -59,9 +59,13 @@
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
   qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
- unless(anyOf(referenceType(), pointerType();
+ unless(anyOf(referenceType(), pointerType(),
+   

[PATCH] D90042: [clang-tidy] performance-unnecessary-copy-initialization: Check for const reference arguments that are replaced template parameter type.

2020-10-23 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 300276.
flx added a comment.

Revert -std=c++17 change.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D90042

Files:
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -411,12 +411,12 @@
 
 template 
 class function;
-template 
-class function {
+template 
+class function {
 public:
   function();
-  function(const function &other);
-  R operator()(Args &&...args) const;
+  function(const function &Other);
+  R operator()(ArgTypes &&...Args) const;
 };
 
 } // namespace __1
@@ -460,3 +460,19 @@
 }
 
 } // namespace fake
+
+void positiveInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is 
copy-constructed from a const reference
+  // CHECK-FIXES: const auto& Copy = Orig.reference();
+  Update(Copy);
+}
+
+void negativeInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  Update(Copy);
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -59,9 +59,13 @@
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
   qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
- unless(anyOf(referenceType(), pointerType();
+ unless(anyOf(referenceType(), pointerType(),
+  substTemplateTypeParmType();
+  auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
+  ConstReferenceOrValue,
+  substTemplateTypeParmType(hasReplacementType(ConstReferenceOrValue;
   auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
-  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue)));
+  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValueOrReplaced)));
   Matches = match(findAll(callExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   Matches =


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -411,12 +411,12 @@
 
 template 
 class function;
-template 
-class function {
+template 
+class function {
 public:
   function();
-  function(const function &other);
-  R operator()(Args &&...args) const;
+  function(const function &Other);
+  R operator()(ArgTypes &&...Args) const;
 };
 
 } // namespace __1
@@ -460,3 +460,19 @@
 }
 
 } // namespace fake
+
+void positiveInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is copy-constructed from a const reference
+  // CHECK-FIXES: const auto& Copy = Orig.reference();
+  Update(Copy);
+}
+
+void negativeInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  Update(Copy);
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -59,9 +59,13 @@
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
   qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
- unless(anyOf(referenceType(), pointerType();
+ unless(anyOf(referenceType(), pointerType(),
+  substTemplateTypeParmType();
+  auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
+  ConstReferenceOrValue,
+  substTemplateTypeParmType(hasReplacementType(ConstReferenceOrValue;
   auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
-  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue)));
+  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValueOrReplaced)));
   Matches = match(findAll(callExpr(UsedAsCons

[PATCH] D90042: [clang-tidy] performance-unnecessary-copy-initialization: Check for const reference arguments that are replaced template parameter type.

2020-10-23 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

I should note that I was only able to reproduce the false positive with the 
actual implementation std::function and not our fake version here.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D90042

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


[PATCH] D90042: [clang-tidy] performance-unnecessary-copy-initialization: Check for const reference arguments that are replaced template parameter type.

2020-10-27 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

In D90042#2356180 , @aaron.ballman 
wrote:

> In D90042#2350035 , @flx wrote:
>
>> I should note that I was only able to reproduce the false positive with the 
>> actual implementation std::function and not our fake version here.
>
> Any reason not to lift enough of the actual definition to be able to 
> reproduce the issue in your test cases? Does the change in definitions break 
> other tests?

I poured over the actual definition and couldn't find any difference wrt the 
call operator that would explain it. I would also think that:

  template 
  void foo(T&& t) {
std::forward(t).modify();
  }

would be a simpler case that should trigger replacement, but it doesn't. Do you 
have any idea what I could be missing?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D90042

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


[PATCH] D90042: [clang-tidy] performance-unnecessary-copy-initialization: Check for const reference arguments that are replaced template parameter type.

2020-10-28 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 301388.
flx added a comment.

Add instantiated template method.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D90042

Files:
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -411,14 +411,37 @@
 
 template 
 class function;
-template 
-class function {
+template 
+class function {
 public:
   function();
-  function(const function &other);
-  R operator()(Args &&...args) const;
+  function(const function &Other);
+  R operator()(ArgTypes &&...Args) const;
+};
+
+template 
+struct remove_reference;
+
+template 
+struct remove_reference {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &> {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &&> {
+  typedef _Tp type;
 };
 
+template 
+constexpr _Tp &&forward(typename remove_reference<_Tp>::type &__t) noexcept {
+  return static_cast<_Tp &&>(__t);
+}
+
 } // namespace __1
 } // namespace std
 
@@ -460,3 +483,24 @@
 }
 
 } // namespace fake
+
+void positiveInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is 
copy-constructed from a const reference
+  // CHECK-FIXES: const auto& Copy = Orig.reference();
+  Update(Copy);
+}
+
+template 
+void foo(Type &&T) {
+  std::forward(T).nonConstMethod();
+}
+
+void negativeInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  foo(Copy);
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -59,7 +59,11 @@
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
   qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
- unless(anyOf(referenceType(), pointerType();
+ unless(anyOf(referenceType(), pointerType(),
+  substTemplateTypeParmType();
+  auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
+  ConstReferenceOrValue,
+  substTemplateTypeParmType(hasReplacementType(ConstReferenceOrValue;
   auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
   DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue)));
   Matches = match(findAll(callExpr(UsedAsConstRefOrValueArg)), Stmt, Context);


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -411,14 +411,37 @@
 
 template 
 class function;
-template 
-class function {
+template 
+class function {
 public:
   function();
-  function(const function &other);
-  R operator()(Args &&...args) const;
+  function(const function &Other);
+  R operator()(ArgTypes &&...Args) const;
+};
+
+template 
+struct remove_reference;
+
+template 
+struct remove_reference {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &> {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &&> {
+  typedef _Tp type;
 };
 
+template 
+constexpr _Tp &&forward(typename remove_reference<_Tp>::type &__t) noexcept {
+  return static_cast<_Tp &&>(__t);
+}
+
 } // namespace __1
 } // namespace std
 
@@ -460,3 +483,24 @@
 }
 
 } // namespace fake
+
+void positiveInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is copy-constructed from a const reference
+  // CHECK-FIXES: const auto& Copy = Orig.reference();
+  Update(Copy);
+}
+
+template 
+void foo(Type &&T) {
+  std::forward(T).nonConstMethod();
+}
+
+void negativeInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  foo(Copy);
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprU

[PATCH] D90042: [clang-tidy] performance-unnecessary-copy-initialization: Check for const reference arguments that are replaced template parameter type.

2020-10-28 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 301389.
flx added a comment.

Comment out replaced parameter.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D90042

Files:
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -411,14 +411,37 @@
 
 template 
 class function;
-template 
-class function {
+template 
+class function {
 public:
   function();
-  function(const function &other);
-  R operator()(Args &&...args) const;
+  function(const function &Other);
+  R operator()(ArgTypes &&...Args) const;
+};
+
+template 
+struct remove_reference;
+
+template 
+struct remove_reference {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &> {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &&> {
+  typedef _Tp type;
 };
 
+template 
+constexpr _Tp &&forward(typename remove_reference<_Tp>::type &__t) noexcept {
+  return static_cast<_Tp &&>(__t);
+}
+
 } // namespace __1
 } // namespace std
 
@@ -460,3 +483,24 @@
 }
 
 } // namespace fake
+
+void positiveInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is 
copy-constructed from a const reference
+  // CHECK-FIXES: const auto& Copy = Orig.reference();
+  Update(Copy);
+}
+
+template 
+void foo(Type &&T) {
+  std::forward(T).nonConstMethod();
+}
+
+void negativeInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  foo(Copy);
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -59,7 +59,11 @@
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   auto ConstReferenceOrValue =
   qualType(anyOf(referenceType(pointee(qualType(isConstQualified(,
- unless(anyOf(referenceType(), pointerType();
+ unless(anyOf(referenceType(), pointerType()/*,
+  
substTemplateTypeParmType()*/;
+  auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
+  ConstReferenceOrValue,
+  substTemplateTypeParmType(hasReplacementType(ConstReferenceOrValue;
   auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
   DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue)));
   Matches = match(findAll(callExpr(UsedAsConstRefOrValueArg)), Stmt, Context);


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -411,14 +411,37 @@
 
 template 
 class function;
-template 
-class function {
+template 
+class function {
 public:
   function();
-  function(const function &other);
-  R operator()(Args &&...args) const;
+  function(const function &Other);
+  R operator()(ArgTypes &&...Args) const;
+};
+
+template 
+struct remove_reference;
+
+template 
+struct remove_reference {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &> {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &&> {
+  typedef _Tp type;
 };
 
+template 
+constexpr _Tp &&forward(typename remove_reference<_Tp>::type &__t) noexcept {
+  return static_cast<_Tp &&>(__t);
+}
+
 } // namespace __1
 } // namespace std
 
@@ -460,3 +483,24 @@
 }
 
 } // namespace fake
+
+void positiveInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is copy-constructed from a const reference
+  // CHECK-FIXES: const auto& Copy = Orig.reference();
+  Update(Copy);
+}
+
+template 
+void foo(Type &&T) {
+  std::forward(T).nonConstMethod();
+}
+
+void negativeInvokedOnStdFunction(
+std::function Update,
+const ExpensiveToCopyType Orig) {
+  auto Copy = Orig.reference();
+  foo(Copy);
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-

[PATCH] D90042: [clang-tidy] performance-unnecessary-copy-initialization: Check for const reference arguments that are replaced template parameter type.

2020-10-28 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

In D90042#2357078 , @aaron.ballman 
wrote:

> In D90042#2356265 , @flx wrote:
>
>> In D90042#2356180 , @aaron.ballman 
>> wrote:
>>
>>> In D90042#2350035 , @flx wrote:
>>>
 I should note that I was only able to reproduce the false positive with 
 the actual implementation std::function and not our fake version here.
>>>
>>> Any reason not to lift enough of the actual definition to be able to 
>>> reproduce the issue in your test cases? Does the change in definitions 
>>> break other tests?
>>
>> I poured over the actual definition and couldn't find any difference wrt the 
>> call operator that would explain it. I would also think that:
>>
>>   template 
>>   void foo(T&& t) {
>> std::forward(t).modify();
>>   }
>>
>> would be a simpler case that should trigger replacement, but it doesn't. Do 
>> you have any idea what I could be missing?
>
> Perhaps silly question, but are you instantiating `foo()`?

I think I added a full implementation of foo now, reverted the change, but am 
still not getting the negative case to fail. Can you spot an issue with the 
code?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D90042

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


[PATCH] D97567: [clang-tidy] performance-* checks: Also allow allow member expressions to be used in a const manner.

2021-05-12 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

Could someone take a look at this patch? Thank you!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97567

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


[PATCH] D102175: [clang-tidy] performance-unnecessary-copy-initialization: Remove the complete statement when the copied variable is unused.

2021-05-14 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

In D102175#2759945 , @ymandel wrote:

> Hi Felix,
> Can you clarify your concern over the warning? Is it the case that the 
> warning is not present before the fix and is only triggered after the fix?  
> I'm concerned that removing the call may have unintended side effects and I 
> would think it might better to leave the check for usage separate.  However, 
> if the fix is causing the warning then I can understand better why you want 
> to make this change.  That said, have considered replacing the var binding 
> with `(void)`, rather than deleting the statement?

Yes, the fix of converting the copied variable to a const reference introduces 
a warning when -Wall (or more specifically -Wunused) is specified and the 
variable is not used at all. The fix converts the local variable to a const 
reference. Take a const reference of an object and not using it has no 
observable side effects I think.

Here is an example of an unused, but copied variable before the fix:

https://godbolt.org/z/a5E4fMWKj

The compiler flags are "-Werror -Wall": no warnings or errors are produced.

Now after the fix:

https://godbolt.org/z/a5E4fMWKj

For more context, the assumption the check makes is that the copy is 
unnecessary. If the type executes specific side-effects in its copy-constructor 
code the type should be excluded from the check using the `AllowedTypes` 
setting.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D102175

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


[PATCH] D103018: [clang-tidy] performance-unnecessary-copy-initialization: Look at the canonical type when checking for aliases.

2021-05-24 Thread Felix Berger via Phabricator via cfe-commits
flx created this revision.
flx added reviewers: hokein, ymandel, aaron.ballman.
Herald added subscribers: jeroen.dobbelaere, xazax.hun.
flx requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

This fixes a false positive case where for instance a pointer is obtained and 
declared using `auto`.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D103018

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -4,6 +4,7 @@
   ExpensiveToCopyType();
   virtual ~ExpensiveToCopyType();
   const ExpensiveToCopyType &reference() const;
+  const ExpensiveToCopyType *pointer() const;
   void nonConstMethod();
   bool constMethod() const;
 };
@@ -500,6 +501,25 @@
   Orig.nonConstMethod();
 }
 
+void negativeAliasNonCanonicalPointerType() {
+  ExpensiveToCopyType Orig;
+  // The use of auto here hides that the type is a pointer type. The check 
needs
+  // to look at the canonical type to detect the aliasing through this pointer.
+  const auto Pointer = Orig.pointer();
+  const auto NecessaryCopy = Pointer->reference();
+  Orig.nonConstMethod();
+}
+
+void negativeAliasTypedefedType() {
+  typedef const ExpensiveToCopyType &ReferenceType;
+  ExpensiveToCopyType Orig;
+  // The typedef hides the fact that this is a reference type. The check needs
+  // to look at the canonical type to detect the aliasing.
+  ReferenceType Ref = Orig.reference();
+  const auto NecessaryCopy = Ref.reference();
+  Orig.nonConstMethod();
+}
+
 void positiveCopiedFromGetterOfReferenceToConstVar() {
   ExpensiveToCopyType Orig;
   const auto &Ref = Orig.reference();
Index: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -86,7 +86,7 @@
   if (!isOnlyUsedAsConst(InitializingVar, BlockStmt, Context))
 return false;
 
-  QualType T = InitializingVar.getType();
+  QualType T = InitializingVar.getType().getCanonicalType();
   // The variable is a value type and we know it is only used as const. Safe
   // to reference it and avoid the copy.
   if (!isa(T))


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -4,6 +4,7 @@
   ExpensiveToCopyType();
   virtual ~ExpensiveToCopyType();
   const ExpensiveToCopyType &reference() const;
+  const ExpensiveToCopyType *pointer() const;
   void nonConstMethod();
   bool constMethod() const;
 };
@@ -500,6 +501,25 @@
   Orig.nonConstMethod();
 }
 
+void negativeAliasNonCanonicalPointerType() {
+  ExpensiveToCopyType Orig;
+  // The use of auto here hides that the type is a pointer type. The check needs
+  // to look at the canonical type to detect the aliasing through this pointer.
+  const auto Pointer = Orig.pointer();
+  const auto NecessaryCopy = Pointer->reference();
+  Orig.nonConstMethod();
+}
+
+void negativeAliasTypedefedType() {
+  typedef const ExpensiveToCopyType &ReferenceType;
+  ExpensiveToCopyType Orig;
+  // The typedef hides the fact that this is a reference type. The check needs
+  // to look at the canonical type to detect the aliasing.
+  ReferenceType Ref = Orig.reference();
+  const auto NecessaryCopy = Ref.reference();
+  Orig.nonConstMethod();
+}
+
 void positiveCopiedFromGetterOfReferenceToConstVar() {
   ExpensiveToCopyType Orig;
   const auto &Ref = Orig.reference();
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -86,7 +86,7 @@
   if (!isOnlyUsedAsConst(InitializingVar, BlockStmt, Context))
 return false;
 
-  QualType T = InitializingVar.getType();
+  QualType T = InitializingVar.getType().getCanonicalType();
   // The variable is a value type and we know it is only used as const. Safe
   // to reference it and avoid the copy.
   if (!isa(T))
___
cfe-commits mail

[PATCH] D103021: [clang-tidy] performance-unnecessary-copy-initialization: Search whole function body for variable initializations.

2021-05-24 Thread Felix Berger via Phabricator via cfe-commits
flx created this revision.
flx added reviewers: hokein, ymandel, aaron.ballman.
Herald added a subscriber: xazax.hun.
flx requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

This fixes false positive cases where a reference is initialized outside of a
block statement and then its initializing variable is modified. Another case is
when the looped over container is modified.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D103021

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -1,9 +1,19 @@
 // RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t
 
+template 
+struct Iterator {
+  void operator++();
+  const T &operator*() const;
+  bool operator!=(const Iterator &) const;
+  typedef const T &const_reference;
+};
+
 struct ExpensiveToCopyType {
   ExpensiveToCopyType();
   virtual ~ExpensiveToCopyType();
   const ExpensiveToCopyType &reference() const;
+  Iterator begin() const;
+  Iterator end() const;
   void nonConstMethod();
   bool constMethod() const;
 };
@@ -508,3 +518,41 @@
   // CHECK-FIXES: const auto& UnnecessaryCopy = Ref.reference();
   Orig.constMethod();
 }
+
+void negativeloopedOverObjectIsModified() {
+  ExpensiveToCopyType Orig;
+  for (const auto &Element : Orig) {
+const auto Copy = Element;
+Orig.nonConstMethod();
+Copy.constMethod();
+  }
+
+  auto Labmda = []() {
+ExpensiveToCopyType Orig;
+for (const auto &Element : Orig) {
+  const auto Copy = Element;
+  Orig.nonConstMethod();
+  Copy.constMethod();
+}
+  };
+}
+
+void negativeReferenceIsInitializedOutsideOfBlock() {
+  ExpensiveToCopyType Orig;
+  const auto &E2 = Orig;
+  if (1 != 2 * 3) {
+const auto C2 = E2;
+Orig.nonConstMethod();
+C2.constMethod();
+  }
+
+  auto Lambda = []() {
+ExpensiveToCopyType Orig;
+const auto &E2 = Orig;
+if (1 != 2 * 3) {
+  const auto C2 = E2;
+  Orig.nonConstMethod();
+  C2.constMethod();
+}
+  };
+}
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
@@ -35,11 +35,12 @@
 
 private:
   void handleCopyFromMethodReturn(const VarDecl &Var, const Stmt &BlockStmt,
-  bool IssueFix, const VarDecl *ObjectArg,
+  const Stmt &Body, bool IssueFix,
+  const VarDecl *ObjectArg,
   ASTContext &Context);
   void handleCopyFromLocalVar(const VarDecl &NewVar, const VarDecl &OldVar,
-  const Stmt &BlockStmt, bool IssueFix,
-  ASTContext &Context);
+  const Stmt &BlockStmt, const Stmt &Body,
+  bool IssueFix, ASTContext &Context);
   const std::vector AllowedTypes;
 };
 
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -82,6 +82,7 @@
 // object arg or variable that is referenced is immutable as well.
 static bool isInitializingVariableImmutable(const VarDecl &InitializingVar,
 const Stmt &BlockStmt,
+const Stmt &Body,
 ASTContext &Context) {
   if (!isOnlyUsedAsConst(InitializingVar, BlockStmt, Context))
 return false;
@@ -92,12 +93,14 @@
   if (!isa(T))
 return true;
 
+  // Search the whole function body for decl statements of the initialization
+  // variable not just the current block statement.
   auto Matches =
   match(findAll(declStmt(has(varDecl(equalsNode(&InitializingVar
 .bind("declStmt")),
-BlockStmt, Context);
-  // The reference or pointer is not initialized in the BlockStmt. We assume
-  // its pointee is not modified then.
+Body, Context);
+  // The reference or pointer is not initialized anywhere witin the function. We
+  // assume its p

[PATCH] D103087: [clang-tidy] performances-unnecessary-* checks: Extend isOnlyUsedAsConst to expressions and catch const methods returning non-const references/pointers.

2021-05-25 Thread Felix Berger via Phabricator via cfe-commits
flx created this revision.
flx added reviewers: aaron.ballman, hokein, ymandel.
Herald added a subscriber: xazax.hun.
flx requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

This change extends isOnlyUsedAsConst() to avoid false positives in cases where
a const method returns a mutable pointer or refernce and the pointed to object
is modified.

To achieve this we look at each const method or operator call and check if it
returns a mutable pointer/reference. If that's the case the call expression
itself is checked for constant use.

We also capture assignments of expressions to non-const references/pointers and
then check that the declared alias variables are used in a const-only fasion as
well.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D103087

Files:
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.h
  clang-tools-extra/clang-tidy/utils/Matchers.h
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -6,6 +6,9 @@
   const ExpensiveToCopyType &reference() const;
   void nonConstMethod();
   bool constMethod() const;
+  ExpensiveToCopyType &operator*() const;
+  ExpensiveToCopyType *operator->() const;
+  ExpensiveToCopyType *get() const;
 };
 
 struct TrivialToCopyType {
@@ -508,3 +511,79 @@
   // CHECK-FIXES: const auto& UnnecessaryCopy = Ref.reference();
   Orig.constMethod();
 }
+
+void negativePointerIsModifiedThroughConstOperator() {
+  ExpensiveToCopyType Orig;
+  auto NecessaryCopy = Orig;
+  NecessaryCopy->nonConstMethod();
+}
+
+void negativeReferenceIsModifiedThroughConstOperator() {
+  ExpensiveToCopyType Orig;
+  auto NecessaryCopy = Orig;
+  (*NecessaryCopy).nonConstMethod();
+}
+
+void negativePointerIsModifiedThroughConstOperatorChain() {
+  ExpensiveToCopyType Orig;
+  auto NecessaryCopy = Orig;
+  (*NecessaryCopy)->nonConstMethod();
+}
+
+void positivePointerIsNotModifiedThroughConstOperator() {
+  ExpensiveToCopyType Orig;
+  auto UnnecessaryCopy = Orig;
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: local copy 'UnnecessaryCopy' of the variable 'Orig' is never modified;
+  // CHECK-FIXES: const auto& UnnecessaryCopy = Orig;
+  UnnecessaryCopy->constMethod();
+}
+
+void positiveReferenceIsNotModifiedThroughConstOperator() {
+  ExpensiveToCopyType Orig;
+  auto UnnecessaryCopy = Orig;
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: local copy 'UnnecessaryCopy' of the variable 'Orig' is never modified;
+  // CHECK-FIXES: const auto& UnnecessaryCopy = Orig;
+  (*UnnecessaryCopy).constMethod();
+}
+
+void negativeReferenceIsAssignedToVarAndModified() {
+  ExpensiveToCopyType Orig;
+  auto NecessaryCopy = Orig;
+  auto &Ref = *NecessaryCopy;
+  Ref.nonConstMethod();
+}
+
+void positiveReferenceIsAssignedToVarAndNotModified() {
+  ExpensiveToCopyType Orig;
+  auto UnnecessaryCopy = Orig;
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: local copy 'UnnecessaryCopy' of the variable 'Orig' is never modified;
+  // CHECK-FIXES: const auto& UnnecessaryCopy = Orig;
+  auto &Ref = *UnnecessaryCopy;
+  Ref.constMethod();
+}
+
+void negativePointerIsAssignedToVarAndModified() {
+  ExpensiveToCopyType Orig;
+  auto NecessaryCopy = Orig;
+  auto *Pointer = NecessaryCopy.get();
+  Pointer->nonConstMethod();
+}
+
+void positivePointerIsAssignedToVarAndNotModified() {
+  ExpensiveToCopyType Orig;
+  auto UnnecessaryCopy = Orig;
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: local copy 'UnnecessaryCopy' of the variable 'Orig' is never modified;
+  // CHECK-FIXES: const auto& UnnecessaryCopy = Orig;
+  auto *Pointer = UnnecessaryCopy.get();
+  Pointer->constMethod();
+}
+
+void positiveConstMethodReturningPointer() {
+  ExpensiveToCopyType Orig;
+  auto UnnecessaryCopy = Orig;
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: local copy 'UnnecessaryCopy' of the variable 'Orig' is never modified;
+  // CHECK-FIXES: const auto& UnnecessaryCopy = Orig;
+  // Test that a const method that returns a mutable pointer/reference that is
+  // unused counts as a const use.
+  UnnecessaryCopy.get();
+}
Index: clang-tools-extra/clang-tidy/utils/Matchers.h
===
--- clang-tools-extra/clang-tidy/utils/Matchers.h
+++ clang-tools-extra/clang-tidy/utils/Matchers.h
@@ -43,12 +43,24 @@
   return referenceType(pointee(qualType(isConstQualified(;
 }
 
+AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isReferenceToNonConst) {
+  using namespace ast_matchers;
+  return allOf(referenceType(),
+   referenceType(pointee(qualType

[PATCH] D102175: [clang-tidy] performance-unnecessary-copy-initialization: Remove the complete statement when the copied variable is unused.

2021-06-09 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

Thank you for the review, Yitzhak!




Comment at: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp:541
   Orig.constMethod();
+  UnnecessaryCopy.constMethod();
 }

ymandel wrote:
> If this line weren't here, then we'd delete line 537, in which case `Ref` 
> itself becomes unused and so line 536 should be deleted as well. Do you 
> handle this case?
Good catch. This case is not handled. It would require recursively checking 
whether the deleted statement was the only reference to another reference which 
is hard and requires subtracting that decl ref from all these calculations.  

 I would like to to see this being a common enough issue before addressing it. 


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D102175

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


[PATCH] D102175: [clang-tidy] performance-unnecessary-copy-initialization: Remove the complete statement when the copied variable is unused.

2021-06-09 Thread Felix Berger 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 rG5dbe3bf4b8db: [clang-tidy] 
performance-unnecessary-copy-initialization: Remove the complete… (authored by 
flx).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D102175

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-allowed-types.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -38,60 +38,88 @@
   const auto AutoAssigned = ExpensiveTypeReference();
   // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' is copy-constructed from a const reference; consider making it a const reference [performance-unnecessary-copy-initialization]
   // CHECK-FIXES: const auto& AutoAssigned = ExpensiveTypeReference();
+  AutoAssigned.constMethod();
+
   const auto AutoCopyConstructed(ExpensiveTypeReference());
   // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed'
   // CHECK-FIXES: const auto& AutoCopyConstructed(ExpensiveTypeReference());
+  AutoCopyConstructed.constMethod();
+
   const ExpensiveToCopyType VarAssigned = ExpensiveTypeReference();
   // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned'
   // CHECK-FIXES:   const ExpensiveToCopyType& VarAssigned = ExpensiveTypeReference();
+  VarAssigned.constMethod();
+
   const ExpensiveToCopyType VarCopyConstructed(ExpensiveTypeReference());
   // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed'
   // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(ExpensiveTypeReference());
+  VarCopyConstructed.constMethod();
 }
 
 void PositiveMethodCallConstReferenceParam(const ExpensiveToCopyType &Obj) {
   const auto AutoAssigned = Obj.reference();
   // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned'
   // CHECK-FIXES: const auto& AutoAssigned = Obj.reference();
+  AutoAssigned.constMethod();
+
   const auto AutoCopyConstructed(Obj.reference());
   // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed'
   // CHECK-FIXES: const auto& AutoCopyConstructed(Obj.reference());
+  AutoCopyConstructed.constMethod();
+
   const ExpensiveToCopyType VarAssigned = Obj.reference();
   // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned'
   // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj.reference();
+  VarAssigned.constMethod();
+
   const ExpensiveToCopyType VarCopyConstructed(Obj.reference());
   // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed'
   // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj.reference());
+  VarCopyConstructed.constMethod();
 }
 
 void PositiveMethodCallConstParam(const ExpensiveToCopyType Obj) {
   const auto AutoAssigned = Obj.reference();
   // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned'
   // CHECK-FIXES: const auto& AutoAssigned = Obj.reference();
+  AutoAssigned.constMethod();
+
   const auto AutoCopyConstructed(Obj.reference());
   // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed'
   // CHECK-FIXES: const auto& AutoCopyConstructed(Obj.reference());
+  AutoCopyConstructed.constMethod();
+
   const ExpensiveToCopyType VarAssigned = Obj.reference();
   // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned'
   // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj.reference();
+  VarAssigned.constMethod();
+
   const ExpensiveToCopyType VarCopyConstructed(Obj.reference());
   // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed'
   // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj.reference());
+  VarCopyConstructed.constMethod();
 }
 
 void PositiveMethodCallConstPointerParam(const ExpensiveToCopyType *const Obj) {
   const auto AutoAssigned = Obj->reference();
   // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned'
   // CHECK-FIXES: const auto& AutoAssigned = Obj->reference();
+  AutoAssigned.constMethod();
+
   const auto AutoCopyConstructed(Obj->reference());
   // CHECK-MESSAGES: [

[PATCH] D103018: [clang-tidy] performance-unnecessary-copy-initialization: Look at the canonical type when checking for aliases.

2021-06-09 Thread Felix Berger via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGefa4dbc32ca9: [clang-tidy] 
performance-unnecessary-copy-initialization: Look at the canonical… (authored 
by flx).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103018

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -4,6 +4,7 @@
   ExpensiveToCopyType();
   virtual ~ExpensiveToCopyType();
   const ExpensiveToCopyType &reference() const;
+  const ExpensiveToCopyType *pointer() const;
   void nonConstMethod();
   bool constMethod() const;
 };
@@ -548,6 +549,25 @@
   Orig.nonConstMethod();
 }
 
+void negativeAliasNonCanonicalPointerType() {
+  ExpensiveToCopyType Orig;
+  // The use of auto here hides that the type is a pointer type. The check 
needs
+  // to look at the canonical type to detect the aliasing through this pointer.
+  const auto Pointer = Orig.pointer();
+  const auto NecessaryCopy = Pointer->reference();
+  Orig.nonConstMethod();
+}
+
+void negativeAliasTypedefedType() {
+  typedef const ExpensiveToCopyType &ReferenceType;
+  ExpensiveToCopyType Orig;
+  // The typedef hides the fact that this is a reference type. The check needs
+  // to look at the canonical type to detect the aliasing.
+  ReferenceType Ref = Orig.reference();
+  const auto NecessaryCopy = Ref.reference();
+  Orig.nonConstMethod();
+}
+
 void positiveCopiedFromGetterOfReferenceToConstVar() {
   ExpensiveToCopyType Orig;
   const auto &Ref = Orig.reference();
Index: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -100,7 +100,7 @@
   if (!isOnlyUsedAsConst(InitializingVar, BlockStmt, Context))
 return false;
 
-  QualType T = InitializingVar.getType();
+  QualType T = InitializingVar.getType().getCanonicalType();
   // The variable is a value type and we know it is only used as const. Safe
   // to reference it and avoid the copy.
   if (!isa(T))


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -4,6 +4,7 @@
   ExpensiveToCopyType();
   virtual ~ExpensiveToCopyType();
   const ExpensiveToCopyType &reference() const;
+  const ExpensiveToCopyType *pointer() const;
   void nonConstMethod();
   bool constMethod() const;
 };
@@ -548,6 +549,25 @@
   Orig.nonConstMethod();
 }
 
+void negativeAliasNonCanonicalPointerType() {
+  ExpensiveToCopyType Orig;
+  // The use of auto here hides that the type is a pointer type. The check needs
+  // to look at the canonical type to detect the aliasing through this pointer.
+  const auto Pointer = Orig.pointer();
+  const auto NecessaryCopy = Pointer->reference();
+  Orig.nonConstMethod();
+}
+
+void negativeAliasTypedefedType() {
+  typedef const ExpensiveToCopyType &ReferenceType;
+  ExpensiveToCopyType Orig;
+  // The typedef hides the fact that this is a reference type. The check needs
+  // to look at the canonical type to detect the aliasing.
+  ReferenceType Ref = Orig.reference();
+  const auto NecessaryCopy = Ref.reference();
+  Orig.nonConstMethod();
+}
+
 void positiveCopiedFromGetterOfReferenceToConstVar() {
   ExpensiveToCopyType Orig;
   const auto &Ref = Orig.reference();
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -100,7 +100,7 @@
   if (!isOnlyUsedAsConst(InitializingVar, BlockStmt, Context))
 return false;
 
-  QualType T = InitializingVar.getType();
+  QualType T = InitializingVar.getType().getCanonicalType();
   // The variable is a value type and we know it is only used as const. Safe
   // to reference it and avoid the copy.
   if (!isa(T))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinf

[PATCH] D103021: [clang-tidy] performance-unnecessary-copy-initialization: Search whole function body for variable initializations.

2021-06-09 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 350994.
flx marked 2 inline comments as done.
flx added a comment.

Addressed first round of comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103021

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -1,9 +1,19 @@
 // RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t
 
+template 
+struct Iterator {
+  void operator++();
+  const T &operator*() const;
+  bool operator!=(const Iterator &) const;
+  typedef const T &const_reference;
+};
+
 struct ExpensiveToCopyType {
   ExpensiveToCopyType();
   virtual ~ExpensiveToCopyType();
   const ExpensiveToCopyType &reference() const;
+  Iterator begin() const;
+  Iterator end() const;
   void nonConstMethod();
   bool constMethod() const;
 };
@@ -508,3 +518,41 @@
   // CHECK-FIXES: const auto& UnnecessaryCopy = Ref.reference();
   Orig.constMethod();
 }
+
+void negativeloopedOverObjectIsModified() {
+  ExpensiveToCopyType Orig;
+  for (const auto &Element : Orig) {
+const auto Copy = Element;
+Orig.nonConstMethod();
+Copy.constMethod();
+  }
+
+  auto Lambda = []() {
+ExpensiveToCopyType Orig;
+for (const auto &Element : Orig) {
+  const auto Copy = Element;
+  Orig.nonConstMethod();
+  Copy.constMethod();
+}
+  };
+}
+
+void negativeReferenceIsInitializedOutsideOfBlock() {
+  ExpensiveToCopyType Orig;
+  const auto &E2 = Orig;
+  if (1 != 2 * 3) {
+const auto C2 = E2;
+Orig.nonConstMethod();
+C2.constMethod();
+  }
+
+  auto Lambda = []() {
+ExpensiveToCopyType Orig;
+const auto &E2 = Orig;
+if (1 != 2 * 3) {
+  const auto C2 = E2;
+  Orig.nonConstMethod();
+  C2.constMethod();
+}
+  };
+}
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
@@ -35,11 +35,12 @@
 
 private:
   void handleCopyFromMethodReturn(const VarDecl &Var, const Stmt &BlockStmt,
-  bool IssueFix, const VarDecl *ObjectArg,
+  const Stmt &Body, bool IssueFix,
+  const VarDecl *ObjectArg,
   ASTContext &Context);
   void handleCopyFromLocalVar(const VarDecl &NewVar, const VarDecl &OldVar,
-  const Stmt &BlockStmt, bool IssueFix,
-  ASTContext &Context);
+  const Stmt &BlockStmt, const Stmt &Body,
+  bool IssueFix, ASTContext &Context);
   const std::vector AllowedTypes;
 };
 
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -82,6 +82,7 @@
 // object arg or variable that is referenced is immutable as well.
 static bool isInitializingVariableImmutable(const VarDecl &InitializingVar,
 const Stmt &BlockStmt,
+const Stmt &Body,
 ASTContext &Context) {
   if (!isOnlyUsedAsConst(InitializingVar, BlockStmt, Context))
 return false;
@@ -92,12 +93,14 @@
   if (!isa(T))
 return true;
 
+  // Search the whole function body, not just the current block statement, for
+  // decl statements of the initialization variable.
   auto Matches =
   match(findAll(declStmt(has(varDecl(equalsNode(&InitializingVar
 .bind("declStmt")),
-BlockStmt, Context);
-  // The reference or pointer is not initialized in the BlockStmt. We assume
-  // its pointee is not modified then.
+Body, Context);
+  // The reference or pointer is not initialized anywhere witin the function. We
+  // assume its pointee is not modified then.
   if (Matches.empty())
 return true;
 
@@ -110,10 +113,10 @@
 return true;
   // Check that the object argument is immutable as well.
   if (const auto *OrigVar = selectFirst(ObjectArgId, Matches))
-

[PATCH] D103021: [clang-tidy] performance-unnecessary-copy-initialization: Search whole function body for variable initializations.

2021-06-09 Thread Felix Berger via Phabricator via cfe-commits
flx added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp:98-101
   auto Matches =
   match(findAll(declStmt(has(varDecl(equalsNode(&InitializingVar
 .bind("declStmt")),
+Body, Context);

ymandel wrote:
> Consider inspecting the `DeclContext`s instead, which should be much more 
> efficient than searching the entire block.  Pass the `FunctionDecl` as an 
> argument instead of `Body`, since it is a `DeclContext`.  e.g. `const 
> DeclContext &Fun`
> 
> Then, either
> 1. Call `Fun.containsDecl(InitializingVar)`, or
> 2. Search through the contexts yourself; something like:
> ```
> DeclContext* DC = InitializingVar->getDeclContext(); 
> while (DC != nullptr && DC != &Fun)
>   DC = DC->getLexicalParent();
> if (DC == nullptr)
>   // The reference or pointer is not initialized anywhere witin the function. 
> We
>   // assume its pointee is not modified then.
>   return true;
> ```
Are #1 and #2 equivalent? From the implementation and comment I cannot tell 
whether #1 would cover cases where the variable is not declared directly in the 
function, but in child block:

```
void Fun() {
 {
   var i;
   {
 i.usedHere();
   }  
 } 
}
```

I'm also reading this as an optimization to more quickly determine whether we 
can stop here. We still need to find the matches for the next steps, but I  
think I could then limit matching to the DeclContext I found here. Is this 
correct? For this I would actually need the DeclContext result from #2.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103021

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


[PATCH] D103021: [clang-tidy] performance-unnecessary-copy-initialization: Search whole function body for variable initializations.

2021-06-11 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 351425.
flx marked an inline comment as not done.
flx added a comment.

Use more efficient method to check for local variable declaration.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103021

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -1,9 +1,19 @@
 // RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t
 
+template 
+struct Iterator {
+  void operator++();
+  const T &operator*() const;
+  bool operator!=(const Iterator &) const;
+  typedef const T &const_reference;
+};
+
 struct ExpensiveToCopyType {
   ExpensiveToCopyType();
   virtual ~ExpensiveToCopyType();
   const ExpensiveToCopyType &reference() const;
+  Iterator begin() const;
+  Iterator end() const;
   void nonConstMethod();
   bool constMethod() const;
 };
@@ -508,3 +518,41 @@
   // CHECK-FIXES: const auto& UnnecessaryCopy = Ref.reference();
   Orig.constMethod();
 }
+
+void negativeloopedOverObjectIsModified() {
+  ExpensiveToCopyType Orig;
+  for (const auto &Element : Orig) {
+const auto Copy = Element;
+Orig.nonConstMethod();
+Copy.constMethod();
+  }
+
+  auto Lambda = []() {
+ExpensiveToCopyType Orig;
+for (const auto &Element : Orig) {
+  const auto Copy = Element;
+  Orig.nonConstMethod();
+  Copy.constMethod();
+}
+  };
+}
+
+void negativeReferenceIsInitializedOutsideOfBlock() {
+  ExpensiveToCopyType Orig;
+  const auto &E2 = Orig;
+  if (1 != 2 * 3) {
+const auto C2 = E2;
+Orig.nonConstMethod();
+C2.constMethod();
+  }
+
+  auto Lambda = []() {
+ExpensiveToCopyType Orig;
+const auto &E2 = Orig;
+if (1 != 2 * 3) {
+  const auto C2 = E2;
+  Orig.nonConstMethod();
+  C2.constMethod();
+}
+  };
+}
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
@@ -10,6 +10,7 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_UNNECESSARY_COPY_INITIALIZATION_H
 
 #include "../ClangTidyCheck.h"
+#include "clang/AST/Decl.h"
 
 namespace clang {
 namespace tidy {
@@ -35,11 +36,12 @@
 
 private:
   void handleCopyFromMethodReturn(const VarDecl &Var, const Stmt &BlockStmt,
-  bool IssueFix, const VarDecl *ObjectArg,
+  const FunctionDecl &Func, bool IssueFix,
+  const VarDecl *ObjectArg,
   ASTContext &Context);
   void handleCopyFromLocalVar(const VarDecl &NewVar, const VarDecl &OldVar,
-  const Stmt &BlockStmt, bool IssueFix,
-  ASTContext &Context);
+  const Stmt &BlockStmt, const FunctionDecl &Func,
+  bool IssueFix, ASTContext &Context);
   const std::vector AllowedTypes;
 };
 
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -12,6 +12,7 @@
 #include "../utils/FixItHintUtils.h"
 #include "../utils/Matchers.h"
 #include "../utils/OptionsUtils.h"
+#include "clang/AST/Decl.h"
 #include "clang/Basic/Diagnostic.h"
 
 namespace clang {
@@ -68,6 +69,16 @@
 hasOperatorName("&"), hasUnaryOperand(OldVarDeclRef;
 }
 
+bool isDeclaredInFunction(const VarDecl &Var, const DeclContext &Func) {
+  const DeclContext *DC = Var.getDeclContext();
+  while (DC != nullptr) {
+if (DC == &Func)
+  return true;
+DC = DC->getLexicalParent();
+  }
+  return false;
+}
+
 // This checks that the variable itself is only used as const, and also makes
 // sure that it does not reference another variable that could be modified in
 // the BlockStmt. It does this by checking the following:
@@ -82,6 +93,7 @@
 // object arg or variable that is referenced is immutable as well.
 static bool isInitializingVariableImmutable(const VarDecl &InitializingVar,
 const Stmt &BlockStmt,
+  

[PATCH] D103021: [clang-tidy] performance-unnecessary-copy-initialization: Search whole function body for variable initializations.

2021-06-11 Thread Felix Berger via Phabricator via cfe-commits
flx marked an inline comment as done.
flx added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp:98-101
   auto Matches =
   match(findAll(declStmt(has(varDecl(equalsNode(&InitializingVar
 .bind("declStmt")),
+Body, Context);

ymandel wrote:
> flx wrote:
> > ymandel wrote:
> > > Consider inspecting the `DeclContext`s instead, which should be much more 
> > > efficient than searching the entire block.  Pass the `FunctionDecl` as an 
> > > argument instead of `Body`, since it is a `DeclContext`.  e.g. `const 
> > > DeclContext &Fun`
> > > 
> > > Then, either
> > > 1. Call `Fun.containsDecl(InitializingVar)`, or
> > > 2. Search through the contexts yourself; something like:
> > > ```
> > > DeclContext* DC = InitializingVar->getDeclContext(); 
> > > while (DC != nullptr && DC != &Fun)
> > >   DC = DC->getLexicalParent();
> > > if (DC == nullptr)
> > >   // The reference or pointer is not initialized anywhere witin the 
> > > function. We
> > >   // assume its pointee is not modified then.
> > >   return true;
> > > ```
> > Are #1 and #2 equivalent? From the implementation and comment I cannot tell 
> > whether #1 would cover cases where the variable is not declared directly in 
> > the function, but in child block:
> > 
> > ```
> > void Fun() {
> >  {
> >var i;
> >{
> >  i.usedHere();
> >}  
> >  } 
> > }
> > ```
> > 
> > I'm also reading this as an optimization to more quickly determine whether 
> > we can stop here. We still need to find the matches for the next steps, but 
> > I  think I could then limit matching to the DeclContext I found here. Is 
> > this correct? For this I would actually need the DeclContext result from #2.
> A. I think you're right that #2 is more suited to what you need. I wasn't 
> sure, so included both. Agreed that the comments are ambiguous.
> B. yes, this is just an optimization. it may be premature for that matter; 
> just that match can be expensive and this seemed a more direct expression of 
> the algorithm.
I was not able to pass the (possibly more narrow) DeclContext to the match 
function as scope since match does not support DeclContexts.

I implemented  isDeclaredInFunction() which iterates through the decl contexts 
as you suggested. I'm not sure though whether we should start with 
VarDecl::getDeclContext() or VarDecl::getLexicalDeclContext()?

While looking at VarDecl::getLexicalDeclContext() I discovered is VarDecl has 
the following method:

```
  /// Returns true for local variable declarations other than parameters.   
 
  /// Note that this includes static variables inside of functions. It also 
 
  /// includes variables inside blocks. 
 
  ///   
 
  ///   void foo() { int x; static int y; extern int z; }   
 
  bool isLocalVarDecl() const;
```

I think this is exactly what we'd want here. What do you think?



Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103021

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


[PATCH] D103087: [clang-tidy] performances-unnecessary-* checks: Extend isOnlyUsedAsConst to expressions and catch const methods returning non-const references/pointers.

2021-06-11 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

In D103087#2793673 , @ymandel wrote:

> I have some concerns about the cost of this checks as it used matching over 
> entire contexts quite extensively.  At this point, the facilities involved 
> seem quite close to doing dataflow analysis and I wonder if you might be 
> better off with a very different implementation. Regardless, have you done 
> any perfomance testing to see the impact on real code?

That's a fair point. Is there prior art in terms of dataflow analysis in 
ClangTidy or LLVM I could take a look at?

In terms of measuring performance, do you have suggestions how to measure this? 
I can add a counter that counts the recursion depth that is reached to see how 
often this happens in practice.

Another idea is to not count const methods from returning mutable pointer or 
reference types as const access. Standard types std::vector and absl::StatusOr 
would not be affected by this restriction, their const accessors return const 
references as well.

I'll hold off on this change until I see more false positives.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103087

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


[PATCH] D103021: [clang-tidy] performance-unnecessary-copy-initialization: Search whole function body for variable initializations.

2021-06-15 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 352233.
flx marked an inline comment as done.
flx added a comment.

Directly examine initializer.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103021

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -1,9 +1,19 @@
 // RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t
 
+template 
+struct Iterator {
+  void operator++();
+  const T &operator*() const;
+  bool operator!=(const Iterator &) const;
+  typedef const T &const_reference;
+};
+
 struct ExpensiveToCopyType {
   ExpensiveToCopyType();
   virtual ~ExpensiveToCopyType();
   const ExpensiveToCopyType &reference() const;
+  Iterator begin() const;
+  Iterator end() const;
   void nonConstMethod();
   bool constMethod() const;
 };
@@ -508,3 +518,41 @@
   // CHECK-FIXES: const auto& UnnecessaryCopy = Ref.reference();
   Orig.constMethod();
 }
+
+void negativeloopedOverObjectIsModified() {
+  ExpensiveToCopyType Orig;
+  for (const auto &Element : Orig) {
+const auto Copy = Element;
+Orig.nonConstMethod();
+Copy.constMethod();
+  }
+
+  auto Lambda = []() {
+ExpensiveToCopyType Orig;
+for (const auto &Element : Orig) {
+  const auto Copy = Element;
+  Orig.nonConstMethod();
+  Copy.constMethod();
+}
+  };
+}
+
+void negativeReferenceIsInitializedOutsideOfBlock() {
+  ExpensiveToCopyType Orig;
+  const auto &E2 = Orig;
+  if (1 != 2 * 3) {
+const auto C2 = E2;
+Orig.nonConstMethod();
+C2.constMethod();
+  }
+
+  auto Lambda = []() {
+ExpensiveToCopyType Orig;
+const auto &E2 = Orig;
+if (1 != 2 * 3) {
+  const auto C2 = E2;
+  Orig.nonConstMethod();
+  C2.constMethod();
+}
+  };
+}
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
@@ -10,6 +10,7 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_UNNECESSARY_COPY_INITIALIZATION_H
 
 #include "../ClangTidyCheck.h"
+#include "clang/AST/Decl.h"
 
 namespace clang {
 namespace tidy {
@@ -35,11 +36,12 @@
 
 private:
   void handleCopyFromMethodReturn(const VarDecl &Var, const Stmt &BlockStmt,
-  bool IssueFix, const VarDecl *ObjectArg,
+  const FunctionDecl &Func, bool IssueFix,
+  const VarDecl *ObjectArg,
   ASTContext &Context);
   void handleCopyFromLocalVar(const VarDecl &NewVar, const VarDecl &OldVar,
-  const Stmt &BlockStmt, bool IssueFix,
-  ASTContext &Context);
+  const Stmt &BlockStmt, const FunctionDecl &Func,
+  bool IssueFix, ASTContext &Context);
   const std::vector AllowedTypes;
 };
 
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -12,6 +12,7 @@
 #include "../utils/FixItHintUtils.h"
 #include "../utils/Matchers.h"
 #include "../utils/OptionsUtils.h"
+#include "clang/AST/Decl.h"
 #include "clang/Basic/Diagnostic.h"
 
 namespace clang {
@@ -61,11 +62,11 @@
 AST_MATCHER_FUNCTION(StatementMatcher, isInitializedFromReferenceToConst) {
   auto OldVarDeclRef =
   declRefExpr(to(varDecl(hasLocalStorage()).bind(OldVarDeclId)));
-  return declStmt(has(varDecl(hasInitializer(
+  return expr(
   anyOf(isConstRefReturningFunctionCall(), isConstRefReturningMethodCall(),
 ignoringImpCasts(OldVarDeclRef),
-ignoringImpCasts(unaryOperator(
-hasOperatorName("&"), hasUnaryOperand(OldVarDeclRef;
+ignoringImpCasts(unaryOperator(hasOperatorName("&"),
+   hasUnaryOperand(OldVarDeclRef);
 }
 
 // This checks that the variable itself is only used as const, and also makes
@@ -82,6 +83,7 @@
 // object arg or variable that is referenced is immutable as well.
 static bool isInitializingVariableImm

[PATCH] D103021: [clang-tidy] performance-unnecessary-copy-initialization: Search whole function body for variable initializations.

2021-06-15 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 352236.
flx added a comment.

Remove now unnecessary FunctionDecl.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103021

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -1,9 +1,19 @@
 // RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t
 
+template 
+struct Iterator {
+  void operator++();
+  const T &operator*() const;
+  bool operator!=(const Iterator &) const;
+  typedef const T &const_reference;
+};
+
 struct ExpensiveToCopyType {
   ExpensiveToCopyType();
   virtual ~ExpensiveToCopyType();
   const ExpensiveToCopyType &reference() const;
+  Iterator begin() const;
+  Iterator end() const;
   void nonConstMethod();
   bool constMethod() const;
 };
@@ -508,3 +518,41 @@
   // CHECK-FIXES: const auto& UnnecessaryCopy = Ref.reference();
   Orig.constMethod();
 }
+
+void negativeloopedOverObjectIsModified() {
+  ExpensiveToCopyType Orig;
+  for (const auto &Element : Orig) {
+const auto Copy = Element;
+Orig.nonConstMethod();
+Copy.constMethod();
+  }
+
+  auto Lambda = []() {
+ExpensiveToCopyType Orig;
+for (const auto &Element : Orig) {
+  const auto Copy = Element;
+  Orig.nonConstMethod();
+  Copy.constMethod();
+}
+  };
+}
+
+void negativeReferenceIsInitializedOutsideOfBlock() {
+  ExpensiveToCopyType Orig;
+  const auto &E2 = Orig;
+  if (1 != 2 * 3) {
+const auto C2 = E2;
+Orig.nonConstMethod();
+C2.constMethod();
+  }
+
+  auto Lambda = []() {
+ExpensiveToCopyType Orig;
+const auto &E2 = Orig;
+if (1 != 2 * 3) {
+  const auto C2 = E2;
+  Orig.nonConstMethod();
+  C2.constMethod();
+}
+  };
+}
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
@@ -10,6 +10,7 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_UNNECESSARY_COPY_INITIALIZATION_H
 
 #include "../ClangTidyCheck.h"
+#include "clang/AST/Decl.h"
 
 namespace clang {
 namespace tidy {
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -12,6 +12,7 @@
 #include "../utils/FixItHintUtils.h"
 #include "../utils/Matchers.h"
 #include "../utils/OptionsUtils.h"
+#include "clang/AST/Decl.h"
 #include "clang/Basic/Diagnostic.h"
 
 namespace clang {
@@ -61,11 +62,11 @@
 AST_MATCHER_FUNCTION(StatementMatcher, isInitializedFromReferenceToConst) {
   auto OldVarDeclRef =
   declRefExpr(to(varDecl(hasLocalStorage()).bind(OldVarDeclId)));
-  return declStmt(has(varDecl(hasInitializer(
+  return expr(
   anyOf(isConstRefReturningFunctionCall(), isConstRefReturningMethodCall(),
 ignoringImpCasts(OldVarDeclRef),
-ignoringImpCasts(unaryOperator(
-hasOperatorName("&"), hasUnaryOperand(OldVarDeclRef;
+ignoringImpCasts(unaryOperator(hasOperatorName("&"),
+   hasUnaryOperand(OldVarDeclRef);
 }
 
 // This checks that the variable itself is only used as const, and also makes
@@ -92,18 +93,14 @@
   if (!isa(T))
 return true;
 
-  auto Matches =
-  match(findAll(declStmt(has(varDecl(equalsNode(&InitializingVar
-.bind("declStmt")),
-BlockStmt, Context);
-  // The reference or pointer is not initialized in the BlockStmt. We assume
-  // its pointee is not modified then.
-  if (Matches.empty())
+  // The reference or pointer is not declared and hence not initialized anywhere
+  // in the function. We assume its pointee is not modified then.
+  if (!InitializingVar.isLocalVarDecl() || !InitializingVar.hasInit()) {
 return true;
+  }
 
-  const auto *Initialization = selectFirst("declStmt", Matches);
-  Matches =
-  match(isInitializedFromReferenceToConst(), *Initialization, Context);
+  auto Matches = match(isInitializedFromReferenceToConst(),
+   *InitializingVar.getInit(), Context);
   // The reference is init

[PATCH] D103021: [clang-tidy] performance-unnecessary-copy-initialization: Search whole function body for variable initializations.

2021-06-15 Thread Felix Berger via Phabricator via cfe-commits
flx marked an inline comment as done.
flx added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp:98-101
   auto Matches =
   match(findAll(declStmt(has(varDecl(equalsNode(&InitializingVar
 .bind("declStmt")),
+Body, Context);

ymandel wrote:
> flx wrote:
> > ymandel wrote:
> > > flx wrote:
> > > > ymandel wrote:
> > > > > Consider inspecting the `DeclContext`s instead, which should be much 
> > > > > more efficient than searching the entire block.  Pass the 
> > > > > `FunctionDecl` as an argument instead of `Body`, since it is a 
> > > > > `DeclContext`.  e.g. `const DeclContext &Fun`
> > > > > 
> > > > > Then, either
> > > > > 1. Call `Fun.containsDecl(InitializingVar)`, or
> > > > > 2. Search through the contexts yourself; something like:
> > > > > ```
> > > > > DeclContext* DC = InitializingVar->getDeclContext(); 
> > > > > while (DC != nullptr && DC != &Fun)
> > > > >   DC = DC->getLexicalParent();
> > > > > if (DC == nullptr)
> > > > >   // The reference or pointer is not initialized anywhere witin the 
> > > > > function. We
> > > > >   // assume its pointee is not modified then.
> > > > >   return true;
> > > > > ```
> > > > Are #1 and #2 equivalent? From the implementation and comment I cannot 
> > > > tell whether #1 would cover cases where the variable is not declared 
> > > > directly in the function, but in child block:
> > > > 
> > > > ```
> > > > void Fun() {
> > > >  {
> > > >var i;
> > > >{
> > > >  i.usedHere();
> > > >}  
> > > >  } 
> > > > }
> > > > ```
> > > > 
> > > > I'm also reading this as an optimization to more quickly determine 
> > > > whether we can stop here. We still need to find the matches for the 
> > > > next steps, but I  think I could then limit matching to the DeclContext 
> > > > I found here. Is this correct? For this I would actually need the 
> > > > DeclContext result from #2.
> > > A. I think you're right that #2 is more suited to what you need. I wasn't 
> > > sure, so included both. Agreed that the comments are ambiguous.
> > > B. yes, this is just an optimization. it may be premature for that 
> > > matter; just that match can be expensive and this seemed a more direct 
> > > expression of the algorithm.
> > I was not able to pass the (possibly more narrow) DeclContext to the match 
> > function as scope since match does not support DeclContexts.
> > 
> > I implemented  isDeclaredInFunction() which iterates through the decl 
> > contexts as you suggested. I'm not sure though whether we should start with 
> > VarDecl::getDeclContext() or VarDecl::getLexicalDeclContext()?
> > 
> > While looking at VarDecl::getLexicalDeclContext() I discovered is VarDecl 
> > has the following method:
> > 
> > ```
> >   /// Returns true for local variable declarations other than parameters.   
> >  
> >   /// Note that this includes static variables inside of functions. It also 
> >  
> >   /// includes variables inside blocks. 
> >  
> >   ///   
> >  
> >   ///   void foo() { int x; static int y; extern int z; }   
> >  
> >   bool isLocalVarDecl() const;
> > ```
> > 
> > I think this is exactly what we'd want here. What do you think?
> > 
> You mean instead of `isDeclaredInFunction`?  If so -- yes, that seems right.  
> But, if so, are you still planning to bind "declStmt" with the `match`, or 
> will you replace that with something more direct?
I was able to examine the`VarDecl.getInit()` expression directly. This 
completely avoids a search inside the function and he FunctionDecl is also no 
longer needed. PTAL.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103021

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


[PATCH] D103021: [clang-tidy] performance-unnecessary-copy-initialization: Search whole function body for variable initializations.

2021-06-18 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 353064.
flx marked 2 inline comments as done.
flx added a comment.

Renamed initializer matcher.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103021

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -1,9 +1,19 @@
 // RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t
 
+template 
+struct Iterator {
+  void operator++();
+  const T &operator*() const;
+  bool operator!=(const Iterator &) const;
+  typedef const T &const_reference;
+};
+
 struct ExpensiveToCopyType {
   ExpensiveToCopyType();
   virtual ~ExpensiveToCopyType();
   const ExpensiveToCopyType &reference() const;
+  Iterator begin() const;
+  Iterator end() const;
   void nonConstMethod();
   bool constMethod() const;
 };
@@ -508,3 +518,41 @@
   // CHECK-FIXES: const auto& UnnecessaryCopy = Ref.reference();
   Orig.constMethod();
 }
+
+void negativeloopedOverObjectIsModified() {
+  ExpensiveToCopyType Orig;
+  for (const auto &Element : Orig) {
+const auto Copy = Element;
+Orig.nonConstMethod();
+Copy.constMethod();
+  }
+
+  auto Lambda = []() {
+ExpensiveToCopyType Orig;
+for (const auto &Element : Orig) {
+  const auto Copy = Element;
+  Orig.nonConstMethod();
+  Copy.constMethod();
+}
+  };
+}
+
+void negativeReferenceIsInitializedOutsideOfBlock() {
+  ExpensiveToCopyType Orig;
+  const auto &E2 = Orig;
+  if (1 != 2 * 3) {
+const auto C2 = E2;
+Orig.nonConstMethod();
+C2.constMethod();
+  }
+
+  auto Lambda = []() {
+ExpensiveToCopyType Orig;
+const auto &E2 = Orig;
+if (1 != 2 * 3) {
+  const auto C2 = E2;
+  Orig.nonConstMethod();
+  C2.constMethod();
+}
+  };
+}
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
@@ -10,6 +10,7 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_UNNECESSARY_COPY_INITIALIZATION_H
 
 #include "../ClangTidyCheck.h"
+#include "clang/AST/Decl.h"
 
 namespace clang {
 namespace tidy {
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -12,6 +12,7 @@
 #include "../utils/FixItHintUtils.h"
 #include "../utils/Matchers.h"
 #include "../utils/OptionsUtils.h"
+#include "clang/AST/Decl.h"
 #include "clang/Basic/Diagnostic.h"
 
 namespace clang {
@@ -58,14 +59,14 @@
   .bind(InitFunctionCallId);
 }
 
-AST_MATCHER_FUNCTION(StatementMatcher, isInitializedFromReferenceToConst) {
+AST_MATCHER_FUNCTION(StatementMatcher, initializerReturnsReferenceToConst) {
   auto OldVarDeclRef =
   declRefExpr(to(varDecl(hasLocalStorage()).bind(OldVarDeclId)));
-  return declStmt(has(varDecl(hasInitializer(
+  return expr(
   anyOf(isConstRefReturningFunctionCall(), isConstRefReturningMethodCall(),
 ignoringImpCasts(OldVarDeclRef),
-ignoringImpCasts(unaryOperator(
-hasOperatorName("&"), hasUnaryOperand(OldVarDeclRef;
+ignoringImpCasts(unaryOperator(hasOperatorName("&"),
+   hasUnaryOperand(OldVarDeclRef);
 }
 
 // This checks that the variable itself is only used as const, and also makes
@@ -92,18 +93,14 @@
   if (!isa(T))
 return true;
 
-  auto Matches =
-  match(findAll(declStmt(has(varDecl(equalsNode(&InitializingVar
-.bind("declStmt")),
-BlockStmt, Context);
-  // The reference or pointer is not initialized in the BlockStmt. We assume
-  // its pointee is not modified then.
-  if (Matches.empty())
+  // The reference or pointer is not declared and hence not initialized anywhere
+  // in the function. We assume its pointee is not modified then.
+  if (!InitializingVar.isLocalVarDecl() || !InitializingVar.hasInit()) {
 return true;
+  }
 
-  const auto *Initialization = selectFirst("declStmt", Matches);
-  Matches =
-  match(isInitializedFromReferenceToConst(), *Initialization, Context);
+  

[PATCH] D103021: [clang-tidy] performance-unnecessary-copy-initialization: Search whole function body for variable initializations.

2021-06-18 Thread Felix Berger 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 rGbdd5da9dec61: [clang-tidy] 
performance-unnecessary-copy-initialization: Directly examine the… (authored by 
flx).

Changed prior to commit:
  https://reviews.llvm.org/D103021?vs=353064&id=353075#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103021

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -1,10 +1,20 @@
 // RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t
 
+template 
+struct Iterator {
+  void operator++();
+  const T &operator*() const;
+  bool operator!=(const Iterator &) const;
+  typedef const T &const_reference;
+};
+
 struct ExpensiveToCopyType {
   ExpensiveToCopyType();
   virtual ~ExpensiveToCopyType();
   const ExpensiveToCopyType &reference() const;
   const ExpensiveToCopyType *pointer() const;
+  Iterator begin() const;
+  Iterator end() const;
   void nonConstMethod();
   bool constMethod() const;
 };
@@ -589,3 +599,41 @@
   // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference(); // Trailing comment.
   // clang-format on
 }
+
+void negativeloopedOverObjectIsModified() {
+  ExpensiveToCopyType Orig;
+  for (const auto &Element : Orig) {
+const auto Copy = Element;
+Orig.nonConstMethod();
+Copy.constMethod();
+  }
+
+  auto Lambda = []() {
+ExpensiveToCopyType Orig;
+for (const auto &Element : Orig) {
+  const auto Copy = Element;
+  Orig.nonConstMethod();
+  Copy.constMethod();
+}
+  };
+}
+
+void negativeReferenceIsInitializedOutsideOfBlock() {
+  ExpensiveToCopyType Orig;
+  const auto &E2 = Orig;
+  if (1 != 2 * 3) {
+const auto C2 = E2;
+Orig.nonConstMethod();
+C2.constMethod();
+  }
+
+  auto Lambda = []() {
+ExpensiveToCopyType Orig;
+const auto &E2 = Orig;
+if (1 != 2 * 3) {
+  const auto C2 = E2;
+  Orig.nonConstMethod();
+  C2.constMethod();
+}
+  };
+}
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
@@ -10,6 +10,7 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_UNNECESSARY_COPY_INITIALIZATION_H
 
 #include "../ClangTidyCheck.h"
+#include "clang/AST/Decl.h"
 
 namespace clang {
 namespace tidy {
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -12,6 +12,7 @@
 #include "../utils/LexerUtils.h"
 #include "../utils/Matchers.h"
 #include "../utils/OptionsUtils.h"
+#include "clang/AST/Decl.h"
 #include "clang/Basic/Diagnostic.h"
 
 namespace clang {
@@ -72,14 +73,14 @@
   .bind(InitFunctionCallId);
 }
 
-AST_MATCHER_FUNCTION(StatementMatcher, isInitializedFromReferenceToConst) {
+AST_MATCHER_FUNCTION(StatementMatcher, initializerReturnsReferenceToConst) {
   auto OldVarDeclRef =
   declRefExpr(to(varDecl(hasLocalStorage()).bind(OldVarDeclId)));
-  return declStmt(has(varDecl(hasInitializer(
+  return expr(
   anyOf(isConstRefReturningFunctionCall(), isConstRefReturningMethodCall(),
 ignoringImpCasts(OldVarDeclRef),
-ignoringImpCasts(unaryOperator(
-hasOperatorName("&"), hasUnaryOperand(OldVarDeclRef;
+ignoringImpCasts(unaryOperator(hasOperatorName("&"),
+   hasUnaryOperand(OldVarDeclRef);
 }
 
 // This checks that the variable itself is only used as const, and also makes
@@ -106,18 +107,14 @@
   if (!isa(T))
 return true;
 
-  auto Matches =
-  match(findAll(declStmt(has(varDecl(equalsNode(&InitializingVar
-.bind("declStmt")),
-BlockStmt, Context);
-  // The reference or pointer is not initialized in the BlockStmt. We assume
-  // its pointee is not modified then.
-  if (Matches.empty())
+  // The reference or pointer is not declared and hence not initialized anywhere
+  // in the function. We ass

[PATCH] D105727: [clang-tidy] performance-unnecessary-copy-initialization: Disable structured bindings.

2021-07-09 Thread Felix Berger via Phabricator via cfe-commits
flx created this revision.
flx added reviewers: aaron.ballman, ymandel, gribozavr2.
Herald added a subscriber: xazax.hun.
flx requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

Structured bindings can currently trigger the check and lead to a wrong
fix. Because the DecompositionDecl itself is not used and the check does not
iterate through its the decl's bindings to verify whether the bindings' holding
vars are used this leads to the whole statement to be deleted.

To support structured bindings properly 3 cases would need to be considered.

1. All holding vars are not used -> The statement can be deleted.
2. All holding vars are used as const or not used -> auto can be converted to 
const auto&.
3. Neither case is true -> leave unchanged.

In the check we'll have to separate the logic that determines this from the code
that produces the diagnostic and fixes and first determine which of the cases
we're dealing with before creating fixes.

Since this is a bigger refactoring we'll disable structured bindings for now to
prevent incorrect fixes.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D105727

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t
+// RUN: %check_clang_tidy -std=c++17 %s 
performance-unnecessary-copy-initialization %t
 
 template 
 struct Iterator {
@@ -637,3 +637,18 @@
 }
   };
 }
+
+void negativeStructuredBinding() {
+  // Structured bindings are not yet supported but can trigger false positives
+  // since the DecompositionDecl itself is unused and the check doesn't 
traverse
+  // VarDecls of the BindingDecls.
+  struct Pair {
+ExpensiveToCopyType first;
+ExpensiveToCopyType second;
+  };
+
+  Pair P;
+  const auto [C, D] = P;
+  C.constMethod();
+  D.constMethod();
+}
Index: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -147,6 +147,7 @@
 return compoundStmt(
forEachDescendant(
declStmt(
+   unless(has(decompositionDecl())),
has(varDecl(hasLocalStorage(),
hasType(qualType(
hasCanonicalType(allOf(


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t
+// RUN: %check_clang_tidy -std=c++17 %s performance-unnecessary-copy-initialization %t
 
 template 
 struct Iterator {
@@ -637,3 +637,18 @@
 }
   };
 }
+
+void negativeStructuredBinding() {
+  // Structured bindings are not yet supported but can trigger false positives
+  // since the DecompositionDecl itself is unused and the check doesn't traverse
+  // VarDecls of the BindingDecls.
+  struct Pair {
+ExpensiveToCopyType first;
+ExpensiveToCopyType second;
+  };
+
+  Pair P;
+  const auto [C, D] = P;
+  C.constMethod();
+  D.constMethod();
+}
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -147,6 +147,7 @@
 return compoundStmt(
forEachDescendant(
declStmt(
+   unless(has(decompositionDecl())),
has(varDecl(hasLocalStorage(),
hasType(qualType(
hasCanonicalType(allOf(
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D105734: [clang-tidy] performance-unnecessary-copy-initialization: Do not remove comments on new lines.

2021-07-09 Thread Felix Berger via Phabricator via cfe-commits
flx created this revision.
flx added reviewers: ymandel, aaron.ballman, hokein.
Herald added a subscriber: xazax.hun.
flx requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

When deleting the copy assignment statement because copied variable is not used
only remove trailing comments on the same line.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D105734

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -596,8 +596,15 @@
   // CHECK-FIXES: int i = 0; // Foo bar.
   auto TrailingCommentRemoved = ExpensiveTypeReference(); // Trailing comment.
   // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 
'TrailingCommentRemoved' is copy-constructed from a const reference but is 
never used;
-  // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference(); 
// Trailing comment.
+  // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference();
+  // CHECK-FIXES-NOT: // Trailing comment.
   // clang-format on
+
+  auto UnusedAndUnnecessary = ExpensiveTypeReference();
+  // Comments on a new line should not be deleted.
+  // CHECK-MESSAGES: [[@LINE-2]]:8: warning: the variable 
'UnusedAndUnnecessary' is copy-constructed
+  // CHECK-FIXES-NOT: auto UnusedAndUnnecessary = ExpensiveTypeReference();
+  // CHECK-FIXES: // Comments on a new line should not be deleted.
 }
 
 void negativeloopedOverObjectIsModified() {
Index: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -41,12 +41,21 @@
 
 void recordRemoval(const DeclStmt &Stmt, ASTContext &Context,
DiagnosticBuilder &Diagnostic) {
-  // Attempt to remove the whole line until the next non-comment token.
+  // Attempt to remove trailing comments as well.
   auto Tok = utils::lexer::findNextTokenSkippingComments(
   Stmt.getEndLoc(), Context.getSourceManager(), Context.getLangOpts());
-  if (Tok) {
-Diagnostic << FixItHint::CreateRemoval(SourceRange(
-Stmt.getBeginLoc(), Tok->getLocation().getLocWithOffset(-1)));
+  bool Invalid;
+  const char *TextAfter =
+  Context.getSourceManager().getCharacterData(Stmt.getEndLoc(), &Invalid);
+  if (Tok && !Invalid) {
+size_t Offset = std::strcspn(TextAfter, "\n");
+auto PastNewLine = Stmt.getEndLoc().getLocWithOffset(Offset + 1);
+auto BeforeFirstTokenAfterComment = 
Tok->getLocation().getLocWithOffset(-1);
+// Remove until the end of the line or the end of a trailing comment which
+// ever comes first.
+auto End = std::min(PastNewLine, BeforeFirstTokenAfterComment);
+Diagnostic << FixItHint::CreateRemoval(
+SourceRange(Stmt.getBeginLoc(), End));
   } else {
 Diagnostic << FixItHint::CreateRemoval(Stmt.getSourceRange());
   }


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -596,8 +596,15 @@
   // CHECK-FIXES: int i = 0; // Foo bar.
   auto TrailingCommentRemoved = ExpensiveTypeReference(); // Trailing comment.
   // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'TrailingCommentRemoved' is copy-constructed from a const reference but is never used;
-  // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference(); // Trailing comment.
+  // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference();
+  // CHECK-FIXES-NOT: // Trailing comment.
   // clang-format on
+
+  auto UnusedAndUnnecessary = ExpensiveTypeReference();
+  // Comments on a new line should not be deleted.
+  // CHECK-MESSAGES: [[@LINE-2]]:8: warning: the variable 'UnusedAndUnnecessary' is copy-constructed
+  // CHECK-FIXES-NOT: auto UnusedAndUnnecessary = ExpensiveTypeReference();
+  // CHECK-FIXES: // Comments on a new line should not be deleted.
 }
 
 void negativeloopedOverObjectIsModified() {
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyI

[PATCH] D105727: [clang-tidy] performance-unnecessary-copy-initialization: Disable structured bindings.

2021-07-12 Thread Felix Berger via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG187e050b33bb: [clang-tidy] 
performance-unnecessary-copy-initialization: Disable structured… (authored by 
flx).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105727

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t
+// RUN: %check_clang_tidy -std=c++17 %s 
performance-unnecessary-copy-initialization %t
 
 template 
 struct Iterator {
@@ -637,3 +637,18 @@
 }
   };
 }
+
+void negativeStructuredBinding() {
+  // Structured bindings are not yet supported but can trigger false positives
+  // since the DecompositionDecl itself is unused and the check doesn't 
traverse
+  // VarDecls of the BindingDecls.
+  struct Pair {
+ExpensiveToCopyType first;
+ExpensiveToCopyType second;
+  };
+
+  Pair P;
+  const auto [C, D] = P;
+  C.constMethod();
+  D.constMethod();
+}
Index: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -147,6 +147,7 @@
 return compoundStmt(
forEachDescendant(
declStmt(
+   unless(has(decompositionDecl())),
has(varDecl(hasLocalStorage(),
hasType(qualType(
hasCanonicalType(allOf(


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t
+// RUN: %check_clang_tidy -std=c++17 %s performance-unnecessary-copy-initialization %t
 
 template 
 struct Iterator {
@@ -637,3 +637,18 @@
 }
   };
 }
+
+void negativeStructuredBinding() {
+  // Structured bindings are not yet supported but can trigger false positives
+  // since the DecompositionDecl itself is unused and the check doesn't traverse
+  // VarDecls of the BindingDecls.
+  struct Pair {
+ExpensiveToCopyType first;
+ExpensiveToCopyType second;
+  };
+
+  Pair P;
+  const auto [C, D] = P;
+  C.constMethod();
+  D.constMethod();
+}
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -147,6 +147,7 @@
 return compoundStmt(
forEachDescendant(
declStmt(
+   unless(has(decompositionDecl())),
has(varDecl(hasLocalStorage(),
hasType(qualType(
hasCanonicalType(allOf(
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D105734: [clang-tidy] performance-unnecessary-copy-initialization: Do not remove comments on new lines.

2021-07-12 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 357993.
flx added a comment.

Make offset operations safer.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105734

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -596,8 +596,15 @@
   // CHECK-FIXES: int i = 0; // Foo bar.
   auto TrailingCommentRemoved = ExpensiveTypeReference(); // Trailing comment.
   // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 
'TrailingCommentRemoved' is copy-constructed from a const reference but is 
never used;
-  // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference(); 
// Trailing comment.
+  // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference();
+  // CHECK-FIXES-NOT: // Trailing comment.
   // clang-format on
+
+  auto UnusedAndUnnecessary = ExpensiveTypeReference();
+  // Comments on a new line should not be deleted.
+  // CHECK-MESSAGES: [[@LINE-2]]:8: warning: the variable 
'UnusedAndUnnecessary' is copy-constructed
+  // CHECK-FIXES-NOT: auto UnusedAndUnnecessary = ExpensiveTypeReference();
+  // CHECK-FIXES: // Comments on a new line should not be deleted.
 }
 
 void negativeloopedOverObjectIsModified() {
Index: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -39,14 +39,35 @@
   }
 }
 
+llvm::Optional firstLocAfterNewLine(SourceLocation Loc,
+SourceManager &SM) {
+  bool Invalid;
+  const char *TextAfter = SM.getCharacterData(Loc, &Invalid);
+  if (Invalid) {
+return llvm::None;
+  }
+  size_t Offset = std::strcspn(TextAfter, "\n");
+  return Loc.getLocWithOffset(TextAfter[Offset] != '\0' ? Offset + 1 : Offset);
+}
+
 void recordRemoval(const DeclStmt &Stmt, ASTContext &Context,
DiagnosticBuilder &Diagnostic) {
-  // Attempt to remove the whole line until the next non-comment token.
-  auto Tok = utils::lexer::findNextTokenSkippingComments(
-  Stmt.getEndLoc(), Context.getSourceManager(), Context.getLangOpts());
-  if (Tok) {
-Diagnostic << FixItHint::CreateRemoval(SourceRange(
-Stmt.getBeginLoc(), Tok->getLocation().getLocWithOffset(-1)));
+  auto &SM = Context.getSourceManager();
+  // Attempt to remove trailing comments as well.
+  auto Tok = utils::lexer::findNextTokenSkippingComments(Stmt.getEndLoc(), SM,
+ 
Context.getLangOpts());
+  llvm::Optional PastNewLine =
+  firstLocAfterNewLine(Stmt.getEndLoc(), SM);
+  if (Tok && PastNewLine) {
+auto BeforeFirstTokenAfterComment = 
Tok->getLocation().getLocWithOffset(-1);
+// Remove until the end of the line or the end of a trailing comment which
+// ever comes first.
+auto End =
+SM.isBeforeInTranslationUnit(*PastNewLine, 
BeforeFirstTokenAfterComment)
+? *PastNewLine
+: BeforeFirstTokenAfterComment;
+Diagnostic << FixItHint::CreateRemoval(
+SourceRange(Stmt.getBeginLoc(), End));
   } else {
 Diagnostic << FixItHint::CreateRemoval(Stmt.getSourceRange());
   }


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -596,8 +596,15 @@
   // CHECK-FIXES: int i = 0; // Foo bar.
   auto TrailingCommentRemoved = ExpensiveTypeReference(); // Trailing comment.
   // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'TrailingCommentRemoved' is copy-constructed from a const reference but is never used;
-  // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference(); // Trailing comment.
+  // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference();
+  // CHECK-FIXES-NOT: // Trailing comment.
   // clang-format on
+
+  auto UnusedAndUnnecessary = ExpensiveTypeReference();
+  // Comments on a new line should not be deleted.
+  // CHECK-MESSAGES: [[@LINE-2]]:8: warning: the variable 'UnusedAndUnnecessary' is copy-constructed
+  // CHECK-FIXES-NOT: auto UnusedAndUnnecessary = ExpensiveTypeR

[PATCH] D105734: [clang-tidy] performance-unnecessary-copy-initialization: Do not remove comments on new lines.

2021-07-12 Thread Felix Berger via Phabricator via cfe-commits
flx marked 2 inline comments as done.
flx added a comment.

Thanks for the review!




Comment at: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp:51
+  if (Tok && !Invalid) {
+size_t Offset = std::strcspn(TextAfter, "\n");
+auto PastNewLine = Stmt.getEndLoc().getLocWithOffset(Offset + 1);

ymandel wrote:
> what happens for the last line in the file? I think the `Offset + 1` below 
> will be sketchy (because PastNewLine will be invalid). It might work, but 
> seems best avoided.
I added a check to not go past the end of the string. 



Comment at: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp:56
+// ever comes first.
+auto End = std::min(PastNewLine, BeforeFirstTokenAfterComment);
+Diagnostic << FixItHint::CreateRemoval(

ymandel wrote:
> I suspect this could get tripped up by macros and other expansions. Instead 
> of `std::min`, consider using `SourceManager::isBeforeInTranslationUnit`
> (clang/include/clang/Basic/SourceManager.h;l=1616)? Alternatively, check that 
> both locations are file ids before calling `std::min`.
We don't apply any fixes when the decl statement is inside of a macro, but 
switched to using SourceManager::isBeforeInTranslationUnit.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105734

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


[PATCH] D105734: [clang-tidy] performance-unnecessary-copy-initialization: Do not remove comments on new lines.

2021-07-12 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 358010.
flx marked 2 inline comments as done.
flx added a comment.

Invert end of string logic.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105734

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -596,8 +596,15 @@
   // CHECK-FIXES: int i = 0; // Foo bar.
   auto TrailingCommentRemoved = ExpensiveTypeReference(); // Trailing comment.
   // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 
'TrailingCommentRemoved' is copy-constructed from a const reference but is 
never used;
-  // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference(); 
// Trailing comment.
+  // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference();
+  // CHECK-FIXES-NOT: // Trailing comment.
   // clang-format on
+
+  auto UnusedAndUnnecessary = ExpensiveTypeReference();
+  // Comments on a new line should not be deleted.
+  // CHECK-MESSAGES: [[@LINE-2]]:8: warning: the variable 
'UnusedAndUnnecessary' is copy-constructed
+  // CHECK-FIXES-NOT: auto UnusedAndUnnecessary = ExpensiveTypeReference();
+  // CHECK-FIXES: // Comments on a new line should not be deleted.
 }
 
 void negativeloopedOverObjectIsModified() {
Index: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -39,14 +39,35 @@
   }
 }
 
+llvm::Optional firstLocAfterNewLine(SourceLocation Loc,
+SourceManager &SM) {
+  bool Invalid;
+  const char *TextAfter = SM.getCharacterData(Loc, &Invalid);
+  if (Invalid) {
+return llvm::None;
+  }
+  size_t Offset = std::strcspn(TextAfter, "\n");
+  return Loc.getLocWithOffset(TextAfter[Offset] == '\0' ? Offset : Offset + 1);
+}
+
 void recordRemoval(const DeclStmt &Stmt, ASTContext &Context,
DiagnosticBuilder &Diagnostic) {
-  // Attempt to remove the whole line until the next non-comment token.
-  auto Tok = utils::lexer::findNextTokenSkippingComments(
-  Stmt.getEndLoc(), Context.getSourceManager(), Context.getLangOpts());
-  if (Tok) {
-Diagnostic << FixItHint::CreateRemoval(SourceRange(
-Stmt.getBeginLoc(), Tok->getLocation().getLocWithOffset(-1)));
+  auto &SM = Context.getSourceManager();
+  // Attempt to remove trailing comments as well.
+  auto Tok = utils::lexer::findNextTokenSkippingComments(Stmt.getEndLoc(), SM,
+ 
Context.getLangOpts());
+  llvm::Optional PastNewLine =
+  firstLocAfterNewLine(Stmt.getEndLoc(), SM);
+  if (Tok && PastNewLine) {
+auto BeforeFirstTokenAfterComment = 
Tok->getLocation().getLocWithOffset(-1);
+// Remove until the end of the line or the end of a trailing comment which
+// ever comes first.
+auto End =
+SM.isBeforeInTranslationUnit(*PastNewLine, 
BeforeFirstTokenAfterComment)
+? *PastNewLine
+: BeforeFirstTokenAfterComment;
+Diagnostic << FixItHint::CreateRemoval(
+SourceRange(Stmt.getBeginLoc(), End));
   } else {
 Diagnostic << FixItHint::CreateRemoval(Stmt.getSourceRange());
   }


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -596,8 +596,15 @@
   // CHECK-FIXES: int i = 0; // Foo bar.
   auto TrailingCommentRemoved = ExpensiveTypeReference(); // Trailing comment.
   // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'TrailingCommentRemoved' is copy-constructed from a const reference but is never used;
-  // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference(); // Trailing comment.
+  // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference();
+  // CHECK-FIXES-NOT: // Trailing comment.
   // clang-format on
+
+  auto UnusedAndUnnecessary = ExpensiveTypeReference();
+  // Comments on a new line should not be deleted.
+  // CHECK-MESSAGES: [[@LINE-2]]:8: warning: the variable 'UnusedAndUnnecessary' is copy-constructed
+  // CHECK-FIXES-NOT: auto U

[PATCH] D105734: [clang-tidy] performance-unnecessary-copy-initialization: Do not remove comments on new lines.

2021-07-12 Thread Felix Berger via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG0ec812023b43: [clang-tidy] 
performance-unnecessary-copy-initialization: Do not remove… (authored by flx).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105734

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -596,8 +596,15 @@
   // CHECK-FIXES: int i = 0; // Foo bar.
   auto TrailingCommentRemoved = ExpensiveTypeReference(); // Trailing comment.
   // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 
'TrailingCommentRemoved' is copy-constructed from a const reference but is 
never used;
-  // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference(); 
// Trailing comment.
+  // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference();
+  // CHECK-FIXES-NOT: // Trailing comment.
   // clang-format on
+
+  auto UnusedAndUnnecessary = ExpensiveTypeReference();
+  // Comments on a new line should not be deleted.
+  // CHECK-MESSAGES: [[@LINE-2]]:8: warning: the variable 
'UnusedAndUnnecessary' is copy-constructed
+  // CHECK-FIXES-NOT: auto UnusedAndUnnecessary = ExpensiveTypeReference();
+  // CHECK-FIXES: // Comments on a new line should not be deleted.
 }
 
 void negativeloopedOverObjectIsModified() {
Index: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -39,14 +39,35 @@
   }
 }
 
+llvm::Optional firstLocAfterNewLine(SourceLocation Loc,
+SourceManager &SM) {
+  bool Invalid;
+  const char *TextAfter = SM.getCharacterData(Loc, &Invalid);
+  if (Invalid) {
+return llvm::None;
+  }
+  size_t Offset = std::strcspn(TextAfter, "\n");
+  return Loc.getLocWithOffset(TextAfter[Offset] == '\0' ? Offset : Offset + 1);
+}
+
 void recordRemoval(const DeclStmt &Stmt, ASTContext &Context,
DiagnosticBuilder &Diagnostic) {
-  // Attempt to remove the whole line until the next non-comment token.
-  auto Tok = utils::lexer::findNextTokenSkippingComments(
-  Stmt.getEndLoc(), Context.getSourceManager(), Context.getLangOpts());
-  if (Tok) {
-Diagnostic << FixItHint::CreateRemoval(SourceRange(
-Stmt.getBeginLoc(), Tok->getLocation().getLocWithOffset(-1)));
+  auto &SM = Context.getSourceManager();
+  // Attempt to remove trailing comments as well.
+  auto Tok = utils::lexer::findNextTokenSkippingComments(Stmt.getEndLoc(), SM,
+ 
Context.getLangOpts());
+  llvm::Optional PastNewLine =
+  firstLocAfterNewLine(Stmt.getEndLoc(), SM);
+  if (Tok && PastNewLine) {
+auto BeforeFirstTokenAfterComment = 
Tok->getLocation().getLocWithOffset(-1);
+// Remove until the end of the line or the end of a trailing comment which
+// ever comes first.
+auto End =
+SM.isBeforeInTranslationUnit(*PastNewLine, 
BeforeFirstTokenAfterComment)
+? *PastNewLine
+: BeforeFirstTokenAfterComment;
+Diagnostic << FixItHint::CreateRemoval(
+SourceRange(Stmt.getBeginLoc(), End));
   } else {
 Diagnostic << FixItHint::CreateRemoval(Stmt.getSourceRange());
   }


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -596,8 +596,15 @@
   // CHECK-FIXES: int i = 0; // Foo bar.
   auto TrailingCommentRemoved = ExpensiveTypeReference(); // Trailing comment.
   // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'TrailingCommentRemoved' is copy-constructed from a const reference but is never used;
-  // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference(); // Trailing comment.
+  // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference();
+  // CHECK-FIXES-NOT: // Trailing comment.
   // clang-format on
+
+  auto UnusedAndUnnecessary = ExpensiveTypeReference();
+  // Comments on a new line should not be deleted.
+  // CHECK-MESSAGES: [[@LINE-2]]:8: warning: the variable 'Un

[PATCH] D106011: [clang-tidy] performance-unnecessary-copy-initialization: Disable check when variable and initializer have different replaced template param types.

2021-07-14 Thread Felix Berger via Phabricator via cfe-commits
flx created this revision.
flx added reviewers: aaron.ballman, ymandel, hokein.
Herald added a subscriber: xazax.hun.
flx requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

This can happen when a template with two parameter types is instantiated with a
single type. The fix would only be valid for this instantiation but fail for
others that rely on an implicit type conversion.

The test cases illustrate when the check should trigger and when not.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D106011

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -17,6 +17,9 @@
   Iterator end() const;
   void nonConstMethod();
   bool constMethod() const;
+  template 
+  const A &templatedAccessor() const;
+  operator int() const; // Implicit conversion to int.
 };
 
 struct TrivialToCopyType {
@@ -659,3 +662,54 @@
   C.constMethod();
   D.constMethod();
 }
+
+template 
+const A &templatedReference();
+
+template 
+void negativeTemplateTypes() {
+  A Orig;
+  // Different replaced template type params do not trigger the check. In some
+  // template instantiation this might not be a copy but an implicit
+  // conversion, so converting this to a reference might not work.
+  B AmbiguousCopy = Orig;
+  // CHECK-NOT-FIXES: B AmbiguousCopy = Orig;
+
+  B NecessaryCopy = templatedReference();
+  // CHECK-NOT-FIXES: B NecessaryCopy = templatedReference();
+
+  B NecessaryCopy2 = Orig.template templatedAccessor();
+
+  // Non-dependent types in template still trigger the check.
+  const auto UnnecessaryCopy = ExpensiveTypeReference();
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' is copy-constructed
+  // CHECK-FIXES: const auto& UnnecessaryCopy = ExpensiveTypeReference();
+  UnnecessaryCopy.constMethod();
+}
+
+void instantiateNegativeTemplateTypes() {
+  negativeTemplateTypes();
+  // This template instantiation would not compile if the `AmbiguousCopy` above was made a reference.
+  negativeTemplateTypes();
+}
+
+template 
+void positiveSingleTemplateType() {
+  A Orig;
+  A SingleTmplParmTypeCopy = Orig;
+  // CHECK-MESSAGES: [[@LINE-1]]:5: warning: local copy 'SingleTmplParmTypeCopy' of the variable 'Orig' is never modified
+  // CHECK-FIXES: const A& SingleTmplParmTypeCopy = Orig;
+  SingleTmplParmTypeCopy.constMethod();
+
+  A UnnecessaryCopy2 = templatedReference();
+  // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the variable 'UnnecessaryCopy2' is copy-constructed from a const reference
+  // CHECK-FIXES: const A& UnnecessaryCopy2 = templatedReference();
+  UnnecessaryCopy2.constMethod();
+
+  A UnnecessaryCopy3 = Orig.template templatedAccessor();
+  // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the variable 'UnnecessaryCopy3' is copy-constructed from a const reference
+  // CHECK-FIXES: const A& UnnecessaryCopy3 = Orig.template templatedAccessor();
+  UnnecessaryCopy3.constMethod();
+}
+
+void instantiatePositiveSingleTemplateType() { positiveSingleTemplateType(); }
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -27,6 +27,8 @@
 
 static constexpr StringRef ObjectArgId = "objectArg";
 static constexpr StringRef InitFunctionCallId = "initFunctionCall";
+static constexpr StringRef MethodDeclId = "methodDecl";
+static constexpr StringRef FunctionDeclId = "functionDecl";
 static constexpr StringRef OldVarDeclId = "oldVarDecl";
 
 void recordFixes(const VarDecl &Var, ASTContext &Context,
@@ -81,7 +83,8 @@
   // returned either points to a global static variable or to a member of the
   // called object.
   return cxxMemberCallExpr(
-  callee(cxxMethodDecl(returns(matchers::isReferenceToConst(,
+  callee(cxxMethodDecl(returns(matchers::isReferenceToConst()))
+ .bind(MethodDeclId)),
   on(declRefExpr(to(varDecl().bind(ObjectArgId);
 }
 
@@ -89,7 +92,8 @@
   // Only allow initialization of a const reference from a free function if it
   // has no arguments. Otherwise it could return an alias to one of its
   // arguments and the arguments need to be checked for const use as well.
-  return callExpr(callee(functionDecl(returns(matchers::isReferenceToConst(,
+  return callExpr(callee(functionDecl(returns(matchers::isReferenc

[PATCH] D112722: [clang-tidy]performance-unnecessary-copy-initialization: fix false negative

2021-10-28 Thread Felix Berger via Phabricator via cfe-commits
flx accepted this revision.
flx added a comment.
This revision is now accepted and ready to land.

Thanks for the fix!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D112722

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


[PATCH] D97567: [clang-tidy] performance-* checks: Also allow allow member expressions to be used in a const manner.

2021-02-26 Thread Felix Berger via Phabricator via cfe-commits
flx created this revision.
flx added reviewers: aaron.ballman, sbenza.
Herald added a subscriber: xazax.hun.
flx requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Until now when determining all the const uses of a VarDecl we only considered
how the variable itself was used. This change extends checking for const usages
of the type's members as well.

This increases the number of true positives for various performance checks that
share the same const usage analysis.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D97567

Files:
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
  clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
@@ -296,3 +296,37 @@
 // SS : createView(*ValueReturningIterator())) {
   }
 }
+
+void positiveConstMemberExpr() {
+  struct Struct {
+Mutable Member;
+  };
+  for (Struct SS : View>()) {
+// CHECK-MESSAGES: [[@LINE-1]]:15: warning: loop variable is copied
+// CHECK-FIXES: for (const Struct& SS : View>()) {
+auto MemberCopy = SS.Member;
+const auto &ConstRef = SS.Member;
+bool b = SS.Member.constMethod();
+use(SS.Member);
+useByConstValue(SS.Member);
+useByValue(SS.Member);
+  }
+}
+
+void negativeNonConstMemberExpr() {
+  struct Struct {
+Mutable Member;
+  };
+  for (Struct SS : View>()) {
+SS.Member.setBool(true);
+  }
+  for (Struct SS : View>()) {
+SS.Member[1];
+  }
+  for (Struct SS : View>()) {
+mutate(SS.Member);
+  }
+  for (Struct SS : View>()) {
+mutate(&SS.Member);
+  }
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -46,14 +46,19 @@
ASTContext &Context) {
   auto DeclRefToVar =
   declRefExpr(to(varDecl(equalsNode(&VarDecl.bind("declRef");
+  auto MemberExprOfVar = memberExpr(has(DeclRefToVar));
+  auto DeclRefToVarOrMemberExprOfVar =
+  stmt(anyOf(DeclRefToVar, MemberExprOfVar));
   auto ConstMethodCallee = callee(cxxMethodDecl(isConst()));
   // Match method call expressions where the variable is referenced as the this
   // implicit object argument and opertor call expression for member operators
   // where the variable is the 0-th argument.
   auto Matches = match(
-  findAll(expr(anyOf(cxxMemberCallExpr(ConstMethodCallee, on(DeclRefToVar)),
- cxxOperatorCallExpr(ConstMethodCallee,
- hasArgument(0, DeclRefToVar),
+  findAll(expr(anyOf(
+  cxxMemberCallExpr(ConstMethodCallee,
+on(DeclRefToVarOrMemberExprOfVar)),
+  cxxOperatorCallExpr(ConstMethodCallee,
+  hasArgument(0, DeclRefToVarOrMemberExprOfVar),
   Stmt, Context);
   SmallPtrSet DeclRefs;
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
@@ -65,22 +70,23 @@
   ConstReferenceOrValue,
   substTemplateTypeParmType(hasReplacementType(ConstReferenceOrValue;
   auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
-  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValueOrReplaced)));
+  DeclRefToVarOrMemberExprOfVar,
+  parmVarDecl(hasType(ConstReferenceOrValueOrReplaced)));
   Matches = match(findAll(invocation(UsedAsConstRefOrValueArg)), Stmt, Context);
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   // References and pointers to const assignments.
-  Matches =
-  match(findAll(declStmt(
-has(varDecl(hasType(qualType(matchers::isReferenceToConst())),
-hasInitializer(ignoringImpCasts(DeclRefToVar)),
-Stmt, Context);
+  Matches = match(
+  findAll(declStmt(has(varDecl(
+  hasType(qualType(matchers::isReferenceToConst())),
+  hasInitializer(ignoringImpCasts(DeclRefToVarOrMemberExprOfVar)),
+  Stmt, Context);
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
-  Matches =
-  match(findAll(declStmt(has(varDecl(
-hasType(qualType(matchers::isPointerToConst())),
-hasInitializer(ignoringImpCasts(unaryOperator(
-hasOperatorName("&"), hasUnaryOperand(DeclRefToVar,
-Stmt, Context);
+  Matches = match(findAll(declStmt(has(varDecl(
+  hasType(qualType(matchers::isPointerToConst())),
+  hasInitializer(ignoringImpCasts(unaryOperator(
+  hasOperatorName("&"),
+  hasUnary

[PATCH] D97577: [clang-tidy] performance-for-range-copy: Don't trigger on implicit type conversions.

2021-02-26 Thread Felix Berger via Phabricator via cfe-commits
flx created this revision.
flx added reviewers: aaron.ballman, alexfh, sbenza.
Herald added a subscriber: xazax.hun.
flx requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This disables the check for false positive cases where implicit type conversion
through either an implicit single argument constructor or a member conversion
operator is triggered when constructing the loop variable.

Fix the test cases that meant to cover these cases.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D97577

Files:
  clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
@@ -60,13 +60,13 @@
 
 void negativeUserDefinedConversion() {
   Convertible C[0];
-  for (const S &S1 : C) {
+  for (const S S1 : C) {
   }
 }
 
 void negativeImplicitConstructorConversion() {
   ConstructorConvertible C[0];
-  for (const S &S1 : C) {
+  for (const S S1 : C) {
   }
 }
 
Index: clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
===
--- clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
+++ clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
@@ -12,6 +12,7 @@
 #include "../utils/Matchers.h"
 #include "../utils/OptionsUtils.h"
 #include "../utils/TypeTraits.h"
+#include 
"third_party/llvm/llvm-project/clang/include/clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Analysis/Analyses/ExprMutationAnalyzer.h"
 #include "clang/Basic/Diagnostic.h"
 
@@ -45,10 +46,14 @@
   hasOverloadedOperatorName("*"),
   callee(
   cxxMethodDecl(returns(unless(hasCanonicalType(referenceType()));
+  auto NotConstructedByCopy = cxxConstructExpr(
+  hasDeclaration(cxxConstructorDecl(unless(isCopyConstructor();
+  auto ConstructedByConversion = 
cxxMemberCallExpr(callee(cxxConversionDecl()));
   auto LoopVar =
   varDecl(HasReferenceOrPointerTypeOrIsAllowed,
-  unless(hasInitializer(expr(hasDescendant(expr(anyOf(
-  materializeTemporaryExpr(), IteratorReturnsValueType)));
+  unless(hasInitializer(expr(hasDescendant(expr(
+  anyOf(materializeTemporaryExpr(), IteratorReturnsValueType,
+NotConstructedByCopy, ConstructedByConversion)));
   Finder->addMatcher(
   traverse(TK_AsIs,
cxxForRangeStmt(hasLoopVariable(LoopVar.bind("loopVar")))


Index: clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
@@ -60,13 +60,13 @@
 
 void negativeUserDefinedConversion() {
   Convertible C[0];
-  for (const S &S1 : C) {
+  for (const S S1 : C) {
   }
 }
 
 void negativeImplicitConstructorConversion() {
   ConstructorConvertible C[0];
-  for (const S &S1 : C) {
+  for (const S S1 : C) {
   }
 }
 
Index: clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
===
--- clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
+++ clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
@@ -12,6 +12,7 @@
 #include "../utils/Matchers.h"
 #include "../utils/OptionsUtils.h"
 #include "../utils/TypeTraits.h"
+#include "third_party/llvm/llvm-project/clang/include/clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Analysis/Analyses/ExprMutationAnalyzer.h"
 #include "clang/Basic/Diagnostic.h"
 
@@ -45,10 +46,14 @@
   hasOverloadedOperatorName("*"),
   callee(
   cxxMethodDecl(returns(unless(hasCanonicalType(referenceType()));
+  auto NotConstructedByCopy = cxxConstructExpr(
+  hasDeclaration(cxxConstructorDecl(unless(isCopyConstructor();
+  auto ConstructedByConversion = cxxMemberCallExpr(callee(cxxConversionDecl()));
   auto LoopVar =
   varDecl(HasReferenceOrPointerTypeOrIsAllowed,
-  unless(hasInitializer(expr(hasDescendant(expr(anyOf(
-  materializeTemporaryExpr(), IteratorReturnsValueType)));
+  unless(hasInitializer(expr(hasDescendant(expr(
+  anyOf(materializeTemporaryExpr(), IteratorReturnsValueType,
+NotConstructedByCopy, ConstructedByConversion)));
   Finder->addMatcher(
   traverse(TK_AsIs,
cxxForRangeStmt(hasLoopVariable(LoopVar.bind("loopVar")))
___
cfe-commits mailing list
cfe-commits@lists.

[PATCH] D97577: [clang-tidy] performance-for-range-copy: Don't trigger on implicit type conversions.

2021-02-26 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 326792.
flx added a comment.

Remove include.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97577

Files:
  clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
@@ -60,13 +60,13 @@
 
 void negativeUserDefinedConversion() {
   Convertible C[0];
-  for (const S &S1 : C) {
+  for (const S S1 : C) {
   }
 }
 
 void negativeImplicitConstructorConversion() {
   ConstructorConvertible C[0];
-  for (const S &S1 : C) {
+  for (const S S1 : C) {
   }
 }
 
Index: clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
===
--- clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
+++ clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
@@ -12,6 +12,7 @@
 #include "../utils/Matchers.h"
 #include "../utils/OptionsUtils.h"
 #include "../utils/TypeTraits.h"
+#include 
"third_party/llvm/llvm-project/clang/include/clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Analysis/Analyses/ExprMutationAnalyzer.h"
 #include "clang/Basic/Diagnostic.h"
 
@@ -45,10 +46,14 @@
   hasOverloadedOperatorName("*"),
   callee(
   cxxMethodDecl(returns(unless(hasCanonicalType(referenceType()));
+  auto NotConstructedByCopy = cxxConstructExpr(
+  hasDeclaration(cxxConstructorDecl(unless(isCopyConstructor();
+  auto ConstructedByConversion = 
cxxMemberCallExpr(callee(cxxConversionDecl()));
   auto LoopVar =
   varDecl(HasReferenceOrPointerTypeOrIsAllowed,
-  unless(hasInitializer(expr(hasDescendant(expr(anyOf(
-  materializeTemporaryExpr(), IteratorReturnsValueType)));
+  unless(hasInitializer(expr(hasDescendant(expr(
+  anyOf(materializeTemporaryExpr(), IteratorReturnsValueType,
+NotConstructedByCopy, ConstructedByConversion)));
   Finder->addMatcher(
   traverse(TK_AsIs,
cxxForRangeStmt(hasLoopVariable(LoopVar.bind("loopVar")))


Index: clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
@@ -60,13 +60,13 @@
 
 void negativeUserDefinedConversion() {
   Convertible C[0];
-  for (const S &S1 : C) {
+  for (const S S1 : C) {
   }
 }
 
 void negativeImplicitConstructorConversion() {
   ConstructorConvertible C[0];
-  for (const S &S1 : C) {
+  for (const S S1 : C) {
   }
 }
 
Index: clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
===
--- clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
+++ clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
@@ -12,6 +12,7 @@
 #include "../utils/Matchers.h"
 #include "../utils/OptionsUtils.h"
 #include "../utils/TypeTraits.h"
+#include "third_party/llvm/llvm-project/clang/include/clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Analysis/Analyses/ExprMutationAnalyzer.h"
 #include "clang/Basic/Diagnostic.h"
 
@@ -45,10 +46,14 @@
   hasOverloadedOperatorName("*"),
   callee(
   cxxMethodDecl(returns(unless(hasCanonicalType(referenceType()));
+  auto NotConstructedByCopy = cxxConstructExpr(
+  hasDeclaration(cxxConstructorDecl(unless(isCopyConstructor();
+  auto ConstructedByConversion = cxxMemberCallExpr(callee(cxxConversionDecl()));
   auto LoopVar =
   varDecl(HasReferenceOrPointerTypeOrIsAllowed,
-  unless(hasInitializer(expr(hasDescendant(expr(anyOf(
-  materializeTemporaryExpr(), IteratorReturnsValueType)));
+  unless(hasInitializer(expr(hasDescendant(expr(
+  anyOf(materializeTemporaryExpr(), IteratorReturnsValueType,
+NotConstructedByCopy, ConstructedByConversion)));
   Finder->addMatcher(
   traverse(TK_AsIs,
cxxForRangeStmt(hasLoopVariable(LoopVar.bind("loopVar")))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D97577: [clang-tidy] performance-for-range-copy: Don't trigger on implicit type conversions.

2021-02-26 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 326793.
flx added a comment.

Remove include.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97577

Files:
  clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
@@ -60,13 +60,13 @@
 
 void negativeUserDefinedConversion() {
   Convertible C[0];
-  for (const S &S1 : C) {
+  for (const S S1 : C) {
   }
 }
 
 void negativeImplicitConstructorConversion() {
   ConstructorConvertible C[0];
-  for (const S &S1 : C) {
+  for (const S S1 : C) {
   }
 }
 
Index: clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
===
--- clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
+++ clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
@@ -45,10 +45,14 @@
   hasOverloadedOperatorName("*"),
   callee(
   cxxMethodDecl(returns(unless(hasCanonicalType(referenceType()));
+  auto NotConstructedByCopy = cxxConstructExpr(
+  hasDeclaration(cxxConstructorDecl(unless(isCopyConstructor();
+  auto ConstructedByConversion = 
cxxMemberCallExpr(callee(cxxConversionDecl()));
   auto LoopVar =
   varDecl(HasReferenceOrPointerTypeOrIsAllowed,
-  unless(hasInitializer(expr(hasDescendant(expr(anyOf(
-  materializeTemporaryExpr(), IteratorReturnsValueType)));
+  unless(hasInitializer(expr(hasDescendant(expr(
+  anyOf(materializeTemporaryExpr(), IteratorReturnsValueType,
+NotConstructedByCopy, ConstructedByConversion)));
   Finder->addMatcher(
   traverse(TK_AsIs,
cxxForRangeStmt(hasLoopVariable(LoopVar.bind("loopVar")))


Index: clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
@@ -60,13 +60,13 @@
 
 void negativeUserDefinedConversion() {
   Convertible C[0];
-  for (const S &S1 : C) {
+  for (const S S1 : C) {
   }
 }
 
 void negativeImplicitConstructorConversion() {
   ConstructorConvertible C[0];
-  for (const S &S1 : C) {
+  for (const S S1 : C) {
   }
 }
 
Index: clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
===
--- clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
+++ clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
@@ -45,10 +45,14 @@
   hasOverloadedOperatorName("*"),
   callee(
   cxxMethodDecl(returns(unless(hasCanonicalType(referenceType()));
+  auto NotConstructedByCopy = cxxConstructExpr(
+  hasDeclaration(cxxConstructorDecl(unless(isCopyConstructor();
+  auto ConstructedByConversion = cxxMemberCallExpr(callee(cxxConversionDecl()));
   auto LoopVar =
   varDecl(HasReferenceOrPointerTypeOrIsAllowed,
-  unless(hasInitializer(expr(hasDescendant(expr(anyOf(
-  materializeTemporaryExpr(), IteratorReturnsValueType)));
+  unless(hasInitializer(expr(hasDescendant(expr(
+  anyOf(materializeTemporaryExpr(), IteratorReturnsValueType,
+NotConstructedByCopy, ConstructedByConversion)));
   Finder->addMatcher(
   traverse(TK_AsIs,
cxxForRangeStmt(hasLoopVariable(LoopVar.bind("loopVar")))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D97567: [clang-tidy] performance-* checks: Also allow allow member expressions to be used in a const manner.

2021-02-26 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 326798.
flx added a comment.

Add tests for PerformanceUnnecssaryCopyInitialization check which actually uses
decl_ref_expr::isOnlyUsedAsConst().


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97567

Files:
  clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
  clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -508,3 +508,36 @@
   // CHECK-FIXES: const auto& UnnecessaryCopy = Ref.reference();
   Orig.constMethod();
 }
+
+struct Struct {
+  ExpensiveToCopyType Member;
+};
+
+void positiveConstMemberExpr() {
+  Struct Orig;
+  auto UC = Orig;
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: local copy 'UC'
+  // CHECK-FIXES: const auto& UC = Orig;
+  const auto &ConstRef = UC.Member;
+  auto MemberCopy = UC.Member;
+  bool b = UC.Member.constMethod();
+  useByValue(UC.Member);
+  useAsConstReference(UC.Member);
+  useByValue(UC.Member);
+}
+
+void negativeNonConstMemberExpr() {
+  Struct Orig;
+  {
+auto Copy = Orig;
+Copy.Member.nonConstMethod();
+  }
+  {
+auto Copy = Orig;
+mutate(Copy.Member);
+  }
+  {
+auto Copy = Orig;
+mutate(&Copy.Member);
+  }
+}
Index: clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
@@ -296,3 +296,37 @@
 // SS : createView(*ValueReturningIterator())) {
   }
 }
+
+void positiveConstMemberExpr() {
+  struct Struct {
+Mutable Member;
+  };
+  for (Struct SS : View>()) {
+// CHECK-MESSAGES: [[@LINE-1]]:15: warning: loop variable is copied
+// CHECK-FIXES: for (const Struct& SS : View>()) {
+auto MemberCopy = SS.Member;
+const auto &ConstRef = SS.Member;
+bool b = SS.Member.constMethod();
+use(SS.Member);
+useByConstValue(SS.Member);
+useByValue(SS.Member);
+  }
+}
+
+void negativeNonConstMemberExpr() {
+  struct Struct {
+Mutable Member;
+  };
+  for (Struct SS : View>()) {
+SS.Member.setBool(true);
+  }
+  for (Struct SS : View>()) {
+SS.Member[1];
+  }
+  for (Struct SS : View>()) {
+mutate(SS.Member);
+  }
+  for (Struct SS : View>()) {
+mutate(&SS.Member);
+  }
+}
Index: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -46,14 +46,19 @@
ASTContext &Context) {
   auto DeclRefToVar =
   declRefExpr(to(varDecl(equalsNode(&VarDecl.bind("declRef");
+  auto MemberExprOfVar = memberExpr(has(DeclRefToVar));
+  auto DeclRefToVarOrMemberExprOfVar =
+  stmt(anyOf(DeclRefToVar, MemberExprOfVar));
   auto ConstMethodCallee = callee(cxxMethodDecl(isConst()));
   // Match method call expressions where the variable is referenced as the this
   // implicit object argument and opertor call expression for member operators
   // where the variable is the 0-th argument.
   auto Matches = match(
-  findAll(expr(anyOf(cxxMemberCallExpr(ConstMethodCallee, on(DeclRefToVar)),
- cxxOperatorCallExpr(ConstMethodCallee,
- hasArgument(0, DeclRefToVar),
+  findAll(expr(anyOf(
+  cxxMemberCallExpr(ConstMethodCallee,
+on(DeclRefToVarOrMemberExprOfVar)),
+  cxxOperatorCallExpr(ConstMethodCallee,
+  hasArgument(0, DeclRefToVarOrMemberExprOfVar),
   Stmt, Context);
   SmallPtrSet DeclRefs;
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
@@ -65,22 +70,23 @@
   ConstReferenceOrValue,
   substTemplateTypeParmType(hasReplacementType(ConstReferenceOrValue;
   auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
-  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValueOrReplaced)));
+  DeclRefToVarOrMemberExprOfVar,
+  parmVarDecl(hasType(ConstReferenceOrValueOrReplaced)));
   Matches = match(findAll(invocation(UsedAsConstRefOrValueArg)), Stmt, Context);
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   // References and pointers to const assignments.
-  Matches =
-  match(findAll(declStmt(
-has(varDecl(hasType(qualType(matchers::isReferenceToConst())),
-   

[PATCH] D97577: [clang-tidy] performance-for-range-copy: Don't trigger on implicit type conversions.

2021-02-28 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

In D97577#2592093 , @lebedev.ri wrote:

> It is best not to change existing tests, but add new ones.

Could elaborate on this, Roman?

In this case the tests use special auto convertible types with the intention to 
test that the check doesn't trigger because the loop variable needs to be 
constructed. But the reason they don't trigger is that the loop variable 
erroneously is already a reference type.

If we keep the tests as is we should rename the test functions and use 
different types or document that the real reason they don't trigger is that 
they already are const reference types, but we already have a test for that as 
well.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97577

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


[PATCH] D97577: [clang-tidy] performance-for-range-copy: Don't trigger on implicit type conversions.

2021-03-02 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

Thank you for the review!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97577

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


[PATCH] D97577: [clang-tidy] performance-for-range-copy: Don't trigger on implicit type conversions.

2021-03-02 Thread Felix Berger via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGa189b3b9e8bb: [clang-tidy] performance-for-range-copy: 
Don't trigger on implicit type… (authored by flx).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97577

Files:
  clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
@@ -60,13 +60,13 @@
 
 void negativeUserDefinedConversion() {
   Convertible C[0];
-  for (const S &S1 : C) {
+  for (const S S1 : C) {
   }
 }
 
 void negativeImplicitConstructorConversion() {
   ConstructorConvertible C[0];
-  for (const S &S1 : C) {
+  for (const S S1 : C) {
   }
 }
 
Index: clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
===
--- clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
+++ clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
@@ -45,10 +45,14 @@
   hasOverloadedOperatorName("*"),
   callee(
   cxxMethodDecl(returns(unless(hasCanonicalType(referenceType()));
+  auto NotConstructedByCopy = cxxConstructExpr(
+  hasDeclaration(cxxConstructorDecl(unless(isCopyConstructor();
+  auto ConstructedByConversion = 
cxxMemberCallExpr(callee(cxxConversionDecl()));
   auto LoopVar =
   varDecl(HasReferenceOrPointerTypeOrIsAllowed,
-  unless(hasInitializer(expr(hasDescendant(expr(anyOf(
-  materializeTemporaryExpr(), IteratorReturnsValueType)));
+  unless(hasInitializer(expr(hasDescendant(expr(
+  anyOf(materializeTemporaryExpr(), IteratorReturnsValueType,
+NotConstructedByCopy, ConstructedByConversion)));
   Finder->addMatcher(
   traverse(TK_AsIs,
cxxForRangeStmt(hasLoopVariable(LoopVar.bind("loopVar")))


Index: clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
@@ -60,13 +60,13 @@
 
 void negativeUserDefinedConversion() {
   Convertible C[0];
-  for (const S &S1 : C) {
+  for (const S S1 : C) {
   }
 }
 
 void negativeImplicitConstructorConversion() {
   ConstructorConvertible C[0];
-  for (const S &S1 : C) {
+  for (const S S1 : C) {
   }
 }
 
Index: clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
===
--- clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
+++ clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
@@ -45,10 +45,14 @@
   hasOverloadedOperatorName("*"),
   callee(
   cxxMethodDecl(returns(unless(hasCanonicalType(referenceType()));
+  auto NotConstructedByCopy = cxxConstructExpr(
+  hasDeclaration(cxxConstructorDecl(unless(isCopyConstructor();
+  auto ConstructedByConversion = cxxMemberCallExpr(callee(cxxConversionDecl()));
   auto LoopVar =
   varDecl(HasReferenceOrPointerTypeOrIsAllowed,
-  unless(hasInitializer(expr(hasDescendant(expr(anyOf(
-  materializeTemporaryExpr(), IteratorReturnsValueType)));
+  unless(hasInitializer(expr(hasDescendant(expr(
+  anyOf(materializeTemporaryExpr(), IteratorReturnsValueType,
+NotConstructedByCopy, ConstructedByConversion)));
   Finder->addMatcher(
   traverse(TK_AsIs,
cxxForRangeStmt(hasLoopVariable(LoopVar.bind("loopVar")))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D97567: [clang-tidy] performance-* checks: Also allow allow member expressions to be used in a const manner.

2021-03-15 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

Hi,

could someone please take a look at this? Thanks!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97567

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


[PATCH] D114212: [clang-tidy] performance-unnecessary-copy-initialization: Correctly match the type name of the thisPointertype.

2021-11-18 Thread Felix Berger via Phabricator via cfe-commits
flx created this revision.
flx added reviewers: ymandel, courbet, aaron.ballman.
Herald added subscribers: carlosgalvezp, xazax.hun.
flx requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

The matching did not work correctly for pointer and reference types.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D114212

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
@@ -58,3 +58,13 @@
   const auto E = C.secretlyMutates();
   E.constMethod();
 }
+
+void excludedConstIncorrectTypeAsPointer(ConstInCorrectType *C) {
+  const auto E = C->secretlyMutates();
+  E.constMethod();
+}
+
+void excludedConstIncorrectTypeAsReference(const ConstInCorrectType &C) {
+  const auto E = C.secretlyMutates();
+  E.constMethod();
+}
Index: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -87,11 +87,9 @@
   callee(cxxMethodDecl(
  returns(hasCanonicalType(matchers::isReferenceToConst(
  .bind(MethodDeclId)),
-  on(declRefExpr(to(
-  varDecl(
-  
unless(hasType(qualType(hasCanonicalType(hasDeclaration(namedDecl(
-  matchers::matchesAnyListedName(ExcludedContainerTypes
-  .bind(ObjectArgId);
+  on(declRefExpr(to(varDecl().bind(ObjectArgId,
+  thisPointerType(namedDecl(
+  unless(matchers::matchesAnyListedName(ExcludedContainerTypes);
 }
 
 AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningFunctionCall) {


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
@@ -58,3 +58,13 @@
   const auto E = C.secretlyMutates();
   E.constMethod();
 }
+
+void excludedConstIncorrectTypeAsPointer(ConstInCorrectType *C) {
+  const auto E = C->secretlyMutates();
+  E.constMethod();
+}
+
+void excludedConstIncorrectTypeAsReference(const ConstInCorrectType &C) {
+  const auto E = C.secretlyMutates();
+  E.constMethod();
+}
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -87,11 +87,9 @@
   callee(cxxMethodDecl(
  returns(hasCanonicalType(matchers::isReferenceToConst(
  .bind(MethodDeclId)),
-  on(declRefExpr(to(
-  varDecl(
-  unless(hasType(qualType(hasCanonicalType(hasDeclaration(namedDecl(
-  matchers::matchesAnyListedName(ExcludedContainerTypes
-  .bind(ObjectArgId);
+  on(declRefExpr(to(varDecl().bind(ObjectArgId,
+  thisPointerType(namedDecl(
+  unless(matchers::matchesAnyListedName(ExcludedContainerTypes);
 }
 
 AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningFunctionCall) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D114249: [clang-tidy] performance-unnecessary-copy-initialization: Fix false negative.

2021-11-19 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

Thank you for catching and fixing this!




Comment at: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp:97
+  cxxOperatorCallExpr(callee(MethodDecl), hasArgument(0, ReceiverExpr),
+  hasArgument(0, hasType(recordType(hasDeclaration(
+ ReceiverTypeDecl)));

Does this work if if the object argument is a pointer or a type alias? Could 
you add a test to confirm?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D114249

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


[PATCH] D114212: [clang-tidy] performance-unnecessary-copy-initialization: Correctly match the type name of the thisPointertype.

2021-11-20 Thread Felix Berger via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGfefe20b99313: [clang-tidy] 
performance-unnecessary-copy-initialization: Correctly match the… (authored by 
flx).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D114212

Files:
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
@@ -58,3 +58,13 @@
   const auto E = C.secretlyMutates();
   E.constMethod();
 }
+
+void excludedConstIncorrectTypeAsPointer(ConstInCorrectType *C) {
+  const auto E = C->secretlyMutates();
+  E.constMethod();
+}
+
+void excludedConstIncorrectTypeAsReference(const ConstInCorrectType &C) {
+  const auto E = C.secretlyMutates();
+  E.constMethod();
+}
Index: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -87,11 +87,9 @@
   callee(cxxMethodDecl(
  returns(hasCanonicalType(matchers::isReferenceToConst(
  .bind(MethodDeclId)),
-  on(declRefExpr(to(
-  varDecl(
-  
unless(hasType(qualType(hasCanonicalType(hasDeclaration(namedDecl(
-  matchers::matchesAnyListedName(ExcludedContainerTypes
-  .bind(ObjectArgId);
+  on(declRefExpr(to(varDecl().bind(ObjectArgId,
+  thisPointerType(namedDecl(
+  unless(matchers::matchesAnyListedName(ExcludedContainerTypes);
 }
 
 AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningFunctionCall) {


Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
@@ -58,3 +58,13 @@
   const auto E = C.secretlyMutates();
   E.constMethod();
 }
+
+void excludedConstIncorrectTypeAsPointer(ConstInCorrectType *C) {
+  const auto E = C->secretlyMutates();
+  E.constMethod();
+}
+
+void excludedConstIncorrectTypeAsReference(const ConstInCorrectType &C) {
+  const auto E = C.secretlyMutates();
+  E.constMethod();
+}
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -87,11 +87,9 @@
   callee(cxxMethodDecl(
  returns(hasCanonicalType(matchers::isReferenceToConst(
  .bind(MethodDeclId)),
-  on(declRefExpr(to(
-  varDecl(
-  unless(hasType(qualType(hasCanonicalType(hasDeclaration(namedDecl(
-  matchers::matchesAnyListedName(ExcludedContainerTypes
-  .bind(ObjectArgId);
+  on(declRefExpr(to(varDecl().bind(ObjectArgId,
+  thisPointerType(namedDecl(
+  unless(matchers::matchesAnyListedName(ExcludedContainerTypes);
 }
 
 AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningFunctionCall) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D114249: [clang-tidy] performance-unnecessary-copy-initialization: Fix false negative.

2021-11-23 Thread Felix Berger via Phabricator via cfe-commits
flx accepted this revision.
flx added inline comments.
This revision is now accepted and ready to land.



Comment at: 
clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp:228-232
+void PositiveOperatorCallConstValueParam(const Container* 
C) {
+  const auto AutoAssigned = (*C)[42];
+  // TODO-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 
'AutoAssigned'
+  // TODO-FIXES: const auto& AutoAssigned = (*C)[42];
+  AutoAssigned.constMethod();

Would you mind adding this test also to the file testing the exclusion of 
containers:

https://github.com/llvm/llvm-project/blob/main/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp

This would cover whether the type matching of pointer types works for excluded 
container types.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D114249

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


[PATCH] D114539: [clang-tidy] performance-unnecessary-copy-initialization: handle pointer containers.

2021-11-24 Thread Felix Berger via Phabricator via cfe-commits
flx added a comment.

This looks great, but goes past my knowledge of the AST API :) While the 
existing and new test coverage provides good confidence, one other reviewer 
taking look would be good.




Comment at: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp:112
+  switch (
+  E->ClassifyModifiable(Finder->getASTContext(), Loc).getModifiable()) 
{
+  case Expr::Classification::CM_Untested:

Reuse Ctx here?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D114539

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


[PATCH] D114559: [clang] ASTMatchers: Fix out-of-bounds access in foreachArgumentWithParamType.

2021-11-24 Thread Felix Berger via Phabricator via cfe-commits
flx created this revision.
flx requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

The matcher crashes when a variadic function pointer is invoked because the
FunctionProtoType has fewer parameters than arguments.

Matching of non-variadic arguments now works.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D114559

Files:
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp


Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1094,6 +1094,31 @@
   S, CallExpr, std::make_unique>("arg")));
 }
 
+TEST(ForEachArgumentWithParamType, MatchesVariadicFunctionPtrCalls) {
+  StatementMatcher ArgumentY =
+  declRefExpr(to(varDecl(hasName("y".bind("arg");
+  TypeMatcher IntType = qualType(builtinType()).bind("type");
+  StatementMatcher CallExpr =
+  callExpr(forEachArgumentWithParamType(ArgumentY, IntType));
+
+  StringRef S = R"cpp(
+void fcntl(int fd, int cmd, ...) {}
+
+template 
+void f(Func F) {
+  int y = 42;
+  F(y, 1, 3);
+}
+
+void g() { f(fcntl); }
+  )cpp";
+
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  S, CallExpr, std::make_unique>("type")));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  S, CallExpr, std::make_unique>("arg")));
+}
+
 TEST(QualType, hasCanonicalType) {
   EXPECT_TRUE(notMatches("typedef int &int_ref;"
"int a;"
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -4885,7 +4885,7 @@
 
   // This test is cheaper compared to the big matcher in the next if.
   // Therefore, please keep this order.
-  if (FProto) {
+  if (FProto && FProto->getNumParams() > ParamIndex) {
 QualType ParamType = FProto->getParamType(ParamIndex);
 if (ParamMatcher.matches(ParamType, Finder, &ParamMatches)) {
   Result.addMatch(ParamMatches);


Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1094,6 +1094,31 @@
   S, CallExpr, std::make_unique>("arg")));
 }
 
+TEST(ForEachArgumentWithParamType, MatchesVariadicFunctionPtrCalls) {
+  StatementMatcher ArgumentY =
+  declRefExpr(to(varDecl(hasName("y".bind("arg");
+  TypeMatcher IntType = qualType(builtinType()).bind("type");
+  StatementMatcher CallExpr =
+  callExpr(forEachArgumentWithParamType(ArgumentY, IntType));
+
+  StringRef S = R"cpp(
+void fcntl(int fd, int cmd, ...) {}
+
+template 
+void f(Func F) {
+  int y = 42;
+  F(y, 1, 3);
+}
+
+void g() { f(fcntl); }
+  )cpp";
+
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  S, CallExpr, std::make_unique>("type")));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  S, CallExpr, std::make_unique>("arg")));
+}
+
 TEST(QualType, hasCanonicalType) {
   EXPECT_TRUE(notMatches("typedef int &int_ref;"
"int a;"
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -4885,7 +4885,7 @@
 
   // This test is cheaper compared to the big matcher in the next if.
   // Therefore, please keep this order.
-  if (FProto) {
+  if (FProto && FProto->getNumParams() > ParamIndex) {
 QualType ParamType = FProto->getParamType(ParamIndex);
 if (ParamMatcher.matches(ParamType, Finder, &ParamMatches)) {
   Result.addMatch(ParamMatches);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D27187: [clang-tidy] Do not move parameter if only DeclRefExpr occurs inside of a loop

2016-12-15 Thread Felix Berger via Phabricator via cfe-commits
flx updated this revision to Diff 81693.

https://reviews.llvm.org/D27187

Files:
  clang-tidy/performance/UnnecessaryValueParamCheck.cpp
  test/clang-tidy/performance-unnecessary-value-param.cpp


Index: test/clang-tidy/performance-unnecessary-value-param.cpp
===
--- test/clang-tidy/performance-unnecessary-value-param.cpp
+++ test/clang-tidy/performance-unnecessary-value-param.cpp
@@ -225,6 +225,15 @@
   // CHECK-FIXES: F = std::move(E);
 }
 
+// The argument could be moved but is not since copy statement is inside a 
loop.
+void PositiveNoMoveInsideLoop(ExpensiveMovableType E) {
+  // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the parameter 'E' is copied
+  // CHECK-FIXES: void PositiveNoMoveInsideLoop(const ExpensiveMovableType& E) 
{
+  for (;;) {
+auto F = E;
+  }
+}
+
 void PositiveConstRefNotMoveConstructible(ExpensiveToCopyType T) {
   // CHECK-MESSAGES: [[@LINE-1]]:63: warning: the parameter 'T' is copied
   // CHECK-FIXES: void PositiveConstRefNotMoveConstructible(const 
ExpensiveToCopyType& T) {
Index: clang-tidy/performance/UnnecessaryValueParamCheck.cpp
===
--- clang-tidy/performance/UnnecessaryValueParamCheck.cpp
+++ clang-tidy/performance/UnnecessaryValueParamCheck.cpp
@@ -47,6 +47,17 @@
   return !Matches.empty();
 }
 
+bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Stmt &Stmt,
+ ASTContext &Context) {
+  auto Matches =
+  match(findAll(declRefExpr(
+equalsNode(&DeclRef),
+unless(hasAncestor(stmt(anyOf(forStmt(), cxxForRangeStmt(),
+  whileStmt(), doStmt())),
+Stmt, Context);
+  return Matches.empty();
+}
+
 } // namespace
 
 UnnecessaryValueParamCheck::UnnecessaryValueParamCheck(
@@ -105,6 +116,8 @@
   if (!IsConstQualified) {
 auto CanonicalType = Param->getType().getCanonicalType();
 if (AllDeclRefExprs.size() == 1 &&
+!hasLoopStmtAncestor(**AllDeclRefExprs.begin(), *Function->getBody(),
+ *Result.Context) &&
 ((utils::type_traits::hasNonTrivialMoveConstructor(CanonicalType) &&
   utils::decl_ref_expr::isCopyConstructorArgument(
   **AllDeclRefExprs.begin(), *Function->getBody(),


Index: test/clang-tidy/performance-unnecessary-value-param.cpp
===
--- test/clang-tidy/performance-unnecessary-value-param.cpp
+++ test/clang-tidy/performance-unnecessary-value-param.cpp
@@ -225,6 +225,15 @@
   // CHECK-FIXES: F = std::move(E);
 }
 
+// The argument could be moved but is not since copy statement is inside a loop.
+void PositiveNoMoveInsideLoop(ExpensiveMovableType E) {
+  // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the parameter 'E' is copied
+  // CHECK-FIXES: void PositiveNoMoveInsideLoop(const ExpensiveMovableType& E) {
+  for (;;) {
+auto F = E;
+  }
+}
+
 void PositiveConstRefNotMoveConstructible(ExpensiveToCopyType T) {
   // CHECK-MESSAGES: [[@LINE-1]]:63: warning: the parameter 'T' is copied
   // CHECK-FIXES: void PositiveConstRefNotMoveConstructible(const ExpensiveToCopyType& T) {
Index: clang-tidy/performance/UnnecessaryValueParamCheck.cpp
===
--- clang-tidy/performance/UnnecessaryValueParamCheck.cpp
+++ clang-tidy/performance/UnnecessaryValueParamCheck.cpp
@@ -47,6 +47,17 @@
   return !Matches.empty();
 }
 
+bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Stmt &Stmt,
+ ASTContext &Context) {
+  auto Matches =
+  match(findAll(declRefExpr(
+equalsNode(&DeclRef),
+unless(hasAncestor(stmt(anyOf(forStmt(), cxxForRangeStmt(),
+  whileStmt(), doStmt())),
+Stmt, Context);
+  return Matches.empty();
+}
+
 } // namespace
 
 UnnecessaryValueParamCheck::UnnecessaryValueParamCheck(
@@ -105,6 +116,8 @@
   if (!IsConstQualified) {
 auto CanonicalType = Param->getType().getCanonicalType();
 if (AllDeclRefExprs.size() == 1 &&
+!hasLoopStmtAncestor(**AllDeclRefExprs.begin(), *Function->getBody(),
+ *Result.Context) &&
 ((utils::type_traits::hasNonTrivialMoveConstructor(CanonicalType) &&
   utils::decl_ref_expr::isCopyConstructorArgument(
   **AllDeclRefExprs.begin(), *Function->getBody(),
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D27187: [clang-tidy] Do not move parameter if only DeclRefExpr occurs inside of a loop

2016-12-15 Thread Felix Berger via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
flx marked an inline comment as done.
Closed by commit rL289912: [clang-tidy] Do not move parameter if only 
DeclRefExpr occurs inside of a loop (authored by flx).

Changed prior to commit:
  https://reviews.llvm.org/D27187?vs=81693&id=81706#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D27187

Files:
  clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
  
clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp


Index: 
clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
===
--- 
clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
+++ 
clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
@@ -47,6 +47,17 @@
   return !Matches.empty();
 }
 
+bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Stmt &Stmt,
+ ASTContext &Context) {
+  auto Matches =
+  match(findAll(declRefExpr(
+equalsNode(&DeclRef),
+unless(hasAncestor(stmt(anyOf(forStmt(), cxxForRangeStmt(),
+  whileStmt(), doStmt())),
+Stmt, Context);
+  return Matches.empty();
+}
+
 } // namespace
 
 UnnecessaryValueParamCheck::UnnecessaryValueParamCheck(
@@ -105,6 +116,8 @@
   if (!IsConstQualified) {
 auto CanonicalType = Param->getType().getCanonicalType();
 if (AllDeclRefExprs.size() == 1 &&
+!hasLoopStmtAncestor(**AllDeclRefExprs.begin(), *Function->getBody(),
+ *Result.Context) &&
 ((utils::type_traits::hasNonTrivialMoveConstructor(CanonicalType) &&
   utils::decl_ref_expr::isCopyConstructorArgument(
   **AllDeclRefExprs.begin(), *Function->getBody(),
Index: 
clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp
===
--- 
clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp
+++ 
clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp
@@ -225,6 +225,15 @@
   // CHECK-FIXES: F = std::move(E);
 }
 
+// The argument could be moved but is not since copy statement is inside a 
loop.
+void PositiveNoMoveInsideLoop(ExpensiveMovableType E) {
+  // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the parameter 'E' is copied
+  // CHECK-FIXES: void PositiveNoMoveInsideLoop(const ExpensiveMovableType& E) 
{
+  for (;;) {
+auto F = E;
+  }
+}
+
 void PositiveConstRefNotMoveConstructible(ExpensiveToCopyType T) {
   // CHECK-MESSAGES: [[@LINE-1]]:63: warning: the parameter 'T' is copied
   // CHECK-FIXES: void PositiveConstRefNotMoveConstructible(const 
ExpensiveToCopyType& T) {


Index: clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
@@ -47,6 +47,17 @@
   return !Matches.empty();
 }
 
+bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Stmt &Stmt,
+ ASTContext &Context) {
+  auto Matches =
+  match(findAll(declRefExpr(
+equalsNode(&DeclRef),
+unless(hasAncestor(stmt(anyOf(forStmt(), cxxForRangeStmt(),
+  whileStmt(), doStmt())),
+Stmt, Context);
+  return Matches.empty();
+}
+
 } // namespace
 
 UnnecessaryValueParamCheck::UnnecessaryValueParamCheck(
@@ -105,6 +116,8 @@
   if (!IsConstQualified) {
 auto CanonicalType = Param->getType().getCanonicalType();
 if (AllDeclRefExprs.size() == 1 &&
+!hasLoopStmtAncestor(**AllDeclRefExprs.begin(), *Function->getBody(),
+ *Result.Context) &&
 ((utils::type_traits::hasNonTrivialMoveConstructor(CanonicalType) &&
   utils::decl_ref_expr::isCopyConstructorArgument(
   **AllDeclRefExprs.begin(), *Function->getBody(),
Index: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp
@@ -225,6 +225,15 @@
   // CHECK-FIXES: F = std::move(E);
 }
 
+// The argument could be moved but is not since copy statement is inside a loop.
+void PositiveNoMoveInsideLoop(ExpensiveMovableType E) {
+  // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the parameter 'E' is copied
+  // CHECK-FIXES: void PositiveNoMoveInsideLoop(const ExpensiveMovableType& E) {
+  for (;;) {
+auto F = E;
+  }
+}
+
 void PositiveConstRefNotMoveConstructible(ExpensiveT

[PATCH] D28899: [clang-tidy] Do not trigger move fix for non-copy assignment operators in performance-unnecessary-value-param check

2017-01-19 Thread Felix Berger via Phabricator via cfe-commits
flx created this revision.
Herald added a subscriber: JDevlieghere.

Repository:
  rL LLVM

https://reviews.llvm.org/D28899

Files:
  clang-tidy/utils/DeclRefExprUtils.cpp
  test/clang-tidy/performance-unnecessary-value-param.cpp


Index: test/clang-tidy/performance-unnecessary-value-param.cpp
===
--- test/clang-tidy/performance-unnecessary-value-param.cpp
+++ test/clang-tidy/performance-unnecessary-value-param.cpp
@@ -247,6 +247,17 @@
   // CHECK-FIXES: F = std::move(E);
 }
 
+struct NotCopyAssigned {
+  NotCopyAssigned &operator=(const ExpensiveMovableType &);
+};
+
+void PositiveNoMoveForNonCopyAssigmentOperator(ExpensiveMovableType E) {
+  // CHECK-MESSAGES: [[@LINE-1]]:69: warning: the parameter 'E' is copied
+  // CHECK-FIXES: void PositiveNoMoveForNonCopyAssigmentOperator(const 
ExpensiveMovableType& E) {
+  NotCopyAssigned N;
+  N = E;
+}
+
 // The argument could be moved but is not since copy statement is inside a 
loop.
 void PositiveNoMoveInsideLoop(ExpensiveMovableType E) {
   // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the parameter 'E' is copied
Index: clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tidy/utils/DeclRefExprUtils.cpp
@@ -159,7 +159,8 @@
   parmVarDecl(hasType(matchers::isReferenceToConst(;
   auto Matches = match(
   decl(hasDescendant(
-  cxxOperatorCallExpr(UsedAsConstRefArg, 
hasOverloadedOperatorName("="))
+  cxxOperatorCallExpr(UsedAsConstRefArg, 
hasOverloadedOperatorName("="),
+  
callee(cxxMethodDecl(isCopyAssignmentOperator(
   .bind("operatorCallExpr"))),
   Decl, Context);
   return !Matches.empty();


Index: test/clang-tidy/performance-unnecessary-value-param.cpp
===
--- test/clang-tidy/performance-unnecessary-value-param.cpp
+++ test/clang-tidy/performance-unnecessary-value-param.cpp
@@ -247,6 +247,17 @@
   // CHECK-FIXES: F = std::move(E);
 }
 
+struct NotCopyAssigned {
+  NotCopyAssigned &operator=(const ExpensiveMovableType &);
+};
+
+void PositiveNoMoveForNonCopyAssigmentOperator(ExpensiveMovableType E) {
+  // CHECK-MESSAGES: [[@LINE-1]]:69: warning: the parameter 'E' is copied
+  // CHECK-FIXES: void PositiveNoMoveForNonCopyAssigmentOperator(const ExpensiveMovableType& E) {
+  NotCopyAssigned N;
+  N = E;
+}
+
 // The argument could be moved but is not since copy statement is inside a loop.
 void PositiveNoMoveInsideLoop(ExpensiveMovableType E) {
   // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the parameter 'E' is copied
Index: clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tidy/utils/DeclRefExprUtils.cpp
@@ -159,7 +159,8 @@
   parmVarDecl(hasType(matchers::isReferenceToConst(;
   auto Matches = match(
   decl(hasDescendant(
-  cxxOperatorCallExpr(UsedAsConstRefArg, hasOverloadedOperatorName("="))
+  cxxOperatorCallExpr(UsedAsConstRefArg, hasOverloadedOperatorName("="),
+  callee(cxxMethodDecl(isCopyAssignmentOperator(
   .bind("operatorCallExpr"))),
   Decl, Context);
   return !Matches.empty();
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D28899: [clang-tidy] Do not trigger move fix for non-copy assignment operators in performance-unnecessary-value-param check

2017-01-19 Thread Felix Berger via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL292491: [clang-tidy] Do not trigger move fix for non-copy 
assignment operators in… (authored by flx).

Changed prior to commit:
  https://reviews.llvm.org/D28899?vs=84960&id=84967#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D28899

Files:
  clang-tools-extra/trunk/clang-tidy/utils/DeclRefExprUtils.cpp
  
clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp


Index: clang-tools-extra/trunk/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/trunk/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/trunk/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -159,7 +159,8 @@
   parmVarDecl(hasType(matchers::isReferenceToConst(;
   auto Matches = match(
   decl(hasDescendant(
-  cxxOperatorCallExpr(UsedAsConstRefArg, 
hasOverloadedOperatorName("="))
+  cxxOperatorCallExpr(UsedAsConstRefArg, 
hasOverloadedOperatorName("="),
+  
callee(cxxMethodDecl(isCopyAssignmentOperator(
   .bind("operatorCallExpr"))),
   Decl, Context);
   return !Matches.empty();
Index: 
clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp
===
--- 
clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp
+++ 
clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp
@@ -247,6 +247,17 @@
   // CHECK-FIXES: F = std::move(E);
 }
 
+struct NotCopyAssigned {
+  NotCopyAssigned &operator=(const ExpensiveMovableType &);
+};
+
+void PositiveNoMoveForNonCopyAssigmentOperator(ExpensiveMovableType E) {
+  // CHECK-MESSAGES: [[@LINE-1]]:69: warning: the parameter 'E' is copied
+  // CHECK-FIXES: void PositiveNoMoveForNonCopyAssigmentOperator(const 
ExpensiveMovableType& E) {
+  NotCopyAssigned N;
+  N = E;
+}
+
 // The argument could be moved but is not since copy statement is inside a 
loop.
 void PositiveNoMoveInsideLoop(ExpensiveMovableType E) {
   // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the parameter 'E' is copied


Index: clang-tools-extra/trunk/clang-tidy/utils/DeclRefExprUtils.cpp
===
--- clang-tools-extra/trunk/clang-tidy/utils/DeclRefExprUtils.cpp
+++ clang-tools-extra/trunk/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -159,7 +159,8 @@
   parmVarDecl(hasType(matchers::isReferenceToConst(;
   auto Matches = match(
   decl(hasDescendant(
-  cxxOperatorCallExpr(UsedAsConstRefArg, hasOverloadedOperatorName("="))
+  cxxOperatorCallExpr(UsedAsConstRefArg, hasOverloadedOperatorName("="),
+  callee(cxxMethodDecl(isCopyAssignmentOperator(
   .bind("operatorCallExpr"))),
   Decl, Context);
   return !Matches.empty();
Index: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp
@@ -247,6 +247,17 @@
   // CHECK-FIXES: F = std::move(E);
 }
 
+struct NotCopyAssigned {
+  NotCopyAssigned &operator=(const ExpensiveMovableType &);
+};
+
+void PositiveNoMoveForNonCopyAssigmentOperator(ExpensiveMovableType E) {
+  // CHECK-MESSAGES: [[@LINE-1]]:69: warning: the parameter 'E' is copied
+  // CHECK-FIXES: void PositiveNoMoveForNonCopyAssigmentOperator(const ExpensiveMovableType& E) {
+  NotCopyAssigned N;
+  N = E;
+}
+
 // The argument could be moved but is not since copy statement is inside a loop.
 void PositiveNoMoveInsideLoop(ExpensiveMovableType E) {
   // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the parameter 'E' is copied
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


  1   2   >