clang-tidy - modernize-use-auto — Extra Clang Tools 19.1.7 documentation

# Extra Clang Tools 19.1.7 documentation

## 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:

    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:

    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.

    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:

    // 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.

    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.

    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.

    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

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 `RemoveStars` option (see below) is set to true, then `*s` in the type are also counted as a part of the type name.

    // 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 = ...

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:

    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;