Author: malcolm.parsons Date: Thu Dec 15 04:19:56 2016 New Revision: 289797
URL: http://llvm.org/viewvc/llvm-project?rev=289797&view=rev Log: [clang-tidy] Enhance modernize-use-auto to templated function casts Summary: Use auto when declaring variables that are initialized by calling a templated function that returns its explicit first argument. Fixes PR26763. Reviewers: aaron.ballman, alexfh, staronj, Prazek Subscribers: Eugene.Zelenko, JDevlieghere, cfe-commits Differential Revision: https://reviews.llvm.org/D27166 Modified: clang-tools-extra/trunk/clang-tidy/modernize/UseAutoCheck.cpp clang-tools-extra/trunk/docs/ReleaseNotes.rst clang-tools-extra/trunk/docs/clang-tidy/checks/modernize-use-auto.rst clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast-remove-stars.cpp clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast.cpp Modified: clang-tools-extra/trunk/clang-tidy/modernize/UseAutoCheck.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/modernize/UseAutoCheck.cpp?rev=289797&r1=289796&r2=289797&view=diff ============================================================================== --- clang-tools-extra/trunk/clang-tidy/modernize/UseAutoCheck.cpp (original) +++ clang-tools-extra/trunk/clang-tidy/modernize/UseAutoCheck.cpp Thu Dec 15 04:19:56 2016 @@ -24,6 +24,7 @@ namespace { const char IteratorDeclStmtId[] = "iterator_decl"; const char DeclWithNewId[] = "decl_new"; const char DeclWithCastId[] = "decl_cast"; +const char DeclWithTemplateCastId[] = "decl_template"; /// \brief Matches variable declarations that have explicit initializers that /// are not initializer lists. @@ -169,6 +170,14 @@ AST_MATCHER(Decl, isFromStdNamespace) { return (Info && Info->isStr("std")); } +/// Matches declaration reference or member expressions with explicit template +/// arguments. +AST_POLYMORPHIC_MATCHER(hasExplicitTemplateArgs, + AST_POLYMORPHIC_SUPPORTED_TYPES(DeclRefExpr, + MemberExpr)) { + return Node.hasExplicitTemplateArgs(); +} + /// \brief Returns a DeclarationMatcher that matches standard iterators nested /// inside records with a standard container name. DeclarationMatcher standardIterator() { @@ -240,18 +249,38 @@ StatementMatcher makeDeclWithCastMatcher .bind(DeclWithCastId); } +StatementMatcher makeDeclWithTemplateCastMatcher() { + auto ST = + substTemplateTypeParmType(hasReplacementType(equalsBoundNode("arg"))); + + auto ExplicitCall = + anyOf(has(memberExpr(hasExplicitTemplateArgs())), + has(ignoringImpCasts(declRefExpr(hasExplicitTemplateArgs())))); + + auto TemplateArg = + hasTemplateArgument(0, refersToType(qualType().bind("arg"))); + + auto TemplateCall = callExpr( + ExplicitCall, + callee(functionDecl(TemplateArg, + returns(anyOf(ST, pointsTo(ST), references(ST)))))); + + return declStmt(unless(has(varDecl( + unless(hasInitializer(ignoringImplicit(TemplateCall))))))) + .bind(DeclWithTemplateCastId); +} + StatementMatcher makeCombinedMatcher() { return declStmt( // At least one varDecl should be a child of the declStmt to ensure // it's a declaration list and avoid matching other declarations, // e.g. using directives. - has(varDecl()), + has(varDecl(unless(isImplicit()))), // Skip declarations that are already using auto. unless(has(varDecl(anyOf(hasType(autoType()), - hasType(pointerType(pointee(autoType()))), - hasType(referenceType(pointee(autoType()))))))), + hasType(qualType(hasDescendant(autoType()))))))), anyOf(makeIteratorDeclMatcher(), makeDeclWithNewMatcher(), - makeDeclWithCastMatcher())); + makeDeclWithCastMatcher(), makeDeclWithTemplateCastMatcher())); } } // namespace @@ -389,6 +418,8 @@ void UseAutoCheck::replaceExpr(const Dec // Space after 'auto' to handle cases where the '*' in the pointer type is // next to the identifier. This avoids changing 'int *p' into 'autop'. + // FIXME: This doesn't work for function pointers because the variable name + // is inside the type. Diag << FixItHint::CreateReplacement(Range, RemoveStars ? "auto " : "auto") << StarRemovals; } @@ -411,6 +442,17 @@ void UseAutoCheck::check(const MatchFind }, "use auto when initializing with a cast to avoid duplicating the type " "name"); + } else if (const auto *Decl = + Result.Nodes.getNodeAs<DeclStmt>(DeclWithTemplateCastId)) { + replaceExpr( + Decl, Result.Context, + [](const Expr *Expr) { + return cast<CallExpr>(Expr->IgnoreImplicit()) + ->getDirectCallee() + ->getReturnType(); + }, + "use auto when initializing with a template cast to avoid duplicating " + "the type name"); } else { llvm_unreachable("Bad Callback. No node provided."); } Modified: clang-tools-extra/trunk/docs/ReleaseNotes.rst URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/ReleaseNotes.rst?rev=289797&r1=289796&r2=289797&view=diff ============================================================================== --- clang-tools-extra/trunk/docs/ReleaseNotes.rst (original) +++ clang-tools-extra/trunk/docs/ReleaseNotes.rst Thu Dec 15 04:19:56 2016 @@ -93,7 +93,8 @@ Improvements to clang-tidy - The `modernize-use-auto <http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-auto.html>`_ check - now warns about variable declarations that are initialized with a cast. + now warns about variable declarations that are initialized with a cast, or by + calling a templated function that behaves as a cast. - The modernize-use-default check has been renamed to `modernize-use-equals-default <http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-equals-default.html>`_. Modified: clang-tools-extra/trunk/docs/clang-tidy/checks/modernize-use-auto.rst URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/modernize-use-auto.rst?rev=289797&r1=289796&r2=289797&view=diff ============================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/modernize-use-auto.rst (original) +++ clang-tools-extra/trunk/docs/clang-tidy/checks/modernize-use-auto.rst Thu Dec 15 04:19:56 2016 @@ -160,7 +160,11 @@ cast expression. In this cases, the decl auto *my_pointer = static_cast<TypeName>(my_param); The check handles ``static_cast``, ``dynamic_cast``, ``const_cast``, -``reinterpret_cast``, functional casts and C-style casts. +``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 ----------------- @@ -170,9 +174,6 @@ Known Limitations * User-defined iterators are not handled at this time. -* Function templates that behave as casts, such as ``llvm::dyn_cast``, - ``boost::lexical_cast`` or ``gsl::narrow_cast`` are not handled. - Options ------- Modified: clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast-remove-stars.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast-remove-stars.cpp?rev=289797&r1=289796&r2=289797&view=diff ============================================================================== --- clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast-remove-stars.cpp (original) +++ clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast-remove-stars.cpp Thu Dec 15 04:19:56 2016 @@ -44,7 +44,7 @@ void f_static_cast() { const B *b3 = static_cast<const B *>(a); // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a cast to avoid duplicating the type name - // CHECK-FIXES: auto b3 = static_cast<const B *>(a); + // CHECK-FIXES: const auto b3 = static_cast<const B *>(a); B &b4 = static_cast<B &>(*a); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name @@ -58,6 +58,9 @@ void f_static_cast() { // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name // CHECK-FIXES: auto &b6 = static_cast<B &>(*a), &b7 = static_cast<B &>(*a); + // Don't warn when non-cast involved + long double cast = static_cast<long double>(l), noncast = 5; + // Don't warn when auto is already being used. auto i3 = static_cast<int>(l); auto *b8 = static_cast<B *>(a); @@ -136,3 +139,95 @@ void f_functional_cast() { B b; A a = A(b); } + +class StringRef +{ +public: + StringRef(const char *); + const char *begin() const; + const char *end() const; +}; + +template <typename T, typename U> +T template_value_cast(const U &u); + +template <typename T, typename U> +T *template_pointer_cast(U *u); + +template <typename T, typename U> +T &template_reference_cast(U &u); + +template <typename T, typename U> +const T *template_const_pointer_cast(const U *u); + +template <typename T, typename U> +const T &template_const_reference_cast(const U &u); + +template <typename T> +T template_value_get(StringRef s); + +struct S { + template <typename T> + const T *template_member_get(); +}; + +template <typename T> +T max(T t1, T t2); + +void f_template_cast() +{ + double d = 0; + int i1 = template_value_cast<int>(d); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: auto i1 = template_value_cast<int>(d); + + A *a = new B(); + B *b1 = template_value_cast<B *>(a); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: auto b1 = template_value_cast<B *>(a); + B &b2 = template_value_cast<B &>(*a); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: auto &b2 = template_value_cast<B &>(*a); + B *b3 = template_pointer_cast<B>(a); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: auto b3 = template_pointer_cast<B>(a); + B &b4 = template_reference_cast<B>(*a); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: auto &b4 = template_reference_cast<B>(*a); + const B *b5 = template_const_pointer_cast<B>(a); + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: const auto b5 = template_const_pointer_cast<B>(a); + const B &b6 = template_const_reference_cast<B>(*a); + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: const auto &b6 = template_const_reference_cast<B>(*a); + B *b7 = template_value_get<B *>("foo"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: auto b7 = template_value_get<B *>("foo"); + B *b8 = template_value_get<B *>("foo"), *b9 = template_value_get<B *>("bar"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: auto b8 = template_value_get<B *>("foo"), b9 = template_value_get<B *>("bar"); + + S s; + const B *b10 = s.template_member_get<B>(); + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: const auto b10 = s.template_member_get<B>(); + + // Don't warn when auto is already being used. + auto i2 = template_value_cast<int>(d); + auto *i3 = template_value_cast<int *>(d); + auto **i4 = template_value_cast<int **>(d); + auto &i5 = template_reference_cast<int>(d); + + // Don't warn for implicit template arguments. + int i6 = max(i1, i2); + + // Don't warn for mismatched var and initializer types. + A *a1 = template_value_cast<B *>(a); + + // Don't warn for mismatched var types. + B *b11 = template_value_get<B *>("foo"), b12 = template_value_get<B>("bar"); + + // Don't warn for implicit variables. + for (auto &c : template_reference_cast<StringRef>(*a)) { + } +} Modified: clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast.cpp?rev=289797&r1=289796&r2=289797&view=diff ============================================================================== --- clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast.cpp (original) +++ clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast.cpp Thu Dec 15 04:19:56 2016 @@ -138,3 +138,95 @@ void f_functional_cast() { B b; A a = A(b); } + +class StringRef +{ +public: + StringRef(const char *); + const char *begin() const; + const char *end() const; +}; + +template <typename T, typename U> +T template_value_cast(const U &u); + +template <typename T, typename U> +T *template_pointer_cast(U *u); + +template <typename T, typename U> +T &template_reference_cast(U &u); + +template <typename T, typename U> +const T *template_const_pointer_cast(const U *u); + +template <typename T, typename U> +const T &template_const_reference_cast(const U &u); + +template <typename T> +T template_value_get(StringRef s); + +struct S { + template <typename T> + const T *template_member_get(); +}; + +template <typename T> +T max(T t1, T t2); + +void f_template_cast() +{ + double d = 0; + int i1 = template_value_cast<int>(d); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: auto i1 = template_value_cast<int>(d); + + A *a = new B(); + B *b1 = template_value_cast<B *>(a); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: auto *b1 = template_value_cast<B *>(a); + B &b2 = template_value_cast<B &>(*a); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: auto &b2 = template_value_cast<B &>(*a); + B *b3 = template_pointer_cast<B>(a); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: auto *b3 = template_pointer_cast<B>(a); + B &b4 = template_reference_cast<B>(*a); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: auto &b4 = template_reference_cast<B>(*a); + const B *b5 = template_const_pointer_cast<B>(a); + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: const auto *b5 = template_const_pointer_cast<B>(a); + const B &b6 = template_const_reference_cast<B>(*a); + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: const auto &b6 = template_const_reference_cast<B>(*a); + B *b7 = template_value_get<B *>("foo"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: auto *b7 = template_value_get<B *>("foo"); + B *b8 = template_value_get<B *>("foo"), *b9 = template_value_get<B *>("bar"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: auto *b8 = template_value_get<B *>("foo"), *b9 = template_value_get<B *>("bar"); + + S s; + const B *b10 = s.template_member_get<B>(); + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name + // CHECK-FIXES: const auto *b10 = s.template_member_get<B>(); + + // Don't warn when auto is already being used. + auto i2 = template_value_cast<int>(d); + auto *i3 = template_value_cast<int *>(d); + auto **i4 = template_value_cast<int **>(d); + auto &i5 = template_reference_cast<int>(d); + + // Don't warn for implicit template arguments. + int i6 = max(i1, i2); + + // Don't warn for mismatched var and initializer types. + A *a1 = template_value_cast<B *>(a); + + // Don't warn for mismatched var types. + B *b11 = template_value_get<B *>("foo"), b12 = template_value_get<B>("bar"); + + // Don't warn for implicit variables. + for (auto &c : template_reference_cast<StringRef>(*a)) { + } +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits