1//==- BlockCounter.h - ADT for counting block visits -------------*- 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//  This file defines BlockCounter, an abstract data type used to count
10//  the number of times a given block has been visited along a path
11//  analyzed by CoreEngine.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
16#include "llvm/ADT/ImmutableMap.h"
17
18using namespace clang;
19using namespace ento;
20
21namespace {
22
23class CountKey {
24  const StackFrameContext *CallSite;
25  unsigned BlockID;
26
27public:
28  CountKey(const StackFrameContext *CS, unsigned ID)
29    : CallSite(CS), BlockID(ID) {}
30
31  bool operator==(const CountKey &RHS) const {
32    return (CallSite == RHS.CallSite) && (BlockID == RHS.BlockID);
33  }
34
35  bool operator<(const CountKey &RHS) const {
36    return std::tie(CallSite, BlockID) < std::tie(RHS.CallSite, RHS.BlockID);
37  }
38
39  void Profile(llvm::FoldingSetNodeID &ID) const {
40    ID.AddPointer(CallSite);
41    ID.AddInteger(BlockID);
42  }
43};
44
45}
46
47typedef llvm::ImmutableMap<CountKey, unsigned> CountMap;
48
49static inline CountMap GetMap(void *D) {
50  return CountMap(static_cast<CountMap::TreeTy*>(D));
51}
52
53static inline CountMap::Factory& GetFactory(void *F) {
54  return *static_cast<CountMap::Factory*>(F);
55}
56
57unsigned BlockCounter::getNumVisited(const StackFrameContext *CallSite,
58                                       unsigned BlockID) const {
59  CountMap M = GetMap(Data);
60  CountMap::data_type* T = M.lookup(CountKey(CallSite, BlockID));
61  return T ? *T : 0;
62}
63
64BlockCounter::Factory::Factory(llvm::BumpPtrAllocator& Alloc) {
65  F = new CountMap::Factory(Alloc);
66}
67
68BlockCounter::Factory::~Factory() {
69  delete static_cast<CountMap::Factory*>(F);
70}
71
72BlockCounter
73BlockCounter::Factory::IncrementCount(BlockCounter BC,
74                                        const StackFrameContext *CallSite,
75                                        unsigned BlockID) {
76  return BlockCounter(GetFactory(F).add(GetMap(BC.Data),
77                                          CountKey(CallSite, BlockID),
78                             BC.getNumVisited(CallSite, BlockID)+1).getRoot());
79}
80
81BlockCounter
82BlockCounter::Factory::GetEmptyCounter() {
83  return BlockCounter(GetFactory(F).getEmptyMap().getRoot());
84}
85