[PATCH] D50102: Use ExprMutationAnalyzer in performance-unnecessary-value-param

Shuai Wang via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 31 14:07:39 PDT 2018


shuaiwang created this revision.
Herald added a reviewer: george.karpenkov.
Herald added subscribers: cfe-commits, a.sidorin.

This yields better recall as ExprMutationAnalyzer is more accurate.

One common pattern this check is now able to catch is:

  void foo(std::vector<X> v) {
    for (const auto& elm : v) {
      // ...
    }
  }


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D50102

Files:
  clang-tidy/performance/UnnecessaryValueParamCheck.cpp


Index: clang-tidy/performance/UnnecessaryValueParamCheck.cpp
===================================================================
--- clang-tidy/performance/UnnecessaryValueParamCheck.cpp
+++ clang-tidy/performance/UnnecessaryValueParamCheck.cpp
@@ -10,6 +10,7 @@
 #include "UnnecessaryValueParamCheck.h"
 
 #include "../utils/DeclRefExprUtils.h"
+#include "../utils/ExprMutationAnalyzer.h"
 #include "../utils/FixItHintUtils.h"
 #include "../utils/Matchers.h"
 #include "../utils/TypeTraits.h"
@@ -98,43 +99,52 @@
 void UnnecessaryValueParamCheck::check(const MatchFinder::MatchResult &Result) {
   const auto *Param = Result.Nodes.getNodeAs<ParmVarDecl>("param");
   const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>("functionDecl");
-  const size_t Index = std::find(Function->parameters().begin(),
-                                 Function->parameters().end(), Param) -
-                       Function->parameters().begin();
-  bool IsConstQualified =
-      Param->getType().getCanonicalType().isConstQualified();
-
-  auto AllDeclRefExprs = utils::decl_ref_expr::allDeclRefExprs(
-      *Param, *Function, *Result.Context);
-  auto ConstDeclRefExprs = utils::decl_ref_expr::constReferenceDeclRefExprs(
-      *Param, *Function, *Result.Context);
 
   // Do not trigger on non-const value parameters when they are not only used as
   // const.
-  if (!isSubset(AllDeclRefExprs, ConstDeclRefExprs))
+  if (utils::ExprMutationAnalyzer(Function->getBody(), Result.Context)
+          .isMutated(Param))
     return;
+  if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Function)) {
+    for (const auto *Init : Ctor->inits()) {
+      if (utils::ExprMutationAnalyzer(Init->getInit(), Result.Context)
+              .isMutated(Param))
+        return;
+    }
+  }
+
+  const bool IsConstQualified =
+      Param->getType().getCanonicalType().isConstQualified();
 
   // If the parameter is non-const, check if it has a move constructor and is
   // only referenced once to copy-construct another object or whether it has a
   // move assignment operator and is only referenced once when copy-assigned.
   // In this case wrap DeclRefExpr with std::move() to avoid the unnecessary
   // copy.
-  if (!IsConstQualified && AllDeclRefExprs.size() == 1) {
-    auto CanonicalType = Param->getType().getCanonicalType();
-    const auto &DeclRefExpr  = **AllDeclRefExprs.begin();
-
-    if (!hasLoopStmtAncestor(DeclRefExpr, *Function, *Result.Context) &&
-        ((utils::type_traits::hasNonTrivialMoveConstructor(CanonicalType) &&
-          utils::decl_ref_expr::isCopyConstructorArgument(
-              DeclRefExpr, *Function, *Result.Context)) ||
-         (utils::type_traits::hasNonTrivialMoveAssignment(CanonicalType) &&
-          utils::decl_ref_expr::isCopyAssignmentArgument(
-              DeclRefExpr, *Function, *Result.Context)))) {
-      handleMoveFix(*Param, DeclRefExpr, *Result.Context);
-      return;
+  if (!IsConstQualified) {
+    auto AllDeclRefExprs = utils::decl_ref_expr::allDeclRefExprs(
+        *Param, *Function, *Result.Context);
+    if (AllDeclRefExprs.size() == 1) {
+      auto CanonicalType = Param->getType().getCanonicalType();
+      const auto &DeclRefExpr = **AllDeclRefExprs.begin();
+
+      if (!hasLoopStmtAncestor(DeclRefExpr, *Function, *Result.Context) &&
+          ((utils::type_traits::hasNonTrivialMoveConstructor(CanonicalType) &&
+            utils::decl_ref_expr::isCopyConstructorArgument(
+                DeclRefExpr, *Function, *Result.Context)) ||
+           (utils::type_traits::hasNonTrivialMoveAssignment(CanonicalType) &&
+            utils::decl_ref_expr::isCopyAssignmentArgument(
+                DeclRefExpr, *Function, *Result.Context)))) {
+        handleMoveFix(*Param, DeclRefExpr, *Result.Context);
+        return;
+      }
     }
   }
 
+  const size_t Index = std::find(Function->parameters().begin(),
+                                 Function->parameters().end(), Param) -
+                       Function->parameters().begin();
+
   auto Diag =
       diag(Param->getLocation(),
            IsConstQualified ? "the const qualified parameter %0 is "


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D50102.158381.patch
Type: text/x-patch
Size: 4142 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180731/aea5bf9d/attachment-0001.bin>


More information about the cfe-commits mailing list