summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdwin Vane <edwin.vane@intel.com>2013-04-02 20:43:57 +0000
committerEdwin Vane <edwin.vane@intel.com>2013-04-02 20:43:57 +0000
commiteeed39a58372135639c0b5918efb13ca552daec5 (patch)
tree320828cd2dfd70e37e60973c788deec4ccda2f39
parent1afa68ed14ad9636dda390add3bf74e32b5c0303 (diff)
downloadbcm5719-llvm-eeed39a58372135639c0b5918efb13ca552daec5.tar.gz
bcm5719-llvm-eeed39a58372135639c0b5918efb13ca552daec5.zip
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 llvm-svn: 178575
-rw-r--r--clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.cpp8
-rw-r--r--clang-tools-extra/cpp11-migrate/UseAuto/UseAutoActions.cpp52
-rw-r--r--clang-tools-extra/cpp11-migrate/UseAuto/UseAutoActions.h35
-rw-r--r--clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.cpp35
-rw-r--r--clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.h10
-rw-r--r--clang-tools-extra/test/cpp11-migrate/UseAuto/new.cpp52
-rw-r--r--clang-tools-extra/test/cpp11-migrate/UseAuto/new_cv_failing.cpp36
7 files changed, 211 insertions, 17 deletions
diff --git a/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.cpp b/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.cpp
index 31f867799b6..7a56e1c1250 100644
--- a/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.cpp
+++ b/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.cpp
@@ -35,9 +35,13 @@ int UseAutoTransform::apply(const FileContentsByPath &InputStates,
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";
diff --git a/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoActions.cpp b/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoActions.cpp
index 14986d8dca9..bd2599c4685 100644
--- a/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoActions.cpp
+++ b/clang-tools-extra/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::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::MatchResult &Result) {
++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.
+}
diff --git a/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoActions.h b/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoActions.h
index d6ea557b369..e28a45b10d1 100644
--- a/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoActions.h
+++ b/clang-tools-extra/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
@@ -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;
diff --git a/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.cpp b/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.cpp
index b17708eabd4..08f9a7e52f6 100644
--- a/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.cpp
+++ b/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.cpp
@@ -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);
}
diff --git a/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.h b/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.h
index db160f8766e..1f09ad407cd 100644
--- a/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.h
+++ b/clang-tools-extra/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
diff --git a/clang-tools-extra/test/cpp11-migrate/UseAuto/new.cpp b/clang-tools-extra/test/cpp11-migrate/UseAuto/new.cpp
new file mode 100644
index 00000000000..911c0cd76bd
--- /dev/null
+++ b/clang-tools-extra/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};
+}
diff --git a/clang-tools-extra/test/cpp11-migrate/UseAuto/new_cv_failing.cpp b/clang-tools-extra/test/cpp11-migrate/UseAuto/new_cv_failing.cpp
new file mode 100644
index 00000000000..8e21018ef90
--- /dev/null
+++ b/clang-tools-extra/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();
+}
OpenPOWER on IntegriCloud