1 //===---- CheckerHelpers.cpp - Helper functions for checkers ----*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines several static functions for use in checkers.
11 //===----------------------------------------------------------------------===//
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"
23 // Recursively find any substatements containing macros
24 bool containsMacro(const Stmt
*S
) {
25 if (S
->getBeginLoc().isMacroID())
28 if (S
->getEndLoc().isMacroID())
31 for (const Stmt
*Child
: S
->children())
32 if (Child
&& containsMacro(Child
))
38 // Recursively find any substatements containing enum constants
39 bool containsEnum(const Stmt
*S
) {
40 const DeclRefExpr
*DR
= dyn_cast
<DeclRefExpr
>(S
);
42 if (DR
&& isa
<EnumConstantDecl
>(DR
->getDecl()))
45 for (const Stmt
*Child
: S
->children())
46 if (Child
&& containsEnum(Child
))
52 // Recursively find any substatements containing static vars
53 bool containsStaticLocal(const Stmt
*S
) {
54 const DeclRefExpr
*DR
= dyn_cast
<DeclRefExpr
>(S
);
57 if (const VarDecl
*VD
= dyn_cast
<VarDecl
>(DR
->getDecl()))
58 if (VD
->isStaticLocal())
61 for (const Stmt
*Child
: S
->children())
62 if (Child
&& containsStaticLocal(Child
))
68 // Recursively find any substatements containing __builtin_offsetof
69 bool containsBuiltinOffsetOf(const Stmt
*S
) {
70 if (isa
<OffsetOfExpr
>(S
))
73 for (const Stmt
*Child
: S
->children())
74 if (Child
&& containsBuiltinOffsetOf(Child
))
80 // Extract lhs and rhs from assignment statement
81 std::pair
<const clang::VarDecl
*, const clang::Expr
*>
82 parseAssignment(const Stmt
*S
) {
83 const VarDecl
*VD
= nullptr;
84 const Expr
*RHS
= nullptr;
86 if (auto Assign
= dyn_cast_or_null
<BinaryOperator
>(S
)) {
87 if (Assign
->isAssignmentOp()) {
88 // Ordinary assignment
89 RHS
= Assign
->getRHS();
90 if (auto DE
= dyn_cast_or_null
<DeclRefExpr
>(Assign
->getLHS()))
91 VD
= dyn_cast_or_null
<VarDecl
>(DE
->getDecl());
93 } else if (auto PD
= dyn_cast_or_null
<DeclStmt
>(S
)) {
95 assert(PD
->isSingleDecl() && "We process decls one by one");
96 VD
= cast
<VarDecl
>(PD
->getSingleDecl());
97 RHS
= VD
->getAnyInitializer();
100 return std::make_pair(VD
, RHS
);
103 Nullability
getNullabilityAnnotation(QualType Type
) {
104 const auto *AttrType
= Type
->getAs
<AttributedType
>();
106 return Nullability::Unspecified
;
107 if (AttrType
->getAttrKind() == attr::TypeNullable
)
108 return Nullability::Nullable
;
109 else if (AttrType
->getAttrKind() == attr::TypeNonNull
)
110 return Nullability::Nonnull
;
111 return Nullability::Unspecified
;
114 std::optional
<int> tryExpandAsInteger(StringRef Macro
, const Preprocessor
&PP
) {
115 const auto *MacroII
= PP
.getIdentifierInfo(Macro
);
118 const MacroInfo
*MI
= PP
.getMacroInfo(MacroII
);
122 // Filter out parens.
123 std::vector
<Token
> FilteredTokens
;
124 FilteredTokens
.reserve(MI
->tokens().size());
125 for (auto &T
: MI
->tokens())
126 if (!T
.isOneOf(tok::l_paren
, tok::r_paren
))
127 FilteredTokens
.push_back(T
);
129 // Parse an integer at the end of the macro definition.
130 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 if (!T
.isLiteral() || !T
.getLiteralData())
135 StringRef ValueStr
= StringRef(T
.getLiteralData(), T
.getLength());
136 llvm::APInt IntValue
;
137 constexpr unsigned AutoSenseRadix
= 0;
138 if (ValueStr
.getAsInteger(AutoSenseRadix
, IntValue
))
141 // Parse an optional minus sign.
142 size_t Size
= FilteredTokens
.size();
144 if (FilteredTokens
[Size
- 2].is(tok::minus
))
145 IntValue
= -IntValue
;
148 return IntValue
.getSExtValue();
151 OperatorKind
operationKindFromOverloadedOperator(OverloadedOperatorKind OOK
,
153 llvm::StringMap
<BinaryOperatorKind
> BinOps
{
154 #define BINARY_OPERATION(Name, Spelling) {Spelling, BO_##Name},
155 #include "clang/AST/OperationKinds.def"
157 llvm::StringMap
<UnaryOperatorKind
> UnOps
{
158 #define UNARY_OPERATION(Name, Spelling) {Spelling, UO_##Name},
159 #include "clang/AST/OperationKinds.def"
163 #define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
166 auto BinOpIt = BinOps.find(Spelling); \
167 if (BinOpIt != BinOps.end()) \
168 return OperatorKind(BinOpIt->second); \
170 llvm_unreachable("operator was expected to be binary but is not"); \
172 auto UnOpIt = UnOps.find(Spelling); \
173 if (UnOpIt != UnOps.end()) \
174 return OperatorKind(UnOpIt->second); \
176 llvm_unreachable("operator was expected to be unary but is not"); \
179 #include "clang/Basic/OperatorKinds.def"
181 llvm_unreachable("unexpected operator kind");