Hi gribozavr, klimek,

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.

http://llvm-reviews.chandlerc.com/D582

Files:
  cpp11-migrate/UseAuto/UseAuto.cpp
  cpp11-migrate/UseAuto/UseAutoActions.cpp
  cpp11-migrate/UseAuto/UseAutoActions.h
  cpp11-migrate/UseAuto/UseAutoMatchers.cpp
  cpp11-migrate/UseAuto/UseAutoMatchers.h
  test/cpp11-migrate/UseAuto/new.cpp
  test/cpp11-migrate/UseAuto/new_cv_failing.cpp
Index: cpp11-migrate/UseAuto/UseAuto.cpp
===================================================================
--- cpp11-migrate/UseAuto/UseAuto.cpp
+++ cpp11-migrate/UseAuto/UseAuto.cpp
@@ -35,9 +35,13 @@
   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";
Index: cpp11-migrate/UseAuto/UseAutoActions.cpp
===================================================================
--- cpp11-migrate/UseAuto/UseAutoActions.cpp
+++ cpp11-migrate/UseAuto/UseAutoActions.cpp
@@ -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::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");
 
@@ -61,3 +62,62 @@
     ++AcceptedChanges;
   }
 }
+
+bool testPointeeCVQualified(QualType QT) {
+  QT.dump();
+  const PointerType *DeclType = QT->getAs<PointerType>();
+  assert(DeclType && "Provided type is not a pointer type!");
+  QualType PointeeType = DeclType->getPointeeType();
+  return PointeeType.hasLocalQualifiers();
+}
+
+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");
+
+  // FIXME: TypeLoc information is not reliable where CV qualifiers are
+  // concerned. Abort for now.
+  if (testPointeeCVQualified(D->getType()))
+    return;
+
+  // 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(), true);
+    // Space after 'auto' to handle styles where the pointer indicator goes
+    // next to the variable and not the type specifier.
+    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. S
+  if (Result.Context->hasSameUnqualifiedType(D->getType(),
+                                             NewExpr->getType())) {
+    TypeLoc TL = D->getTypeSourceInfo()->getTypeLoc();
+    CharSourceRange Range(TL.getSourceRange(), true);
+    // Space after 'auto' to handle styles where the pointer indicator goes
+    // next to the variable and not the type specifier.
+    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.
+}
Index: cpp11-migrate/UseAuto/UseAutoActions.h
===================================================================
--- cpp11-migrate/UseAuto/UseAutoActions.h
+++ cpp11-migrate/UseAuto/UseAutoActions.h
@@ -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
@@ -20,15 +20,35 @@
 #include "clang/Tooling/Refactoring.h"
 
 /// \brief The callback to be used for use-auto AST matchers.
-class UseAutoFixer : public clang::ast_matchers::MatchFinder::MatchCallback {
+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;
Index: cpp11-migrate/UseAuto/UseAutoMatchers.cpp
===================================================================
--- cpp11-migrate/UseAuto/UseAutoMatchers.cpp
+++ cpp11-migrate/UseAuto/UseAutoMatchers.cpp
@@ -15,10 +15,15 @@
 #include "UseAutoMatchers.h"
 #include "clang/AST/ASTContext.h"
 
+// DEBUG
+#include "llvm/Support/raw_ostream.h"
+
 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 {
@@ -155,6 +160,14 @@
   return false;
 }
 
+AST_MATCHER(Type, blah) {
+  Node.dump();
+  const ParenType *PT = Node.getAs<ParenType>();
+  PT->getInnerType()->dump();
+  llvm::errs() << "type: " << PT->getInnerType()->getTypeClassName() << "\n";
+  return functionType().matches(*PT->getInnerType(), Finder, Builder);
+}
+
 } // namespace ast_matchers
 } // namespace clang
 
@@ -230,7 +243,7 @@
 }
 } // namespace
 
-DeclarationMatcher makeIteratorMatcher() {
+DeclarationMatcher makeIteratorDeclMatcher() {
   return varDecl(allOf(
                    hasWrittenNonListInitializer(),
                    unless(hasType(autoType())),
@@ -243,5 +256,28 @@
                        )
                      )
                    )
-                 )).bind(DeclNodeId);
+                 )).bind(IteratorDeclId);
+}
+
+DeclarationMatcher makeDeclWithNewMatcher() {
+  return varDecl(
+           hasInitializer(
+             ignoringParenImpCasts(
+               newExpr().bind(NewExprId)
+             )
+           ),
+
+           // 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(hasInnerType(functionType()))
+                 )
+               )
+             )
+           )
+         ).bind(DeclWithNewId);
 }
Index: cpp11-migrate/UseAuto/UseAutoMatchers.h
===================================================================
--- cpp11-migrate/UseAuto/UseAutoMatchers.h
+++ cpp11-migrate/UseAuto/UseAutoMatchers.h
@@ -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
Index: test/cpp11-migrate/UseAuto/new.cpp
===================================================================
--- /dev/null
+++ test/cpp11-migrate/UseAuto/new.cpp
@@ -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};
+}
Index: test/cpp11-migrate/UseAuto/new_cv_failing.cpp
===================================================================
--- /dev/null
+++ test/cpp11-migrate/UseAuto/new_cv_failing.cpp
@@ -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();
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to