File: use-auto.rst

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (233 lines) | stat: -rw-r--r-- 7,788 bytes parent folder | download | duplicates (18)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
.. title:: clang-tidy - modernize-use-auto

modernize-use-auto
==================

This check is responsible for using the ``auto`` type specifier for variable
declarations to *improve code readability and maintainability*. For example:

.. code-block:: c++

  std::vector<int>::iterator I = my_container.begin();

  // transforms to:

  auto I = my_container.begin();

The ``auto`` type specifier will only be introduced in situations where the
variable type matches the type of the initializer expression. In other words
``auto`` should deduce the same type that was originally spelled in the source.
However, not every situation should be transformed:

.. code-block:: c++

  int val = 42;
  InfoStruct &I = SomeObject.getInfo();

  // Should not become:

  auto val = 42;
  auto &I = SomeObject.getInfo();

In this example using ``auto`` for builtins doesn't improve readability. In
other situations it makes the code less self-documenting impairing readability
and maintainability. As a result, ``auto`` is used only introduced in specific
situations described below.

Iterators
---------

Iterator type specifiers tend to be long and used frequently, especially in
loop constructs. Since the functions generating iterators have a common format,
the type specifier can be replaced without obscuring the meaning of code while
improving readability and maintainability.

.. code-block:: c++

  for (std::vector<int>::iterator I = my_container.begin(),
                                  E = my_container.end();
       I != E; ++I) {
  }

  // becomes

  for (auto I = my_container.begin(), E = my_container.end(); I != E; ++I) {
  }

The check will only replace iterator type-specifiers when all of the following
conditions are satisfied:

* The iterator is for one of the standard containers in ``std`` namespace:

  * ``array``
  * ``deque``
  * ``forward_list``
  * ``list``
  * ``vector``
  * ``map``
  * ``multimap``
  * ``set``
  * ``multiset``
  * ``unordered_map``
  * ``unordered_multimap``
  * ``unordered_set``
  * ``unordered_multiset``
  * ``queue``
  * ``priority_queue``
  * ``stack``

* The iterator is one of the possible iterator types for standard containers:

  * ``iterator``
  * ``reverse_iterator``
  * ``const_iterator``
  * ``const_reverse_iterator``

* In addition to using iterator types directly, typedefs or other ways of
  referring to those types are also allowed. However, implementation-specific
  types for which a type like ``std::vector<int>::iterator`` is itself a
  typedef will not be transformed. Consider the following examples:

.. code-block:: c++

  // The following direct uses of iterator types will be transformed.
  std::vector<int>::iterator I = MyVec.begin();
  {
    using namespace std;
    list<int>::iterator I = MyList.begin();
  }

  // The type specifier for J would transform to auto since it's a typedef
  // to a standard iterator type.
  typedef std::map<int, std::string>::const_iterator map_iterator;
  map_iterator J = MyMap.begin();

  // The following implementation-specific iterator type for which
  // std::vector<int>::iterator could be a typedef would not be transformed.
  __gnu_cxx::__normal_iterator<int*, std::vector> K = MyVec.begin();

* The initializer for the variable being declared is not a braced initializer
  list. Otherwise, use of ``auto`` would cause the type of the variable to be
  deduced as ``std::initializer_list``.

New expressions
---------------

Frequently, when a pointer is declared and initialized with ``new``, the
pointee type is written twice: in the declaration type and in the
``new`` expression. In this case, the declaration type can be replaced with
``auto`` improving readability and maintainability.

.. code-block:: c++

  TypeName *my_pointer = new TypeName(my_param);

  // becomes

  auto *my_pointer = new TypeName(my_param);

The check will also replace the declaration type in multiple declarations, if
the following conditions are satisfied:

* All declared variables have the same type (i.e. all of them are pointers to
  the same type).
* All declared variables are initialized with a ``new`` expression.
* The types of all the new expressions are the same than the pointee of the
  declaration type.

.. code-block:: c++

  TypeName *my_first_pointer = new TypeName, *my_second_pointer = new TypeName;

  // becomes

  auto *my_first_pointer = new TypeName, *my_second_pointer = new TypeName;

Cast expressions
----------------

Frequently, when a variable is declared and initialized with a cast, the
variable type is written twice: in the declaration type and in the
cast expression. In this case, the declaration type can be replaced with
``auto`` improving readability and maintainability.

.. code-block:: c++

  TypeName *my_pointer = static_cast<TypeName>(my_param);

  // becomes

  auto *my_pointer = static_cast<TypeName>(my_param);

The check handles ``static_cast``, ``dynamic_cast``, ``const_cast``,
``reinterpret_cast``, functional casts, C-style casts and function templates
that behave as casts, such as ``llvm::dyn_cast``, ``boost::lexical_cast`` and
``gsl::narrow_cast``. Calls to function templates are considered to behave as
casts if the first template argument is explicit and is a type, and the function
returns that type, or a pointer or reference to it.

Known Limitations
-----------------

* If the initializer is an explicit conversion constructor, the check will not
  replace the type specifier even though it would be safe to do so.

* User-defined iterators are not handled at this time.

Options
-------

.. option:: MinTypeNameLength

   If the option is set to non-zero (default `5`), the check will ignore type
   names having a length less than the option value. The option affects
   expressions only, not iterators.
   Spaces between multi-lexeme type names (``long int``) are considered as one.
   If the :option:`RemoveStars` option (see below) is set to `true`, then ``*s``
   in the type are also counted as a part of the type name.

.. code-block:: c++

  // MinTypeNameLength = 0, RemoveStars=0

  int a = static_cast<int>(foo());            // ---> auto a = ...
  // length(bool *) = 4
  bool *b = new bool;                         // ---> auto *b = ...
  unsigned c = static_cast<unsigned>(foo());  // ---> auto c = ...

  // MinTypeNameLength = 5, RemoveStars=0

  int a = static_cast<int>(foo());                 // ---> int  a = ...
  bool b = static_cast<bool>(foo());               // ---> bool b = ...
  bool *pb = static_cast<bool*>(foo());            // ---> bool *pb = ...
  unsigned c = static_cast<unsigned>(foo());       // ---> auto c = ...
  // length(long <on-or-more-spaces> int) = 8
  long int d = static_cast<long int>(foo());       // ---> auto d = ...

  // MinTypeNameLength = 5, RemoveStars=1

  int a = static_cast<int>(foo());                 // ---> int  a = ...
  // length(int * * ) = 5
  int **pa = static_cast<int**>(foo());            // ---> auto pa = ...
  bool b = static_cast<bool>(foo());               // ---> bool b = ...
  bool *pb = static_cast<bool*>(foo());            // ---> auto pb = ...
  unsigned c = static_cast<unsigned>(foo());       // ---> auto c = ...
  long int d = static_cast<long int>(foo());       // ---> auto d = ...

.. option:: RemoveStars

   If the option is set to `true` (default is `false`), the check will remove
   stars from the non-typedef pointer types when replacing type names with
   ``auto``. Otherwise, the check will leave stars. For example:

.. code-block:: c++

  TypeName *my_first_pointer = new TypeName, *my_second_pointer = new TypeName;

  // RemoveStars = 0

  auto *my_first_pointer = new TypeName, *my_second_pointer = new TypeName;

  // RemoveStars = 1

  auto my_first_pointer = new TypeName, my_second_pointer = new TypeName;