1*12c85518Srobert //===-- ChromiumCheckModel.cpp ----------------------------------*- C++ -*-===// 2*12c85518Srobert // 3*12c85518Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*12c85518Srobert // See https://llvm.org/LICENSE.txt for license information. 5*12c85518Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*12c85518Srobert // 7*12c85518Srobert //===----------------------------------------------------------------------===// 8*12c85518Srobert 9*12c85518Srobert #include "clang/Analysis/FlowSensitive/Models/ChromiumCheckModel.h" 10*12c85518Srobert #include "clang/AST/Decl.h" 11*12c85518Srobert #include "clang/AST/DeclCXX.h" 12*12c85518Srobert #include "llvm/ADT/DenseSet.h" 13*12c85518Srobert 14*12c85518Srobert namespace clang { 15*12c85518Srobert namespace dataflow { 16*12c85518Srobert 17*12c85518Srobert /// Determines whether `D` is one of the methods used to implement Chromium's 18*12c85518Srobert /// `CHECK` macros. Populates `CheckDecls`, if empty. isCheckLikeMethod(llvm::SmallDenseSet<const CXXMethodDecl * > & CheckDecls,const CXXMethodDecl & D)19*12c85518Srobertbool isCheckLikeMethod(llvm::SmallDenseSet<const CXXMethodDecl *> &CheckDecls, 20*12c85518Srobert const CXXMethodDecl &D) { 21*12c85518Srobert // All of the methods of interest are static, so avoid any lookup for 22*12c85518Srobert // non-static methods (the common case). 23*12c85518Srobert if (!D.isStatic()) 24*12c85518Srobert return false; 25*12c85518Srobert 26*12c85518Srobert if (CheckDecls.empty()) { 27*12c85518Srobert // Attempt to initialize `CheckDecls` with the methods in class 28*12c85518Srobert // `CheckError`. 29*12c85518Srobert const CXXRecordDecl *ParentClass = D.getParent(); 30*12c85518Srobert if (ParentClass == nullptr || !ParentClass->getDeclName().isIdentifier() || 31*12c85518Srobert ParentClass->getName() != "CheckError") 32*12c85518Srobert return false; 33*12c85518Srobert 34*12c85518Srobert // Check whether namespace is "logging". 35*12c85518Srobert const auto *N = 36*12c85518Srobert dyn_cast_or_null<NamespaceDecl>(ParentClass->getDeclContext()); 37*12c85518Srobert if (N == nullptr || !N->getDeclName().isIdentifier() || 38*12c85518Srobert N->getName() != "logging") 39*12c85518Srobert return false; 40*12c85518Srobert 41*12c85518Srobert // Check whether "logging" is a top-level namespace. 42*12c85518Srobert if (N->getParent() == nullptr || !N->getParent()->isTranslationUnit()) 43*12c85518Srobert return false; 44*12c85518Srobert 45*12c85518Srobert for (const CXXMethodDecl *M : ParentClass->methods()) 46*12c85518Srobert if (M->getDeclName().isIdentifier() && M->getName().endswith("Check")) 47*12c85518Srobert CheckDecls.insert(M); 48*12c85518Srobert } 49*12c85518Srobert 50*12c85518Srobert return CheckDecls.contains(&D); 51*12c85518Srobert } 52*12c85518Srobert transfer(const CFGElement * Element,Environment & Env)53*12c85518Srobertbool ChromiumCheckModel::transfer(const CFGElement *Element, Environment &Env) { 54*12c85518Srobert auto CS = Element->getAs<CFGStmt>(); 55*12c85518Srobert if (!CS) 56*12c85518Srobert return false; 57*12c85518Srobert auto Stmt = CS->getStmt(); 58*12c85518Srobert if (const auto *Call = dyn_cast<CallExpr>(Stmt)) { 59*12c85518Srobert if (const auto *M = dyn_cast<CXXMethodDecl>(Call->getDirectCallee())) { 60*12c85518Srobert if (isCheckLikeMethod(CheckDecls, *M)) { 61*12c85518Srobert // Mark this branch as unreachable. 62*12c85518Srobert Env.addToFlowCondition(Env.getBoolLiteralValue(false)); 63*12c85518Srobert return true; 64*12c85518Srobert } 65*12c85518Srobert } 66*12c85518Srobert } 67*12c85518Srobert return false; 68*12c85518Srobert } 69*12c85518Srobert 70*12c85518Srobert } // namespace dataflow 71*12c85518Srobert } // namespace clang 72