xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
18 #include <optional>
19 
20 namespace clang {
21 
22 namespace ento {
23 
24 // Recursively find any substatements containing macros
containsMacro(const Stmt * S)25 bool containsMacro(const Stmt *S) {
26   if (S->getBeginLoc().isMacroID())
27     return true;
28 
29   if (S->getEndLoc().isMacroID())
30     return true;
31 
32   for (const Stmt *Child : S->children())
33     if (Child && containsMacro(Child))
34       return true;
35 
36   return false;
37 }
38 
39 // Recursively find any substatements containing enum constants
containsEnum(const Stmt * S)40 bool containsEnum(const Stmt *S) {
41   const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S);
42 
43   if (DR && isa<EnumConstantDecl>(DR->getDecl()))
44     return true;
45 
46   for (const Stmt *Child : S->children())
47     if (Child && containsEnum(Child))
48       return true;
49 
50   return false;
51 }
52 
53 // Recursively find any substatements containing static vars
containsStaticLocal(const Stmt * S)54 bool containsStaticLocal(const Stmt *S) {
55   const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S);
56 
57   if (DR)
58     if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
59       if (VD->isStaticLocal())
60         return true;
61 
62   for (const Stmt *Child : S->children())
63     if (Child && containsStaticLocal(Child))
64       return true;
65 
66   return false;
67 }
68 
69 // Recursively find any substatements containing __builtin_offsetof
containsBuiltinOffsetOf(const Stmt * S)70 bool containsBuiltinOffsetOf(const Stmt *S) {
71   if (isa<OffsetOfExpr>(S))
72     return true;
73 
74   for (const Stmt *Child : S->children())
75     if (Child && containsBuiltinOffsetOf(Child))
76       return true;
77 
78   return false;
79 }
80 
81 // Extract lhs and rhs from assignment statement
82 std::pair<const clang::VarDecl *, const clang::Expr *>
parseAssignment(const Stmt * S)83 parseAssignment(const Stmt *S) {
84   const VarDecl *VD = nullptr;
85   const Expr *RHS = nullptr;
86 
87   if (auto Assign = dyn_cast_or_null<BinaryOperator>(S)) {
88     if (Assign->isAssignmentOp()) {
89       // Ordinary assignment
90       RHS = Assign->getRHS();
91       if (auto DE = dyn_cast_or_null<DeclRefExpr>(Assign->getLHS()))
92         VD = dyn_cast_or_null<VarDecl>(DE->getDecl());
93     }
94   } else if (auto PD = dyn_cast_or_null<DeclStmt>(S)) {
95     // Initialization
96     assert(PD->isSingleDecl() && "We process decls one by one");
97     VD = cast<VarDecl>(PD->getSingleDecl());
98     RHS = VD->getAnyInitializer();
99   }
100 
101   return std::make_pair(VD, RHS);
102 }
103 
getNullabilityAnnotation(QualType Type)104 Nullability getNullabilityAnnotation(QualType Type) {
105   const auto *AttrType = Type->getAs<AttributedType>();
106   if (!AttrType)
107     return Nullability::Unspecified;
108   if (AttrType->getAttrKind() == attr::TypeNullable)
109     return Nullability::Nullable;
110   else if (AttrType->getAttrKind() == attr::TypeNonNull)
111     return Nullability::Nonnull;
112   return Nullability::Unspecified;
113 }
114 
tryExpandAsInteger(StringRef Macro,const Preprocessor & PP)115 std::optional<int> tryExpandAsInteger(StringRef Macro, const Preprocessor &PP) {
116   const auto *MacroII = PP.getIdentifierInfo(Macro);
117   if (!MacroII)
118     return std::nullopt;
119   const MacroInfo *MI = PP.getMacroInfo(MacroII);
120   if (!MI)
121     return std::nullopt;
122 
123   // Filter out parens.
124   std::vector<Token> FilteredTokens;
125   FilteredTokens.reserve(MI->tokens().size());
126   for (auto &T : MI->tokens())
127     if (!T.isOneOf(tok::l_paren, tok::r_paren))
128       FilteredTokens.push_back(T);
129 
130   // Parse an integer at the end of the macro definition.
131   const Token &T = FilteredTokens.back();
132 
133   if (!T.isLiteral())
134     return std::nullopt;
135 
136   bool InvalidSpelling = false;
137   SmallVector<char> Buffer(T.getLength());
138   // `Preprocessor::getSpelling` can get the spelling of the token regardless of
139   // whether the macro is defined in a PCH or not:
140   StringRef ValueStr = PP.getSpelling(T, Buffer, &InvalidSpelling);
141 
142   if (InvalidSpelling)
143     return std::nullopt;
144 
145   llvm::APInt IntValue;
146   constexpr unsigned AutoSenseRadix = 0;
147   if (ValueStr.getAsInteger(AutoSenseRadix, IntValue))
148     return std::nullopt;
149 
150   // Parse an optional minus sign.
151   size_t Size = FilteredTokens.size();
152   if (Size >= 2) {
153     if (FilteredTokens[Size - 2].is(tok::minus))
154       IntValue = -IntValue;
155   }
156 
157   return IntValue.getSExtValue();
158 }
159 
operationKindFromOverloadedOperator(OverloadedOperatorKind OOK,bool IsBinary)160 OperatorKind operationKindFromOverloadedOperator(OverloadedOperatorKind OOK,
161                                                  bool IsBinary) {
162   llvm::StringMap<BinaryOperatorKind> BinOps{
163 #define BINARY_OPERATION(Name, Spelling) {Spelling, BO_##Name},
164 #include "clang/AST/OperationKinds.def"
165   };
166   llvm::StringMap<UnaryOperatorKind> UnOps{
167 #define UNARY_OPERATION(Name, Spelling) {Spelling, UO_##Name},
168 #include "clang/AST/OperationKinds.def"
169   };
170 
171   switch (OOK) {
172 #define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly)  \
173   case OO_##Name:                                                              \
174     if (IsBinary) {                                                            \
175       auto BinOpIt = BinOps.find(Spelling);                                    \
176       if (BinOpIt != BinOps.end())                                             \
177         return OperatorKind(BinOpIt->second);                                  \
178       else                                                                     \
179         llvm_unreachable("operator was expected to be binary but is not");     \
180     } else {                                                                   \
181       auto UnOpIt = UnOps.find(Spelling);                                      \
182       if (UnOpIt != UnOps.end())                                               \
183         return OperatorKind(UnOpIt->second);                                   \
184       else                                                                     \
185         llvm_unreachable("operator was expected to be unary but is not");      \
186     }                                                                          \
187     break;
188 #include "clang/Basic/OperatorKinds.def"
189   default:
190     llvm_unreachable("unexpected operator kind");
191   }
192 }
193 
getPointeeVal(SVal PtrSVal,ProgramStateRef State)194 std::optional<SVal> getPointeeVal(SVal PtrSVal, ProgramStateRef State) {
195   if (const auto *Ptr = PtrSVal.getAsRegion()) {
196     return State->getSVal(Ptr);
197   }
198   return std::nullopt;
199 }
200 
isWithinStdNamespace(const Decl * D)201 bool isWithinStdNamespace(const Decl *D) {
202   const DeclContext *DC = D->getDeclContext();
203   while (DC) {
204     if (const auto *NS = dyn_cast<NamespaceDecl>(DC);
205         NS && NS->isStdNamespace())
206       return true;
207     DC = DC->getParent();
208   }
209   return false;
210 }
211 
212 } // namespace ento
213 } // namespace clang
214