| 1 | //=======- ASTUtis.h ---------------------------------------------*- 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 | #ifndef LLVM_CLANG_ANALYZER_WEBKIT_ASTUTILS_H |
| 10 | #define LLVM_CLANG_ANALYZER_WEBKIT_ASTUTILS_H |
| 11 | |
| 12 | #include "clang/AST/Decl.h" |
| 13 | #include "llvm/ADT/APInt.h" |
| 14 | #include "llvm/Support/Casting.h" |
| 15 | |
| 16 | #include <functional> |
| 17 | #include <string> |
| 18 | #include <utility> |
| 19 | |
| 20 | namespace clang { |
| 21 | class Expr; |
| 22 | |
| 23 | /// This function de-facto defines a set of transformations that we consider |
| 24 | /// safe (in heuristical sense). These transformation if passed a safe value as |
| 25 | /// an input should provide a safe value (or an object that provides safe |
| 26 | /// values). |
| 27 | /// |
| 28 | /// For more context see Static Analyzer checkers documentation - specifically |
| 29 | /// webkit.UncountedCallArgsChecker checker. Allowed list of transformations: |
| 30 | /// - constructors of ref-counted types (including factory methods) |
| 31 | /// - getters of ref-counted types |
| 32 | /// - member overloaded operators |
| 33 | /// - casts |
| 34 | /// - unary operators like ``&`` or ``*`` |
| 35 | /// |
| 36 | /// If passed expression is of type uncounted pointer/reference we try to find |
| 37 | /// the "origin" of the pointer value. |
| 38 | /// Origin can be for example a local variable, nullptr, constant or |
| 39 | /// this-pointer. |
| 40 | /// |
| 41 | /// Certain subexpression nodes represent transformations that don't affect |
| 42 | /// where the memory address originates from. We try to traverse such |
| 43 | /// subexpressions to get to the relevant child nodes. Whenever we encounter a |
| 44 | /// subexpression that either can't be ignored, we don't model its semantics or |
| 45 | /// that has multiple children we stop. |
| 46 | /// |
| 47 | /// \p E is an expression of uncounted pointer/reference type. |
| 48 | /// If \p StopAtFirstRefCountedObj is true and we encounter a subexpression that |
| 49 | /// represents ref-counted object during the traversal we return relevant |
| 50 | /// sub-expression and true. |
| 51 | /// |
| 52 | /// Calls \p callback with the subexpression that we traversed to and if \p |
| 53 | /// StopAtFirstRefCountedObj is true we also specify whether we stopped early. |
| 54 | /// Returns false if any of calls to callbacks returned false. Otherwise true. |
| 55 | bool tryToFindPtrOrigin( |
| 56 | const clang::Expr *E, bool StopAtFirstRefCountedObj, |
| 57 | std::function<bool(const clang::CXXRecordDecl *)> isSafePtr, |
| 58 | std::function<bool(const clang::QualType)> isSafePtrType, |
| 59 | std::function<bool(const clang::Expr *, bool)> callback); |
| 60 | |
| 61 | /// For \p E referring to a ref-countable/-counted pointer/reference we return |
| 62 | /// whether it's a safe call argument. Examples: function parameter or |
| 63 | /// this-pointer. The logic relies on the set of recursive rules we enforce for |
| 64 | /// WebKit codebase. |
| 65 | /// |
| 66 | /// \returns Whether \p E is a safe call arugment. |
| 67 | bool isASafeCallArg(const clang::Expr *E); |
| 68 | |
| 69 | /// \returns true if E is a MemberExpr accessing a const smart pointer type. |
| 70 | bool isConstOwnerPtrMemberExpr(const clang::Expr *E); |
| 71 | |
| 72 | /// \returns true if E is a MemberExpr accessing a member variable which |
| 73 | /// supports CheckedPtr. |
| 74 | bool isExprToGetCheckedPtrCapableMember(const clang::Expr *E); |
| 75 | |
| 76 | /// \returns true if E is a CXXMemberCallExpr which returns a const smart |
| 77 | /// pointer type. |
| 78 | class EnsureFunctionAnalysis { |
| 79 | using CacheTy = llvm::DenseMap<const FunctionDecl *, bool>; |
| 80 | mutable CacheTy Cache{}; |
| 81 | |
| 82 | public: |
| 83 | bool isACallToEnsureFn(const Expr *E) const; |
| 84 | }; |
| 85 | |
| 86 | /// \returns name of AST node or empty string. |
| 87 | template <typename T> std::string safeGetName(const T *ASTNode) { |
| 88 | const auto *const ND = llvm::dyn_cast_or_null<clang::NamedDecl>(ASTNode); |
| 89 | if (!ND) |
| 90 | return "" ; |
| 91 | |
| 92 | // In case F is for example "operator|" the getName() method below would |
| 93 | // assert. |
| 94 | if (!ND->getDeclName().isIdentifier()) |
| 95 | return "" ; |
| 96 | |
| 97 | return ND->getName().str(); |
| 98 | } |
| 99 | |
| 100 | } // namespace clang |
| 101 | |
| 102 | #endif |
| 103 | |