xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BlockCounter.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //==- BlockCounter.h - ADT for counting block visits -------------*- C++ -*-//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric //  This file defines BlockCounter, an abstract data type used to count
10*0b57cec5SDimitry Andric //  the number of times a given block has been visited along a path
11*0b57cec5SDimitry Andric //  analyzed by CoreEngine.
12*0b57cec5SDimitry Andric //
13*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
14*0b57cec5SDimitry Andric 
15*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
16*0b57cec5SDimitry Andric #include "llvm/ADT/ImmutableMap.h"
17*0b57cec5SDimitry Andric 
18*0b57cec5SDimitry Andric using namespace clang;
19*0b57cec5SDimitry Andric using namespace ento;
20*0b57cec5SDimitry Andric 
21*0b57cec5SDimitry Andric namespace {
22*0b57cec5SDimitry Andric 
23*0b57cec5SDimitry Andric class CountKey {
24*0b57cec5SDimitry Andric   const StackFrameContext *CallSite;
25*0b57cec5SDimitry Andric   unsigned BlockID;
26*0b57cec5SDimitry Andric 
27*0b57cec5SDimitry Andric public:
CountKey(const StackFrameContext * CS,unsigned ID)28*0b57cec5SDimitry Andric   CountKey(const StackFrameContext *CS, unsigned ID)
29*0b57cec5SDimitry Andric     : CallSite(CS), BlockID(ID) {}
30*0b57cec5SDimitry Andric 
operator ==(const CountKey & RHS) const31*0b57cec5SDimitry Andric   bool operator==(const CountKey &RHS) const {
32*0b57cec5SDimitry Andric     return (CallSite == RHS.CallSite) && (BlockID == RHS.BlockID);
33*0b57cec5SDimitry Andric   }
34*0b57cec5SDimitry Andric 
operator <(const CountKey & RHS) const35*0b57cec5SDimitry Andric   bool operator<(const CountKey &RHS) const {
36*0b57cec5SDimitry Andric     return std::tie(CallSite, BlockID) < std::tie(RHS.CallSite, RHS.BlockID);
37*0b57cec5SDimitry Andric   }
38*0b57cec5SDimitry Andric 
Profile(llvm::FoldingSetNodeID & ID) const39*0b57cec5SDimitry Andric   void Profile(llvm::FoldingSetNodeID &ID) const {
40*0b57cec5SDimitry Andric     ID.AddPointer(CallSite);
41*0b57cec5SDimitry Andric     ID.AddInteger(BlockID);
42*0b57cec5SDimitry Andric   }
43*0b57cec5SDimitry Andric };
44*0b57cec5SDimitry Andric 
45*0b57cec5SDimitry Andric }
46*0b57cec5SDimitry Andric 
47*0b57cec5SDimitry Andric typedef llvm::ImmutableMap<CountKey, unsigned> CountMap;
48*0b57cec5SDimitry Andric 
GetMap(void * D)49*0b57cec5SDimitry Andric static inline CountMap GetMap(void *D) {
50*0b57cec5SDimitry Andric   return CountMap(static_cast<CountMap::TreeTy*>(D));
51*0b57cec5SDimitry Andric }
52*0b57cec5SDimitry Andric 
GetFactory(void * F)53*0b57cec5SDimitry Andric static inline CountMap::Factory& GetFactory(void *F) {
54*0b57cec5SDimitry Andric   return *static_cast<CountMap::Factory*>(F);
55*0b57cec5SDimitry Andric }
56*0b57cec5SDimitry Andric 
getNumVisited(const StackFrameContext * CallSite,unsigned BlockID) const57*0b57cec5SDimitry Andric unsigned BlockCounter::getNumVisited(const StackFrameContext *CallSite,
58*0b57cec5SDimitry Andric                                        unsigned BlockID) const {
59*0b57cec5SDimitry Andric   CountMap M = GetMap(Data);
60*0b57cec5SDimitry Andric   CountMap::data_type* T = M.lookup(CountKey(CallSite, BlockID));
61*0b57cec5SDimitry Andric   return T ? *T : 0;
62*0b57cec5SDimitry Andric }
63*0b57cec5SDimitry Andric 
Factory(llvm::BumpPtrAllocator & Alloc)64*0b57cec5SDimitry Andric BlockCounter::Factory::Factory(llvm::BumpPtrAllocator& Alloc) {
65*0b57cec5SDimitry Andric   F = new CountMap::Factory(Alloc);
66*0b57cec5SDimitry Andric }
67*0b57cec5SDimitry Andric 
~Factory()68*0b57cec5SDimitry Andric BlockCounter::Factory::~Factory() {
69*0b57cec5SDimitry Andric   delete static_cast<CountMap::Factory*>(F);
70*0b57cec5SDimitry Andric }
71*0b57cec5SDimitry Andric 
72*0b57cec5SDimitry Andric BlockCounter
IncrementCount(BlockCounter BC,const StackFrameContext * CallSite,unsigned BlockID)73*0b57cec5SDimitry Andric BlockCounter::Factory::IncrementCount(BlockCounter BC,
74*0b57cec5SDimitry Andric                                         const StackFrameContext *CallSite,
75*0b57cec5SDimitry Andric                                         unsigned BlockID) {
76*0b57cec5SDimitry Andric   return BlockCounter(GetFactory(F).add(GetMap(BC.Data),
77*0b57cec5SDimitry Andric                                           CountKey(CallSite, BlockID),
78*0b57cec5SDimitry Andric                              BC.getNumVisited(CallSite, BlockID)+1).getRoot());
79*0b57cec5SDimitry Andric }
80*0b57cec5SDimitry Andric 
81*0b57cec5SDimitry Andric BlockCounter
GetEmptyCounter()82*0b57cec5SDimitry Andric BlockCounter::Factory::GetEmptyCounter() {
83*0b57cec5SDimitry Andric   return BlockCounter(GetFactory(F).getEmptyMap().getRoot());
84*0b57cec5SDimitry Andric }
85