file(GLOB_RECURSE UseNullptrSources "UseNullptr/*.cpp")
list(APPEND Cpp11MigrateSources ${UseNullptrSources})
+file(GLOB_RECURSE UseAutoSources "UseAuto/*.cpp")
+list(APPEND Cpp11MigrateSources ${UseAutoSources})
+
add_clang_executable(cpp11-migrate
${Cpp11MigrateSources}
)
BUILT_SOURCES = $(ObjDir)/LoopConvert/.objdir
SOURCES += $(addprefix UseNullptr/,$(notdir $(wildcard $(PROJ_SRC_DIR)/UseNullptr/*.cpp)))
BUILT_SOURCES += $(ObjDir)/UseNullptr/.objdir
+SOURCES += $(addprefix UseAuto/,$(notdir $(wildcard $(PROJ_SRC_DIR)/UseAuto/*.cpp)))
+BUILT_SOURCES += $(ObjDir)/UseAuto/.objdir
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
#include "Transforms.h"
#include "LoopConvert/LoopConvert.h"
#include "UseNullptr/UseNullptr.h"
+#include "UseAuto/UseAuto.h"
namespace cl = llvm::cl;
cl::desc("Make use of nullptr keyword where possible")),
&ConstructTransform<UseNullptrTransform>));
+ Options.push_back(
+ OptionVec::value_type(
+ new cl::opt<bool>("use-auto",
+ cl::desc("Use of 'auto' type specifier")),
+ &ConstructTransform<UseAutoTransform>));
+
// Add more transform options here.
}
--- /dev/null
+//===-- UseAuto/UseAuto.cpp - Use auto type specifier ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides the implementation of the UseAutoTransform class.
+///
+//===----------------------------------------------------------------------===//
+
+#include "UseAuto.h"
+#include "UseAutoActions.h"
+#include "UseAutoMatchers.h"
+
+using clang::ast_matchers::MatchFinder;
+using namespace clang;
+using namespace clang::tooling;
+
+int UseAutoTransform::apply(const FileContentsByPath &InputStates,
+ RiskLevel MaxRisk,
+ const clang::tooling::CompilationDatabase &Database,
+ const std::vector<std::string> &SourcePaths,
+ FileContentsByPath &ResultStates) {
+ RefactoringTool UseAutoTool(Database, SourcePaths);
+
+ for (FileContentsByPath::const_iterator I = InputStates.begin(),
+ E = InputStates.end();
+ I != E; ++I)
+ UseAutoTool.mapVirtualFile(I->first, I->second);
+
+ unsigned AcceptedChanges = 0;
+
+ MatchFinder Finder;
+ UseAutoFixer Fixer(UseAutoTool.getReplacements(), AcceptedChanges, MaxRisk);
+
+ Finder.addMatcher(makeIteratorMatcher(), &Fixer);
+
+ if (int Result = UseAutoTool.run(newFrontendActionFactory(&Finder))) {
+ llvm::errs() << "Error encountered during translation.\n";
+ return Result;
+ }
+
+ RewriterContainer Rewrite(UseAutoTool.getFiles(), InputStates);
+
+ // FIXME: Do something if some replacements didn't get applied?
+ UseAutoTool.applyAllReplacements(Rewrite.getRewriter());
+
+ collectResults(Rewrite.getRewriter(), InputStates, ResultStates);
+
+ if (AcceptedChanges > 0)
+ setChangesMade();
+
+ return 0;
+}
--- /dev/null
+//===-- UseAuto/UseAuto.h - Use auto type specifier -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides the definition of the UseAutoTransform class
+/// which is the main interface to the use-auto transform that replaces
+/// type specifiers with the special C++11 'auto' type specifier in certain
+/// situations.
+///
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_H
+#define LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_H
+
+#include "Transform.h"
+#include "llvm/Support/Compiler.h"
+
+/// \brief Subclass of Transform that transforms type specifiers for variable
+/// declarations into the special C++11 'auto' type specifier for certain cases:
+/// * Iterators of std containers.
+/// * More to come...
+///
+/// Other uses of the auto type specifier as outlined in C++11 [dcl.spec.auto]
+/// p2 are not handled by this transform.
+class UseAutoTransform : public Transform {
+public:
+ /// \see Transform::run().
+ virtual int apply(const FileContentsByPath &InputStates,
+ RiskLevel MaxRiskLEvel,
+ const clang::tooling::CompilationDatabase &Database,
+ const std::vector<std::string> &SourcePaths,
+ FileContentsByPath &ResultStates) LLVM_OVERRIDE;
+};
+
+#endif // LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_H
--- /dev/null
+//===-- UseAuto/UseAutoActions.cpp - Matcher callback impl ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file contains the implementation of the UseAutoFixer class.
+///
+//===----------------------------------------------------------------------===//
+#include "UseAutoActions.h"
+#include "UseAutoMatchers.h"
+#include "clang/AST/ASTContext.h"
+
+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);
+
+ assert(D && "Bad Callback. No node provided");
+
+ SourceManager &SM = *Result.SourceManager;
+ if (!SM.isFromMainFile(D->getLocStart()))
+ return;
+
+ const CXXConstructExpr *Construct = cast<CXXConstructExpr>(D->getInit());
+ assert(Construct->getNumArgs() == 1u &&
+ "Expected constructor with single argument");
+
+ // Drill down to the as-written initializer.
+ const Expr *E = Construct->arg_begin()->IgnoreParenImpCasts();
+ if (E != E->IgnoreConversionOperator())
+ // We hit a conversion operator. Early-out now as they imply an implicit
+ // conversion from a different type. Could also mean an explicit conversion
+ // from the same type but that's pretty rare.
+ return;
+
+ if (const CXXConstructExpr *NestedConstruct = dyn_cast<CXXConstructExpr>(E))
+ // If we ran into an implicit conversion constructor, can't convert.
+ //
+ // FIXME: The following only checks if the constructor can be used
+ // implicitly, not if it actually was. Cases where the converting constructor
+ // was used explicitly won't get converted.
+ if (NestedConstruct->getConstructor()->isConvertingConstructor(false))
+ return;
+
+ if (Result.Context->hasSameType(D->getType(), E->getType())) {
+ TypeLoc TL = D->getTypeSourceInfo()->getTypeLoc();
+
+ // WARNING: TypeLoc::getSourceRange() will include the identifier for things
+ // like function pointers. Not a concern since this action only works with
+ // iterators but something to keep in mind in the future.
+
+ CharSourceRange Range(TL.getSourceRange(), true);
+ Replace.insert(tooling::Replacement(SM, Range, "auto"));
+ ++AcceptedChanges;
+ }
+}
--- /dev/null
+//===-- UseAuto/Actions.h - Matcher callback ---------------------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file contains the declaration of the UseAutoFixer class which
+/// is used as an ASTMatcher callback.
+///
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_ACTIONS_H
+#define LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_ACTIONS_H
+
+#include "Transform.h"
+#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 {
+public:
+ UseAutoFixer(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);
+
+private:
+ clang::tooling::Replacements &Replace;
+ unsigned &AcceptedChanges;
+};
+
+#endif // LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_ACTIONS_H
--- /dev/null
+//===-- UseAutoMatchers.cpp - Matchers for use-auto transform -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file contains the implementation for matcher-generating
+/// functions and custom AST_MATCHERs.
+///
+//===----------------------------------------------------------------------===//
+#include "UseAutoMatchers.h"
+#include "clang/AST/ASTContext.h"
+
+using namespace clang::ast_matchers;
+using namespace clang;
+
+const char *DeclNodeId = "decl";
+
+namespace clang {
+namespace ast_matchers {
+
+/// \brief Matches variable declarations that have explicit initializers that
+/// are not initializer lists.
+///
+/// Given
+/// \code
+/// iterator I = Container.begin();
+/// MyType A(42);
+/// MyType B{2};
+/// MyType C;
+/// \endcode
+/// varDecl(hasWrittenNonListInitializer()) matches \c I and \c A but not \c B
+/// or \c C.
+AST_MATCHER(VarDecl, hasWrittenNonListInitializer) {
+ const Expr *Init = Node.getAnyInitializer();
+ if (!Init)
+ return false;
+
+ // The following test is based on DeclPrinter::VisitVarDecl() to find if an
+ // initializer is implicit or not.
+ bool ImplicitInit = false;
+ if (const CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init)) {
+ if (Construct->isListInitialization())
+ return false;
+ ImplicitInit = Construct->getNumArgs() == 0 ||
+ Construct->getArg(0)->isDefaultArgument();
+ } else
+ if (Node.getInitStyle() == VarDecl::ListInit)
+ return false;
+
+ return !ImplicitInit;
+}
+
+/// \brief Matches QualTypes that are type sugar for QualTypes that match \c
+/// SugarMatcher.
+///
+/// Given
+/// \code
+/// class C {};
+/// typedef C my_type
+/// typedef my_type my_other_type;
+/// \code
+///
+/// \c qualType(isSugarFor(recordType(hasDeclaration(namedDecl(hasName("C"))))))
+/// matches \c my_type and \c my_other_type.
+AST_MATCHER_P(QualType, isSugarFor, internal::Matcher<QualType>, SugarMatcher) {
+ QualType QT = Node;
+ for (;;) {
+ if (SugarMatcher.matches(QT, Finder, Builder))
+ return true;
+
+ QualType NewQT = QT.getSingleStepDesugaredType(Finder->getASTContext());
+ if (NewQT == QT)
+ break;
+ QT = NewQT;
+ }
+ return false;
+}
+
+/// \brief Matches named declarations that have one of the standard iterator
+/// names: iterator, reverse_iterator, const_iterator, const_reverse_iterator.
+///
+/// Given
+/// \code
+/// iterator I;
+/// const_iterator CI;
+/// \code
+///
+/// \c namedDecl(hasStdIteratorName()) matches \c I and \c CI.
+AST_MATCHER(NamedDecl, hasStdIteratorName) {
+ static const char *IteratorNames[] = {
+ "iterator",
+ "reverse_iterator",
+ "const_iterator",
+ "const_reverse_iterator"
+ };
+
+ for (unsigned int i = 0;
+ i < llvm::array_lengthof(IteratorNames);
+ ++i) {
+ if (hasName(IteratorNames[i]).matches(Node, Finder, Builder))
+ return true;
+ }
+ return false;
+}
+
+/// \brief Matches named declarations that have one of the standard container
+/// names.
+///
+/// Given
+/// \code
+/// class vector {};
+/// class forward_list {};
+/// class my_vec {};
+/// \code
+///
+/// \c recordDecl(hasStdContainerName()) matches \c vector and \c forward_list
+/// but not \c my_vec.
+AST_MATCHER_P(NamedDecl, hasStdContainerName, bool, WithStd) {
+ static const char *ContainerNames[] = {
+ "array",
+ "deque",
+ "forward_list",
+ "list",
+ "vector",
+
+ "map",
+ "multimap",
+ "set",
+ "multiset",
+
+ "unordered_map",
+ "unordered_multimap",
+ "unordered_set",
+ "unordered_multiset",
+
+ "queue",
+ "priority_queue",
+ "stack"
+ };
+
+ for (unsigned int i = 0;
+ i < llvm::array_lengthof(ContainerNames);
+ ++i) {
+ std::string Name(ContainerNames[i]);
+ if (WithStd)
+ Name = "std::" + Name;
+ if (hasName(Name).matches(Node, Finder, Builder))
+ return true;
+ }
+ return false;
+}
+
+} // namespace ast_matchers
+} // namespace clang
+
+namespace {
+// \brief Returns a TypeMatcher that matches typedefs for standard iterators
+// inside records with a standard container name.
+TypeMatcher typedefIterator() {
+ return typedefType(
+ hasDeclaration(
+ allOf(
+ namedDecl(hasStdIteratorName()),
+ hasDeclContext(
+ recordDecl(hasStdContainerName(true))
+ )
+ )
+ )
+ );
+}
+
+// \brief Returns a TypeMatcher that matches records named for standard
+// iterators nested inside records named for standard containers.
+TypeMatcher nestedIterator() {
+ return recordType(
+ hasDeclaration(
+ allOf(
+ namedDecl(hasStdIteratorName()),
+ hasDeclContext(
+ recordDecl(hasStdContainerName(true))
+ )
+ )
+ )
+ );
+}
+
+// \brief Returns a TypeMatcher that matches types declared with using
+// declarations and which name standard iterators for standard containers.
+TypeMatcher iteratorFromUsingDeclaration() {
+ // Types resulting from using declarations are
+ // represented by ElaboratedType.
+ return elaboratedType(
+ allOf(
+ // Unwrap the nested name specifier to test for
+ // one of the standard containers.
+ hasQualifier(allOf(
+ specifiesType(
+ templateSpecializationType(
+ hasDeclaration(
+ namedDecl(hasStdContainerName(false))
+ )
+ )
+ ),
+ hasPrefix(
+ specifiesNamespace(hasName("std"))
+ )
+ )),
+ // The named type is what comes after the final
+ // '::' in the type. It should name one of the
+ // standard iterator names.
+ namesType(anyOf(
+ typedefType(
+ hasDeclaration(
+ namedDecl(hasStdIteratorName())
+ )
+ ),
+ recordType(
+ hasDeclaration(
+ namedDecl(hasStdIteratorName())
+ )
+ )
+ ))
+ )
+ );
+}
+} // namespace
+
+DeclarationMatcher makeIteratorMatcher() {
+ return varDecl(allOf(
+ hasWrittenNonListInitializer(),
+ unless(hasType(autoType())),
+ hasType(
+ isSugarFor(
+ anyOf(
+ typedefIterator(),
+ nestedIterator(),
+ iteratorFromUsingDeclaration()
+ )
+ )
+ )
+ )).bind(DeclNodeId);
+}
--- /dev/null
+//===-- UseAutoMatchers.h - Matchers for use-auto transform ----*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file contains the declarations for matcher-generating functions
+/// and names for bound nodes found by AST matchers.
+///
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_MATCHERS_H
+#define LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_MATCHERS_H
+
+#include "clang/ASTMatchers/ASTMatchers.h"
+
+extern const char *DeclNodeId;
+
+/// \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();
+
+#endif // LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_MATCHERS_H
#!/usr/bin/python
+# Each std container is represented below. To test the various ways in which
+# a type may be defined, the containers are split into categories:
+# * Define iterator types with typedefs
+# * Define iterator types as nested classes
+# * Define iterator types with using declarations
+#
+# Further, one class in each category is chosen to be defined in a way mimicing
+# libc++: The container is actually defined in a different namespace (std::_1
+# is used here) and then imported into the std namespace with a using
+# declaration. This is controlled with the 'using' key in the dictionary
+# describing each container.
typedef_containers = [
- "array",
- "deque",
- "forward_list",
- "list",
- "vector"
+ {"name" : "array",
+ "using" : True},
+ {"name" : "deque",
+ "using" : False},
+ {"name" : "forward_list",
+ "using" : False},
+ {"name" : "list",
+ "using" : False},
+ {"name" : "vector",
+ "using" : False}
]
subclass_containers = [
- "map",
- "multimap",
- "set",
- "multiset",
+ {"name" : "map",
+ "using" : True},
+ {"name" : "multimap",
+ "using" : False},
+ {"name" : "set",
+ "using" : False},
+ {"name" : "multiset",
+ "using" : False},
]
using_containers = [
- "unordered_map",
- "unordered_multimap",
- "unordered_set",
- "unordered_multiset",
- "queue",
- "priority_queue",
- "stack"
+ {"name" : "unordered_map",
+ "using" : True},
+ {"name" : "unordered_multimap",
+ "using" : False},
+ {"name" : "unordered_set",
+ "using" : False},
+ {"name" : "unordered_multiset",
+ "using" : False},
+ {"name" : "queue",
+ "using" : False},
+ {"name" : "priority_queue",
+ "using" : False},
+ {"name" : "stack",
+ "using" : False}
]
-print """namespace internal {
-
-template <typename T, int i>
-struct iterator_wrapper {
-};
-
-template <typename T>
-class iterator_provider {
-public:
- class iterator {};
- class const_iterator {};
- class reverse_iterator {};
- class const_reverse_iterator {};
-};
-
-} // namespace internal
-
-namespace std {"""
+# Every class requires these functions.
iterator_generators = """
iterator begin() { return iterator(); }
iterator end() { return iterator(); }
const_reverse_iterator rend() const { return const_reverse_iterator(); }
"""
+
+# Convenience function for nested class definition within a special namespace
+# to mimic libc++ style std container definitions.
+def outputClassDef(Definition, ClassName, Import):
+ if Import:
+ print "namespace _1 {"
+
+ print Definition
+
+ if Import:
+ print """
+}} // namespace _1
+using _1::{0};""".format(ClassName)
+
+
+# Output preamble and common functionality
+print """
+//===-----------------------------------------------------------*- C++ -*--===//
+//
+// This file was automatically generated from gen_my_std.h.py by the build
+// system as a dependency for cpp11-migrate's test suite.
+//
+// This file contains a shell implementation of std containers and iterators for
+// testing the use-auto transform of cpp11-migrate. All std containers and
+// iterators are present. Container and iterator implementations vary to cover
+// various ways the std container and iterator types are made available:
+//
+// Variations for how iterator types are presented:
+// * Typedef (array, deque, forward_list, list, vector)
+// * Nested class (map, multimap, set, multiset)
+// * Using declaration {unordered_} X {map, multimap, set, multiset}
+//
+// Variations for how container types are presented:
+// * Defined directly in namespace std
+// * Imported into namespace std with using declarations (a la libc++).
+//
+//===----------------------------------------------------------------------===//
+
+namespace internal {
+
+template <typename T, int i>
+struct iterator_wrapper {
+ iterator_wrapper() {}
+
+ // These are required for tests using iteration statements.
+ bool operator!=(const iterator_wrapper<T, i>&) { return false; }
+ iterator_wrapper& operator++() { return *this; }
+ typename T::value_type operator*() { return typename T::value_type(); }
+};
+
+template <typename T>
+class iterator_provider {
+public:
+ class iterator {
+ public:
+ iterator() {}
+ iterator(const iterator&) {}
+ };
+ class const_iterator {
+ public:
+ const_iterator(int i=0) {}
+ const_iterator(const iterator &) {}
+ const_iterator(const const_iterator &) {}
+ operator iterator() { return iterator(); }
+ };
+ class reverse_iterator {};
+ class const_reverse_iterator {};
+};
+
+} // namespace internal
+
+namespace std {""".lstrip() # Take off leading newline
+
for c in typedef_containers:
- print """
+ Definition = """
template <typename T>
class {0} {{
public:
+ typedef T value_type;
typedef typename internal::iterator_wrapper<{0}<T>, 0> iterator;
typedef typename internal::iterator_wrapper<{0}<T>, 1> const_iterator;
typedef typename internal::iterator_wrapper<{0}<T>, 3> reverse_iterator;
typedef typename internal::iterator_wrapper<{0}<T>, 2> const_reverse_iterator;
{0}() {{}}
- {1}}};""".format(c, iterator_generators)
+ {1}}};""".format(c['name'], iterator_generators)
+
+ outputClassDef(Definition, c['name'], c['using'])
for c in subclass_containers:
- print """
+ Definition = """
template <typename T>
class {0} {{
public:
class const_reverse_iterator {{}};
{0}() {{}}
- {1}}};""".format(c, iterator_generators)
+ {1}}};""".format(c['name'], iterator_generators)
+
+ outputClassDef(Definition, c['name'], c['using'])
for c in using_containers:
- print """
+ Definition = """
template <typename T>
class {0} : internal::iterator_provider<{0}<T> > {{
public:
using typename internal::iterator_provider<{0}<T> >::const_reverse_iterator;
{0}() {{}}
- {1}}};""".format(c, iterator_generators)
+ {1}}};""".format(c['name'], iterator_generators)
+
+ outputClassDef(Definition, c['name'], c['using'])
print "} // namespace std"
"stack"
]
-print """// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
-// RUN: cpp11-migrate -use-auto %t.cpp -- --std=c++11 -I %S/Inputs
+print """
+//===----------------------------------------------------------------------===//
+//
+// This file was automatically generated from
+// gen_basic_std_iterator_tests.cpp.py by the build system as a dependency for
+// cpp11-migrate's test suite.
+//
+// This file contains basic positive tests for the use-auto transform's ability
+// to replace standard iterators. Variables considered:
+// * All std container names
+// * All std iterator names
+//
+//===----------------------------------------------------------------------===//
+
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: cpp11-migrate -use-auto %t.cpp -- -I %S/Inputs
// RUN: FileCheck -input-file=%t.cpp %s
-// XFAIL: *
#include "my_std.h"
-int main(int argc, char **argv) {"""
+int main(int argc, char **argv) {""".lstrip() # Strip leading newline
for c in containers:
print """
--- /dev/null
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: cpp11-migrate -use-auto %t.cpp -- --std=c++11 -I %gen_root/UseAuto/Inputs
+// RUN: FileCheck -input-file=%t.cpp %s
+#include "my_std.h"
+
+typedef std::vector<int>::iterator int_iterator;
+
+namespace foo {
+ template <typename T>
+ class vector {
+ public:
+ class iterator {};
+
+ iterator begin() { return iterator(); }
+ };
+} // namespace foo
+
+int main(int argc, char **argv) {
+ std::vector<int> Vec;
+ // CHECK: std::vector<int> Vec;
+
+ std::unordered_map<int> Map;
+ // CHECK: std::unordered_map<int> Map;
+
+ // Types with more sugar should work. Types with less should not.
+ {
+ int_iterator more_sugar = Vec.begin();
+ // CHECK: auto more_sugar = Vec.begin();
+
+ internal::iterator_wrapper<std::vector<int>, 0> less_sugar = Vec.begin();
+ // CHECK: internal::iterator_wrapper<std::vector<int>, 0> less_sugar = Vec.begin();
+ }
+
+ // Initialization from initializer lists isn't allowed. Using 'auto'
+ // would result in std::initializer_list being deduced for the type.
+ {
+ std::unordered_map<int>::iterator I{Map.begin()};
+ // CHECK: std::unordered_map<int>::iterator I{Map.begin()};
+
+ std::unordered_map<int>::iterator I2 = {Map.begin()};
+ // CHECK: std::unordered_map<int>::iterator I2 = {Map.begin()};
+ }
+
+ // Various forms of construction. Default constructors and constructors with
+ // all-default parameters shouldn't get transformed. Construction from other
+ // types is also not allowed.
+ {
+ std::unordered_map<int>::iterator copy(Map.begin());
+ // CHECK: auto copy(Map.begin());
+
+ std::unordered_map<int>::iterator def;
+ // CHECK: std::unordered_map<int>::iterator def;
+
+ // const_iterator has no default constructor, just one that has >0 params
+ // with defaults.
+ std::unordered_map<int>::const_iterator constI;
+ // CHECK: std::unordered_map<int>::const_iterator constI;
+
+ // Uses iterator_provider::const_iterator's conversion constructor.
+
+ std::unordered_map<int>::const_iterator constI2 = def;
+ // CHECK: std::unordered_map<int>::const_iterator constI2 = def;
+
+ std::unordered_map<int>::const_iterator constI3(def);
+ // CHECK: std::unordered_map<int>::const_iterator constI3(def);
+
+ // Explicit use of conversion constructor
+
+ std::unordered_map<int>::const_iterator constI4 = std::unordered_map<int>::const_iterator(def);
+ // CHECK: auto constI4 = std::unordered_map<int>::const_iterator(def);
+
+ // Uses iterator_provider::iterator's const_iterator conversion operator.
+
+ std::unordered_map<int>::iterator I = constI;
+ // CHECK: std::unordered_map<int>::iterator I = constI;
+
+ std::unordered_map<int>::iterator I2(constI);
+ // CHECK: std::unordered_map<int>::iterator I2(constI);
+ }
+
+ // Weird cases of pointers and references to iterators are not transformed.
+ {
+ int_iterator I = Vec.begin();
+
+ int_iterator *IPtr = &I;
+ // CHECK: int_iterator *IPtr = &I;
+
+ int_iterator &IRef = I;
+ // CHECK: int_iterator &IRef = I;
+ }
+
+ {
+ // Variable declarations in iteration statements.
+ for (std::vector<int>::iterator I = Vec.begin(); I != Vec.end(); ++I) {
+ // CHECK: for (auto I = Vec.begin(); I != Vec.end(); ++I) {
+ }
+
+ // Range-based for loops.
+ std::array<std::vector<int>::iterator> iter_arr;
+ for (std::vector<int>::iterator I: iter_arr) {
+ // CHECK: for (auto I: iter_arr) {
+ }
+
+ // Test with init-declarator-list.
+ for (int_iterator I = Vec.begin(),
+ E = Vec.end(); I != E; ++I) {
+ // CHECK: for (auto I = Vec.begin(),
+ // CHECK-NEXT: E = Vec.end(); I != E; ++I) {
+ }
+ }
+
+ // Only std containers should be changed.
+ {
+ using namespace foo;
+ vector<int> foo_vec;
+ vector<int>::iterator I = foo_vec.begin();
+ // CHECK: vector<int>::iterator I = foo_vec.begin();
+ }
+
+ // Ensure using directives don't interfere with replacement.
+ {
+ using namespace std;
+ vector<int> std_vec;
+ vector<int>::iterator I = std_vec.begin();
+ // CHECK: auto I = std_vec.begin();
+ }
+
+ // Make sure references and cv qualifiers don't get removed (i.e. replaced
+ // with just 'auto').
+ {
+ const auto & I = Vec.begin();
+ // CHECK: const auto & I = Vec.begin();
+
+ auto && I2 = Vec.begin();
+ // CHECK: auto && I2 = Vec.begin();
+ }
+
+ return 0;
+}