[clang-tools-extra] r178575 - Use 'auto' with 'new' expressions

Edwin Vane edwin.vane at intel.com
Tue Apr 2 13:43:58 PDT 2013


Author: revane
Date: Tue Apr  2 15:43:57 2013
New Revision: 178575

URL: http://llvm.org/viewvc/llvm-project?rev=178575&view=rev
Log:
Use 'auto' with 'new' expressions

For variable declarations initialized with new expressions, use 'auto' for the
type specifier.

The 'auto' replacement happens only when the type of the VarDecl exactly
matches the type of the initializer and the VarDecl is *not* CV-qualified. The
only case that is currently handled is if the pointer type of the VarDecl is
itself CV qualified.

Some improvements need to be made to Clang's TypeLoc information in order for
other CV qualifier cases to be successfully handled. See the new test suite
new_cv_failing.cpp for examples of usages that could be handled with such an
improvement.

Function pointers are, for now, not transformed until the identifier info can
be extracted.

Reviewer: klimek


Added:
    clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/new.cpp
    clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/new_cv_failing.cpp
Modified:
    clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAuto.cpp
    clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.cpp
    clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.h
    clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.cpp
    clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.h

Modified: clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAuto.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAuto.cpp?rev=178575&r1=178574&r2=178575&view=diff
==============================================================================
--- clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAuto.cpp (original)
+++ clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAuto.cpp Tue Apr  2 15:43:57 2013
@@ -35,9 +35,13 @@ int UseAutoTransform::apply(const FileCo
   unsigned AcceptedChanges = 0;
 
   MatchFinder Finder;
-  UseAutoFixer Fixer(UseAutoTool.getReplacements(), AcceptedChanges, MaxRisk);
+  IteratorReplacer ReplaceIterators(UseAutoTool.getReplacements(),
+                                    AcceptedChanges, MaxRisk);
+  NewReplacer ReplaceNew(UseAutoTool.getReplacements(), AcceptedChanges,
+                         MaxRisk);
 
-  Finder.addMatcher(makeIteratorMatcher(), &Fixer);
+  Finder.addMatcher(makeIteratorDeclMatcher(), &ReplaceIterators);
+  Finder.addMatcher(makeDeclWithNewMatcher(), &ReplaceNew);
 
   if (int Result = UseAutoTool.run(newFrontendActionFactory(&Finder))) {
     llvm::errs() << "Error encountered during translation.\n";

Modified: clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.cpp?rev=178575&r1=178574&r2=178575&view=diff
==============================================================================
--- clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.cpp (original)
+++ clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.cpp Tue Apr  2 15:43:57 2013
@@ -8,7 +8,8 @@
 //===----------------------------------------------------------------------===//
 ///
 ///  \file
-///  \brief This file contains the implementation of the UseAutoFixer class.
+///  \brief This file contains the implementation of callbacks for the UseAuto
+///  transform.
 ///
 //===----------------------------------------------------------------------===//
 #include "UseAutoActions.h"
@@ -19,8 +20,8 @@ using namespace clang::ast_matchers;
 using namespace clang::tooling;
 using namespace clang;
 
-void UseAutoFixer::run(const MatchFinder::MatchResult &Result) {
-  const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>(DeclNodeId);
+void IteratorReplacer::run(const MatchFinder::MatchResult &Result) {
+  const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>(IteratorDeclId);
 
   assert(D && "Bad Callback. No node provided");
 
@@ -68,3 +69,48 @@ void UseAutoFixer::run(const MatchFinder
     ++AcceptedChanges;
   }
 }
+
+void NewReplacer::run(const MatchFinder::MatchResult &Result) {
+  const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>(DeclWithNewId);
+  assert(D && "Bad Callback. No node provided");
+
+  SourceManager &SM = *Result.SourceManager;
+  if (!SM.isFromMainFile(D->getLocStart()))
+    return;
+  
+  const CXXNewExpr *NewExpr = Result.Nodes.getNodeAs<CXXNewExpr>(NewExprId);
+  assert(NewExpr && "Bad Callback. No CXXNewExpr bound");
+
+  // If declaration and initializer have exactly the same type, just replace
+  // with 'auto'.
+  if (Result.Context->hasSameType(D->getType(), NewExpr->getType())) {
+    TypeLoc TL = D->getTypeSourceInfo()->getTypeLoc();
+    CharSourceRange Range(TL.getSourceRange(), /*IsTokenRange=*/ true);
+    // Space after 'auto' to handle cases where the '*' in the pointer type
+    // is next to the identifier. This avoids changing 'int *p' into 'autop'.
+    Replace.insert(tooling::Replacement(SM, Range, "auto "));
+    ++AcceptedChanges;
+    return;
+  }
+
+  // If the CV qualifiers for the pointer differ then we still use auto, just
+  // need to leave the qualifier behind.
+  if (Result.Context->hasSameUnqualifiedType(D->getType(),
+                                             NewExpr->getType())) {
+    TypeLoc TL = D->getTypeSourceInfo()->getTypeLoc();
+    CharSourceRange Range(TL.getSourceRange(), /*IsTokenRange=*/ true);
+    // Space after 'auto' to handle cases where the '*' in the pointer type
+    // is next to the identifier. This avoids changing 'int *p' into 'autop'.
+    Replace.insert(tooling::Replacement(SM, Range, "auto "));
+    ++AcceptedChanges;
+    return;
+  }
+
+  // The VarDecl and Initializer have mismatching types.
+  return;
+
+  // FIXME: There is, however, one case we can address: when the VarDecl
+  // pointee is the same as the initializer, just more CV-qualified. However,
+  // TypeLoc information is not reliable where CV qualifiers are concerned so
+  // we can't do anything about this case for now.
+}

Modified: clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.h?rev=178575&r1=178574&r2=178575&view=diff
==============================================================================
--- clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.h (original)
+++ clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.h Tue Apr  2 15:43:57 2013
@@ -8,8 +8,8 @@
 //===----------------------------------------------------------------------===//
 ///
 ///  \file
-///  \brief This file contains the declaration of the UseAutoFixer class which
-///  is used as an ASTMatcher callback.
+///  \brief This file contains the declarations for callbacks used by the
+///  UseAuto transform.
 ///
 //===----------------------------------------------------------------------===//
 #ifndef LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_ACTIONS_H
@@ -19,16 +19,37 @@
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Tooling/Refactoring.h"
 
-/// \brief The callback to be used for use-auto AST matchers.
-class UseAutoFixer : public clang::ast_matchers::MatchFinder::MatchCallback {
+/// \brief The callback to be used when replacing type specifiers of variable
+/// declarations that are iterators.
+class IteratorReplacer
+    : public clang::ast_matchers::MatchFinder::MatchCallback {
 public:
-  UseAutoFixer(clang::tooling::Replacements &Replace, unsigned &AcceptedChanges,
-               RiskLevel)
+  IteratorReplacer(clang::tooling::Replacements &Replace,
+                   unsigned &AcceptedChanges, RiskLevel)
       : Replace(Replace), AcceptedChanges(AcceptedChanges) {
   }
 
   /// \brief Entry point to the callback called when matches are made.
-  virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result);
+  virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result)
+      LLVM_OVERRIDE;
+
+private:
+  clang::tooling::Replacements &Replace;
+  unsigned &AcceptedChanges;
+};
+
+/// \brief The callback used when replacing type specifiers of variable
+/// declarations initialized by a C++ new expression.
+class NewReplacer : public clang::ast_matchers::MatchFinder::MatchCallback {
+public:
+  NewReplacer(clang::tooling::Replacements &Replace, unsigned &AcceptedChanges,
+              RiskLevel)
+      : Replace(Replace), AcceptedChanges(AcceptedChanges) {
+  }
+
+  /// \brief Entry point to the callback called when matches are made.
+  virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result)
+      LLVM_OVERRIDE;
 
 private:
   clang::tooling::Replacements &Replace;

Modified: clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.cpp?rev=178575&r1=178574&r2=178575&view=diff
==============================================================================
--- clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.cpp (original)
+++ clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.cpp Tue Apr  2 15:43:57 2013
@@ -18,7 +18,9 @@
 using namespace clang::ast_matchers;
 using namespace clang;
 
-const char *DeclNodeId = "decl";
+const char *IteratorDeclId = "iterator_decl";
+const char *DeclWithNewId = "decl_new";
+const char *NewExprId = "new_expr";
 
 namespace clang {
 namespace ast_matchers {
@@ -230,7 +232,7 @@ TypeMatcher iteratorFromUsingDeclaration
 }
 } // namespace
 
-DeclarationMatcher makeIteratorMatcher() {
+DeclarationMatcher makeIteratorDeclMatcher() {
   return varDecl(allOf(
                    hasWrittenNonListInitializer(),
                    unless(hasType(autoType())),
@@ -243,5 +245,32 @@ DeclarationMatcher makeIteratorMatcher()
                        )
                      )
                    )
-                 )).bind(DeclNodeId);
+                 )).bind(IteratorDeclId);
+}
+
+DeclarationMatcher makeDeclWithNewMatcher() {
+  return varDecl(
+           hasInitializer(
+             ignoringParenImpCasts(
+               newExpr().bind(NewExprId)
+             )
+           ),
+
+           // FIXME: TypeLoc information is not reliable where CV qualifiers are
+           // concerned so these types can't be handled for now.
+           unless(hasType(pointerType(pointee(hasLocalQualifiers())))),
+
+           // FIXME: Handle function pointers. For now we ignore them because
+           // the replacement replaces the entire type specifier source range
+           // which includes the identifier.
+           unless(
+             hasType(
+               pointsTo(
+                 pointsTo(
+                   parenType(innerType(functionType()))
+                 )
+               )
+             )
+           )
+         ).bind(DeclWithNewId);
 }

