clang-tools  3.9.0
ProTypeVarargCheck.cpp
Go to the documentation of this file.
1 //===--- ProTypeVarargCheck.cpp - clang-tidy-------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "ProTypeVarargCheck.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.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 void ProTypeVarargCheck::registerMatchers(MatchFinder *Finder) {
23  if (!getLangOpts().CPlusPlus)
24  return;
25 
26  Finder->addMatcher(vAArgExpr().bind("va_use"), this);
27 
28  Finder->addMatcher(
29  callExpr(callee(functionDecl(isVariadic())))
30  .bind("callvararg"),
31  this);
32 }
33 
34 static bool hasSingleVariadicArgumentWithValue(const CallExpr *C, uint64_t I) {
35  const auto *FDecl = dyn_cast<FunctionDecl>(C->getCalleeDecl());
36  if (!FDecl)
37  return false;
38 
39  auto N = FDecl->getNumParams(); // Number of parameters without '...'
40  if (C->getNumArgs() != N + 1)
41  return false; // more/less than one argument passed to '...'
42 
43  const auto *IntLit =
44  dyn_cast<IntegerLiteral>(C->getArg(N)->IgnoreParenImpCasts());
45  if (!IntLit)
46  return false;
47 
48  if (IntLit->getValue() != I)
49  return false;
50 
51  return true;
52 }
53 
54 void ProTypeVarargCheck::check(const MatchFinder::MatchResult &Result) {
55  if (const auto *Matched = Result.Nodes.getNodeAs<CallExpr>("callvararg")) {
56  if (hasSingleVariadicArgumentWithValue(Matched, 0))
57  return;
58  diag(Matched->getExprLoc(), "do not call c-style vararg functions");
59  }
60 
61  if (const auto *Matched = Result.Nodes.getNodeAs<Expr>("va_use")) {
62  diag(Matched->getExprLoc(),
63  "do not use va_start/va_arg to define c-style vararg functions; "
64  "use variadic templates instead");
65  }
66 
67  if (const auto *Matched = Result.Nodes.getNodeAs<VarDecl>("va_list")) {
68  auto SR = Matched->getSourceRange();
69  if (SR.isInvalid())
70  return; // some implicitly generated builtins take va_list
71  diag(SR.getBegin(), "do not declare variables of type va_list; "
72  "use variadic templates instead");
73  }
74 }
75 
76 } // namespace cppcoreguidelines
77 } // namespace tidy
78 } // namespace clang
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:210
const internal::VariadicDynCastAllOfMatcher< Stmt, VAArgExpr > vAArgExpr
static bool hasSingleVariadicArgumentWithValue(const CallExpr *C, uint64_t I)
const NamedDecl * Result
Definition: USRFinder.cpp:137