/src/solidity/libsolidity/ast/ASTJsonExporter.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 | | * @date 2017 |
20 | | * Converts the AST into json format |
21 | | */ |
22 | | |
23 | | #include <libsolidity/ast/ASTJsonExporter.h> |
24 | | |
25 | | #include <libsolidity/ast/AST.h> |
26 | | #include <libsolidity/ast/TypeProvider.h> |
27 | | |
28 | | #include <libyul/AsmJsonConverter.h> |
29 | | #include <libyul/AST.h> |
30 | | #include <libyul/backends/evm/EVMDialect.h> |
31 | | |
32 | | #include <libsolutil/JSON.h> |
33 | | #include <libsolutil/UTF8.h> |
34 | | #include <libsolutil/CommonData.h> |
35 | | #include <libsolutil/Visitor.h> |
36 | | #include <libsolutil/Keccak256.h> |
37 | | |
38 | | #include <boost/algorithm/string/join.hpp> |
39 | | |
40 | | #include <utility> |
41 | | #include <vector> |
42 | | #include <algorithm> |
43 | | #include <limits> |
44 | | #include <type_traits> |
45 | | #include <range/v3/view/map.hpp> |
46 | | |
47 | | using namespace std::string_literals; |
48 | | using namespace solidity::langutil; |
49 | | using namespace solidity; |
50 | | |
51 | | namespace |
52 | | { |
53 | | |
54 | | template<typename V, template<typename> typename C> |
55 | | void addIfSet(std::vector<std::pair<std::string, Json>>& _attributes, std::string const& _name, C<V> const& _value) |
56 | 0 | { |
57 | 0 | if constexpr (std::is_same_v<C<V>, solidity::util::SetOnce<V>>) |
58 | 0 | { |
59 | 0 | if (!_value.set()) |
60 | 0 | return; |
61 | 0 | } |
62 | 0 | else if constexpr (std::is_same_v<C<V>, std::optional<V>>) |
63 | 0 | { |
64 | 0 | if (!_value.has_value()) |
65 | 0 | return; |
66 | 0 | } |
67 | | |
68 | 0 | _attributes.emplace_back(_name, *_value); |
69 | 0 | } Unexecuted instantiation: ASTJsonExporter.cpp:void (anonymous namespace)::addIfSet<bool, solidity::util::SetOnce>(std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, void> >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, void> > > >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, solidity::util::SetOnce<bool> const&) Unexecuted instantiation: ASTJsonExporter.cpp:void (anonymous namespace)::addIfSet<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, solidity::util::SetOnce>(std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, void> >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, void> > > >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, solidity::util::SetOnce<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&) |
70 | | |
71 | | } |
72 | | |
73 | | namespace solidity::frontend |
74 | | { |
75 | | |
76 | | ASTJsonExporter::ASTJsonExporter(CompilerStack::State _stackState, std::map<std::string, unsigned> _sourceIndices): |
77 | | m_stackState(_stackState), |
78 | | m_sourceIndices(std::move(_sourceIndices)) |
79 | 0 | { |
80 | 0 | } |
81 | | |
82 | | |
83 | | void ASTJsonExporter::setJsonNode( |
84 | | ASTNode const& _node, |
85 | | std::string const& _nodeName, |
86 | | std::initializer_list<std::pair<std::string, Json>>&& _attributes |
87 | | ) |
88 | 0 | { |
89 | 0 | ASTJsonExporter::setJsonNode( |
90 | 0 | _node, |
91 | 0 | _nodeName, |
92 | 0 | std::vector<std::pair<std::string, Json>>(std::move(_attributes)) |
93 | 0 | ); |
94 | 0 | } |
95 | | |
96 | | void ASTJsonExporter::setJsonNode( |
97 | | ASTNode const& _node, |
98 | | std::string const& _nodeType, |
99 | | std::vector<std::pair<std::string, Json>>&& _attributes |
100 | | ) |
101 | 0 | { |
102 | 0 | m_currentValue = Json::object(); |
103 | 0 | m_currentValue["id"] = nodeId(_node); |
104 | 0 | m_currentValue["src"] = sourceLocationToString(_node.location()); |
105 | 0 | if (auto const* documented = dynamic_cast<Documented const*>(&_node)) |
106 | 0 | if (documented->documentation()) |
107 | 0 | m_currentValue["documentation"] = *documented->documentation(); |
108 | 0 | m_currentValue["nodeType"] = _nodeType; |
109 | 0 | for (auto& e: _attributes) |
110 | 0 | m_currentValue[e.first] = std::move(e.second); |
111 | 0 | } |
112 | | |
113 | | std::optional<size_t> ASTJsonExporter::sourceIndexFromLocation(SourceLocation const& _location) const |
114 | 0 | { |
115 | 0 | if (_location.sourceName && m_sourceIndices.count(*_location.sourceName)) |
116 | 0 | return m_sourceIndices.at(*_location.sourceName); |
117 | 0 | else |
118 | 0 | return std::nullopt; |
119 | 0 | } |
120 | | |
121 | | std::string ASTJsonExporter::sourceLocationToString(SourceLocation const& _location) const |
122 | 0 | { |
123 | 0 | std::optional<size_t> sourceIndexOpt = sourceIndexFromLocation(_location); |
124 | 0 | int length = -1; |
125 | 0 | if (_location.start >= 0 && _location.end >= 0) |
126 | 0 | length = _location.end - _location.start; |
127 | 0 | return std::to_string(_location.start) + ":" + std::to_string(length) + ":" + (sourceIndexOpt.has_value() ? std::to_string(sourceIndexOpt.value()) : "-1"); |
128 | 0 | } |
129 | | |
130 | | Json ASTJsonExporter::sourceLocationsToJson(std::vector<SourceLocation> const& _sourceLocations) const |
131 | 0 | { |
132 | 0 | Json locations = Json::array(); |
133 | |
|
134 | 0 | for (SourceLocation const& location: _sourceLocations) |
135 | 0 | locations.emplace_back(sourceLocationToString(location)); |
136 | |
|
137 | 0 | return locations; |
138 | 0 | } |
139 | | |
140 | | std::string ASTJsonExporter::namePathToString(std::vector<ASTString> const& _namePath) |
141 | 0 | { |
142 | 0 | return boost::algorithm::join(_namePath, "."s); |
143 | 0 | } |
144 | | |
145 | | Json ASTJsonExporter::typePointerToJson(Type const* _tp, bool _withoutDataLocation) |
146 | 0 | { |
147 | 0 | Json typeDescriptions; |
148 | 0 | typeDescriptions["typeString"] = _tp ? Json(_tp->toString(_withoutDataLocation)) : Json(); |
149 | 0 | typeDescriptions["typeIdentifier"] = _tp ? Json(_tp->identifier()) : Json(); |
150 | 0 | return typeDescriptions; |
151 | |
|
152 | 0 | } |
153 | | Json ASTJsonExporter::typePointerToJson(std::optional<FuncCallArguments> const& _tps) |
154 | 0 | { |
155 | 0 | if (_tps) |
156 | 0 | { |
157 | 0 | Json arguments = Json::array(); |
158 | 0 | for (auto const& tp: _tps->types) |
159 | 0 | appendMove(arguments, typePointerToJson(tp)); |
160 | 0 | return arguments; |
161 | 0 | } |
162 | 0 | else |
163 | 0 | return Json(); |
164 | 0 | } |
165 | | |
166 | | void ASTJsonExporter::appendExpressionAttributes( |
167 | | std::vector<std::pair<std::string, Json>>& _attributes, |
168 | | ExpressionAnnotation const& _annotation |
169 | | ) |
170 | 0 | { |
171 | 0 | std::vector<std::pair<std::string, Json>> exprAttributes = { |
172 | 0 | std::make_pair("typeDescriptions", typePointerToJson(_annotation.type)), |
173 | 0 | std::make_pair("argumentTypes", typePointerToJson(_annotation.arguments)) |
174 | 0 | }; |
175 | |
|
176 | 0 | addIfSet(exprAttributes, "isLValue", _annotation.isLValue); |
177 | 0 | addIfSet(exprAttributes, "isPure", _annotation.isPure); |
178 | 0 | addIfSet(exprAttributes, "isConstant", _annotation.isConstant); |
179 | |
|
180 | 0 | if (m_stackState > CompilerStack::State::ParsedAndImported) |
181 | 0 | exprAttributes.emplace_back("lValueRequested", _annotation.willBeWrittenTo); |
182 | |
|
183 | 0 | _attributes += exprAttributes; |
184 | 0 | } |
185 | | |
186 | | Json ASTJsonExporter::inlineAssemblyIdentifierToJson(std::pair<yul::Identifier const*, InlineAssemblyAnnotation::ExternalIdentifierInfo> _info) const |
187 | 0 | { |
188 | 0 | Json tuple; |
189 | 0 | tuple["src"] = sourceLocationToString(nativeLocationOf(*_info.first)); |
190 | 0 | tuple["declaration"] = idOrNull(_info.second.declaration); |
191 | 0 | tuple["isSlot"] = Json(_info.second.suffix == "slot"); |
192 | 0 | tuple["isOffset"] = Json(_info.second.suffix == "offset"); |
193 | |
|
194 | 0 | if (!_info.second.suffix.empty()) |
195 | 0 | tuple["suffix"] = Json(_info.second.suffix); |
196 | |
|
197 | 0 | tuple["valueSize"] = Json(static_cast<Json::number_integer_t>(_info.second.valueSize)); |
198 | |
|
199 | 0 | return tuple; |
200 | 0 | } |
201 | | |
202 | | void ASTJsonExporter::print(std::ostream& _stream, ASTNode const& _node, util::JsonFormat const& _format) |
203 | 0 | { |
204 | 0 | _stream << util::jsonPrint(toJson(_node), _format); |
205 | 0 | } |
206 | | |
207 | | Json ASTJsonExporter::toJson(ASTNode const& _node) |
208 | 0 | { |
209 | 0 | _node.accept(*this); |
210 | 0 | return util::removeNullMembers(std::move(m_currentValue)); |
211 | 0 | } |
212 | | |
213 | | Json ASTJsonExporter::toJson(ASTNode const* _node) |
214 | 0 | { |
215 | 0 | if (!_node) |
216 | 0 | return Json(); |
217 | 0 | return toJson(*_node); |
218 | 0 | } |
219 | | |
220 | | bool ASTJsonExporter::visit(SourceUnit const& _node) |
221 | 0 | { |
222 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
223 | 0 | std::make_pair("license", _node.licenseString() ? Json(*_node.licenseString()) : Json()), |
224 | 0 | std::make_pair("nodes", toJson(_node.nodes())), |
225 | 0 | }; |
226 | |
|
227 | 0 | if (_node.experimentalSolidity()) |
228 | 0 | attributes.emplace_back("experimentalSolidity", Json(_node.experimentalSolidity())); |
229 | |
|
230 | 0 | if (_node.annotation().exportedSymbols.set()) |
231 | 0 | { |
232 | 0 | Json exportedSymbols = Json::object(); |
233 | 0 | for (auto const& sym: *_node.annotation().exportedSymbols) |
234 | 0 | { |
235 | 0 | exportedSymbols[sym.first] = Json::array(); |
236 | 0 | for (Declaration const* overload: sym.second) |
237 | 0 | exportedSymbols[sym.first].emplace_back(nodeId(*overload)); |
238 | 0 | } |
239 | |
|
240 | 0 | attributes.emplace_back("exportedSymbols", exportedSymbols); |
241 | 0 | }; |
242 | |
|
243 | 0 | addIfSet(attributes, "absolutePath", _node.annotation().path); |
244 | |
|
245 | 0 | setJsonNode(_node, "SourceUnit", std::move(attributes)); |
246 | |
|
247 | 0 | return false; |
248 | 0 | } |
249 | | |
250 | | bool ASTJsonExporter::visit(PragmaDirective const& _node) |
251 | 0 | { |
252 | 0 | Json literals = Json::array(); |
253 | 0 | for (auto const& literal: _node.literals()) |
254 | 0 | literals.emplace_back(literal); |
255 | 0 | setJsonNode(_node, "PragmaDirective", { |
256 | 0 | std::make_pair("literals", std::move(literals)) |
257 | 0 | }); |
258 | 0 | return false; |
259 | 0 | } |
260 | | |
261 | | bool ASTJsonExporter::visit(ImportDirective const& _node) |
262 | 0 | { |
263 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
264 | 0 | std::make_pair("file", _node.path()), |
265 | 0 | std::make_pair("sourceUnit", idOrNull(_node.annotation().sourceUnit)), |
266 | 0 | std::make_pair("scope", idOrNull(_node.scope())) |
267 | 0 | }; |
268 | |
|
269 | 0 | addIfSet(attributes, "absolutePath", _node.annotation().absolutePath); |
270 | |
|
271 | 0 | attributes.emplace_back("unitAlias", _node.name()); |
272 | 0 | attributes.emplace_back("nameLocation", Json(sourceLocationToString(_node.nameLocation()))); |
273 | |
|
274 | 0 | Json symbolAliases = Json::array(); |
275 | 0 | for (auto const& symbolAlias: _node.symbolAliases()) |
276 | 0 | { |
277 | 0 | Json tuple; |
278 | 0 | solAssert(symbolAlias.symbol, ""); |
279 | 0 | tuple["foreign"] = toJson(*symbolAlias.symbol); |
280 | 0 | tuple["local"] = symbolAlias.alias ? Json(*symbolAlias.alias) : Json(); |
281 | 0 | tuple["nameLocation"] = sourceLocationToString(_node.nameLocation()); |
282 | 0 | symbolAliases.emplace_back(tuple); |
283 | 0 | } |
284 | 0 | attributes.emplace_back("symbolAliases", std::move(symbolAliases)); |
285 | 0 | setJsonNode(_node, "ImportDirective", std::move(attributes)); |
286 | 0 | return false; |
287 | 0 | } |
288 | | |
289 | | bool ASTJsonExporter::visit(StorageLayoutSpecifier const& _node) |
290 | 0 | { |
291 | 0 | setJsonNode(_node, "StorageLayoutSpecifier", { |
292 | 0 | {"baseSlotExpression", toJson(_node.baseSlotExpression())} |
293 | 0 | }); |
294 | 0 | return false; |
295 | 0 | } |
296 | | |
297 | | bool ASTJsonExporter::visit(ContractDefinition const& _node) |
298 | 0 | { |
299 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
300 | 0 | std::make_pair("name", _node.name()), |
301 | 0 | std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), |
302 | 0 | std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json()), |
303 | 0 | std::make_pair("contractKind", contractKind(_node.contractKind())), |
304 | 0 | std::make_pair("abstract", _node.abstract()), |
305 | 0 | std::make_pair("baseContracts", toJson(_node.baseContracts())), |
306 | 0 | std::make_pair("contractDependencies", getContainerIds(_node.annotation().contractDependencies | ranges::views::keys)), |
307 | | // Do not require call graph because the AST is also created for incorrect sources. |
308 | 0 | std::make_pair("usedEvents", getContainerIds(_node.interfaceEvents(false))), |
309 | 0 | std::make_pair("usedErrors", getContainerIds(_node.interfaceErrors(false))), |
310 | 0 | std::make_pair("nodes", toJson(_node.subNodes())), |
311 | 0 | std::make_pair("scope", idOrNull(_node.scope())), |
312 | 0 | std::make_pair("storageLayout", toJson(_node.storageLayoutSpecifier())) |
313 | 0 | }; |
314 | 0 | addIfSet(attributes, "canonicalName", _node.annotation().canonicalName); |
315 | |
|
316 | 0 | if (_node.annotation().unimplementedDeclarations.has_value()) |
317 | 0 | attributes.emplace_back("fullyImplemented", _node.annotation().unimplementedDeclarations->empty()); |
318 | 0 | if (!_node.annotation().linearizedBaseContracts.empty()) |
319 | 0 | attributes.emplace_back("linearizedBaseContracts", getContainerIds(_node.annotation().linearizedBaseContracts)); |
320 | |
|
321 | 0 | if (!_node.annotation().internalFunctionIDs.empty()) |
322 | 0 | { |
323 | 0 | Json internalFunctionIDs; |
324 | 0 | for (auto const& [functionDefinition, internalFunctionID]: _node.annotation().internalFunctionIDs) |
325 | 0 | internalFunctionIDs[std::to_string(functionDefinition->id())] = internalFunctionID; |
326 | 0 | attributes.emplace_back("internalFunctionIDs", std::move(internalFunctionIDs)); |
327 | 0 | } |
328 | |
|
329 | 0 | setJsonNode(_node, "ContractDefinition", std::move(attributes)); |
330 | 0 | return false; |
331 | 0 | } |
332 | | |
333 | | bool ASTJsonExporter::visit(IdentifierPath const& _node) |
334 | 0 | { |
335 | 0 | Json nameLocations = Json::array(); |
336 | |
|
337 | 0 | for (SourceLocation location: _node.pathLocations()) |
338 | 0 | nameLocations.emplace_back(sourceLocationToString(location)); |
339 | |
|
340 | 0 | setJsonNode(_node, "IdentifierPath", { |
341 | 0 | std::make_pair("name", namePathToString(_node.path())), |
342 | 0 | std::make_pair("nameLocations", nameLocations), |
343 | 0 | std::make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)) |
344 | 0 | }); |
345 | 0 | return false; |
346 | 0 | } |
347 | | |
348 | | bool ASTJsonExporter::visit(InheritanceSpecifier const& _node) |
349 | 0 | { |
350 | 0 | setJsonNode(_node, "InheritanceSpecifier", { |
351 | 0 | std::make_pair("baseName", toJson(_node.name())), |
352 | 0 | std::make_pair("arguments", _node.arguments() ? toJson(*_node.arguments()) : Json()) |
353 | 0 | }); |
354 | 0 | return false; |
355 | 0 | } |
356 | | |
357 | | bool ASTJsonExporter::visit(UsingForDirective const& _node) |
358 | 0 | { |
359 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
360 | 0 | std::make_pair("typeName", _node.typeName() ? toJson(*_node.typeName()) : Json()) |
361 | 0 | }; |
362 | |
|
363 | 0 | if (_node.usesBraces()) |
364 | 0 | { |
365 | 0 | Json functionList = Json::array(); |
366 | 0 | for (auto&& [function, op]: _node.functionsAndOperators()) |
367 | 0 | { |
368 | 0 | Json functionNode; |
369 | 0 | if (!op.has_value()) |
370 | 0 | functionNode["function"] = toJson(*function); |
371 | 0 | else |
372 | 0 | { |
373 | 0 | functionNode["definition"] = toJson(*function); |
374 | 0 | functionNode["operator"] = std::string(TokenTraits::toString(*op)); |
375 | 0 | } |
376 | 0 | functionList.emplace_back(std::move(functionNode)); |
377 | 0 | } |
378 | 0 | attributes.emplace_back("functionList", std::move(functionList)); |
379 | 0 | } |
380 | 0 | else |
381 | 0 | { |
382 | 0 | auto const& functionAndOperators = _node.functionsAndOperators(); |
383 | 0 | solAssert(_node.functionsAndOperators().size() == 1); |
384 | 0 | solAssert(!functionAndOperators.front().second.has_value()); |
385 | 0 | attributes.emplace_back("libraryName", toJson(*(functionAndOperators.front().first))); |
386 | 0 | } |
387 | 0 | attributes.emplace_back("global", _node.global()); |
388 | |
|
389 | 0 | setJsonNode(_node, "UsingForDirective", std::move(attributes)); |
390 | |
|
391 | 0 | return false; |
392 | 0 | } |
393 | | |
394 | | bool ASTJsonExporter::visit(StructDefinition const& _node) |
395 | 0 | { |
396 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
397 | 0 | std::make_pair("name", _node.name()), |
398 | 0 | std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), |
399 | 0 | std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json()), |
400 | 0 | std::make_pair("visibility", Declaration::visibilityToString(_node.visibility())), |
401 | 0 | std::make_pair("members", toJson(_node.members())), |
402 | 0 | std::make_pair("scope", idOrNull(_node.scope())) |
403 | 0 | }; |
404 | |
|
405 | 0 | addIfSet(attributes,"canonicalName", _node.annotation().canonicalName); |
406 | |
|
407 | 0 | setJsonNode(_node, "StructDefinition", std::move(attributes)); |
408 | |
|
409 | 0 | return false; |
410 | 0 | } |
411 | | |
412 | | bool ASTJsonExporter::visit(EnumDefinition const& _node) |
413 | 0 | { |
414 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
415 | 0 | std::make_pair("name", _node.name()), |
416 | 0 | std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), |
417 | 0 | std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json()), |
418 | 0 | std::make_pair("members", toJson(_node.members())) |
419 | 0 | }; |
420 | |
|
421 | 0 | addIfSet(attributes,"canonicalName", _node.annotation().canonicalName); |
422 | |
|
423 | 0 | setJsonNode(_node, "EnumDefinition", std::move(attributes)); |
424 | |
|
425 | 0 | return false; |
426 | 0 | } |
427 | | |
428 | | bool ASTJsonExporter::visit(EnumValue const& _node) |
429 | 0 | { |
430 | 0 | setJsonNode(_node, "EnumValue", { |
431 | 0 | std::make_pair("name", _node.name()), |
432 | 0 | std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), |
433 | 0 | std::make_pair("documentation", toJson(_node.documentation().get())), |
434 | 0 | }); |
435 | 0 | return false; |
436 | 0 | } |
437 | | |
438 | | bool ASTJsonExporter::visit(UserDefinedValueTypeDefinition const& _node) |
439 | 0 | { |
440 | 0 | solAssert(_node.underlyingType(), ""); |
441 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
442 | 0 | std::make_pair("name", _node.name()), |
443 | 0 | std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), |
444 | 0 | std::make_pair("underlyingType", toJson(*_node.underlyingType())) |
445 | 0 | }; |
446 | 0 | addIfSet(attributes, "canonicalName", _node.annotation().canonicalName); |
447 | |
|
448 | 0 | setJsonNode(_node, "UserDefinedValueTypeDefinition", std::move(attributes)); |
449 | |
|
450 | 0 | return false; |
451 | 0 | } |
452 | | |
453 | | bool ASTJsonExporter::visit(ParameterList const& _node) |
454 | 0 | { |
455 | 0 | setJsonNode(_node, "ParameterList", { |
456 | 0 | std::make_pair("parameters", toJson(_node.parameters())) |
457 | 0 | }); |
458 | 0 | return false; |
459 | 0 | } |
460 | | |
461 | | bool ASTJsonExporter::visit(OverrideSpecifier const& _node) |
462 | 0 | { |
463 | 0 | setJsonNode(_node, "OverrideSpecifier", { |
464 | 0 | std::make_pair("overrides", toJson(_node.overrides())) |
465 | 0 | }); |
466 | 0 | return false; |
467 | 0 | } |
468 | | |
469 | | bool ASTJsonExporter::visit(FunctionDefinition const& _node) |
470 | 0 | { |
471 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
472 | 0 | std::make_pair("name", _node.name()), |
473 | 0 | std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), |
474 | 0 | std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json()), |
475 | 0 | std::make_pair("kind", _node.isFree() ? "freeFunction" : TokenTraits::toString(_node.kind())), |
476 | 0 | std::make_pair("stateMutability", stateMutabilityToString(_node.stateMutability())), |
477 | 0 | std::make_pair("virtual", _node.markedVirtual()), |
478 | 0 | std::make_pair("overrides", _node.overrides() ? toJson(*_node.overrides()) : Json()), |
479 | 0 | std::make_pair("parameters", toJson(_node.parameterList())), |
480 | 0 | std::make_pair("returnParameters", toJson(*_node.returnParameterList())), |
481 | 0 | std::make_pair("modifiers", toJson(_node.modifiers())), |
482 | 0 | std::make_pair("body", _node.isImplemented() ? toJson(_node.body()) : Json()), |
483 | 0 | std::make_pair("implemented", _node.isImplemented()), |
484 | 0 | std::make_pair("scope", idOrNull(_node.scope())) |
485 | 0 | }; |
486 | |
|
487 | 0 | std::optional<Visibility> visibility; |
488 | 0 | if (_node.isConstructor()) |
489 | 0 | { |
490 | 0 | if (_node.annotation().contract) |
491 | 0 | visibility = _node.annotation().contract->abstract() ? Visibility::Internal : Visibility::Public; |
492 | 0 | } |
493 | 0 | else |
494 | 0 | visibility = _node.visibility(); |
495 | |
|
496 | 0 | if (visibility) |
497 | 0 | attributes.emplace_back("visibility", Declaration::visibilityToString(*visibility)); |
498 | |
|
499 | 0 | if (_node.isPartOfExternalInterface() && m_stackState > CompilerStack::State::ParsedAndImported) |
500 | 0 | attributes.emplace_back("functionSelector", _node.externalIdentifierHex()); |
501 | 0 | if (!_node.annotation().baseFunctions.empty()) |
502 | 0 | attributes.emplace_back(std::make_pair("baseFunctions", getContainerIds(_node.annotation().baseFunctions, true))); |
503 | |
|
504 | 0 | setJsonNode(_node, "FunctionDefinition", std::move(attributes)); |
505 | 0 | return false; |
506 | 0 | } |
507 | | |
508 | | bool ASTJsonExporter::visit(VariableDeclaration const& _node) |
509 | 0 | { |
510 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
511 | 0 | std::make_pair("name", _node.name()), |
512 | 0 | std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), |
513 | 0 | std::make_pair("typeName", toJson(_node.typeName())), |
514 | 0 | std::make_pair("constant", _node.isConstant()), |
515 | 0 | std::make_pair("mutability", VariableDeclaration::mutabilityToString(_node.mutability())), |
516 | 0 | std::make_pair("stateVariable", _node.isStateVariable()), |
517 | 0 | std::make_pair("storageLocation", location(_node.referenceLocation())), |
518 | 0 | std::make_pair("overrides", _node.overrides() ? toJson(*_node.overrides()) : Json()), |
519 | 0 | std::make_pair("visibility", Declaration::visibilityToString(_node.visibility())), |
520 | 0 | std::make_pair("value", _node.value() ? toJson(*_node.value()) : Json()), |
521 | 0 | std::make_pair("scope", idOrNull(_node.scope())), |
522 | 0 | std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) |
523 | 0 | }; |
524 | 0 | if (_node.isStateVariable() && _node.isPublic()) |
525 | 0 | attributes.emplace_back("functionSelector", _node.externalIdentifierHex()); |
526 | 0 | if (_node.isStateVariable() && _node.documentation()) |
527 | 0 | attributes.emplace_back("documentation", toJson(*_node.documentation())); |
528 | 0 | if (m_inEvent) |
529 | 0 | attributes.emplace_back("indexed", _node.isIndexed()); |
530 | 0 | if (!_node.annotation().baseFunctions.empty()) |
531 | 0 | attributes.emplace_back(std::make_pair("baseFunctions", getContainerIds(_node.annotation().baseFunctions, true))); |
532 | 0 | setJsonNode(_node, "VariableDeclaration", std::move(attributes)); |
533 | 0 | return false; |
534 | 0 | } |
535 | | |
536 | | bool ASTJsonExporter::visit(ModifierDefinition const& _node) |
537 | 0 | { |
538 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
539 | 0 | std::make_pair("name", _node.name()), |
540 | 0 | std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), |
541 | 0 | std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json()), |
542 | 0 | std::make_pair("visibility", Declaration::visibilityToString(_node.visibility())), |
543 | 0 | std::make_pair("parameters", toJson(_node.parameterList())), |
544 | 0 | std::make_pair("virtual", _node.markedVirtual()), |
545 | 0 | std::make_pair("overrides", _node.overrides() ? toJson(*_node.overrides()) : Json()), |
546 | 0 | std::make_pair("body", _node.isImplemented() ? toJson(_node.body()) : Json()) |
547 | 0 | }; |
548 | 0 | if (!_node.annotation().baseFunctions.empty()) |
549 | 0 | attributes.emplace_back(std::make_pair("baseModifiers", getContainerIds(_node.annotation().baseFunctions, true))); |
550 | 0 | setJsonNode(_node, "ModifierDefinition", std::move(attributes)); |
551 | 0 | return false; |
552 | 0 | } |
553 | | |
554 | | bool ASTJsonExporter::visit(ModifierInvocation const& _node) |
555 | 0 | { |
556 | 0 | std::vector<std::pair<std::string, Json>> attributes{ |
557 | 0 | std::make_pair("modifierName", toJson(_node.name())), |
558 | 0 | std::make_pair("arguments", _node.arguments() ? toJson(*_node.arguments()) : Json()) |
559 | 0 | }; |
560 | 0 | if (Declaration const* declaration = _node.name().annotation().referencedDeclaration) |
561 | 0 | { |
562 | 0 | if (dynamic_cast<ModifierDefinition const*>(declaration)) |
563 | 0 | attributes.emplace_back("kind", "modifierInvocation"); |
564 | 0 | else if (dynamic_cast<ContractDefinition const*>(declaration)) |
565 | 0 | attributes.emplace_back("kind", "baseConstructorSpecifier"); |
566 | 0 | } |
567 | 0 | setJsonNode(_node, "ModifierInvocation", std::move(attributes)); |
568 | 0 | return false; |
569 | 0 | } |
570 | | |
571 | | bool ASTJsonExporter::visit(EventDefinition const& _node) |
572 | 0 | { |
573 | 0 | m_inEvent = true; |
574 | 0 | std::vector<std::pair<std::string, Json>> _attributes = { |
575 | 0 | std::make_pair("name", _node.name()), |
576 | 0 | std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), |
577 | 0 | std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json()), |
578 | 0 | std::make_pair("parameters", toJson(_node.parameterList())), |
579 | 0 | std::make_pair("anonymous", _node.isAnonymous()) |
580 | 0 | }; |
581 | 0 | if (m_stackState >= CompilerStack::State::AnalysisSuccessful) |
582 | 0 | _attributes.emplace_back( |
583 | 0 | std::make_pair( |
584 | 0 | "eventSelector", |
585 | 0 | toHex(u256(util::h256::Arith(util::keccak256(_node.functionType(true)->externalSignature())))) |
586 | 0 | )); |
587 | |
|
588 | 0 | setJsonNode(_node, "EventDefinition", std::move(_attributes)); |
589 | 0 | return false; |
590 | 0 | } |
591 | | |
592 | | bool ASTJsonExporter::visit(ErrorDefinition const& _node) |
593 | 0 | { |
594 | 0 | std::vector<std::pair<std::string, Json>> _attributes = { |
595 | 0 | std::make_pair("name", _node.name()), |
596 | 0 | std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), |
597 | 0 | std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json()), |
598 | 0 | std::make_pair("parameters", toJson(_node.parameterList())) |
599 | 0 | }; |
600 | 0 | if (m_stackState >= CompilerStack::State::AnalysisSuccessful) |
601 | 0 | _attributes.emplace_back(std::make_pair("errorSelector", _node.functionType(true)->externalIdentifierHex())); |
602 | |
|
603 | 0 | setJsonNode(_node, "ErrorDefinition", std::move(_attributes)); |
604 | 0 | return false; |
605 | 0 | } |
606 | | |
607 | | bool ASTJsonExporter::visit(ElementaryTypeName const& _node) |
608 | 0 | { |
609 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
610 | 0 | std::make_pair("name", _node.typeName().toString()), |
611 | 0 | std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) |
612 | 0 | }; |
613 | |
|
614 | 0 | if (_node.stateMutability()) |
615 | 0 | attributes.emplace_back(std::make_pair("stateMutability", stateMutabilityToString(*_node.stateMutability()))); |
616 | |
|
617 | 0 | setJsonNode(_node, "ElementaryTypeName", std::move(attributes)); |
618 | 0 | return false; |
619 | 0 | } |
620 | | |
621 | | bool ASTJsonExporter::visit(UserDefinedTypeName const& _node) |
622 | 0 | { |
623 | 0 | setJsonNode(_node, "UserDefinedTypeName", { |
624 | 0 | std::make_pair("pathNode", toJson(_node.pathNode())), |
625 | 0 | std::make_pair("referencedDeclaration", idOrNull(_node.pathNode().annotation().referencedDeclaration)), |
626 | 0 | std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) |
627 | 0 | }); |
628 | 0 | return false; |
629 | 0 | } |
630 | | |
631 | | bool ASTJsonExporter::visit(FunctionTypeName const& _node) |
632 | 0 | { |
633 | 0 | setJsonNode(_node, "FunctionTypeName", { |
634 | 0 | std::make_pair("visibility", Declaration::visibilityToString(_node.visibility())), |
635 | 0 | std::make_pair("stateMutability", stateMutabilityToString(_node.stateMutability())), |
636 | 0 | std::make_pair("parameterTypes", toJson(*_node.parameterTypeList())), |
637 | 0 | std::make_pair("returnParameterTypes", toJson(*_node.returnParameterTypeList())), |
638 | 0 | std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) |
639 | 0 | }); |
640 | 0 | return false; |
641 | 0 | } |
642 | | |
643 | | bool ASTJsonExporter::visit(Mapping const& _node) |
644 | 0 | { |
645 | 0 | setJsonNode(_node, "Mapping", { |
646 | 0 | std::make_pair("keyType", toJson(_node.keyType())), |
647 | 0 | std::make_pair("keyName", _node.keyName()), |
648 | 0 | std::make_pair("keyNameLocation", sourceLocationToString(_node.keyNameLocation())), |
649 | 0 | std::make_pair("valueType", toJson(_node.valueType())), |
650 | 0 | std::make_pair("valueName", _node.valueName()), |
651 | 0 | std::make_pair("valueNameLocation", sourceLocationToString(_node.valueNameLocation())), |
652 | 0 | std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) |
653 | 0 | }); |
654 | 0 | return false; |
655 | 0 | } |
656 | | |
657 | | bool ASTJsonExporter::visit(ArrayTypeName const& _node) |
658 | 0 | { |
659 | 0 | setJsonNode(_node, "ArrayTypeName", { |
660 | 0 | std::make_pair("baseType", toJson(_node.baseType())), |
661 | 0 | std::make_pair("length", toJsonOrNull(_node.length())), |
662 | 0 | std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) |
663 | 0 | }); |
664 | 0 | return false; |
665 | 0 | } |
666 | | |
667 | | bool ASTJsonExporter::visit(InlineAssembly const& _node) |
668 | 0 | { |
669 | 0 | std::vector<std::pair<std::string, Json>> externalReferences; |
670 | |
|
671 | 0 | for (auto const& it: _node.annotation().externalReferences) |
672 | 0 | if (it.first) |
673 | 0 | externalReferences.emplace_back(std::make_pair( |
674 | 0 | it.first->name.str(), |
675 | 0 | inlineAssemblyIdentifierToJson(it) |
676 | 0 | )); |
677 | |
|
678 | 0 | Json externalReferencesJson = Json::array(); |
679 | |
|
680 | 0 | std::sort(externalReferences.begin(), externalReferences.end()); |
681 | 0 | for (Json& it: externalReferences | ranges::views::values) |
682 | 0 | externalReferencesJson.emplace_back(std::move(it)); |
683 | |
|
684 | 0 | auto const& evmDialect = dynamic_cast<solidity::yul::EVMDialect const&>(_node.dialect()); |
685 | |
|
686 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
687 | 0 | std::make_pair("AST", Json(yul::AsmJsonConverter(evmDialect, sourceIndexFromLocation(_node.location()))(_node.operations().root()))), |
688 | 0 | std::make_pair("externalReferences", std::move(externalReferencesJson)), |
689 | 0 | std::make_pair("evmVersion", evmDialect.evmVersion().name()) |
690 | 0 | }; |
691 | | |
692 | | // TODO: Add test in test/linsolidity/ASTJSON/assembly. This requires adding support for eofVersion in ASTJSONTest |
693 | 0 | if (evmDialect.eofVersion()) |
694 | 0 | { |
695 | 0 | solAssert(*evmDialect.eofVersion() > 0); |
696 | 0 | attributes.push_back(std::make_pair("eofVersion", *evmDialect.eofVersion())); |
697 | 0 | } |
698 | | |
699 | 0 | if (_node.flags()) |
700 | 0 | { |
701 | 0 | Json flags = Json::array(); |
702 | 0 | for (auto const& flag: *_node.flags()) |
703 | 0 | if (flag) |
704 | 0 | flags.emplace_back(*flag); |
705 | 0 | else |
706 | 0 | flags.emplace_back(Json()); |
707 | 0 | attributes.emplace_back(std::make_pair("flags", std::move(flags))); |
708 | 0 | } |
709 | 0 | setJsonNode(_node, "InlineAssembly", std::move(attributes)); |
710 | |
|
711 | 0 | return false; |
712 | 0 | } |
713 | | |
714 | | bool ASTJsonExporter::visit(Block const& _node) |
715 | 0 | { |
716 | 0 | setJsonNode(_node, _node.unchecked() ? "UncheckedBlock" : "Block", { |
717 | 0 | std::make_pair("statements", toJson(_node.statements())) |
718 | 0 | }); |
719 | 0 | return false; |
720 | 0 | } |
721 | | |
722 | | bool ASTJsonExporter::visit(PlaceholderStatement const& _node) |
723 | 0 | { |
724 | 0 | setJsonNode(_node, "PlaceholderStatement", {}); |
725 | 0 | return false; |
726 | 0 | } |
727 | | |
728 | | bool ASTJsonExporter::visit(IfStatement const& _node) |
729 | 0 | { |
730 | 0 | setJsonNode(_node, "IfStatement", { |
731 | 0 | std::make_pair("condition", toJson(_node.condition())), |
732 | 0 | std::make_pair("trueBody", toJson(_node.trueStatement())), |
733 | 0 | std::make_pair("falseBody", toJsonOrNull(_node.falseStatement())) |
734 | 0 | }); |
735 | 0 | return false; |
736 | 0 | } |
737 | | |
738 | | bool ASTJsonExporter::visit(TryCatchClause const& _node) |
739 | 0 | { |
740 | 0 | setJsonNode(_node, "TryCatchClause", { |
741 | 0 | std::make_pair("errorName", _node.errorName()), |
742 | 0 | std::make_pair("parameters", toJsonOrNull(_node.parameters())), |
743 | 0 | std::make_pair("block", toJson(_node.block())) |
744 | 0 | }); |
745 | 0 | return false; |
746 | 0 | } |
747 | | |
748 | | bool ASTJsonExporter::visit(TryStatement const& _node) |
749 | 0 | { |
750 | 0 | setJsonNode(_node, "TryStatement", { |
751 | 0 | std::make_pair("externalCall", toJson(_node.externalCall())), |
752 | 0 | std::make_pair("clauses", toJson(_node.clauses())) |
753 | 0 | }); |
754 | 0 | return false; |
755 | 0 | } |
756 | | |
757 | | bool ASTJsonExporter::visit(WhileStatement const& _node) |
758 | 0 | { |
759 | 0 | setJsonNode( |
760 | 0 | _node, |
761 | 0 | _node.isDoWhile() ? "DoWhileStatement" : "WhileStatement", |
762 | 0 | { |
763 | 0 | std::make_pair("condition", toJson(_node.condition())), |
764 | 0 | std::make_pair("body", toJson(_node.body())) |
765 | 0 | } |
766 | 0 | ); |
767 | 0 | return false; |
768 | 0 | } |
769 | | |
770 | | bool ASTJsonExporter::visit(ForStatement const& _node) |
771 | 0 | { |
772 | |
|
773 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
774 | 0 | std::make_pair("initializationExpression", toJsonOrNull(_node.initializationExpression())), |
775 | 0 | std::make_pair("condition", toJsonOrNull(_node.condition())), |
776 | 0 | std::make_pair("loopExpression", toJsonOrNull(_node.loopExpression())), |
777 | 0 | std::make_pair("body", toJson(_node.body())) |
778 | 0 | }; |
779 | |
|
780 | 0 | if (_node.annotation().isSimpleCounterLoop.set()) |
781 | 0 | attributes.emplace_back("isSimpleCounterLoop", *_node.annotation().isSimpleCounterLoop); |
782 | |
|
783 | 0 | setJsonNode(_node, "ForStatement", std::move(attributes)); |
784 | 0 | return false; |
785 | 0 | } |
786 | | |
787 | | bool ASTJsonExporter::visit(Continue const& _node) |
788 | 0 | { |
789 | 0 | setJsonNode(_node, "Continue", {}); |
790 | 0 | return false; |
791 | 0 | } |
792 | | |
793 | | bool ASTJsonExporter::visit(Break const& _node) |
794 | 0 | { |
795 | 0 | setJsonNode(_node, "Break", {}); |
796 | 0 | return false; |
797 | 0 | } |
798 | | |
799 | | bool ASTJsonExporter::visit(Return const& _node) |
800 | 0 | { |
801 | 0 | setJsonNode(_node, "Return", { |
802 | 0 | std::make_pair("expression", toJsonOrNull(_node.expression())), |
803 | 0 | std::make_pair("functionReturnParameters", idOrNull(_node.annotation().functionReturnParameters)) |
804 | 0 | }); |
805 | 0 | return false; |
806 | 0 | } |
807 | | |
808 | | bool ASTJsonExporter::visit(Throw const& _node) |
809 | 0 | { |
810 | 0 | setJsonNode(_node, "Throw", {}); |
811 | 0 | return false; |
812 | 0 | } |
813 | | |
814 | | bool ASTJsonExporter::visit(EmitStatement const& _node) |
815 | 0 | { |
816 | 0 | setJsonNode(_node, "EmitStatement", { |
817 | 0 | std::make_pair("eventCall", toJson(_node.eventCall())) |
818 | 0 | }); |
819 | 0 | return false; |
820 | 0 | } |
821 | | |
822 | | bool ASTJsonExporter::visit(RevertStatement const& _node) |
823 | 0 | { |
824 | 0 | setJsonNode(_node, "RevertStatement", { |
825 | 0 | std::make_pair("errorCall", toJson(_node.errorCall())) |
826 | 0 | }); |
827 | 0 | return false; |
828 | 0 | } |
829 | | |
830 | | bool ASTJsonExporter::visit(VariableDeclarationStatement const& _node) |
831 | 0 | { |
832 | 0 | Json varDecs = Json::array(); |
833 | 0 | for (auto const& v: _node.declarations()) |
834 | 0 | appendMove(varDecs, idOrNull(v.get())); |
835 | 0 | setJsonNode(_node, "VariableDeclarationStatement", { |
836 | 0 | std::make_pair("assignments", std::move(varDecs)), |
837 | 0 | std::make_pair("declarations", toJson(_node.declarations())), |
838 | 0 | std::make_pair("initialValue", toJsonOrNull(_node.initialValue())) |
839 | 0 | }); |
840 | 0 | return false; |
841 | 0 | } |
842 | | |
843 | | bool ASTJsonExporter::visit(ExpressionStatement const& _node) |
844 | 0 | { |
845 | 0 | setJsonNode(_node, "ExpressionStatement", { |
846 | 0 | std::make_pair("expression", toJson(_node.expression())) |
847 | 0 | }); |
848 | 0 | return false; |
849 | 0 | } |
850 | | |
851 | | bool ASTJsonExporter::visit(Conditional const& _node) |
852 | 0 | { |
853 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
854 | 0 | std::make_pair("condition", toJson(_node.condition())), |
855 | 0 | std::make_pair("trueExpression", toJson(_node.trueExpression())), |
856 | 0 | std::make_pair("falseExpression", toJson(_node.falseExpression())) |
857 | 0 | }; |
858 | 0 | appendExpressionAttributes(attributes, _node.annotation()); |
859 | 0 | setJsonNode(_node, "Conditional", std::move(attributes)); |
860 | 0 | return false; |
861 | 0 | } |
862 | | |
863 | | bool ASTJsonExporter::visit(Assignment const& _node) |
864 | 0 | { |
865 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
866 | 0 | std::make_pair("operator", TokenTraits::toString(_node.assignmentOperator())), |
867 | 0 | std::make_pair("leftHandSide", toJson(_node.leftHandSide())), |
868 | 0 | std::make_pair("rightHandSide", toJson(_node.rightHandSide())) |
869 | 0 | }; |
870 | 0 | appendExpressionAttributes(attributes, _node.annotation()); |
871 | 0 | setJsonNode(_node, "Assignment", std::move(attributes)); |
872 | 0 | return false; |
873 | 0 | } |
874 | | |
875 | | bool ASTJsonExporter::visit(TupleExpression const& _node) |
876 | 0 | { |
877 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
878 | 0 | std::make_pair("isInlineArray", Json(_node.isInlineArray())), |
879 | 0 | std::make_pair("components", toJson(_node.components())), |
880 | 0 | }; |
881 | 0 | appendExpressionAttributes(attributes, _node.annotation()); |
882 | 0 | setJsonNode(_node, "TupleExpression", std::move(attributes)); |
883 | 0 | return false; |
884 | 0 | } |
885 | | |
886 | | bool ASTJsonExporter::visit(UnaryOperation const& _node) |
887 | 0 | { |
888 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
889 | 0 | std::make_pair("prefix", _node.isPrefixOperation()), |
890 | 0 | std::make_pair("operator", TokenTraits::toString(_node.getOperator())), |
891 | 0 | std::make_pair("subExpression", toJson(_node.subExpression())) |
892 | 0 | }; |
893 | | // NOTE: This annotation is guaranteed to be set but only if we didn't stop at the parsing stage. |
894 | 0 | if (_node.annotation().userDefinedFunction.set() && *_node.annotation().userDefinedFunction != nullptr) |
895 | 0 | attributes.emplace_back("function", nodeId(**_node.annotation().userDefinedFunction)); |
896 | 0 | appendExpressionAttributes(attributes, _node.annotation()); |
897 | 0 | setJsonNode(_node, "UnaryOperation", std::move(attributes)); |
898 | 0 | return false; |
899 | 0 | } |
900 | | |
901 | | bool ASTJsonExporter::visit(BinaryOperation const& _node) |
902 | 0 | { |
903 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
904 | 0 | std::make_pair("operator", TokenTraits::toString(_node.getOperator())), |
905 | 0 | std::make_pair("leftExpression", toJson(_node.leftExpression())), |
906 | 0 | std::make_pair("rightExpression", toJson(_node.rightExpression())), |
907 | 0 | std::make_pair("commonType", typePointerToJson(_node.annotation().commonType)), |
908 | 0 | }; |
909 | | // NOTE: This annotation is guaranteed to be set but only if we didn't stop at the parsing stage. |
910 | 0 | if (_node.annotation().userDefinedFunction.set() && *_node.annotation().userDefinedFunction != nullptr) |
911 | 0 | attributes.emplace_back("function", nodeId(**_node.annotation().userDefinedFunction)); |
912 | 0 | appendExpressionAttributes(attributes, _node.annotation()); |
913 | 0 | setJsonNode(_node, "BinaryOperation", std::move(attributes)); |
914 | 0 | return false; |
915 | 0 | } |
916 | | |
917 | | bool ASTJsonExporter::visit(FunctionCall const& _node) |
918 | 0 | { |
919 | 0 | Json names = Json::array(); |
920 | 0 | for (auto const& name: _node.names()) |
921 | 0 | names.push_back(Json(*name)); |
922 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
923 | 0 | std::make_pair("expression", toJson(_node.expression())), |
924 | 0 | std::make_pair("names", std::move(names)), |
925 | 0 | std::make_pair("nameLocations", sourceLocationsToJson(_node.nameLocations())), |
926 | 0 | std::make_pair("arguments", toJson(_node.arguments())), |
927 | 0 | std::make_pair("tryCall", _node.annotation().tryCall) |
928 | 0 | }; |
929 | |
|
930 | 0 | if (_node.annotation().kind.set()) |
931 | 0 | { |
932 | 0 | FunctionCallKind nodeKind = *_node.annotation().kind; |
933 | 0 | attributes.emplace_back("kind", functionCallKind(nodeKind)); |
934 | 0 | } |
935 | |
|
936 | 0 | appendExpressionAttributes(attributes, _node.annotation()); |
937 | 0 | setJsonNode(_node, "FunctionCall", std::move(attributes)); |
938 | 0 | return false; |
939 | 0 | } |
940 | | |
941 | | bool ASTJsonExporter::visit(FunctionCallOptions const& _node) |
942 | 0 | { |
943 | 0 | Json names = Json::array(); |
944 | 0 | for (auto const& name: _node.names()) |
945 | 0 | names.emplace_back(Json(*name)); |
946 | |
|
947 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
948 | 0 | std::make_pair("expression", toJson(_node.expression())), |
949 | 0 | std::make_pair("names", std::move(names)), |
950 | 0 | std::make_pair("options", toJson(_node.options())), |
951 | 0 | }; |
952 | 0 | appendExpressionAttributes(attributes, _node.annotation()); |
953 | |
|
954 | 0 | setJsonNode(_node, "FunctionCallOptions", std::move(attributes)); |
955 | 0 | return false; |
956 | 0 | } |
957 | | |
958 | | bool ASTJsonExporter::visit(NewExpression const& _node) |
959 | 0 | { |
960 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
961 | 0 | std::make_pair("typeName", toJson(_node.typeName())) |
962 | 0 | }; |
963 | 0 | appendExpressionAttributes(attributes, _node.annotation()); |
964 | 0 | setJsonNode(_node, "NewExpression", std::move(attributes)); |
965 | 0 | return false; |
966 | 0 | } |
967 | | |
968 | | bool ASTJsonExporter::visit(MemberAccess const& _node) |
969 | 0 | { |
970 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
971 | 0 | std::make_pair("memberName", _node.memberName()), |
972 | 0 | std::make_pair("memberLocation", Json(sourceLocationToString(_node.memberLocation()))), |
973 | 0 | std::make_pair("expression", toJson(_node.expression())), |
974 | 0 | std::make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)), |
975 | 0 | }; |
976 | 0 | appendExpressionAttributes(attributes, _node.annotation()); |
977 | 0 | setJsonNode(_node, "MemberAccess", std::move(attributes)); |
978 | 0 | return false; |
979 | 0 | } |
980 | | |
981 | | bool ASTJsonExporter::visit(IndexAccess const& _node) |
982 | 0 | { |
983 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
984 | 0 | std::make_pair("baseExpression", toJson(_node.baseExpression())), |
985 | 0 | std::make_pair("indexExpression", toJsonOrNull(_node.indexExpression())), |
986 | 0 | }; |
987 | 0 | appendExpressionAttributes(attributes, _node.annotation()); |
988 | 0 | setJsonNode(_node, "IndexAccess", std::move(attributes)); |
989 | 0 | return false; |
990 | 0 | } |
991 | | |
992 | | bool ASTJsonExporter::visit(IndexRangeAccess const& _node) |
993 | 0 | { |
994 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
995 | 0 | std::make_pair("baseExpression", toJson(_node.baseExpression())), |
996 | 0 | std::make_pair("startExpression", toJsonOrNull(_node.startExpression())), |
997 | 0 | std::make_pair("endExpression", toJsonOrNull(_node.endExpression())), |
998 | 0 | }; |
999 | 0 | appendExpressionAttributes(attributes, _node.annotation()); |
1000 | 0 | setJsonNode(_node, "IndexRangeAccess", std::move(attributes)); |
1001 | 0 | return false; |
1002 | 0 | } |
1003 | | |
1004 | | bool ASTJsonExporter::visit(Identifier const& _node) |
1005 | 0 | { |
1006 | 0 | Json overloads = Json::array(); |
1007 | 0 | for (auto const& dec: _node.annotation().overloadedDeclarations) |
1008 | 0 | overloads.emplace_back(nodeId(*dec)); |
1009 | 0 | setJsonNode(_node, "Identifier", { |
1010 | 0 | std::make_pair("name", _node.name()), |
1011 | 0 | std::make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)), |
1012 | 0 | std::make_pair("overloadedDeclarations", overloads), |
1013 | 0 | std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)), |
1014 | 0 | std::make_pair("argumentTypes", typePointerToJson(_node.annotation().arguments)) |
1015 | 0 | }); |
1016 | 0 | return false; |
1017 | 0 | } |
1018 | | |
1019 | | bool ASTJsonExporter::visit(ElementaryTypeNameExpression const& _node) |
1020 | 0 | { |
1021 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
1022 | 0 | std::make_pair("typeName", toJson(_node.type())) |
1023 | 0 | }; |
1024 | 0 | appendExpressionAttributes(attributes, _node.annotation()); |
1025 | 0 | setJsonNode(_node, "ElementaryTypeNameExpression", std::move(attributes)); |
1026 | 0 | return false; |
1027 | 0 | } |
1028 | | |
1029 | | bool ASTJsonExporter::visit(Literal const& _node) |
1030 | 0 | { |
1031 | 0 | Json value = _node.value(); |
1032 | 0 | if (!util::validateUTF8(_node.value())) |
1033 | 0 | value = Json(); |
1034 | 0 | Token subdenomination = Token(_node.subDenomination()); |
1035 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
1036 | 0 | std::make_pair("kind", literalTokenKind(_node.token())), |
1037 | 0 | std::make_pair("value", value), |
1038 | 0 | std::make_pair("hexValue", util::toHex(util::asBytes(_node.value()))), |
1039 | 0 | std::make_pair( |
1040 | 0 | "subdenomination", |
1041 | 0 | subdenomination == Token::Illegal ? |
1042 | 0 | Json() : |
1043 | 0 | Json(TokenTraits::toString(subdenomination)) |
1044 | 0 | ) |
1045 | 0 | }; |
1046 | 0 | appendExpressionAttributes(attributes, _node.annotation()); |
1047 | 0 | setJsonNode(_node, "Literal", std::move(attributes)); |
1048 | 0 | return false; |
1049 | 0 | } |
1050 | | |
1051 | | bool ASTJsonExporter::visit(StructuredDocumentation const& _node) |
1052 | 0 | { |
1053 | 0 | Json text = *_node.text(); |
1054 | 0 | std::vector<std::pair<std::string, Json>> attributes = { |
1055 | 0 | std::make_pair("text", text) |
1056 | 0 | }; |
1057 | 0 | setJsonNode(_node, "StructuredDocumentation", std::move(attributes)); |
1058 | 0 | return false; |
1059 | 0 | } |
1060 | | |
1061 | | void ASTJsonExporter::endVisit(EventDefinition const&) |
1062 | 0 | { |
1063 | 0 | m_inEvent = false; |
1064 | 0 | } |
1065 | | |
1066 | | bool ASTJsonExporter::visitNode(ASTNode const& _node) |
1067 | 0 | { |
1068 | 0 | solAssert(false, _node.experimentalSolidityOnly() ? |
1069 | 0 | "Attempt to export an AST of experimental solidity." : |
1070 | 0 | "Attempt to export an AST that contains unexpected nodes." |
1071 | 0 | ); |
1072 | 0 | return false; |
1073 | 0 | } |
1074 | | |
1075 | | std::string ASTJsonExporter::location(VariableDeclaration::Location _location) |
1076 | 0 | { |
1077 | 0 | switch (_location) |
1078 | 0 | { |
1079 | 0 | case VariableDeclaration::Location::Unspecified: |
1080 | 0 | return "default"; |
1081 | 0 | case VariableDeclaration::Location::Storage: |
1082 | 0 | return "storage"; |
1083 | 0 | case VariableDeclaration::Location::Memory: |
1084 | 0 | return "memory"; |
1085 | 0 | case VariableDeclaration::Location::CallData: |
1086 | 0 | return "calldata"; |
1087 | 0 | case VariableDeclaration::Location::Transient: |
1088 | 0 | return "transient"; |
1089 | 0 | } |
1090 | | // To make the compiler happy |
1091 | 0 | return {}; |
1092 | 0 | } |
1093 | | |
1094 | | std::string ASTJsonExporter::contractKind(ContractKind _kind) |
1095 | 0 | { |
1096 | 0 | switch (_kind) |
1097 | 0 | { |
1098 | 0 | case ContractKind::Interface: |
1099 | 0 | return "interface"; |
1100 | 0 | case ContractKind::Contract: |
1101 | 0 | return "contract"; |
1102 | 0 | case ContractKind::Library: |
1103 | 0 | return "library"; |
1104 | 0 | } |
1105 | | |
1106 | | // To make the compiler happy |
1107 | 0 | return {}; |
1108 | 0 | } |
1109 | | |
1110 | | std::string ASTJsonExporter::functionCallKind(FunctionCallKind _kind) |
1111 | 0 | { |
1112 | 0 | switch (_kind) |
1113 | 0 | { |
1114 | 0 | case FunctionCallKind::FunctionCall: |
1115 | 0 | return "functionCall"; |
1116 | 0 | case FunctionCallKind::TypeConversion: |
1117 | 0 | return "typeConversion"; |
1118 | 0 | case FunctionCallKind::StructConstructorCall: |
1119 | 0 | return "structConstructorCall"; |
1120 | 0 | default: |
1121 | 0 | solAssert(false, "Unknown kind of function call."); |
1122 | 0 | } |
1123 | 0 | } |
1124 | | |
1125 | | std::string ASTJsonExporter::literalTokenKind(Token _token) |
1126 | 0 | { |
1127 | 0 | switch (_token) |
1128 | 0 | { |
1129 | 0 | case Token::Number: |
1130 | 0 | return "number"; |
1131 | 0 | case Token::StringLiteral: |
1132 | 0 | return "string"; |
1133 | 0 | case Token::UnicodeStringLiteral: |
1134 | 0 | return "unicodeString"; |
1135 | 0 | case Token::HexStringLiteral: |
1136 | 0 | return "hexString"; |
1137 | 0 | case Token::TrueLiteral: |
1138 | 0 | case Token::FalseLiteral: |
1139 | 0 | return "bool"; |
1140 | 0 | default: |
1141 | 0 | solAssert(false, "Unknown kind of literal token."); |
1142 | 0 | } |
1143 | 0 | } |
1144 | | |
1145 | | std::string ASTJsonExporter::type(Expression const& _expression) |
1146 | 0 | { |
1147 | 0 | return _expression.annotation().type ? _expression.annotation().type->toString() : "Unknown"; |
1148 | 0 | } |
1149 | | |
1150 | | std::string ASTJsonExporter::type(VariableDeclaration const& _varDecl) |
1151 | 0 | { |
1152 | 0 | return _varDecl.annotation().type ? _varDecl.annotation().type->toString() : "Unknown"; |
1153 | 0 | } |
1154 | | |
1155 | | } |