avogelsgesang created this revision.
Herald added subscribers: carlosgalvezp, xazax.hun.
avogelsgesang requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

This commit improves the fix-its of `modernize-pass-by-value` in two ways:

1. No longer propose partial fixes. In the presence of `using`/`typedef`, we 
failed to rewrite the function signature but still adjusted the function body. 
This led to incorrect, partial fix-its. Instead, the check now simply doesn't 
offer any fixes at all in such a situation
2. The check unconditionally added a whitespace after the new type name. This 
is necessary, e.g., for LLVM's code style where the `&` is directly attached to 
the variable name. For other code styles, we don't want this whitespace, 
though. The check now checks if a whitespace is already present and if so 
doesn't introduce a 2nd duplicated whitespace


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D112648

Files:
  clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize-pass-by-value.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/modernize-pass-by-value.cpp
===================================================================
--- clang-tools-extra/test/clang-tidy/checkers/modernize-pass-by-value.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-pass-by-value.cpp
@@ -231,5 +231,33 @@
 
 struct U {
   U(const POD &M) : M(M) {}
+  // CHECK-FIXES: U(const POD &M) : M(M) {}
   POD M;
 };
+
+// The rewrite can't look through `typedefs` and `using`.
+// Test that we don't partially rewrite one decl without rewriting the other.
+using MovableConstRef = const Movable &;
+struct V {
+  V(MovableConstRef M);
+  // CHECK-FIXES: V(MovableConstRef M);
+  Movable M;
+};
+V::V(const Movable &M) : M(M) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move
+// CHECK-FIXES: V::V(const Movable &M) : M(M) {}
+
+// Check that we don't insert an unnecessary whitespace if not required
+struct W {
+  // Here we need a whitespace so we don't write `MovableM`
+  W(const Movable &M);
+  // CHECK-FIXES: W(Movable M);
+  Movable M;
+};
+// Here we don't need an additional whitepace, as there already is a whitespace
+// between `&` and the variable name
+// clang-format off
+W::W(const Movable& M) : M(M) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move
+// CHECK-FIXES: W::W(Movable M) : M(std::move(M)) {}
+// clang-format on
Index: clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp
@@ -190,24 +190,46 @@
 
   auto Diag = diag(ParamDecl->getBeginLoc(), "pass by value and use std::move");
 
-  // Iterate over all declarations of the constructor.
-  for (const ParmVarDecl *ParmDecl : collectParamDecls(Ctor, ParamDecl)) {
-    auto ParamTL = ParmDecl->getTypeSourceInfo()->getTypeLoc();
-    auto RefTL = ParamTL.getAs<ReferenceTypeLoc>();
+  // If we received a `const&` type, we need to rewrite the function
+  // declarations
+  if (ParamDecl->getType()->isLValueReferenceType()) {
+    // Check if we can succesfully rewrite all declarations of the constructor.
+    for (const ParmVarDecl *ParmDecl : collectParamDecls(Ctor, ParamDecl)) {
+      auto ParamTL = ParmDecl->getTypeSourceInfo()->getTypeLoc();
+      auto RefTL = ParamTL.getAs<ReferenceTypeLoc>();
+      if (RefTL.isNull()) {
+        // We cannot rewrite this instance. The type is probably hidden behind
+        // some `typedef`. Do not offer a fix-it in this case.
+        return;
+      }
+    }
+    // Rewrite all declarations.
+    for (const ParmVarDecl *ParmDecl : collectParamDecls(Ctor, ParamDecl)) {
+      auto ParamTL = ParmDecl->getTypeSourceInfo()->getTypeLoc();
+      auto RefTL = ParamTL.getAs<ReferenceTypeLoc>();
 
-    // Do not replace if it is already a value, skip.
-    if (RefTL.isNull())
-      continue;
+      TypeLoc ValueTL = RefTL.getPointeeLoc();
+      auto TypeRange = CharSourceRange::getTokenRange(ParmDecl->getBeginLoc(),
+                                                      ParamTL.getEndLoc());
+      std::string ValueStr =
+          Lexer::getSourceText(
+              CharSourceRange::getTokenRange(ValueTL.getSourceRange()), SM,
+              getLangOpts())
+              .str();
 
-    TypeLoc ValueTL = RefTL.getPointeeLoc();
-    auto TypeRange = CharSourceRange::getTokenRange(ParmDecl->getBeginLoc(),
-                                                    ParamTL.getEndLoc());
-    std::string ValueStr = Lexer::getSourceText(CharSourceRange::getTokenRange(
-                                                    ValueTL.getSourceRange()),
-                                                SM, getLangOpts())
-                               .str();
-    ValueStr += ' ';
-    Diag << FixItHint::CreateReplacement(TypeRange, ValueStr);
+      // Check if we need to append an additional whitespace
+      auto TypeRangeEnd =
+          Lexer::getLocForEndOfToken(ParamTL.getEndLoc(), 0, SM, getLangOpts());
+      auto NextChar = Lexer::getSourceText(
+          CharSourceRange::getCharRange(TypeRangeEnd,
+                                        TypeRangeEnd.getLocWithOffset(1)),
+          SM, getLangOpts());
+      if (NextChar != " ") {
+        ValueStr += ' ';
+      }
+
+      Diag << FixItHint::CreateReplacement(TypeRange, ValueStr);
+    }
   }
 
   // Use std::move in the initialization list.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to