xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===---- CheckerHelpers.cpp - Helper functions for checkers ----*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric //  This file defines several static functions for use in checkers.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
140b57cec5SDimitry Andric #include "clang/AST/Decl.h"
150b57cec5SDimitry Andric #include "clang/AST/Expr.h"
165ffd83dbSDimitry Andric #include "clang/Lex/Preprocessor.h"
17*0fca6ea1SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
18bdd1243dSDimitry Andric #include <optional>
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric namespace clang {
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric namespace ento {
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric // Recursively find any substatements containing macros
250b57cec5SDimitry Andric bool containsMacro(const Stmt *S) {
260b57cec5SDimitry Andric   if (S->getBeginLoc().isMacroID())
270b57cec5SDimitry Andric     return true;
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric   if (S->getEndLoc().isMacroID())
300b57cec5SDimitry Andric     return true;
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric   for (const Stmt *Child : S->children())
330b57cec5SDimitry Andric     if (Child && containsMacro(Child))
340b57cec5SDimitry Andric       return true;
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric   return false;
370b57cec5SDimitry Andric }
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric // Recursively find any substatements containing enum constants
400b57cec5SDimitry Andric bool containsEnum(const Stmt *S) {
410b57cec5SDimitry Andric   const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S);
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric   if (DR && isa<EnumConstantDecl>(DR->getDecl()))
440b57cec5SDimitry Andric     return true;
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric   for (const Stmt *Child : S->children())
470b57cec5SDimitry Andric     if (Child && containsEnum(Child))
480b57cec5SDimitry Andric       return true;
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric   return false;
510b57cec5SDimitry Andric }
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric // Recursively find any substatements containing static vars
540b57cec5SDimitry Andric bool containsStaticLocal(const Stmt *S) {
550b57cec5SDimitry Andric   const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S);
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric   if (DR)
580b57cec5SDimitry Andric     if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
590b57cec5SDimitry Andric       if (VD->isStaticLocal())
600b57cec5SDimitry Andric         return true;
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric   for (const Stmt *Child : S->children())
630b57cec5SDimitry Andric     if (Child && containsStaticLocal(Child))
640b57cec5SDimitry Andric       return true;
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric   return false;
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric // Recursively find any substatements containing __builtin_offsetof
700b57cec5SDimitry Andric bool containsBuiltinOffsetOf(const Stmt *S) {
710b57cec5SDimitry Andric   if (isa<OffsetOfExpr>(S))
720b57cec5SDimitry Andric     return true;
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric   for (const Stmt *Child : S->children())
750b57cec5SDimitry Andric     if (Child && containsBuiltinOffsetOf(Child))
760b57cec5SDimitry Andric       return true;
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric   return false;
790b57cec5SDimitry Andric }
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric // Extract lhs and rhs from assignment statement
820b57cec5SDimitry Andric std::pair<const clang::VarDecl *, const clang::Expr *>
830b57cec5SDimitry Andric parseAssignment(const Stmt *S) {
840b57cec5SDimitry Andric   const VarDecl *VD = nullptr;
850b57cec5SDimitry Andric   const Expr *RHS = nullptr;
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric   if (auto Assign = dyn_cast_or_null<BinaryOperator>(S)) {
880b57cec5SDimitry Andric     if (Assign->isAssignmentOp()) {
890b57cec5SDimitry Andric       // Ordinary assignment
900b57cec5SDimitry Andric       RHS = Assign->getRHS();
910b57cec5SDimitry Andric       if (auto DE = dyn_cast_or_null<DeclRefExpr>(Assign->getLHS()))
920b57cec5SDimitry Andric         VD = dyn_cast_or_null<VarDecl>(DE->getDecl());
930b57cec5SDimitry Andric     }
940b57cec5SDimitry Andric   } else if (auto PD = dyn_cast_or_null<DeclStmt>(S)) {
950b57cec5SDimitry Andric     // Initialization
960b57cec5SDimitry Andric     assert(PD->isSingleDecl() && "We process decls one by one");
97a7dea167SDimitry Andric     VD = cast<VarDecl>(PD->getSingleDecl());
980b57cec5SDimitry Andric     RHS = VD->getAnyInitializer();
990b57cec5SDimitry Andric   }
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   return std::make_pair(VD, RHS);
1020b57cec5SDimitry Andric }
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric Nullability getNullabilityAnnotation(QualType Type) {
1050b57cec5SDimitry Andric   const auto *AttrType = Type->getAs<AttributedType>();
1060b57cec5SDimitry Andric   if (!AttrType)
1070b57cec5SDimitry Andric     return Nullability::Unspecified;
1080b57cec5SDimitry Andric   if (AttrType->getAttrKind() == attr::TypeNullable)
1090b57cec5SDimitry Andric     return Nullability::Nullable;
1100b57cec5SDimitry Andric   else if (AttrType->getAttrKind() == attr::TypeNonNull)
1110b57cec5SDimitry Andric     return Nullability::Nonnull;
1120b57cec5SDimitry Andric   return Nullability::Unspecified;
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric 
115bdd1243dSDimitry Andric std::optional<int> tryExpandAsInteger(StringRef Macro, const Preprocessor &PP) {
1165ffd83dbSDimitry Andric   const auto *MacroII = PP.getIdentifierInfo(Macro);
1175ffd83dbSDimitry Andric   if (!MacroII)
118bdd1243dSDimitry Andric     return std::nullopt;
1195ffd83dbSDimitry Andric   const MacroInfo *MI = PP.getMacroInfo(MacroII);
1205ffd83dbSDimitry Andric   if (!MI)
121bdd1243dSDimitry Andric     return std::nullopt;
1220b57cec5SDimitry Andric 
1235ffd83dbSDimitry Andric   // Filter out parens.
1245ffd83dbSDimitry Andric   std::vector<Token> FilteredTokens;
1255ffd83dbSDimitry Andric   FilteredTokens.reserve(MI->tokens().size());
1265ffd83dbSDimitry Andric   for (auto &T : MI->tokens())
1275ffd83dbSDimitry Andric     if (!T.isOneOf(tok::l_paren, tok::r_paren))
1285ffd83dbSDimitry Andric       FilteredTokens.push_back(T);
1295ffd83dbSDimitry Andric 
1305ffd83dbSDimitry Andric   // Parse an integer at the end of the macro definition.
1315ffd83dbSDimitry Andric   const Token &T = FilteredTokens.back();
1325ffd83dbSDimitry Andric   // FIXME: EOF macro token coming from a PCH file on macOS while marked as
1335ffd83dbSDimitry Andric   //        literal, doesn't contain any literal data
1345ffd83dbSDimitry Andric   if (!T.isLiteral() || !T.getLiteralData())
135bdd1243dSDimitry Andric     return std::nullopt;
1365ffd83dbSDimitry Andric   StringRef ValueStr = StringRef(T.getLiteralData(), T.getLength());
1375ffd83dbSDimitry Andric   llvm::APInt IntValue;
1385ffd83dbSDimitry Andric   constexpr unsigned AutoSenseRadix = 0;
1395ffd83dbSDimitry Andric   if (ValueStr.getAsInteger(AutoSenseRadix, IntValue))
140bdd1243dSDimitry Andric     return std::nullopt;
1415ffd83dbSDimitry Andric 
1425ffd83dbSDimitry Andric   // Parse an optional minus sign.
1435ffd83dbSDimitry Andric   size_t Size = FilteredTokens.size();
1445ffd83dbSDimitry Andric   if (Size >= 2) {
1455ffd83dbSDimitry Andric     if (FilteredTokens[Size - 2].is(tok::minus))
1465ffd83dbSDimitry Andric       IntValue = -IntValue;
1475ffd83dbSDimitry Andric   }
1485ffd83dbSDimitry Andric 
1495ffd83dbSDimitry Andric   return IntValue.getSExtValue();
1505ffd83dbSDimitry Andric }
1515ffd83dbSDimitry Andric 
152fe6060f1SDimitry Andric OperatorKind operationKindFromOverloadedOperator(OverloadedOperatorKind OOK,
153fe6060f1SDimitry Andric                                                  bool IsBinary) {
154fe6060f1SDimitry Andric   llvm::StringMap<BinaryOperatorKind> BinOps{
155fe6060f1SDimitry Andric #define BINARY_OPERATION(Name, Spelling) {Spelling, BO_##Name},
156fe6060f1SDimitry Andric #include "clang/AST/OperationKinds.def"
157fe6060f1SDimitry Andric   };
158fe6060f1SDimitry Andric   llvm::StringMap<UnaryOperatorKind> UnOps{
159fe6060f1SDimitry Andric #define UNARY_OPERATION(Name, Spelling) {Spelling, UO_##Name},
160fe6060f1SDimitry Andric #include "clang/AST/OperationKinds.def"
161fe6060f1SDimitry Andric   };
162fe6060f1SDimitry Andric 
163fe6060f1SDimitry Andric   switch (OOK) {
164fe6060f1SDimitry Andric #define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly)  \
165fe6060f1SDimitry Andric   case OO_##Name:                                                              \
166fe6060f1SDimitry Andric     if (IsBinary) {                                                            \
167fe6060f1SDimitry Andric       auto BinOpIt = BinOps.find(Spelling);                                    \
168fe6060f1SDimitry Andric       if (BinOpIt != BinOps.end())                                             \
169fe6060f1SDimitry Andric         return OperatorKind(BinOpIt->second);                                  \
170fe6060f1SDimitry Andric       else                                                                     \
171fe6060f1SDimitry Andric         llvm_unreachable("operator was expected to be binary but is not");     \
172fe6060f1SDimitry Andric     } else {                                                                   \
173fe6060f1SDimitry Andric       auto UnOpIt = UnOps.find(Spelling);                                      \
174fe6060f1SDimitry Andric       if (UnOpIt != UnOps.end())                                               \
175fe6060f1SDimitry Andric         return OperatorKind(UnOpIt->second);                                   \
176fe6060f1SDimitry Andric       else                                                                     \
177fe6060f1SDimitry Andric         llvm_unreachable("operator was expected to be unary but is not");      \
178fe6060f1SDimitry Andric     }                                                                          \
179fe6060f1SDimitry Andric     break;
180fe6060f1SDimitry Andric #include "clang/Basic/OperatorKinds.def"
181fe6060f1SDimitry Andric   default:
182fe6060f1SDimitry Andric     llvm_unreachable("unexpected operator kind");
183fe6060f1SDimitry Andric   }
184fe6060f1SDimitry Andric }
185fe6060f1SDimitry Andric 
186*0fca6ea1SDimitry Andric std::optional<SVal> getPointeeVal(SVal PtrSVal, ProgramStateRef State) {
187*0fca6ea1SDimitry Andric   if (const auto *Ptr = PtrSVal.getAsRegion()) {
188*0fca6ea1SDimitry Andric     return State->getSVal(Ptr);
189*0fca6ea1SDimitry Andric   }
190*0fca6ea1SDimitry Andric   return std::nullopt;
191*0fca6ea1SDimitry Andric }
192*0fca6ea1SDimitry Andric 
1935ffd83dbSDimitry Andric } // namespace ento
1945ffd83dbSDimitry Andric } // namespace clang
195