11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 using namespace clang::ast_matchers;
20 void FoldInitTypeCheck::registerMatchers(MatchFinder *
Finder) {
23 const auto BuiltinTypeWithId = [](
const char *ID) {
24 return hasCanonicalType(builtinType().bind(ID));
26 const auto IteratorWithValueType = [&BuiltinTypeWithId](
const char *ID) {
29 pointsTo(BuiltinTypeWithId(ID)),
31 recordType(hasDeclaration(has(typedefNameDecl(
32 hasName(
"value_type"), hasType(BuiltinTypeWithId(ID)))))));
35 const auto IteratorParam = parmVarDecl(
36 hasType(hasCanonicalType(IteratorWithValueType(
"IterValueType"))));
37 const auto Iterator2Param = parmVarDecl(
38 hasType(hasCanonicalType(IteratorWithValueType(
"Iter2ValueType"))));
39 const auto InitParam = parmVarDecl(hasType(BuiltinTypeWithId(
"InitType")));
43 callExpr(callee(functionDecl(
44 hasAnyName(
"::std::accumulate",
"::std::reduce"),
45 hasParameter(0, IteratorParam), hasParameter(2, InitParam))),
51 callExpr(callee(functionDecl(hasName(
"::std::inner_product"),
52 hasParameter(0, IteratorParam),
53 hasParameter(2, Iterator2Param),
54 hasParameter(3, InitParam))),
60 callExpr(callee(functionDecl(hasName(
"::std::reduce"),
61 hasParameter(1, IteratorParam),
62 hasParameter(3, InitParam))),
68 callExpr(callee(functionDecl(hasName(
"::std::inner_product"),
69 hasParameter(1, IteratorParam),
70 hasParameter(3, Iterator2Param),
71 hasParameter(4, InitParam))),
81 const BuiltinType &InitType,
83 const auto ValueTypeSize = Context.getTypeSize(&ValueType);
84 const auto InitTypeSize = Context.getTypeSize(&InitType);
87 if (ValueType.isFloatingPoint())
88 return InitType.isFloatingPoint() && InitTypeSize >= ValueTypeSize;
93 if (ValueType.isInteger()) {
94 if (InitType.isInteger()) {
95 if (InitType.isSignedInteger() == ValueType.isSignedInteger())
96 return InitTypeSize >= ValueTypeSize;
97 return InitTypeSize > ValueTypeSize;
99 if (InitType.isFloatingPoint())
100 return InitTypeSize >= ValueTypeSize;
107 void FoldInitTypeCheck::doCheck(
const BuiltinType &IterValueType,
108 const BuiltinType &InitType,
110 const CallExpr &CallNode) {
112 diag(CallNode.getExprLoc(),
"folding type %0 into type %1 might result in "
114 << IterValueType.desugar() << InitType.desugar();
118 void FoldInitTypeCheck::check(
const MatchFinder::MatchResult &Result) {
122 const auto *InitType = Result.Nodes.getNodeAs<BuiltinType>(
"InitType");
123 const auto *IterValueType =
124 Result.Nodes.getNodeAs<BuiltinType>(
"IterValueType");
125 assert(InitType !=
nullptr);
126 assert(IterValueType !=
nullptr);
128 const auto *CallNode = Result.Nodes.getNodeAs<CallExpr>(
"Call");
129 assert(CallNode !=
nullptr);
131 doCheck(*IterValueType, *InitType, *Result.Context, *CallNode);
133 if (
const auto *Iter2ValueType =
134 Result.Nodes.getNodeAs<BuiltinType>(
"Iter2ValueType"))
135 doCheck(*Iter2ValueType, *InitType, *Result.Context, *CallNode);
std::unique_ptr< ast_matchers::MatchFinder > Finder
ClangTidyContext & Context
static bool isValidBuiltinFold(const BuiltinType &ValueType, const BuiltinType &InitType, const ASTContext &Context)
Returns true if ValueType is allowed to fold into InitType, i.e.