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