[clang-tools-extra] r190212 - clang-modernize: Fix bugs in Pass-By-Value transform

Guillaume Papin guillaume.papin at epitech.eu
Fri Sep 6 15:28:53 PDT 2013


Author: papin_g
Date: Fri Sep  6 17:28:53 2013
New Revision: 190212

URL: http://llvm.org/viewvc/llvm-project?rev=190212&view=rev
Log:
clang-modernize: Fix bugs in Pass-By-Value transform

- Limit the transform to const-ref and non-const value parameters only.
- Do not generate a replacement when the type is already a value.

See CM-139 for the bugs corresponding to this issue.

Modified:
    clang-tools-extra/trunk/clang-modernize/PassByValue/PassByValueActions.cpp
    clang-tools-extra/trunk/clang-modernize/PassByValue/PassByValueMatchers.cpp
    clang-tools-extra/trunk/test/clang-modernize/PassByValue/basic.cpp

Modified: clang-tools-extra/trunk/clang-modernize/PassByValue/PassByValueActions.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-modernize/PassByValue/PassByValueActions.cpp?rev=190212&r1=190211&r2=190212&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-modernize/PassByValue/PassByValueActions.cpp (original)
+++ clang-tools-extra/trunk/clang-modernize/PassByValue/PassByValueActions.cpp Fri Sep  6 17:28:53 2013
@@ -113,16 +113,20 @@ void ConstructorParamReplacer::run(const
   collectParamDecls(Ctor, ParamDecl, AllParamDecls);
 
   // Generate all replacements for the params.
-  llvm::SmallVector<Replacement, 2> ParamReplaces(AllParamDecls.size());
+  llvm::SmallVector<Replacement, 2> ParamReplaces;
   for (unsigned I = 0, E = AllParamDecls.size(); I != E; ++I) {
     TypeLoc ParamTL = AllParamDecls[I]->getTypeSourceInfo()->getTypeLoc();
+    ReferenceTypeLoc RefTL = ParamTL.getAs<ReferenceTypeLoc>();
     SourceRange Range(AllParamDecls[I]->getLocStart(), ParamTL.getLocEnd());
     CharSourceRange CharRange = Lexer::makeFileCharRange(
         CharSourceRange::getTokenRange(Range), SM, LangOptions());
-    TypeLoc ValueTypeLoc = ParamTL;
+
+    // do not generate a replacement when the parameter is already a value
+    if (RefTL.isNull())
+      continue;
+
     // transform non-value parameters (e.g: const-ref) to values
-    if (!ParamTL.getNextTypeLoc().isNull())
-      ValueTypeLoc = ParamTL.getNextTypeLoc();
+    TypeLoc ValueTypeLoc = RefTL.getPointeeLoc();
     llvm::SmallString<32> ValueStr = Lexer::getSourceText(
         CharSourceRange::getTokenRange(ValueTypeLoc.getSourceRange()), SM,
         LangOptions());
@@ -136,7 +140,7 @@ void ConstructorParamReplacer::run(const
     // 'const Foo &param' -> 'Foo param'
     //  ~~~~~~~~~~~           ~~~^
     ValueStr += ' ';
-    ParamReplaces[I] = Replacement(SM, CharRange, ValueStr);
+    ParamReplaces.push_back(Replacement(SM, CharRange, ValueStr));
   }
 
   // Reject the changes if the the risk level is not acceptable.

Modified: clang-tools-extra/trunk/clang-modernize/PassByValue/PassByValueMatchers.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-modernize/PassByValue/PassByValueMatchers.cpp?rev=190212&r1=190211&r2=190212&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-modernize/PassByValue/PassByValueMatchers.cpp (original)
+++ clang-tools-extra/trunk/clang-modernize/PassByValue/PassByValueMatchers.cpp Fri Sep  6 17:28:53 2013
@@ -63,6 +63,14 @@ AST_MATCHER(CXXConstructorDecl, isNonDel
 using namespace clang;
 using namespace clang::ast_matchers;
 
+static TypeMatcher constRefType() {
+  return lValueReferenceType(pointee(isConstQualified()));
+}
+
+static TypeMatcher nonConstValueType() {
+  return qualType(unless(anyOf(referenceType(), isConstQualified())));
+}
+
 DeclarationMatcher makePassByValueCtorParamMatcher() {
   return constructorDecl(
       forEachConstructorInitializer(ctorInitializer(
@@ -71,7 +79,13 @@ DeclarationMatcher makePassByValueCtorPa
           // is generated instead of a CXXConstructExpr, filtering out templates
           // automatically for us.
           withInitializer(constructExpr(
-              has(declRefExpr(to(parmVarDecl().bind(PassByValueParamId)))),
+              has(declRefExpr(to(
+                  parmVarDecl(hasType(qualType(
+                                  // match only const-ref or a non-const value
+                                  // parameters, rvalues and const-values
+                                  // shouldn't be modified.
+                                  anyOf(constRefType(), nonConstValueType()))))
+                      .bind(PassByValueParamId)))),
               hasDeclaration(constructorDecl(
                   isNonDeletedCopyConstructor(),
                   hasDeclContext(recordDecl(isMoveConstructible())))))))

Modified: clang-tools-extra/trunk/test/clang-modernize/PassByValue/basic.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-modernize/PassByValue/basic.cpp?rev=190212&r1=190211&r2=190212&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clang-modernize/PassByValue/basic.cpp (original)
+++ clang-tools-extra/trunk/test/clang-modernize/PassByValue/basic.cpp Fri Sep  6 17:28:53 2013
@@ -150,7 +150,7 @@ struct O {
 // Test with a const-value parameter
 struct P {
   P(const Movable M) : M(M) {}
-  // CHECK: P(Movable M) : M(std::move(M)) {}
+  // CHECK: P(const Movable M) : M(M) {}
   Movable M;
 };
 
@@ -166,3 +166,20 @@ struct Q {
   Movable C;
   double D;
 };
+
+// Test that value-parameters with a nested name specifier are left as-is
+namespace ns_R {
+typedef ::Movable RMovable;
+}
+struct R {
+  R(ns_R::RMovable M) : M(M) {}
+  // CHECK: R(ns_R::RMovable M) : M(std::move(M)) {}
+  ns_R::RMovable M;
+};
+
+// Test with rvalue parameter
+struct S {
+  S(Movable &&M) : M(M) {}
+  // CHECK: S(Movable &&M) : M(M) {}
+  Movable M;
+};





More information about the cfe-commits mailing list