/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 | } |