diff options
author | Malcolm Parsons <malcolm.parsons@gmail.com> | 2016-10-31 14:43:37 +0000 |
---|---|---|
committer | Malcolm Parsons <malcolm.parsons@gmail.com> | 2016-10-31 14:43:37 +0000 |
commit | db04833fcabea67dd38182fe81fab902015c1e8c (patch) | |
tree | 62b3bdb34067fe1307bf5c6e572c4bbe2f39b8af /clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp | |
parent | 30354ebb003375b1f112bd491bb61d54d5f37f22 (diff) | |
download | bcm5719-llvm-db04833fcabea67dd38182fe81fab902015c1e8c.tar.gz bcm5719-llvm-db04833fcabea67dd38182fe81fab902015c1e8c.zip |
[clang-tidy] Enhance modernize-use-auto to casts
Summary:
Extend modernize-use-auto to cases when a variable is assigned with a cast.
e.g.
Type *Ptr1 = dynamic_cast<Type*>(Ptr2);
http://llvm.org/PR25499
Reviewers: angelgarcia, aaron.ballman, klimek, Prazek, alexfh
Subscribers: Prazek, Eugene.Zelenko, cfe-commits
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D25316
llvm-svn: 285579
Diffstat (limited to 'clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp')
-rw-r--r-- | clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp | 77 |
1 files changed, 53 insertions, 24 deletions
diff --git a/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp index 8c43e6b754f..29d21f07505 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp @@ -23,6 +23,7 @@ namespace { const char IteratorDeclStmtId[] = "iterator_decl"; const char DeclWithNewId[] = "decl_new"; +const char DeclWithCastId[] = "decl_cast"; /// \brief Matches variable declarations that have explicit initializers that /// are not initializer lists. @@ -208,27 +209,18 @@ TypeMatcher iteratorFromUsingDeclaration() { /// \brief This matcher returns declaration statements that contain variable /// declarations with written non-list initializer for standard iterators. StatementMatcher makeIteratorDeclMatcher() { - 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()), - unless(has(varDecl(anyOf( - unless(hasWrittenNonListInitializer()), hasType(autoType()), - unless(hasType( - isSugarFor(anyOf(typedefIterator(), nestedIterator(), - iteratorFromUsingDeclaration()))))))))) + return declStmt(unless(has( + varDecl(anyOf(unless(hasWrittenNonListInitializer()), + unless(hasType(isSugarFor(anyOf( + typedefIterator(), nestedIterator(), + iteratorFromUsingDeclaration()))))))))) .bind(IteratorDeclStmtId); } StatementMatcher makeDeclWithNewMatcher() { return declStmt( - has(varDecl()), unless(has(varDecl(anyOf( unless(hasInitializer(ignoringParenImpCasts(cxxNewExpr()))), - // Skip declarations that are already using auto. - anyOf(hasType(autoType()), - hasType(pointerType(pointee(autoType())))), // FIXME: TypeLoc information is not reliable where CV // qualifiers are concerned so these types can't be // handled for now. @@ -243,6 +235,26 @@ StatementMatcher makeDeclWithNewMatcher() { .bind(DeclWithNewId); } +StatementMatcher makeDeclWithCastMatcher() { + return declStmt( + unless(has(varDecl(unless(hasInitializer(explicitCastExpr())))))) + .bind(DeclWithCastId); +} + +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()), + // Skip declarations that are already using auto. + unless(has(varDecl(anyOf(hasType(autoType()), + hasType(pointerType(pointee(autoType()))), + hasType(referenceType(pointee(autoType()))))))), + anyOf(makeIteratorDeclMatcher(), makeDeclWithNewMatcher(), + makeDeclWithCastMatcher())); +} + } // namespace UseAutoCheck::UseAutoCheck(StringRef Name, ClangTidyContext *Context) @@ -257,8 +269,7 @@ 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. if (getLangOpts().CPlusPlus) { - Finder->addMatcher(makeIteratorDeclMatcher(), this); - Finder->addMatcher(makeDeclWithNewMatcher(), this); + Finder->addMatcher(makeCombinedMatcher(), this); } } @@ -313,7 +324,9 @@ void UseAutoCheck::replaceIterators(const DeclStmt *D, ASTContext *Context) { << FixItHint::CreateReplacement(Range, "auto"); } -void UseAutoCheck::replaceNew(const DeclStmt *D, ASTContext *Context) { +void UseAutoCheck::replaceExpr(const DeclStmt *D, ASTContext *Context, + std::function<QualType(const Expr *)> GetType, + StringRef Message) { const auto *FirstDecl = dyn_cast<VarDecl>(*D->decl_begin()); // Ensure that there is at least one VarDecl within the DeclStmt. if (!FirstDecl) @@ -328,13 +341,13 @@ void UseAutoCheck::replaceNew(const DeclStmt *D, ASTContext *Context) { if (!V) return; - const auto *NewExpr = cast<CXXNewExpr>(V->getInit()->IgnoreParenImpCasts()); - // Ensure that every VarDecl has a CXXNewExpr initializer. - if (!NewExpr) + const auto *Expr = V->getInit()->IgnoreParenImpCasts(); + // Ensure that every VarDecl has an initializer. + if (!Expr) return; // If VarDecl and Initializer have mismatching unqualified types. - if (!Context->hasSameUnqualifiedType(V->getType(), NewExpr->getType())) + if (!Context->hasSameUnqualifiedType(V->getType(), GetType(Expr))) return; // All subsequent variables in this declaration should have the same @@ -367,9 +380,13 @@ void UseAutoCheck::replaceNew(const DeclStmt *D, ASTContext *Context) { Loc.getTypeLocClass() == TypeLoc::Qualified) Loc = Loc.getNextTypeLoc(); } + while (Loc.getTypeLocClass() == TypeLoc::LValueReference || + Loc.getTypeLocClass() == TypeLoc::RValueReference || + 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"); + auto Diag = diag(Range.getBegin(), Message); // Space after 'auto' to handle cases where the '*' in the pointer type is // next to the identifier. This avoids changing 'int *p' into 'autop'. @@ -382,7 +399,19 @@ void UseAutoCheck::check(const MatchFinder::MatchResult &Result) { replaceIterators(Decl, Result.Context); } else if (const auto *Decl = Result.Nodes.getNodeAs<DeclStmt>(DeclWithNewId)) { - replaceNew(Decl, Result.Context); + replaceExpr(Decl, Result.Context, + [](const Expr *Expr) { return Expr->getType(); }, + "use auto when initializing with new to avoid " + "duplicating the type name"); + } else if (const auto *Decl = + Result.Nodes.getNodeAs<DeclStmt>(DeclWithCastId)) { + replaceExpr( + Decl, Result.Context, + [](const Expr *Expr) { + return cast<ExplicitCastExpr>(Expr)->getTypeAsWritten(); + }, + "use auto when initializing with a cast to avoid duplicating the type " + "name"); } else { llvm_unreachable("Bad Callback. No node provided."); } |