Coverage Report

Created: 2023-09-12 09:32

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp
Line
Count
Source (jump to first uncovered line)
1
//===---- CheckerHelpers.cpp - Helper functions for checkers ----*- C++ -*-===//
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
//  This file defines several static functions for use in checkers.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
14
#include "clang/AST/Decl.h"
15
#include "clang/AST/Expr.h"
16
#include "clang/Lex/Preprocessor.h"
17
#include <optional>
18
19
namespace clang {
20
21
namespace ento {
22
23
// Recursively find any substatements containing macros
24
44
bool containsMacro(const Stmt *S) {
25
44
  if (S->getBeginLoc().isMacroID())
26
2
    return true;
27
28
42
  if (S->getEndLoc().isMacroID())
29
0
    return true;
30
31
42
  for (const Stmt *Child : S->children())
32
31
    if (Child && containsMacro(Child))
33
0
      return true;
34
35
42
  return false;
36
42
}
37
38
// Recursively find any substatements containing enum constants
39
42
bool containsEnum(const Stmt *S) {
40
42
  const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S);
41
42
42
  if (DR && 
isa<EnumConstantDecl>(DR->getDecl())10
)
43
0
    return true;
44
45
42
  for (const Stmt *Child : S->children())
46
31
    if (Child && containsEnum(Child))
47
0
      return true;
48
49
42
  return false;
50
42
}
51
52
// Recursively find any substatements containing static vars
53
42
bool containsStaticLocal(const Stmt *S) {
54
42
  const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S);
55
56
42
  if (DR)
57
10
    if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
58
10
      if (VD->isStaticLocal())
59
1
        return true;
60
61
41
  for (const Stmt *Child : S->children())
62
31
    if (Child && containsStaticLocal(Child))
63
1
      return true;
64
65
40
  return false;
66
41
}
67
68
// Recursively find any substatements containing __builtin_offsetof
69
40
bool containsBuiltinOffsetOf(const Stmt *S) {
70
40
  if (isa<OffsetOfExpr>(S))
71
0
    return true;
72
73
40
  for (const Stmt *Child : S->children())
74
30
    if (Child && containsBuiltinOffsetOf(Child))
75
0
      return true;
76
77
40
  return false;
78
40
}
79
80
// Extract lhs and rhs from assignment statement
81
std::pair<const clang::VarDecl *, const clang::Expr *>
82
36
parseAssignment(const Stmt *S) {
83
36
  const VarDecl *VD = nullptr;
84
36
  const Expr *RHS = nullptr;
85
86
36
  if (auto Assign = dyn_cast_or_null<BinaryOperator>(S)) {
87
6
    if (Assign->isAssignmentOp()) {
88
      // Ordinary assignment
89
2
      RHS = Assign->getRHS();
90
2
      if (auto DE = dyn_cast_or_null<DeclRefExpr>(Assign->getLHS()))
91
2
        VD = dyn_cast_or_null<VarDecl>(DE->getDecl());
92
2
    }
93
30
  } else if (auto PD = dyn_cast_or_null<DeclStmt>(S)) {
94
    // Initialization
95
22
    assert(PD->isSingleDecl() && "We process decls one by one");
96
22
    VD = cast<VarDecl>(PD->getSingleDecl());
97
22
    RHS = VD->getAnyInitializer();
98
22
  }
99
100
36
  return std::make_pair(VD, RHS);
101
36
}
102
103
6.82k
Nullability getNullabilityAnnotation(QualType Type) {
104
6.82k
  const auto *AttrType = Type->getAs<AttributedType>();
105
6.82k
  if (!AttrType)
106
4.10k
    return Nullability::Unspecified;
107
2.72k
  if (AttrType->getAttrKind() == attr::TypeNullable)
108
968
    return Nullability::Nullable;
109
1.75k
  else if (AttrType->getAttrKind() == attr::TypeNonNull)
110
1.75k
    return Nullability::Nonnull;
111
0
  return Nullability::Unspecified;
112
2.72k
}
113
114
171
std::optional<int> tryExpandAsInteger(StringRef Macro, const Preprocessor &PP) {
115
171
  const auto *MacroII = PP.getIdentifierInfo(Macro);
116
171
  if (!MacroII)
117
0
    return std::nullopt;
118
171
  const MacroInfo *MI = PP.getMacroInfo(MacroII);
119
171
  if (!MI)
120
86
    return std::nullopt;
121
122
  // Filter out parens.
123
85
  std::vector<Token> FilteredTokens;
124
85
  FilteredTokens.reserve(MI->tokens().size());
125
85
  for (auto &T : MI->tokens())
126
235
    if (!T.isOneOf(tok::l_paren, tok::r_paren))
127
135
      FilteredTokens.push_back(T);
128
129
  // Parse an integer at the end of the macro definition.
130
85
  const Token &T = FilteredTokens.back();
131
  // FIXME: EOF macro token coming from a PCH file on macOS while marked as
132
  //        literal, doesn't contain any literal data
133
85
  if (!T.isLiteral() || !T.getLiteralData())
134
0
    return std::nullopt;
135
85
  StringRef ValueStr = StringRef(T.getLiteralData(), T.getLength());
136
85
  llvm::APInt IntValue;
137
85
  constexpr unsigned AutoSenseRadix = 0;
138
85
  if (ValueStr.getAsInteger(AutoSenseRadix, IntValue))
139
0
    return std::nullopt;
140
141
  // Parse an optional minus sign.
142
85
  size_t Size = FilteredTokens.size();
143
85
  if (Size >= 2) {
144
49
    if (FilteredTokens[Size - 2].is(tok::minus))
145
48
      IntValue = -IntValue;
146
49
  }
147
148
85
  return IntValue.getSExtValue();
149
85
}
150
151
OperatorKind operationKindFromOverloadedOperator(OverloadedOperatorKind OOK,
152
36
                                                 bool IsBinary) {
153
36
  llvm::StringMap<BinaryOperatorKind> BinOps{
154
1.18k
#define BINARY_OPERATION(Name, Spelling) {Spelling, BO_##Name},
155
36
#include "clang/AST/OperationKinds.def"
156
36
  };
157
36
  llvm::StringMap<UnaryOperatorKind> UnOps{
158
504
#define UNARY_OPERATION(Name, Spelling) {Spelling, UO_##Name},
159
36
#include "clang/AST/OperationKinds.def"
160
36
  };
161
162
36
  switch (OOK) {
163
0
#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly)  \
164
0
  case OO_##Name:                                                              \
165
36
    if (IsBinary) {                                                            \
166
36
      auto BinOpIt = BinOps.find(Spelling);                                    \
167
36
      if (BinOpIt != BinOps.end())                                             \
168
36
        return OperatorKind(BinOpIt->second);                                  \
169
36
      else                                                                     \
170
36
        
llvm_unreachable0
("operator was expected to be binary but is not"); \
171
36
    } else {                                                                   \
172
0
      auto UnOpIt = UnOps.find(Spelling);                                      \
173
0
      if (UnOpIt != UnOps.end())                                               \
174
0
        return OperatorKind(UnOpIt->second);                                   \
175
0
      else                                                                     \
176
0
        llvm_unreachable("operator was expected to be unary but is not");      \
177
0
    }                                                                          \
178
0
    break;
179
0
#include "clang/Basic/OperatorKinds.def"
180
0
  default:
181
0
    llvm_unreachable("unexpected operator kind");
182
36
  }
183
36
}
184
185
} // namespace ento
186
} // namespace clang