10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
20 const auto BuiltinTypeWithId = [](
const char *
ID) {
21 return hasCanonicalType(builtinType().bind(
ID));
23 const auto IteratorWithValueType = [&BuiltinTypeWithId](
const char *
ID) {
26 pointsTo(BuiltinTypeWithId(
ID)),
34 hasDeclaration(cxxRecordDecl(isSameOrDerivedFrom(has(functionDecl(
35 hasOverloadedOperatorName(
"*"),
36 returns(qualType(hasCanonicalType(anyOf(
38 references(BuiltinTypeWithId(
ID)),
40 BuiltinTypeWithId(
ID),
42 autoType(hasDeducedType(BuiltinTypeWithId(
ID)))
47 const auto IteratorParam = parmVarDecl(
48 hasType(hasCanonicalType(IteratorWithValueType(
"IterValueType"))));
49 const auto Iterator2Param = parmVarDecl(
50 hasType(hasCanonicalType(IteratorWithValueType(
"Iter2ValueType"))));
51 const auto InitParam = parmVarDecl(hasType(BuiltinTypeWithId(
"InitType")));
55 callExpr(callee(functionDecl(
56 hasAnyName(
"::std::accumulate",
"::std::reduce"),
57 hasParameter(0, IteratorParam), hasParameter(2, InitParam))),
63 callExpr(callee(functionDecl(hasName(
"::std::inner_product"),
64 hasParameter(0, IteratorParam),
65 hasParameter(2, Iterator2Param),
66 hasParameter(3, InitParam))),
72 callExpr(callee(functionDecl(hasName(
"::std::reduce"),
73 hasParameter(1, IteratorParam),
74 hasParameter(3, InitParam))),
80 callExpr(callee(functionDecl(hasName(
"::std::inner_product"),
81 hasParameter(1, IteratorParam),
82 hasParameter(3, Iterator2Param),
83 hasParameter(4, InitParam))),
93 const BuiltinType &InitType,
94 const ASTContext &Context) {
95 const auto ValueTypeSize = Context.getTypeSize(&ValueType);
96 const auto InitTypeSize = Context.getTypeSize(&InitType);
99 if (ValueType.isFloatingPoint())
100 return InitType.isFloatingPoint() && InitTypeSize >= ValueTypeSize;
105 if (ValueType.isInteger()) {
106 if (InitType.isInteger()) {
107 if (InitType.isSignedInteger() == ValueType.isSignedInteger())
108 return InitTypeSize >= ValueTypeSize;
109 return InitTypeSize > ValueTypeSize;
111 if (InitType.isFloatingPoint())
112 return InitTypeSize >= ValueTypeSize;
119void FoldInitTypeCheck::doCheck(
const BuiltinType &IterValueType,
120 const BuiltinType &InitType,
121 const ASTContext &Context,
122 const CallExpr &CallNode) {
124 diag(CallNode.getExprLoc(),
"folding type %0 into type %1 might result in "
126 << IterValueType.desugar() << InitType.desugar();
134 const auto *InitType = Result.Nodes.getNodeAs<BuiltinType>(
"InitType");
135 const auto *IterValueType =
136 Result.Nodes.getNodeAs<BuiltinType>(
"IterValueType");
137 assert(InitType !=
nullptr);
138 assert(IterValueType !=
nullptr);
140 const auto *CallNode = Result.Nodes.getNodeAs<CallExpr>(
"Call");
141 assert(CallNode !=
nullptr);
143 doCheck(*IterValueType, *InitType, *Result.Context, *CallNode);
145 if (
const auto *Iter2ValueType =
146 Result.Nodes.getNodeAs<BuiltinType>(
"Iter2ValueType"))
147 doCheck(*Iter2ValueType, *InitType, *Result.Context, *CallNode);
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
static bool isValidBuiltinFold(const BuiltinType &ValueType, const BuiltinType &InitType, const ASTContext &Context)
Returns true if ValueType is allowed to fold into InitType, i.e.