ProTypeVarargCheck.cpp
4.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//===--- ProTypeVarargCheck.cpp - clang-tidy-------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "ProTypeVarargCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace cppcoreguidelines {
const internal::VariadicDynCastAllOfMatcher<Stmt, VAArgExpr> vAArgExpr;
static constexpr StringRef AllowedVariadics[] = {
// clang-format off
"__builtin_isgreater",
"__builtin_isgreaterequal",
"__builtin_isless",
"__builtin_islessequal",
"__builtin_islessgreater",
"__builtin_isunordered",
"__builtin_fpclassify",
"__builtin_isfinite",
"__builtin_isinf",
"__builtin_isinf_sign",
"__builtin_isnan",
"__builtin_isnormal",
"__builtin_signbit",
"__builtin_constant_p",
"__builtin_classify_type",
"__builtin_va_start",
"__builtin_assume_aligned", // Documented as variadic to support default
// parameters.
"__builtin_prefetch", // Documented as variadic to support default
// parameters.
"__builtin_shufflevector", // Documented as variadic but with a defined
// number of args based on vector size.
"__builtin_convertvector",
"__builtin_call_with_static_chain",
"__builtin_annotation",
"__builtin_add_overflow",
"__builtin_sub_overflow",
"__builtin_mul_overflow",
"__builtin_preserve_access_index",
"__builtin_nontemporal_store",
"__builtin_nontemporal_load",
"__builtin_ms_va_start",
// clang-format on
};
namespace {
AST_MATCHER(QualType, isVAList) {
ASTContext &Context = Finder->getASTContext();
QualType Desugar = Node.getDesugaredType(Context);
return Context.getBuiltinVaListType().getDesugaredType(Context) == Desugar ||
Context.getBuiltinMSVaListType().getDesugaredType(Context) == Desugar;
}
AST_MATCHER_P(AdjustedType, hasOriginalType,
ast_matchers::internal::Matcher<QualType>, InnerType) {
return InnerType.matches(Node.getOriginalType(), Finder, Builder);
}
} // namespace
void ProTypeVarargCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(vAArgExpr().bind("va_use"), this);
Finder->addMatcher(
callExpr(callee(functionDecl(isVariadic(),
unless(hasAnyName(AllowedVariadics)))))
.bind("callvararg"),
this);
Finder->addMatcher(
varDecl(unless(parmVarDecl()),
hasType(qualType(
anyOf(isVAList(), decayedType(hasOriginalType(isVAList()))))))
.bind("va_list"),
this);
}
static bool hasSingleVariadicArgumentWithValue(const CallExpr *C, uint64_t I) {
const auto *FDecl = dyn_cast<FunctionDecl>(C->getCalleeDecl());
if (!FDecl)
return false;
auto N = FDecl->getNumParams(); // Number of parameters without '...'
if (C->getNumArgs() != N + 1)
return false; // more/less than one argument passed to '...'
const auto *IntLit =
dyn_cast<IntegerLiteral>(C->getArg(N)->IgnoreParenImpCasts());
if (!IntLit)
return false;
if (IntLit->getValue() != I)
return false;
return true;
}
void ProTypeVarargCheck::check(const MatchFinder::MatchResult &Result) {
if (const auto *Matched = Result.Nodes.getNodeAs<CallExpr>("callvararg")) {
if (hasSingleVariadicArgumentWithValue(Matched, 0))
return;
diag(Matched->getExprLoc(), "do not call c-style vararg functions");
}
if (const auto *Matched = Result.Nodes.getNodeAs<Expr>("va_use")) {
diag(Matched->getExprLoc(),
"do not use va_arg to define c-style vararg functions; "
"use variadic templates instead");
}
if (const auto *Matched = Result.Nodes.getNodeAs<VarDecl>("va_list")) {
auto SR = Matched->getSourceRange();
if (SR.isInvalid())
return; // some implicitly generated builtins take va_list
diag(SR.getBegin(), "do not declare variables of type va_list; "
"use variadic templates instead");
}
}
} // namespace cppcoreguidelines
} // namespace tidy
} // namespace clang