• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tudasc / TypeART / 13955121336

19 Mar 2025 07:30PM UTC coverage: 88.842%. First build
13955121336

push

github

web-flow
Merge PR #167 from tudasc/devel

1174 of 1361 new or added lines in 49 files covered. (86.26%)

4212 of 4741 relevant lines covered (88.84%)

261950.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.95
/lib/passes/filter/CGInterface.cpp
1
// TypeART library
2
//
3
// Copyright (c) 2017-2025 TypeART Authors
4
// Distributed under the BSD 3-Clause license.
5
// (See accompanying file LICENSE.txt or copy at
6
// https://opensource.org/licenses/BSD-3-Clause)
7
//
8
// Project home: https://github.com/tudasc/TypeART
9
//
10
// SPDX-License-Identifier: BSD-3-Clause
11
//
12

13
#include "CGInterface.h"
14

15
#include "support/Logger.h"
16
#include "support/Util.h"
17

18
#include "llvm/Support/Error.h"
19
#include "llvm/Support/ErrorOr.h"
20
#include "llvm/Support/JSON.h"
21
#include "llvm/Support/MemoryBuffer.h"
22
#include "llvm/Support/raw_ostream.h"
23

24
#include <algorithm>
25
#include <cassert>
26
#include <cstdlib>
27

