74 lines · cpp
1//===-- ChromiumCheckModel.cpp ----------------------------------*- 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-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/Analysis/FlowSensitive/Models/ChromiumCheckModel.h"10#include "clang/AST/Decl.h"11#include "clang/AST/DeclCXX.h"12#include "llvm/ADT/DenseSet.h"13 14namespace clang {15namespace dataflow {16 17/// Determines whether `D` is one of the methods used to implement Chromium's18/// `CHECK` macros. Populates `CheckDecls`, if empty.19static bool20isCheckLikeMethod(llvm::SmallDenseSet<const CXXMethodDecl *> &CheckDecls,21 const CXXMethodDecl &D) {22 // All of the methods of interest are static, so avoid any lookup for23 // non-static methods (the common case).24 if (!D.isStatic())25 return false;26 27 if (CheckDecls.empty()) {28 // Attempt to initialize `CheckDecls` with the methods in class29 // `CheckError`.30 const CXXRecordDecl *ParentClass = D.getParent();31 if (ParentClass == nullptr || !ParentClass->getDeclName().isIdentifier() ||32 ParentClass->getName() != "CheckError")33 return false;34 35 // Check whether namespace is "logging".36 const auto *N =37 dyn_cast_or_null<NamespaceDecl>(ParentClass->getDeclContext());38 if (N == nullptr || !N->getDeclName().isIdentifier() ||39 N->getName() != "logging")40 return false;41 42 // Check whether "logging" is a top-level namespace.43 if (N->getParent() == nullptr || !N->getParent()->isTranslationUnit())44 return false;45 46 for (const CXXMethodDecl *M : ParentClass->methods())47 if (M->getDeclName().isIdentifier() && M->getName().ends_with("Check"))48 CheckDecls.insert(M);49 }50 51 return CheckDecls.contains(&D);52}53 54bool ChromiumCheckModel::transfer(const CFGElement &Element, Environment &Env) {55 auto CS = Element.getAs<CFGStmt>();56 if (!CS)57 return false;58 auto Stmt = CS->getStmt();59 if (const auto *Call = dyn_cast<CallExpr>(Stmt)) {60 if (const auto *M =61 dyn_cast_or_null<CXXMethodDecl>(Call->getDirectCallee())) {62 if (isCheckLikeMethod(CheckDecls, *M)) {63 // Mark this branch as unreachable.64 Env.assume(Env.arena().makeLiteral(false));65 return true;66 }67 }68 }69 return false;70}71 72} // namespace dataflow73} // namespace clang74