xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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.
safeGetName(const T * ASTNode)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