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