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