Modified: clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.h?rev=178575&r1=178574&r2=178575&view=diff
==============================================================================
--- clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.h (original)
+++ clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.h Tue Apr  2 15:43:57 2013
@@ -17,11 +17,17 @@
 
 #include "clang/ASTMatchers/ASTMatchers.h"
 
-extern const char *DeclNodeId;
+extern const char *IteratorDeclId;
+extern const char *DeclWithNewId;
+extern const char *NewExprId;
 
 /// \brief Create a matcher that matches variable declarations where the type
 /// is an iterator for an std container and has an explicit initializer of the
 /// same type.
-clang::ast_matchers::DeclarationMatcher makeIteratorMatcher();
+clang::ast_matchers::DeclarationMatcher makeIteratorDeclMatcher();
+
+/// \brief Create a matcher that matches variable declarations that are
+/// initialized by a C++ new expression.
+clang::ast_matchers::DeclarationMatcher makeDeclWithNewMatcher();
 
 #endif // LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_MATCHERS_H

Added: clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/new.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/new.cpp?rev=178575&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/new.cpp (added)
+++ clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/new.cpp Tue Apr  2 15:43:57 2013
@@ -0,0 +1,52 @@
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: cpp11-migrate -use-auto %t.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%t.cpp %s
+
+class MyType {
+};
+
+class MyDerivedType : public MyType {
+};
+
+int main(int argc, char **argv) {
+  MyType *a = new MyType();
+  // CHECK: auto a = new MyType();
+
+  static MyType *a_static = new MyType();
+  // CHECK: static auto a_static = new MyType();
+
+  MyType *b = new MyDerivedType();
+  // CHECK: MyType *b = new MyDerivedType();
+
+  void *c = new MyType();
+  // CHECK: void *c = new MyType();
+
+  // CV-qualifier tests.
+  //
+  // NOTE : the form "type const" is expected here because of a deficiency in
+  // TypeLoc where CV qualifiers are not considered part of the type location
+  // info. That is, all that is being replaced in each case is "MyType *" and
+  // not "MyType * const".
+  {
+    static MyType * const d_static = new MyType();
+    // CHECK: static auto const d_static = new MyType();
+
+    MyType * const d3 = new MyType();
+    // CHECK: auto const d3 = new MyType();
+
+    MyType * volatile d4 = new MyType();
+    // CHECK: auto volatile d4 = new MyType();
+  }
+
+  int (**func)(int, int) = new (int(*[5])(int,int));
+  // CHECK: int (**func)(int, int) = new (int(*[5])(int,int));
+
+  int *e = new int[5];
+  // CHECK: auto e = new int[5];
+
+  MyType *f(new MyType);
+  // CHECK: auto f(new MyType);
+
+  MyType *g{new MyType};
+  // CHECK: MyType *g{new MyType};
+}

