Index: clang-tidy/modernize/UseAutoCheck.h =================================================================== --- clang-tidy/modernize/UseAutoCheck.h +++ clang-tidy/modernize/UseAutoCheck.h @@ -18,15 +18,16 @@ class UseAutoCheck : public ClangTidyCheck { public: - UseAutoCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - + UseAutoCheck(StringRef Name, ClangTidyContext *Context); + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; private: void replaceIterators(const DeclStmt *D, ASTContext *Context); void replaceNew(const DeclStmt *D, ASTContext *Context); + + const bool RemoveStars; }; } // namespace modernize Index: clang-tidy/modernize/UseAutoCheck.cpp =================================================================== --- clang-tidy/modernize/UseAutoCheck.cpp +++ clang-tidy/modernize/UseAutoCheck.cpp @@ -243,6 +243,14 @@ } // namespace +UseAutoCheck::UseAutoCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + RemoveStars(Options.get("RemoveStars", 0)) {} + +void UseAutoCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "RemoveStars", RemoveStars ? 1 : 0); +} + void UseAutoCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++; the functionality currently does not // provide any benefit to other languages, despite being benign. @@ -311,7 +319,7 @@ const QualType FirstDeclType = FirstDecl->getType().getCanonicalType(); - std::vector StarLocations; + std::vector StarRemovals; for (const auto *Dec : D->decls()) { const auto *V = cast(Dec); // Ensure that every DeclStmt child is a VarDecl. @@ -327,19 +335,21 @@ if (!Context->hasSameUnqualifiedType(V->getType(), NewExpr->getType())) return; - // Remove explicitly written '*' from declarations where there's more than - // one declaration in the declaration list. - if (Dec == *D->decl_begin()) - continue; - // All subsequent declarations should match the same non-decorated type. if (FirstDeclType != V->getType().getCanonicalType()) return; - auto Q = V->getTypeSourceInfo()->getTypeLoc().getAs(); - while (!Q.isNull()) { - StarLocations.push_back(Q.getStarLoc()); - Q = Q.getNextTypeLoc().getAs(); + if (RemoveStars) { + // Remove explicitly written '*' from declarations where there's more than + // one declaration in the declaration list. + if (Dec == *D->decl_begin()) + continue; + + auto Q = V->getTypeSourceInfo()->getTypeLoc().getAs(); + while (!Q.isNull()) { + StarRemovals.push_back(FixItHint::CreateRemoval(Q.getStarLoc())); + Q = Q.getNextTypeLoc().getAs(); + } } } @@ -347,19 +357,20 @@ // 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. - SourceRange Range( - FirstDecl->getTypeSourceInfo()->getTypeLoc().getSourceRange()); + TypeLoc Loc = FirstDecl->getTypeSourceInfo()->getTypeLoc(); + if (!RemoveStars) { + while (Loc.getTypeLocClass() == TypeLoc::Pointer || + Loc.getTypeLocClass() == TypeLoc::Qualified) + Loc = Loc.getNextTypeLoc(); + } + SourceRange Range(Loc.getSourceRange()); auto Diag = diag(Range.getBegin(), "use auto when initializing with new" " to avoid duplicating the type name"); // Space after 'auto' to handle cases where the '*' in the pointer type is // next to the identifier. This avoids changing 'int *p' into 'autop'. - Diag << FixItHint::CreateReplacement(Range, "auto "); - - // Remove '*' from declarations using the saved star locations. - for (const auto &Loc : StarLocations) { - Diag << FixItHint::CreateReplacement(Loc, ""); - } + Diag << FixItHint::CreateReplacement(Range, RemoveStars ? "auto " : "auto") + << StarRemovals; } void UseAutoCheck::check(const MatchFinder::MatchResult &Result) { Index: docs/clang-tidy/checks/modernize-use-auto.rst =================================================================== --- docs/clang-tidy/checks/modernize-use-auto.rst +++ docs/clang-tidy/checks/modernize-use-auto.rst @@ -124,7 +124,7 @@ // becomes - auto my_pointer = new TypeName(my_param); + auto *my_pointer = new TypeName(my_param); The check will also replace the declaration type in multiple declarations, if the following conditions are satisfied: @@ -141,7 +141,7 @@ // becomes - auto my_first_pointer = new TypeName, my_second_pointer = new TypeName; + auto *my_first_pointer = new TypeName, *my_second_pointer = new TypeName; Known Limitations ----------------- @@ -150,3 +150,20 @@ * User-defined iterators are not handled at this time. +RemoveStars option +------------------ +If the option is set to non-zero (default is `0`), 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; Index: test/clang-tidy/modernize-use-auto-new-remove-stars.cpp =================================================================== --- test/clang-tidy/modernize-use-auto-new-remove-stars.cpp +++ test/clang-tidy/modernize-use-auto-new-remove-stars.cpp @@ -1,4 +1,6 @@ -// RUN: %check_clang_tidy %s modernize-use-auto %t +// RUN: %check_clang_tidy %s modernize-use-auto %t -- \ +// RUN: -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: '1'}]}" \ +// RUN: -- -std=c++11 class MyType {}; @@ -75,6 +77,7 @@ { // Test for typedefs. typedef int * int_p; + // CHECK-FIXES: typedef int * int_p; int_p a = new int; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new Index: test/clang-tidy/modernize-use-auto-new.cpp =================================================================== --- test/clang-tidy/modernize-use-auto-new.cpp +++ test/clang-tidy/modernize-use-auto-new.cpp @@ -9,11 +9,11 @@ void auto_new() { MyType *a_new = new MyType(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new - // CHECK-FIXES: auto a_new = new MyType(); + // CHECK-FIXES: auto *a_new = new MyType(); static MyType *a_static = new MyType(); // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use auto when initializing with new - // CHECK-FIXES: static auto a_static = new MyType(); + // CHECK-FIXES: static auto *a_static = new MyType(); MyType *derived = new MyDerivedType(); @@ -27,15 +27,15 @@ // not "MyType * const". static MyType * const d_static = new MyType(); // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use auto when initializing with new - // CHECK-FIXES: static auto const d_static = new MyType(); + // CHECK-FIXES: static auto * const d_static = new MyType(); MyType * const a_const = new MyType(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new - // CHECK-FIXES: auto const a_const = new MyType(); + // CHECK-FIXES: auto * const a_const = new MyType(); MyType * volatile vol = new MyType(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new - // CHECK-FIXES: auto volatile vol = new MyType(); + // CHECK-FIXES: auto * volatile vol = new MyType(); struct SType {} *stype = new SType; @@ -43,11 +43,11 @@ int *array = new int[5]; // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new - // CHECK-FIXES: auto array = new int[5]; + // CHECK-FIXES: auto *array = new int[5]; MyType *ptr(new MyType); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new - // CHECK-FIXES: auto ptr(new MyType); + // CHECK-FIXES: auto *ptr(new MyType); MyType *ptr2{new MyType}; @@ -55,14 +55,14 @@ // Test for declaration lists. MyType *a = new MyType(), *b = new MyType(), *c = new MyType(); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new - // CHECK-FIXES: auto a = new MyType(), b = new MyType(), c = new MyType(); + // CHECK-FIXES: auto *a = new MyType(), *b = new MyType(), *c = new MyType(); // Non-initialized declaration should not be transformed. MyType *d = new MyType(), *e; MyType **f = new MyType*(), **g = new MyType*(); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new - // CHECK-FIXES: auto f = new MyType*(), g = new MyType*(); + // CHECK-FIXES: auto **f = new MyType*(), **g = new MyType*(); // Mismatching types in declaration lists should not be transformed. MyType *h = new MyType(), **i = new MyType*(); @@ -75,25 +75,26 @@ { // Test for typedefs. typedef int * int_p; + // CHECK-FIXES: typedef int * int_p; int_p a = new int; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new - // CHECK-FIXES: auto a = new int; + // CHECK-FIXES: auto a = new int; int_p *b = new int*; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new - // CHECK-FIXES: auto b = new int*; + // CHECK-FIXES: auto *b = new int*; // Test for typedefs in declarations lists. int_p c = new int, d = new int; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new - // CHECK-FIXES: auto c = new int, d = new int; + // CHECK-FIXES: auto c = new int, d = new int; // Different types should not be transformed. int_p e = new int, *f = new int_p; int_p *g = new int*, *h = new int_p; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new - // CHECK-FIXES: auto g = new int*, h = new int_p; + // CHECK-FIXES: auto *g = new int*, *h = new int_p; } // Don't warn when 'auto' is already being used.