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

tudasc / TypeART / 12904858633

22 Jan 2025 09:11AM UTC coverage: 90.735% (+0.005%) from 90.73%
12904858633

Pull #149

github

web-flow
Merge f0a5eda87 into 37d7f8cb1
Pull Request #149: Replace llvm::Optional with std::optional

88 of 102 new or added lines in 23 files covered. (86.27%)

1 existing line in 1 file now uncovered.

3829 of 4220 relevant lines covered (90.73%)

117945.73 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,
12✔
31
                                                  bool case_sensitive, bool short_circuit) {
32
  const auto reachables = get_reachable_functions(source);
12✔
33
  bool matches          = false;
12✔
34
  bool allBodies        = true;
12✔
35

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

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

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

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

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

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

66
  // No match and all functions had bodies -> never reaches (all call targets found)
67
  return ReachabilityResult::never_reaches;
×
68
}
12✔
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,
12✔
82
                                                                bool considerOverrides) const {
83
  std::unordered_set<std::string> ret;
12✔
84
  std::unordered_set<std::string> worklist;
12✔
85

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

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

115
JSONCG::JSONCG(const llvm::json::Value& cg) {
56✔
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");
56✔
121
  const llvm::json::Object* tlobj = cg.getAsObject();
28✔
122
  if (tlobj != nullptr) {
28✔
123
    for (const auto& entry : *tlobj) {
68✔
124
      // std::cout << "Building call site info for " << entry.first.str() << std::endl;
125
      construct_call_information(entry.first.str(), *tlobj);
40✔
126
    }
127
  }
28✔
128
}
28✔
129

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

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

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

179
    if (!json) {
28✔
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());
28✔
188
  }
28✔
189
  LOG_FATAL("No CG file provided / file cannot be found: " << fileName);
×
190
  return nullptr;
×
191
}
28✔
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