diff options
Diffstat (limited to 'clang-tools-extra/test/cpp11-migrate/UseAuto')
3 files changed, 286 insertions, 44 deletions
diff --git a/clang-tools-extra/test/cpp11-migrate/UseAuto/Inputs/gen_my_std.h.py b/clang-tools-extra/test/cpp11-migrate/UseAuto/Inputs/gen_my_std.h.py index 06709abcb4c..3f8be5862da 100644 --- a/clang-tools-extra/test/cpp11-migrate/UseAuto/Inputs/gen_my_std.h.py +++ b/clang-tools-extra/test/cpp11-migrate/UseAuto/Inputs/gen_my_std.h.py @@ -1,47 +1,57 @@ #!/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(); } @@ -56,21 +66,97 @@ iterator_generators = """ 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: @@ -80,10 +166,12 @@ 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: @@ -93,6 +181,8 @@ 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" diff --git a/clang-tools-extra/test/cpp11-migrate/UseAuto/gen_basic_std_iterator_tests.cpp.py b/clang-tools-extra/test/cpp11-migrate/UseAuto/gen_basic_std_iterator_tests.cpp.py index 56b6f5c41d2..8f118245db1 100644 --- a/clang-tools-extra/test/cpp11-migrate/UseAuto/gen_basic_std_iterator_tests.cpp.py +++ b/clang-tools-extra/test/cpp11-migrate/UseAuto/gen_basic_std_iterator_tests.cpp.py @@ -19,13 +19,26 @@ containers = [ "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 """ diff --git a/clang-tools-extra/test/cpp11-migrate/UseAuto/iterator.cpp b/clang-tools-extra/test/cpp11-migrate/UseAuto/iterator.cpp new file mode 100644 index 00000000000..a6d00c7bf96 --- /dev/null +++ b/clang-tools-extra/test/cpp11-migrate/UseAuto/iterator.cpp @@ -0,0 +1,139 @@ +// 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; +} |