Added: clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/new_cv_failing.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/new_cv_failing.cpp?rev=178575&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/new_cv_failing.cpp (added)
+++ clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/new_cv_failing.cpp Tue Apr  2 15:43:57 2013
@@ -0,0 +1,36 @@
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: cpp11-migrate -use-auto %t.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%t.cpp %s
+// XFAIL: *
+
+// None of these tests can pass right now because TypeLoc information where CV
+// qualifiers are concerned is not reliable/available.
+
+class MyType {
+};
+
+int main (int argc, char **argv) {
+  const MyType *d = new MyType();
+  // CHECK: const auto *d = new MyType();
+
+  volatile MyType *d2 = new MyType();
+  // CHECK: volatile auto *d2 = new MyType();
+
+  const MyType * volatile e = new MyType();
+  // CHECK: const auto * volatile d = new MyType();
+
+  volatile MyType * const f = new MyType();
+  // CHECK: volatile auto * const d2 = new MyType();
+
+  const MyType *d5 = new const MyType();
+  // CHECK: auto d5 = new const MyType();
+
+  volatile MyType *d6 = new volatile MyType();
+  // CHECK: auto d6 = new volatile MyType();
+
+  const MyType * const d7 = new const MyType();
+  // CHECK: const auto d7 = new const MyType();
+
+  volatile MyType * volatile d8 = new volatile MyType();
+  // CHECK: volatile auto d8 = new volatile MyType();
+}





More information about the cfe-commits mailing list