summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp')
-rw-r--r--clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp50
1 files changed, 46 insertions, 4 deletions
diff --git a/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp
index e2ddceb33b5..12c19f6d283 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp
@@ -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 DeclStmt *D, ASTContext *Context,
// 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 MatchFinder::MatchResult &Result) {
},
"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.");
}
OpenPOWER on IntegriCloud