1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #pragma once
11 
12 #include <clang/AST/RecursiveASTVisitor.h>
13 #include <unordered_set>
14 #include "plugin.hxx"
15 
16 /**
17  * Common code for checking if the address of a function was taken.
18  */
19 namespace loplugin {
20 
21 template<typename Base>
22 class FunctionAddress : public Base
23 {
24 public:
FunctionAddress(const InstantiationData & data)25     explicit FunctionAddress( const InstantiationData& data ) : Base(data) {}
26 
TraverseCallExpr(CallExpr * expr)27     bool TraverseCallExpr(CallExpr * expr) {
28         auto const saved = callee_;
29         callee_ = expr->getCallee();
30         auto const ret = Base::TraverseCallExpr(expr);
31         callee_ = saved;
32         return ret;
33     }
34 
TraverseCXXOperatorCallExpr(CXXOperatorCallExpr * expr)35     bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr * expr) {
36         auto const saved = callee_;
37         callee_ = expr->getCallee();
38         auto const ret = Base::TraverseCXXOperatorCallExpr(expr);
39         callee_ = saved;
40         return ret;
41     }
42 
TraverseCXXMemberCallExpr(CXXMemberCallExpr * expr)43     bool TraverseCXXMemberCallExpr(CXXMemberCallExpr * expr) {
44         auto const saved = callee_;
45         callee_ = expr->getCallee();
46         auto const ret = Base::TraverseCXXMemberCallExpr(expr);
47         callee_ = saved;
48         return ret;
49     }
50 
TraverseCUDAKernelCallExpr(CUDAKernelCallExpr * expr)51     bool TraverseCUDAKernelCallExpr(CUDAKernelCallExpr * expr) {
52         auto const saved = callee_;
53         callee_ = expr->getCallee();
54         auto const ret = Base::TraverseCUDAKernelCallExpr(expr);
55         callee_ = saved;
56         return ret;
57     }
58 
TraverseUserDefinedLiteral(UserDefinedLiteral * expr)59     bool TraverseUserDefinedLiteral(UserDefinedLiteral * expr) {
60         auto const saved = callee_;
61         callee_ = expr->getCallee();
62         auto const ret = Base::TraverseUserDefinedLiteral(expr);
63         callee_ = saved;
64         return ret;
65     }
66 
VisitImplicitCastExpr(ImplicitCastExpr const * expr)67     bool VisitImplicitCastExpr(ImplicitCastExpr const * expr) {
68         if (expr == callee_) {
69             return true;
70         }
71         if (this->ignoreLocation(expr)) {
72             return true;
73         }
74         if (expr->getCastKind() != CK_FunctionToPointerDecay) {
75             return true;
76         }
77         auto const dre = dyn_cast<DeclRefExpr>(
78             expr->getSubExpr()->IgnoreParens());
79         if (dre == nullptr) {
80             return true;
81         }
82         auto const fd = dyn_cast<FunctionDecl>(dre->getDecl());
83         if (fd == nullptr) {
84             return true;
85         }
86         ignoredFunctions_.insert(fd->getCanonicalDecl());
87         return true;
88     }
89 
VisitUnaryOperator(UnaryOperator * expr)90     bool VisitUnaryOperator(UnaryOperator * expr) {
91         if (expr->getOpcode() != UO_AddrOf) {
92             return Base::VisitUnaryOperator(expr);
93         }
94         if (this->ignoreLocation(expr)) {
95             return true;
96         }
97         auto const dre = dyn_cast<DeclRefExpr>(
98             expr->getSubExpr()->IgnoreParenImpCasts());
99         if (dre == nullptr) {
100             return true;
101         }
102         auto const fd = dyn_cast<FunctionDecl>(dre->getDecl());
103         if (fd == nullptr) {
104             return true;
105         }
106         ignoredFunctions_.insert(fd->getCanonicalDecl());
107         return true;
108     }
109 
110 protected:
getFunctionsWithAddressTaken()111     std::unordered_set<FunctionDecl const *> const & getFunctionsWithAddressTaken() { return ignoredFunctions_; }
112 
113 private:
114     std::unordered_set<FunctionDecl const *> ignoredFunctions_;
115     Expr const * callee_ = nullptr;
116 };
117 
118 }
119 
120 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
121