Home | History | Annotate | Line # | Download | only in Core
      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 
     18 namespace clang {
     19 
     20 namespace ento {
     21 
     22 // Recursively find any substatements containing macros
     23 bool containsMacro(const Stmt *S) {
     24   if (S->getBeginLoc().isMacroID())
     25     return true;
     26 
     27   if (S->getEndLoc().isMacroID())
     28     return true;
     29 
     30   for (const Stmt *Child : S->children())
     31     if (Child && containsMacro(Child))
     32       return true;
     33 
     34   return false;
     35 }
     36 
     37 // Recursively find any substatements containing enum constants
     38 bool containsEnum(const Stmt *S) {
     39   const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S);
     40 
     41   if (DR && isa<EnumConstantDecl>(DR->getDecl()))
     42     return true;
     43 
     44   for (const Stmt *Child : S->children())
     45     if (Child && containsEnum(Child))
     46       return true;
     47 
     48   return false;
     49 }
     50 
     51 // Recursively find any substatements containing static vars
     52 bool containsStaticLocal(const Stmt *S) {
     53   const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S);
     54 
     55   if (DR)
     56     if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
     57       if (VD->isStaticLocal())
     58         return true;
     59 
     60   for (const Stmt *Child : S->children())
     61     if (Child && containsStaticLocal(Child))
     62       return true;
     63 
     64   return false;
     65 }
     66 
     67 // Recursively find any substatements containing __builtin_offsetof
     68 bool containsBuiltinOffsetOf(const Stmt *S) {
     69   if (isa<OffsetOfExpr>(S))
     70     return true;
     71 
     72   for (const Stmt *Child : S->children())
     73     if (Child && containsBuiltinOffsetOf(Child))
     74       return true;
     75 
     76   return false;
     77 }
     78 
     79 // Extract lhs and rhs from assignment statement
     80 std::pair<const clang::VarDecl *, const clang::Expr *>
     81 parseAssignment(const Stmt *S) {
     82   const VarDecl *VD = nullptr;
     83   const Expr *RHS = nullptr;
     84 
     85   if (auto Assign = dyn_cast_or_null<BinaryOperator>(S)) {
     86     if (Assign->isAssignmentOp()) {
     87       // Ordinary assignment
     88       RHS = Assign->getRHS();
     89       if (auto DE = dyn_cast_or_null<DeclRefExpr>(Assign->getLHS()))
     90         VD = dyn_cast_or_null<VarDecl>(DE->getDecl());
     91     }
     92   } else if (auto PD = dyn_cast_or_null<DeclStmt>(S)) {
     93     // Initialization
     94     assert(PD->isSingleDecl() && "We process decls one by one");
     95     VD = cast<VarDecl>(PD->getSingleDecl());
     96     RHS = VD->getAnyInitializer();
     97   }
     98 
     99   return std::make_pair(VD, RHS);
    100 }
    101 
    102 Nullability getNullabilityAnnotation(QualType Type) {
    103   const auto *AttrType = Type->getAs<AttributedType>();
    104   if (!AttrType)
    105     return Nullability::Unspecified;
    106   if (AttrType->getAttrKind() == attr::TypeNullable)
    107     return Nullability::Nullable;
    108   else if (AttrType->getAttrKind() == attr::TypeNonNull)
    109     return Nullability::Nonnull;
    110   return Nullability::Unspecified;
    111 }
    112 
    113 llvm::Optional<int> tryExpandAsInteger(StringRef Macro,
    114                                        const Preprocessor &PP) {
    115   const auto *MacroII = PP.getIdentifierInfo(Macro);
    116   if (!MacroII)
    117     return llvm::None;
    118   const MacroInfo *MI = PP.getMacroInfo(MacroII);
    119   if (!MI)
    120     return llvm::None;
    121 
    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);
    128 
    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())
    134     return llvm::None;
    135   StringRef ValueStr = StringRef(T.getLiteralData(), T.getLength());
    136   llvm::APInt IntValue;
    137   constexpr unsigned AutoSenseRadix = 0;
    138   if (ValueStr.getAsInteger(AutoSenseRadix, IntValue))
    139     return llvm::None;
    140 
    141   // Parse an optional minus sign.
    142   size_t Size = FilteredTokens.size();
    143   if (Size >= 2) {
    144     if (FilteredTokens[Size - 2].is(tok::minus))
    145       IntValue = -IntValue;
    146   }
    147 
    148   return IntValue.getSExtValue();
    149 }
    150 
    151 } // namespace ento
    152 } // namespace clang
    153