28
namespace typeart::filter {
29

30
CGInterface::ReachabilityResult JSONCG::reachable(const std::string& source, const std::string& target,
24✔
31
                                                  bool case_sensitive, bool short_circuit) {
32
  const auto reachables = get_reachable_functions(source);
24✔
33
  bool matches          = false;
24✔
34
  bool allBodies        = true;
24✔
35

36
  // bool what{false};
37
  if (!hasBodyMap[source]) {
24✔
38
    ++no_call_chain;
24✔
39
  }
24✔
40

41
  if (!reachables.empty()) {
24✔
42
    ++call_chain;
12✔
43
    f.push_back(source);
12✔
44
  }
12✔
45

46
  for (const auto& function_n : reachables) {
24✔
47
    matches |= util::regex_matches(target, function_n, case_sensitive);
12✔
48
    allBodies = allBodies && hasBodyMap[target];
12✔
49

50
    if (matches && short_circuit) {
12✔
51
      // we have found a match -> whether all functions have bodies is irrelevant
52
      return ReachabilityResult::reaches;
12✔
53
    }
54
  }
55

56
  if (matches) {
12✔
57
    // matches but no short circuit
58
    return ReachabilityResult::reaches;
×
59
  }
28✔
60

28✔
61
  if (!matches && (!allBodies || !hasBodyMap[source])) {
12✔
62
    // We did not find a match, but not all functions had bodies, we don't know
63
    return ReachabilityResult::maybe_reaches;
12✔
64
  }
65

66
  // No match and all functions had bodies -> never reaches (all call targets found)
67
  return ReachabilityResult::never_reaches;
×
68
}
24✔
69

70
std::vector<std::string> JSONCG::get_decl_only() {
×
71
  std::vector<std::string> list;
×
72
  list.reserve(hasBodyMap.size());
×
73
  for (const auto& [func, has_body] : hasBodyMap) {
×
74
    if (!has_body) {
×
75
      list.push_back(func);
×
76
    }
×
77
  }
78
  return list;
×
79
}
×
80

81
std::unordered_set<std::string> JSONCG::get_reachable_functions(const std::string& caller,
24✔
82
                                                                bool considerOverrides) const {
83
  std::unordered_set<std::string> ret;
24✔
84
  std::unordered_set<std::string> worklist;
24✔
85

86
  worklist = get_directly_called_function_names(caller, considerOverrides);
24✔
87
  while (!worklist.empty()) {
36✔
88
    const std::string func_name = *worklist.begin();
12✔
89
    // Check if we did not already handled it
90
    if (ret.find(func_name) == ret.end()) {
12✔
91
      worklist.merge(get_directly_called_function_names(func_name));
12✔
92
      ret.insert(func_name);
12✔
93
    }
12✔
94
    worklist.erase(worklist.find(func_name));  // Iterators get invalidated by merge, so we need to search again
12✔
95
  }
12✔
96
  return ret;
24✔
97
}
24✔
98

99
std::unordered_set<std::string> JSONCG::get_directly_called_function_names(const std::string& caller,
36✔
100
                                                                           bool considerOverrides) const {
101
  auto ref = directly_called_functions.find(caller);
36✔
102
  if (ref != std::end(directly_called_functions)) {
36✔
103
    // If the caller is virtual and overridden, add the overriding functions
104
    if (considerOverrides && (virtualTargets.find(caller) != std::end(virtualTargets))) {
24✔
105
      auto targets  = ref->second;
×
106
      auto vTargets = virtualTargets.find(caller)->second;
×
107
      targets.merge(vTargets);
×
108
      return targets;
×
109
    }
×
110
    return ref->second;
24✔
111
  }
112
  return {};
12✔
113
}
36✔
114

115
JSONCG::JSONCG(const llvm::json::Value& cg) {
68✔
116
  // Expected json format is the following:
117
  // A top level object/map Key is the function name, value is an object/map with information
118
  // We only care about "callees"
119
  // callees itself is an array with function names (as strings)
120
  assert(cg.kind() == llvm::json::Value::Kind::Object && "Top level json must be an Object");
80✔
121
  const llvm::json::Object* tlobj = cg.getAsObject();
40✔
122
  if (tlobj != nullptr) {
40✔
123
    for (const auto& entry : *tlobj) {
104✔
124
      // std::cout << "Building call site info for " << entry.first.str() << std::endl;
125
      construct_call_information(entry.first.str(), *tlobj);
64✔
126
    }
127
  }
40✔
128
}
28✔
129

130
void JSONCG::construct_call_information(const std::string& entry_caller, const llvm::json::Object& j) {
64✔
131
  if (directly_called_functions.find(entry_caller) == directly_called_functions.end()) {
64✔
132
    // We did not handle this function yet
133
    directly_called_functions[entry_caller] = std::unordered_set<std::string>();
64✔
134
    const auto caller                       = j.getObject(entry_caller);
64✔
135
    if (caller != nullptr) {
64✔
136
      const auto hasBody = caller->get("hasBody");
64✔
137
      if (hasBody != nullptr) {
64✔
138
        assert(hasBody->kind() == llvm::json::Value::Kind::Boolean && "hasBody must be boolean");
128✔
139
        hasBodyMap[entry_caller] = *hasBody->getAsBoolean();
64✔
140
      }
64✔
141
      const auto calls = caller->getArray("callees");
64✔
142
      assert(calls != nullptr && "Json callee information is missing");
128✔
143
      if (calls != nullptr) {
64✔
144
        // Now iterate over them
145
        for (const auto& callee : *calls) {
144✔
146
          assert(callee.kind() == llvm::json::Value::Kind::String && "Callees must be strings");
160✔
147
          const auto callee_json_string = callee.getAsString();
80✔
148
          assert(callee_json_string && "Could not get callee as string");
160✔
149
          if (callee_json_string) {
80✔
150
            const std::string callee_string = std::string{*callee_json_string};
80✔
151
            directly_called_functions[entry_caller].insert(callee_string);
80✔
152
          }
80✔
153
        }
154
      }
64✔
155
      // if the function is virtual, overriding functions are _potential_ call targets
156
      const auto overridingFunctions = caller->getArray("overriddenBy");
64✔
157
      if (overridingFunctions != nullptr) {
64✔
158
        for (const auto& function : *overridingFunctions) {
64✔
159
          assert(function.kind() == llvm::json::Value::Kind::String && "Function names are always strings");
×
160
          const auto functionStr = function.getAsString();
×
NEW
161
          assert(functionStr && "Retrieving overriding function as String failed");
×
NEW
162
          if (functionStr) {
×
NEW
163
            const std::string functionName = std::string{*functionStr};
×
164
            virtualTargets[entry_caller].insert(functionName);
×
165
          }
×
166
        }
167
      }
64✔
168
    }
64✔
169
  }
64✔
170
}
64✔
171

172
std::unique_ptr<JSONCG> JSONCG::getJSON(const std::string& fileName) {
40✔
173
  using namespace llvm;
174
  auto memBuffer = MemoryBuffer::getFile(fileName);
40✔
175

176
  if (memBuffer) {
40✔
177
    auto json = llvm::json::parse(memBuffer.get()->getBuffer());
40✔
178

179
    if (!json) {
40✔
180
      std::string str;
×
181
      llvm::raw_string_ostream ostr(str);
×
182
      ostr << json.takeError();
×
183
      LOG_FATAL(ostr.str());
×
184
      exit(-1);
×
185
    }
×
186

187
    return std::make_unique<JSONCG>(json.get());
40✔
188
  }
40✔
189
  LOG_FATAL("No CG file provided / file cannot be found: " << fileName);
×
190
  return nullptr;
×
191
}
40✔
192

193
}  // namespace typeart::filter
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc