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