#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Tooling/FixIt.h"
using namespace clang;
const char DeclWithCastId[] = "decl_cast";
const char DeclWithTemplateCastId[] = "decl_template";
+size_t GetTypeNameLength(bool RemoveStars, StringRef Text) {
+ enum CharType { Space, Alpha, Punctuation };
+ CharType LastChar = Space, BeforeSpace = Punctuation;
+ size_t NumChars = 0;
+ int TemplateTypenameCntr = 0;
+ for (const unsigned char C : Text) {
+ if (C == '<')
+ ++TemplateTypenameCntr;
+ else if (C == '>')
+ --TemplateTypenameCntr;
+ const CharType NextChar =
+ isAlphanumeric(C)
+ ? Alpha
+ : (isWhitespace(C) ||
+ (!RemoveStars && TemplateTypenameCntr == 0 && C == '*'))
+ ? Space
+ : Punctuation;
+ if (NextChar != Space) {
+ ++NumChars; // Count the non-space character.
+ if (LastChar == Space && NextChar == Alpha && BeforeSpace == Alpha)
+ ++NumChars; // Count a single space character between two words.
+ BeforeSpace = NextChar;
+ }
+ LastChar = NextChar;
+ }
+ return NumChars;
+}
+
/// \brief Matches variable declarations that have explicit initializers that
/// are not initializer lists.
///
SourceRange Range(Loc.getSourceRange());
if (MinTypeNameLength != 0 &&
- tooling::fixit::getText(Loc.getSourceRange(), FirstDecl->getASTContext())
- .size() < MinTypeNameLength)
+ GetTypeNameLength(RemoveStars,
+ tooling::fixit::getText(Loc.getSourceRange(),
+ FirstDecl->getASTContext())) <
+ MinTypeNameLength)
return;
auto Diag = diag(Range.getBegin(), Message);
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 ``RemoveStars`` option (see below) is set to non-zero, then ``*s`` in
+ the type are also counted as a part of the type name.
.. code-block:: c++
- // MinTypeNameLength = 0
+ // MinTypeNameLength = 0, RemoveStars=0
int a = static_cast<int>(foo()); // ---> auto a = ...
- bool b = new bool; // ---> auto b = ...
+ // length(bool *) = 4
+ bool *b = new bool; // ---> auto *b = ...
unsigned c = static_cast<unsigned>(foo()); // ---> auto c = ...
- // MinTypeNameLength = 8
+ // MinTypeNameLength = 5, RemoveStars=0
- int a = static_cast<int>(foo()); // ---> int a = ...
- bool b = new bool; // ---> bool b = ...
- unsigned c = static_cast<unsigned>(foo()); // ---> auto c = ...
+ 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
-// RUN: %check_clang_tidy %s modernize-use-auto %t -- \
-// RUN: -config="{CheckOptions: [{key: modernize-use-auto.MinTypeNameLength, value: '5'}]}" \
-// RUN: -- -std=c++11 -frtti
+// RUN: %check_clang_tidy -check-suffix=0-0 %s modernize-use-auto %t -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 0}, {key: modernize-use-auto.MinTypeNameLength, value: 0}]}" -- --std=c++11 -frtti
+// RUN: %check_clang_tidy -check-suffix=0-8 %s modernize-use-auto %t -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 0}, {key: modernize-use-auto.MinTypeNameLength, value: 8}]}" -- --std=c++11 -frtti
+// RUN: %check_clang_tidy -check-suffix=1-0 %s modernize-use-auto %t -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 1}, {key: modernize-use-auto.MinTypeNameLength, value: 0}]}" -- --std=c++11 -frtti
+// RUN: %check_clang_tidy -check-suffix=1-8 %s modernize-use-auto %t -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 1}, {key: modernize-use-auto.MinTypeNameLength, value: 8}]}" -- --std=c++11 -frtti
-extern int foo();
-
-using VeryVeryVeryLongTypeName = int;
+template <class T> extern T foo();
+template <class T> struct P { explicit P(T t) : t_(t) {} T t_;};
+template <class T> P<T> *foo_ptr();
+template <class T> P<T> &foo_ref();
int bar() {
- int a = static_cast<VeryVeryVeryLongTypeName>(foo());
- // strlen('int') = 4 < 5, so skip it,
- // even strlen('VeryVeryVeryLongTypeName') > 5.
+ {
+ // Lenth(long) = 4
+ long i = static_cast<long>(foo<long>());
+ // CHECK-FIXES-0-0: auto i = {{.*}}
+ // CHECK-FIXES-0-8: long i = {{.*}}
+ // CHECK-FIXES-1-0: auto i = {{.*}}
+ // CHECK-FIXES-1-8: long i = {{.*}}
+ const long ci = static_cast<long>(foo<const long>());
+ // CHECK-FIXES-0-0: auto ci = {{.*}}
+ // CHECK-FIXES-0-8: long ci = {{.*}}
+ // CHECK-FIXES-1-0: auto ci = {{.*}}
+ // CHECK-FIXES-1-8: long ci = {{.*}}
+ long *pi = static_cast<long *>(foo<long *>());
+ // CHECK-FIXES-0-0: auto *pi = {{.*}}
+ // CHECK-FIXES-0-8: long *pi = {{.*}}
+ // CHECK-FIXES-1-0: auto pi = {{.*}}
+ // CHECK-FIXES-1-8: long *pi = {{.*}}
+
+ // Length(long *) is still 5
+ long * pi2 = static_cast<long *>(foo<long *>());
+ // CHECK-FIXES-0-0: auto * pi2 = {{.*}}
+ // CHECK-FIXES-0-8: long * pi2 = {{.*}}
+ // CHECK-FIXES-1-0: auto pi2 = {{.*}}
+ // CHECK-FIXES-1-8: long * pi2 = {{.*}}
+
+ // Length(long **) = 6
+ long **ppi = static_cast<long **>(foo<long **>());
+ // CHECK-FIXES-0-0: auto **ppi = {{.*}}
+ // CHECK-FIXES-0-8: long **ppi = {{.*}}
+ // CHECK-FIXES-1-0: auto ppi = {{.*}}
+ // CHECK-FIXES-1-8: long **ppi = {{.*}}
+ }
- unsigned b = static_cast<unsigned>(foo());
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name [modernize-use-auto]
- // CHECK-FIXES: auto b = static_cast<unsigned>(foo());
+ {
+ // Lenth(long int) = 4 + 1 + 3 = 8
+ // Lenth(long int) is still 8
+ long int i = static_cast<long int>(foo<long int>());
+ // CHECK-FIXES-0-0: auto i = {{.*}}
+ // CHECK-FIXES-0-8: auto i = {{.*}}
+ // CHECK-FIXES-1-0: auto i = {{.*}}
+ // CHECK-FIXES-1-8: auto i = {{.*}}
- bool c = static_cast<bool>(foo());
- // strlen('bool') = 4 < 5, so skip it.
+ long int *pi = static_cast<long int *>(foo<long int *>());
+ // CHECK-FIXES-0-0: auto *pi = {{.*}}
+ // CHECK-FIXES-0-8: auto *pi = {{.*}}
+ // CHECK-FIXES-1-0: auto pi = {{.*}}
+ // CHECK-FIXES-1-8: auto pi = {{.*}}
+ }
- const bool c1 = static_cast<const bool>(foo());
- // strlen('bool') = 4 < 5, so skip it, even there's a 'const'.
+ // Templates
+ {
+ // Length(P<long>) = 7
+ P<long>& i = static_cast<P<long>&>(foo_ref<long>());
+ // CHECK-FIXES-0-0: auto& i = {{.*}}
+ // CHECK-FIXES-0-8: P<long>& i = {{.*}}
+ // CHECK-FIXES-1-0: auto & i = {{.*}}
+ // CHECK-FIXES-1-8: P<long>& i = {{.*}}
- unsigned long long ull = static_cast<unsigned long long>(foo());
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name [modernize-use-auto]
- // CHECK-FIXES: auto ull = static_cast<unsigned long long>(foo());
+ // Length(P<long*>) = 8
+ P<long*>& pi = static_cast<P<long*> &>(foo_ref<long*>());
+ // CHECK-FIXES-0-0: auto& pi = {{.*}}
+ // CHECK-FIXES-0-8: auto& pi = {{.*}}
+ // CHECK-FIXES-1-0: auto & pi = {{.*}}
+ // CHECK-FIXES-1-8: auto & pi = {{.*}}
+
+ P<long>* pi2 = static_cast<P<long>*>(foo_ptr<long>());
+ // CHECK-FIXES-0-0: auto* pi2 = {{.*}}
+ // CHECK-FIXES-0-8: P<long>* pi2 = {{.*}}
+ // CHECK-FIXES-1-0: auto pi2 = {{.*}}
+ // CHECK-FIXES-1-8: auto pi2 = {{.*}}
+ }
return 1;
}
-