Coverage Report

Created: 2022-08-24 06:28

/src/solidity/libyul/Object.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
  This file is part of solidity.
3
4
  solidity is free software: you can redistribute it and/or modify
5
  it under the terms of the GNU General Public License as published by
6
  the Free Software Foundation, either version 3 of the License, or
7
  (at your option) any later version.
8
9
  solidity is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
14
  You should have received a copy of the GNU General Public License
15
  along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
// SPDX-License-Identifier: GPL-3.0
18
/**
19
 * Yul code and data object container.
20
 */
21
22
#include <libyul/Object.h>
23
24
#include <libyul/AsmPrinter.h>
25
#include <libyul/Exceptions.h>
26
27
#include <libsolutil/CommonData.h>
28
#include <libsolutil/StringUtils.h>
29
30
#include <boost/algorithm/string.hpp>
31
#include <boost/algorithm/string/split.hpp>
32
#include <boost/algorithm/string/replace.hpp>
33
34
#include <range/v3/view/transform.hpp>
35
36
using namespace std;
37
using namespace solidity;
38
using namespace solidity::langutil;
39
using namespace solidity::util;
40
using namespace solidity::yul;
41
42
namespace
43
{
44
45
string indent(std::string const& _input)
46
0
{
47
0
  if (_input.empty())
48
0
    return _input;
49
0
  return boost::replace_all_copy("    " + _input, "\n", "\n    ");
50
0
}
51
52
}
53
54
string Data::toString(Dialect const*, DebugInfoSelection const&, CharStreamProvider const*) const
55
0
{
56
0
  return "data \"" + name.str() + "\" hex\"" + util::toHex(data) + "\"";
57
0
}
58
59
string Object::toString(
60
  Dialect const* _dialect,
61
  DebugInfoSelection const& _debugInfoSelection,
62
  CharStreamProvider const* _soliditySourceProvider
63
) const
64
0
{
65
0
  yulAssert(code, "No code");
66
0
  yulAssert(debugData, "No debug data");
67
68
0
  string useSrcComment;
69
70
0
  if (debugData->sourceNames)
71
0
    useSrcComment =
72
0
      "/// @use-src " +
73
0
      joinHumanReadable(ranges::views::transform(*debugData->sourceNames, [](auto&& _pair) {
74
0
        return to_string(_pair.first) + ":" + util::escapeAndQuoteString(*_pair.second);
75
0
      })) +
76
0
      "\n";
77
78
0
  string inner = "code " + AsmPrinter(
79
0
    _dialect,
80
0
    debugData->sourceNames,
81
0
    _debugInfoSelection,
82
0
    _soliditySourceProvider
83
0
  )(*code);
84
85
0
  for (auto const& obj: subObjects)
86
0
    inner += "\n" + obj->toString(_dialect, _debugInfoSelection, _soliditySourceProvider);
87
88
0
  return useSrcComment + "object \"" + name.str() + "\" {\n" + indent(inner) + "\n}";
89
0
}
90
91
set<YulString> Object::qualifiedDataNames() const
92
0
{
93
0
  set<YulString> qualifiedNames =
94
0
    name.empty() || util::contains(name.str(), '.') ?
95
0
    set<YulString>{} :
96
0
    set<YulString>{name};
97
0
  for (shared_ptr<ObjectNode> const& subObjectNode: subObjects)
98
0
  {
99
0
    yulAssert(qualifiedNames.count(subObjectNode->name) == 0, "");
100
0
    if (util::contains(subObjectNode->name.str(), '.'))
101
0
      continue;
102
0
    qualifiedNames.insert(subObjectNode->name);
103
0
    if (auto const* subObject = dynamic_cast<Object const*>(subObjectNode.get()))
104
0
      for (YulString const& subSubObj: subObject->qualifiedDataNames())
105
0
        if (subObject->name != subSubObj)
106
0
        {
107
0
          yulAssert(qualifiedNames.count(YulString{subObject->name.str() + "." + subSubObj.str()}) == 0, "");
108
0
          qualifiedNames.insert(YulString{subObject->name.str() + "." + subSubObj.str()});
109
0
        }
110
0
  }
111
112
0
  yulAssert(qualifiedNames.count(YulString{}) == 0, "");
113
0
  qualifiedNames.erase(YulString{});
114
0
  return qualifiedNames;
115
0
}
116
117
vector<size_t> Object::pathToSubObject(YulString _qualifiedName) const
118
0
{
119
0
  yulAssert(_qualifiedName != name, "");
120
0
  yulAssert(subIndexByName.count(name) == 0, "");
121
122
0
  if (boost::algorithm::starts_with(_qualifiedName.str(), name.str() + "."))
123
0
    _qualifiedName = YulString{_qualifiedName.str().substr(name.str().length() + 1)};
124
0
  yulAssert(!_qualifiedName.empty(), "");
125
126
0
  vector<string> subObjectPathComponents;
127
0
  boost::algorithm::split(subObjectPathComponents, _qualifiedName.str(), boost::is_any_of("."));
128
129
0
  vector<size_t> path;
130
0
  Object const* object = this;
131
0
  for (string const& currentSubObjectName: subObjectPathComponents)
132
0
  {
133
0
    yulAssert(!currentSubObjectName.empty(), "");
134
0
    auto subIndexIt = object->subIndexByName.find(YulString{currentSubObjectName});
135
0
    yulAssert(
136
0
      subIndexIt != object->subIndexByName.end(),
137
0
      "Assembly object <" + _qualifiedName.str() + "> not found or does not contain code."
138
0
    );
139
0
    object = dynamic_cast<Object const*>(object->subObjects[subIndexIt->second].get());
140
0
    yulAssert(object, "Assembly object <" + _qualifiedName.str() + "> not found or does not contain code.");
141
0
    yulAssert(object->subId != numeric_limits<size_t>::max(), "");
142
0
    path.push_back({object->subId});
143
0
  }
144
145
0
  return path;
146
0
}