2015-01-05 14:46:40 +00:00
|
|
|
/*
|
2019-02-13 15:56:46 +00:00
|
|
|
This file is part of solidity.
|
2015-01-05 14:46:40 +00:00
|
|
|
|
2019-02-13 15:56:46 +00:00
|
|
|
solidity is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
2015-01-05 14:46:40 +00:00
|
|
|
|
2019-02-13 15:56:46 +00:00
|
|
|
solidity is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
2015-01-05 14:46:40 +00:00
|
|
|
|
2019-02-13 15:56:46 +00:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
2015-01-05 14:46:40 +00:00
|
|
|
*/
|
2020-07-17 14:54:12 +00:00
|
|
|
// SPDX-License-Identifier: GPL-3.0
|
2015-01-05 14:46:40 +00:00
|
|
|
/**
|
2017-07-27 14:40:01 +00:00
|
|
|
* @date 2017
|
2015-01-05 14:46:40 +00:00
|
|
|
* Converts the AST into json format
|
|
|
|
*/
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
#include <libsolidity/ast/ASTJsonExporter.h>
|
2018-12-17 14:33:15 +00:00
|
|
|
|
2015-10-20 22:21:52 +00:00
|
|
|
#include <libsolidity/ast/AST.h>
|
2020-07-08 20:08:50 +00:00
|
|
|
#include <libsolidity/ast/TypeProvider.h>
|
2019-10-15 10:38:12 +00:00
|
|
|
|
|
|
|
#include <libyul/AsmJsonConverter.h>
|
2020-10-29 14:00:27 +00:00
|
|
|
#include <libyul/AST.h>
|
2020-01-14 11:46:47 +00:00
|
|
|
#include <libyul/backends/evm/EVMDialect.h>
|
|
|
|
|
2020-01-06 10:52:23 +00:00
|
|
|
#include <libsolutil/JSON.h>
|
|
|
|
#include <libsolutil/UTF8.h>
|
2021-09-22 10:06:57 +00:00
|
|
|
#include <libsolutil/CommonData.h>
|
2021-10-11 08:16:52 +00:00
|
|
|
#include <libsolutil/Visitor.h>
|
2022-02-10 14:14:08 +00:00
|
|
|
#include <libsolutil/Keccak256.h>
|
2019-10-15 10:38:12 +00:00
|
|
|
|
2018-12-17 14:33:15 +00:00
|
|
|
#include <boost/algorithm/string/join.hpp>
|
2021-08-24 17:08:18 +00:00
|
|
|
|
2020-04-01 03:04:29 +00:00
|
|
|
#include <utility>
|
2019-08-19 14:26:14 +00:00
|
|
|
#include <vector>
|
|
|
|
#include <algorithm>
|
2020-06-02 13:42:46 +00:00
|
|
|
#include <limits>
|
2020-09-10 10:01:23 +00:00
|
|
|
#include <type_traits>
|
2020-10-29 14:07:09 +00:00
|
|
|
#include <range/v3/view/map.hpp>
|
2019-08-19 14:26:14 +00:00
|
|
|
|
Type recognition workaround for some GCC compilers
Looks like somewhat old GCC compilers, namely 12.2.1, cannot recognize a
string literal sometimes. Let's help it to avoid error logs like this
one:
```
[ 75%] Building CXX object libsolidity/CMakeFiles/solidity.dir/codegen/ir/IRGeneratorForStatements.cpp.o
cd /builddir/build/BUILD/solidity-0.8.18/redhat-linux-build/libsolidity && /usr/bin/g++ -DBOOST_ATOMIC_DYN_LINK -DBOOST_ATOMIC_NO_LIB -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_FILESYSTEM_NO_LIB -DBOOST_SYSTEM_DYN_LINK -DBOOST_SYSTEM_NO_LIB -DFMT_HEADER_ONLY=1 -DHAVE_CVC4 -DHAVE_Z3 -I/builddir/build/BUILD/solidity-0.8.18/redhat-linux-build/include -I/builddir/build/BUILD/solidity-0.8.18 -isystem /usr/include/z3 -O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -fuse-ld=gold -O3 -DNDEBUG -fstack-protector-strong -Wimplicit-fallthrough -fmacro-prefix-map=/builddir/build/BUILD/solidity-0.8.18=/solidity -Wpessimizing-move -Wredundant-move -Wall -Wextra -Werror -pedantic -Wmissing-declarations -Wno-unknown-pragmas -Wsign-conversion -Wconversion -Wextra-semi -Wduplicated-cond -Wlogical-op -fdiagnostics-color -std=c++17 -MD -MT libsolidity/CMakeFiles/solidity.dir/codegen/ir/IRGeneratorForStatements.cpp.o -MF CMakeFiles/solidity.dir/codegen/ir/IRGeneratorForStatements.cpp.o.d -o CMakeFiles/solidity.dir/codegen/ir/IRGeneratorForStatements.cpp.o -c /builddir/build/BUILD/solidity-0.8.18/libsolidity/codegen/ir/IRGeneratorForStatements.cpp
In file included from /usr/include/c++/12/string:40,
from /builddir/build/BUILD/solidity-0.8.18/libsolidity/ast/ASTForward.h:27,
from /builddir/build/BUILD/solidity-0.8.18/libsolidity/ast/AST.h:26,
from /builddir/build/BUILD/solidity-0.8.18/libsolidity/ast/ASTVisitor.h:26,
from /builddir/build/BUILD/solidity-0.8.18/libsolidity/codegen/ir/IRGeneratorForStatements.h:24,
from /builddir/build/BUILD/solidity-0.8.18/libsolidity/codegen/ir/IRGeneratorForStatements.cpp:22:
In function 'std::char_traits<char>::copy(char*, char const*, unsigned long)',
inlined from 'std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy(char*, char const*, unsigned long)' at /usr/include/c++/12/bits/basic_string.h:423:21,
inlined from 'std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_replace(unsigned long, unsigned long, char const*, unsigned long)' at /usr/include/c++/12/bits/basic_string.tcc:532:22,
inlined from 'std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::assign(char const*)' at /usr/include/c++/12/bits/basic_string.h:1647:19,
inlined from 'std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator=(char const*)' at /usr/include/c++/12/bits/basic_string.h:815:28,
inlined from '(anonymous namespace)::CopyTranslate::translateReference(solidity::yul::Identifier const&)' at /builddir/build/BUILD/solidity-0.8.18/libsolidity/codegen/ir/IRGeneratorForStatements.cpp:182:13:
/usr/include/c++/12/bits/char_traits.h:431:56: error: 'memcpy' accessing 9223372036854775810 or more bytes at offsets -4611686018427387902 and [-4611686018427387903, 4611686018427387904] may overlap up to 9223372036854775813 bytes at offset -3 [-Werror=restrict]
431 | return static_cast<char_type*>(__builtin_memcpy(__s1, __s2, __n));
| ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~
cc1plus: all warnings being treated as errors
gmake[2]: *** [libsolidity/CMakeFiles/solidity.dir/build.make:695: libsolidity/CMakeFiles/solidity.dir/codegen/ir/IRGeneratorForStatements.cpp.o] Error 1
gmake[2]: *** Waiting for unfinished jobs....
gmake[2]: Leaving directory '/builddir/build/BUILD/solidity-0.8.18/redhat-linux-build'
gmake[1]: *** [CMakeFiles/Makefile2:414: libsolidity/CMakeFiles/solidity.dir/all] Error 2
gmake[1]: Leaving directory '/builddir/build/BUILD/solidity-0.8.18/redhat-linux-build'
gmake: *** [Makefile:139: all] Error 2
```
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
2022-12-25 21:43:26 +00:00
|
|
|
using namespace std::string_literals;
|
2019-12-11 16:31:36 +00:00
|
|
|
using namespace solidity::langutil;
|
2015-01-05 14:46:40 +00:00
|
|
|
|
2020-09-10 10:01:23 +00:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
|
|
|
template<typename V, template<typename> typename C>
|
2023-08-14 12:39:16 +00:00
|
|
|
void addIfSet(std::vector<std::pair<std::string, Json::Value>>& _attributes, std::string const& _name, C<V> const& _value)
|
2020-09-10 10:01:23 +00:00
|
|
|
{
|
|
|
|
if constexpr (std::is_same_v<C<V>, solidity::util::SetOnce<V>>)
|
|
|
|
{
|
|
|
|
if (!_value.set())
|
|
|
|
return;
|
|
|
|
}
|
2023-08-14 12:39:16 +00:00
|
|
|
else if constexpr (std::is_same_v<C<V>, std::optional<V>>)
|
2020-09-10 10:01:23 +00:00
|
|
|
{
|
|
|
|
if (!_value.has_value())
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_attributes.emplace_back(_name, *_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-12-11 16:31:36 +00:00
|
|
|
namespace solidity::frontend
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
|
|
|
|
2023-08-14 12:39:16 +00:00
|
|
|
ASTJsonExporter::ASTJsonExporter(CompilerStack::State _stackState, std::map<std::string, unsigned> _sourceIndices):
|
2020-07-08 20:08:50 +00:00
|
|
|
m_stackState(_stackState),
|
2020-04-01 03:04:29 +00:00
|
|
|
m_sourceIndices(std::move(_sourceIndices))
|
2017-03-20 18:06:17 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
void ASTJsonExporter::setJsonNode(
|
2016-07-01 08:14:50 +00:00
|
|
|
ASTNode const& _node,
|
2023-08-14 12:39:16 +00:00
|
|
|
std::string const& _nodeName,
|
|
|
|
std::initializer_list<std::pair<std::string, Json::Value>>&& _attributes
|
2016-07-01 08:14:50 +00:00
|
|
|
)
|
2017-03-13 14:19:41 +00:00
|
|
|
{
|
2022-06-16 16:05:51 +00:00
|
|
|
ASTJsonExporter::setJsonNode(
|
2017-03-13 14:19:41 +00:00
|
|
|
_node,
|
|
|
|
_nodeName,
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>>(std::move(_attributes))
|
2017-03-13 14:19:41 +00:00
|
|
|
);
|
|
|
|
}
|
2017-03-20 18:06:17 +00:00
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
void ASTJsonExporter::setJsonNode(
|
2017-03-13 14:19:41 +00:00
|
|
|
ASTNode const& _node,
|
2023-08-14 12:39:16 +00:00
|
|
|
std::string const& _nodeType,
|
|
|
|
std::vector<std::pair<std::string, Json::Value>>&& _attributes
|
2017-03-13 14:19:41 +00:00
|
|
|
)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2017-03-20 18:06:17 +00:00
|
|
|
m_currentValue = Json::objectValue;
|
|
|
|
m_currentValue["id"] = nodeId(_node);
|
|
|
|
m_currentValue["src"] = sourceLocationToString(_node.location());
|
2021-02-09 14:12:59 +00:00
|
|
|
if (auto const* documented = dynamic_cast<Documented const*>(&_node))
|
|
|
|
if (documented->documentation())
|
|
|
|
m_currentValue["documentation"] = *documented->documentation();
|
2020-11-20 14:35:53 +00:00
|
|
|
m_currentValue["nodeType"] = _nodeType;
|
|
|
|
for (auto& e: _attributes)
|
|
|
|
m_currentValue[e.first] = std::move(e.second);
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 12:39:16 +00:00
|
|
|
std::optional<size_t> ASTJsonExporter::sourceIndexFromLocation(SourceLocation const& _location) const
|
2016-07-01 08:14:50 +00:00
|
|
|
{
|
2021-06-29 12:38:59 +00:00
|
|
|
if (_location.sourceName && m_sourceIndices.count(*_location.sourceName))
|
|
|
|
return m_sourceIndices.at(*_location.sourceName);
|
2019-10-15 10:38:12 +00:00
|
|
|
else
|
2023-08-14 12:39:16 +00:00
|
|
|
return std::nullopt;
|
2019-10-15 10:38:12 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 12:39:16 +00:00
|
|
|
std::string ASTJsonExporter::sourceLocationToString(SourceLocation const& _location) const
|
2019-10-15 10:38:12 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::optional<size_t> sourceIndexOpt = sourceIndexFromLocation(_location);
|
2016-07-01 08:14:50 +00:00
|
|
|
int length = -1;
|
|
|
|
if (_location.start >= 0 && _location.end >= 0)
|
|
|
|
length = _location.end - _location.start;
|
2023-08-14 12:39:16 +00:00
|
|
|
return std::to_string(_location.start) + ":" + std::to_string(length) + ":" + (sourceIndexOpt.has_value() ? std::to_string(sourceIndexOpt.value()) : "-1");
|
2016-07-01 08:14:50 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 12:39:16 +00:00
|
|
|
Json::Value ASTJsonExporter::sourceLocationsToJson(std::vector<SourceLocation> const& _sourceLocations) const
|
2022-06-16 17:21:38 +00:00
|
|
|
{
|
|
|
|
Json::Value locations = Json::arrayValue;
|
|
|
|
|
|
|
|
for (SourceLocation const& location: _sourceLocations)
|
|
|
|
locations.append(sourceLocationToString(location));
|
|
|
|
|
|
|
|
return locations;
|
|
|
|
}
|
|
|
|
|
2023-08-14 12:39:16 +00:00
|
|
|
std::string ASTJsonExporter::namePathToString(std::vector<ASTString> const& _namePath)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
Type recognition workaround for some GCC compilers
Looks like somewhat old GCC compilers, namely 12.2.1, cannot recognize a
string literal sometimes. Let's help it to avoid error logs like this
one:
```
[ 75%] Building CXX object libsolidity/CMakeFiles/solidity.dir/codegen/ir/IRGeneratorForStatements.cpp.o
cd /builddir/build/BUILD/solidity-0.8.18/redhat-linux-build/libsolidity && /usr/bin/g++ -DBOOST_ATOMIC_DYN_LINK -DBOOST_ATOMIC_NO_LIB -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_FILESYSTEM_NO_LIB -DBOOST_SYSTEM_DYN_LINK -DBOOST_SYSTEM_NO_LIB -DFMT_HEADER_ONLY=1 -DHAVE_CVC4 -DHAVE_Z3 -I/builddir/build/BUILD/solidity-0.8.18/redhat-linux-build/include -I/builddir/build/BUILD/solidity-0.8.18 -isystem /usr/include/z3 -O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -fuse-ld=gold -O3 -DNDEBUG -fstack-protector-strong -Wimplicit-fallthrough -fmacro-prefix-map=/builddir/build/BUILD/solidity-0.8.18=/solidity -Wpessimizing-move -Wredundant-move -Wall -Wextra -Werror -pedantic -Wmissing-declarations -Wno-unknown-pragmas -Wsign-conversion -Wconversion -Wextra-semi -Wduplicated-cond -Wlogical-op -fdiagnostics-color -std=c++17 -MD -MT libsolidity/CMakeFiles/solidity.dir/codegen/ir/IRGeneratorForStatements.cpp.o -MF CMakeFiles/solidity.dir/codegen/ir/IRGeneratorForStatements.cpp.o.d -o CMakeFiles/solidity.dir/codegen/ir/IRGeneratorForStatements.cpp.o -c /builddir/build/BUILD/solidity-0.8.18/libsolidity/codegen/ir/IRGeneratorForStatements.cpp
In file included from /usr/include/c++/12/string:40,
from /builddir/build/BUILD/solidity-0.8.18/libsolidity/ast/ASTForward.h:27,
from /builddir/build/BUILD/solidity-0.8.18/libsolidity/ast/AST.h:26,
from /builddir/build/BUILD/solidity-0.8.18/libsolidity/ast/ASTVisitor.h:26,
from /builddir/build/BUILD/solidity-0.8.18/libsolidity/codegen/ir/IRGeneratorForStatements.h:24,
from /builddir/build/BUILD/solidity-0.8.18/libsolidity/codegen/ir/IRGeneratorForStatements.cpp:22:
In function 'std::char_traits<char>::copy(char*, char const*, unsigned long)',
inlined from 'std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy(char*, char const*, unsigned long)' at /usr/include/c++/12/bits/basic_string.h:423:21,
inlined from 'std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_replace(unsigned long, unsigned long, char const*, unsigned long)' at /usr/include/c++/12/bits/basic_string.tcc:532:22,
inlined from 'std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::assign(char const*)' at /usr/include/c++/12/bits/basic_string.h:1647:19,
inlined from 'std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator=(char const*)' at /usr/include/c++/12/bits/basic_string.h:815:28,
inlined from '(anonymous namespace)::CopyTranslate::translateReference(solidity::yul::Identifier const&)' at /builddir/build/BUILD/solidity-0.8.18/libsolidity/codegen/ir/IRGeneratorForStatements.cpp:182:13:
/usr/include/c++/12/bits/char_traits.h:431:56: error: 'memcpy' accessing 9223372036854775810 or more bytes at offsets -4611686018427387902 and [-4611686018427387903, 4611686018427387904] may overlap up to 9223372036854775813 bytes at offset -3 [-Werror=restrict]
431 | return static_cast<char_type*>(__builtin_memcpy(__s1, __s2, __n));
| ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~
cc1plus: all warnings being treated as errors
gmake[2]: *** [libsolidity/CMakeFiles/solidity.dir/build.make:695: libsolidity/CMakeFiles/solidity.dir/codegen/ir/IRGeneratorForStatements.cpp.o] Error 1
gmake[2]: *** Waiting for unfinished jobs....
gmake[2]: Leaving directory '/builddir/build/BUILD/solidity-0.8.18/redhat-linux-build'
gmake[1]: *** [CMakeFiles/Makefile2:414: libsolidity/CMakeFiles/solidity.dir/all] Error 2
gmake[1]: Leaving directory '/builddir/build/BUILD/solidity-0.8.18/redhat-linux-build'
gmake: *** [Makefile:139: all] Error 2
```
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
2022-12-25 21:43:26 +00:00
|
|
|
return boost::algorithm::join(_namePath, "."s);
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-07-05 17:45:01 +00:00
|
|
|
Json::Value ASTJsonExporter::typePointerToJson(Type const* _tp, bool _withoutDataLocation)
|
2017-03-20 18:06:17 +00:00
|
|
|
{
|
|
|
|
Json::Value typeDescriptions(Json::objectValue);
|
2022-07-05 17:45:01 +00:00
|
|
|
typeDescriptions["typeString"] = _tp ? Json::Value(_tp->toString(_withoutDataLocation)) : Json::nullValue;
|
2017-03-20 18:06:17 +00:00
|
|
|
typeDescriptions["typeIdentifier"] = _tp ? Json::Value(_tp->identifier()) : Json::nullValue;
|
|
|
|
return typeDescriptions;
|
|
|
|
|
|
|
|
}
|
2022-06-16 16:05:51 +00:00
|
|
|
Json::Value ASTJsonExporter::typePointerToJson(std::optional<FuncCallArguments> const& _tps)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2017-03-20 18:06:17 +00:00
|
|
|
if (_tps)
|
|
|
|
{
|
|
|
|
Json::Value arguments(Json::arrayValue);
|
2019-03-19 16:12:21 +00:00
|
|
|
for (auto const& tp: _tps->types)
|
2017-07-27 14:40:01 +00:00
|
|
|
appendMove(arguments, typePointerToJson(tp));
|
2017-03-20 18:06:17 +00:00
|
|
|
return arguments;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return Json::nullValue;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
void ASTJsonExporter::appendExpressionAttributes(
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>>& _attributes,
|
2017-03-20 18:06:17 +00:00
|
|
|
ExpressionAnnotation const& _annotation
|
|
|
|
)
|
2015-01-28 07:50:53 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> exprAttributes = {
|
|
|
|
std::make_pair("typeDescriptions", typePointerToJson(_annotation.type)),
|
|
|
|
std::make_pair("argumentTypes", typePointerToJson(_annotation.arguments))
|
2017-03-20 18:06:17 +00:00
|
|
|
};
|
2020-09-10 10:01:23 +00:00
|
|
|
|
|
|
|
addIfSet(exprAttributes, "isLValue", _annotation.isLValue);
|
|
|
|
addIfSet(exprAttributes, "isPure", _annotation.isPure);
|
|
|
|
addIfSet(exprAttributes, "isConstant", _annotation.isConstant);
|
|
|
|
|
2020-07-08 20:08:50 +00:00
|
|
|
if (m_stackState > CompilerStack::State::ParsedAndImported)
|
|
|
|
exprAttributes.emplace_back("lValueRequested", _annotation.willBeWrittenTo);
|
|
|
|
|
2017-05-19 13:45:01 +00:00
|
|
|
_attributes += exprAttributes;
|
2015-01-28 07:50:53 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 12:39:16 +00:00
|
|
|
Json::Value ASTJsonExporter::inlineAssemblyIdentifierToJson(std::pair<yul::Identifier const*, InlineAssemblyAnnotation::ExternalIdentifierInfo> _info) const
|
2017-05-17 13:52:45 +00:00
|
|
|
{
|
|
|
|
Json::Value tuple(Json::objectValue);
|
2021-09-20 15:51:01 +00:00
|
|
|
tuple["src"] = sourceLocationToString(nativeLocationOf(*_info.first));
|
2017-05-17 13:52:45 +00:00
|
|
|
tuple["declaration"] = idOrNull(_info.second.declaration);
|
2020-11-05 13:39:39 +00:00
|
|
|
tuple["isSlot"] = Json::Value(_info.second.suffix == "slot");
|
|
|
|
tuple["isOffset"] = Json::Value(_info.second.suffix == "offset");
|
2021-09-22 10:06:57 +00:00
|
|
|
|
2020-11-05 13:39:39 +00:00
|
|
|
if (!_info.second.suffix.empty())
|
|
|
|
tuple["suffix"] = Json::Value(_info.second.suffix);
|
2021-09-22 10:06:57 +00:00
|
|
|
|
2017-05-22 18:36:41 +00:00
|
|
|
tuple["valueSize"] = Json::Value(Json::LargestUInt(_info.second.valueSize));
|
2021-09-22 10:06:57 +00:00
|
|
|
|
2017-05-17 13:52:45 +00:00
|
|
|
return tuple;
|
|
|
|
}
|
2017-03-20 18:06:17 +00:00
|
|
|
|
2023-08-14 12:39:16 +00:00
|
|
|
void ASTJsonExporter::print(std::ostream& _stream, ASTNode const& _node, util::JsonFormat const& _format)
|
2016-08-18 12:51:17 +00:00
|
|
|
{
|
2021-10-22 02:05:49 +00:00
|
|
|
_stream << util::jsonPrint(toJson(_node), _format);
|
2017-03-20 18:06:17 +00:00
|
|
|
}
|
2016-08-18 12:51:17 +00:00
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
Json::Value ASTJsonExporter::toJson(ASTNode const& _node)
|
2017-03-20 18:06:17 +00:00
|
|
|
{
|
|
|
|
_node.accept(*this);
|
2020-08-18 14:23:55 +00:00
|
|
|
return util::removeNullMembers(std::move(m_currentValue));
|
2017-03-20 18:06:17 +00:00
|
|
|
}
|
2016-08-18 12:51:17 +00:00
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(SourceUnit const& _node)
|
2017-03-20 18:06:17 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("license", _node.licenseString() ? Json::Value(*_node.licenseString()) : Json::nullValue),
|
|
|
|
std::make_pair("nodes", toJson(_node.nodes())),
|
2020-09-10 10:01:23 +00:00
|
|
|
};
|
|
|
|
|
2023-04-27 17:39:59 +00:00
|
|
|
if (_node.experimentalSolidity())
|
|
|
|
attributes.emplace_back("experimentalSolidity", Json::Value(_node.experimentalSolidity()));
|
|
|
|
|
2020-09-10 10:01:23 +00:00
|
|
|
if (_node.annotation().exportedSymbols.set())
|
2017-03-20 18:06:17 +00:00
|
|
|
{
|
2020-09-10 10:01:23 +00:00
|
|
|
Json::Value exportedSymbols = Json::objectValue;
|
|
|
|
for (auto const& sym: *_node.annotation().exportedSymbols)
|
2017-03-20 18:06:17 +00:00
|
|
|
{
|
2020-09-10 10:01:23 +00:00
|
|
|
exportedSymbols[sym.first] = Json::arrayValue;
|
|
|
|
for (Declaration const* overload: sym.second)
|
|
|
|
exportedSymbols[sym.first].append(nodeId(*overload));
|
2017-03-20 18:06:17 +00:00
|
|
|
}
|
2020-09-10 10:01:23 +00:00
|
|
|
|
|
|
|
attributes.emplace_back("exportedSymbols", exportedSymbols);
|
|
|
|
};
|
|
|
|
|
|
|
|
addIfSet(attributes, "absolutePath", _node.annotation().path);
|
|
|
|
|
|
|
|
setJsonNode(_node, "SourceUnit", std::move(attributes));
|
2020-07-08 20:08:50 +00:00
|
|
|
|
2017-03-20 18:06:17 +00:00
|
|
|
return false;
|
2016-08-18 12:51:17 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(PragmaDirective const& _node)
|
2016-08-19 17:57:21 +00:00
|
|
|
{
|
|
|
|
Json::Value literals(Json::arrayValue);
|
|
|
|
for (auto const& literal: _node.literals())
|
|
|
|
literals.append(literal);
|
2020-07-08 20:08:50 +00:00
|
|
|
setJsonNode(_node, "PragmaDirective", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("literals", std::move(literals))
|
2017-03-20 18:06:17 +00:00
|
|
|
});
|
|
|
|
return false;
|
2016-08-19 17:57:21 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(ImportDirective const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("file", _node.path()),
|
|
|
|
std::make_pair("sourceUnit", idOrNull(_node.annotation().sourceUnit)),
|
|
|
|
std::make_pair("scope", idOrNull(_node.scope()))
|
2017-03-20 18:06:17 +00:00
|
|
|
};
|
2020-09-10 10:01:23 +00:00
|
|
|
|
|
|
|
addIfSet(attributes, "absolutePath", _node.annotation().absolutePath);
|
|
|
|
|
2018-12-10 18:02:39 +00:00
|
|
|
attributes.emplace_back("unitAlias", _node.name());
|
2021-01-21 15:01:39 +00:00
|
|
|
attributes.emplace_back("nameLocation", Json::Value(sourceLocationToString(_node.nameLocation())));
|
|
|
|
|
2017-03-20 18:06:17 +00:00
|
|
|
Json::Value symbolAliases(Json::arrayValue);
|
|
|
|
for (auto const& symbolAlias: _node.symbolAliases())
|
|
|
|
{
|
|
|
|
Json::Value tuple(Json::objectValue);
|
2019-09-25 12:14:44 +00:00
|
|
|
solAssert(symbolAlias.symbol, "");
|
2019-11-21 14:47:10 +00:00
|
|
|
tuple["foreign"] = toJson(*symbolAlias.symbol);
|
2019-09-25 12:14:44 +00:00
|
|
|
tuple["local"] = symbolAlias.alias ? Json::Value(*symbolAlias.alias) : Json::nullValue;
|
2021-01-21 15:01:39 +00:00
|
|
|
tuple["nameLocation"] = sourceLocationToString(_node.nameLocation());
|
2017-03-20 18:06:17 +00:00
|
|
|
symbolAliases.append(tuple);
|
|
|
|
}
|
2018-12-10 18:02:39 +00:00
|
|
|
attributes.emplace_back("symbolAliases", std::move(symbolAliases));
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "ImportDirective", std::move(attributes));
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(ContractDefinition const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("name", _node.name()),
|
|
|
|
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
|
|
|
std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
|
|
|
|
std::make_pair("contractKind", contractKind(_node.contractKind())),
|
|
|
|
std::make_pair("abstract", _node.abstract()),
|
|
|
|
std::make_pair("baseContracts", toJson(_node.baseContracts())),
|
|
|
|
std::make_pair("contractDependencies", getContainerIds(_node.annotation().contractDependencies | ranges::views::keys)),
|
2021-02-23 13:13:52 +00:00
|
|
|
// Do not require call graph because the AST is also created for incorrect sources.
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("usedEvents", getContainerIds(_node.interfaceEvents(false))),
|
|
|
|
std::make_pair("usedErrors", getContainerIds(_node.interfaceErrors(false))),
|
|
|
|
std::make_pair("nodes", toJson(_node.subNodes())),
|
|
|
|
std::make_pair("scope", idOrNull(_node.scope()))
|
2020-09-10 10:01:23 +00:00
|
|
|
};
|
2021-09-28 09:05:52 +00:00
|
|
|
addIfSet(attributes, "canonicalName", _node.annotation().canonicalName);
|
2020-09-10 10:01:23 +00:00
|
|
|
|
|
|
|
if (_node.annotation().unimplementedDeclarations.has_value())
|
|
|
|
attributes.emplace_back("fullyImplemented", _node.annotation().unimplementedDeclarations->empty());
|
|
|
|
if (!_node.annotation().linearizedBaseContracts.empty())
|
|
|
|
attributes.emplace_back("linearizedBaseContracts", getContainerIds(_node.annotation().linearizedBaseContracts));
|
|
|
|
|
2023-05-02 13:30:59 +00:00
|
|
|
if (!_node.annotation().internalFunctionIDs.empty())
|
|
|
|
{
|
|
|
|
Json::Value internalFunctionIDs(Json::objectValue);
|
|
|
|
for (auto const& [functionDefinition, internalFunctionID]: _node.annotation().internalFunctionIDs)
|
2023-08-14 12:39:16 +00:00
|
|
|
internalFunctionIDs[std::to_string(functionDefinition->id())] = internalFunctionID;
|
2023-05-02 13:30:59 +00:00
|
|
|
attributes.emplace_back("internalFunctionIDs", std::move(internalFunctionIDs));
|
|
|
|
}
|
|
|
|
|
2020-09-10 10:01:23 +00:00
|
|
|
setJsonNode(_node, "ContractDefinition", std::move(attributes));
|
2017-03-20 18:06:17 +00:00
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(IdentifierPath const& _node)
|
2020-08-31 15:37:03 +00:00
|
|
|
{
|
2022-06-08 16:13:49 +00:00
|
|
|
Json::Value nameLocations = Json::arrayValue;
|
|
|
|
|
|
|
|
for (SourceLocation location: _node.pathLocations())
|
|
|
|
nameLocations.append(sourceLocationToString(location));
|
|
|
|
|
2020-08-31 15:37:03 +00:00
|
|
|
setJsonNode(_node, "IdentifierPath", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("name", namePathToString(_node.path())),
|
|
|
|
std::make_pair("nameLocations", nameLocations),
|
|
|
|
std::make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration))
|
2020-08-31 15:37:03 +00:00
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(InheritanceSpecifier const& _node)
|
2016-08-16 13:25:25 +00:00
|
|
|
{
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "InheritanceSpecifier", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("baseName", toJson(_node.name())),
|
|
|
|
std::make_pair("arguments", _node.arguments() ? toJson(*_node.arguments()) : Json::nullValue)
|
2017-03-20 18:06:17 +00:00
|
|
|
});
|
|
|
|
return false;
|
2016-08-16 14:28:28 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(UsingForDirective const& _node)
|
2016-08-16 14:28:28 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("typeName", _node.typeName() ? toJson(*_node.typeName()) : Json::nullValue)
|
2021-10-11 08:16:52 +00:00
|
|
|
};
|
2022-07-06 07:17:59 +00:00
|
|
|
|
2021-10-11 08:16:52 +00:00
|
|
|
if (_node.usesBraces())
|
|
|
|
{
|
|
|
|
Json::Value functionList;
|
2022-07-06 07:17:59 +00:00
|
|
|
for (auto&& [function, op]: _node.functionsAndOperators())
|
2021-10-11 08:16:52 +00:00
|
|
|
{
|
|
|
|
Json::Value functionNode;
|
2022-07-06 07:17:59 +00:00
|
|
|
if (!op.has_value())
|
|
|
|
functionNode["function"] = toJson(*function);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
functionNode["definition"] = toJson(*function);
|
2023-08-14 12:39:16 +00:00
|
|
|
functionNode["operator"] = std::string(TokenTraits::toString(*op));
|
2022-07-06 07:17:59 +00:00
|
|
|
}
|
2022-08-23 17:28:45 +00:00
|
|
|
functionList.append(std::move(functionNode));
|
2021-10-11 08:16:52 +00:00
|
|
|
}
|
2022-08-23 17:28:45 +00:00
|
|
|
attributes.emplace_back("functionList", std::move(functionList));
|
2021-10-11 08:16:52 +00:00
|
|
|
}
|
|
|
|
else
|
2022-07-06 07:17:59 +00:00
|
|
|
{
|
|
|
|
auto const& functionAndOperators = _node.functionsAndOperators();
|
|
|
|
solAssert(_node.functionsAndOperators().size() == 1);
|
|
|
|
solAssert(!functionAndOperators.front().second.has_value());
|
|
|
|
attributes.emplace_back("libraryName", toJson(*(functionAndOperators.front().first)));
|
|
|
|
}
|
2021-11-16 16:01:09 +00:00
|
|
|
attributes.emplace_back("global", _node.global());
|
2021-10-11 08:16:52 +00:00
|
|
|
|
2022-08-23 17:28:45 +00:00
|
|
|
setJsonNode(_node, "UsingForDirective", std::move(attributes));
|
2021-10-11 08:16:52 +00:00
|
|
|
|
2017-03-20 18:06:17 +00:00
|
|
|
return false;
|
2016-08-16 13:25:25 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(StructDefinition const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("name", _node.name()),
|
|
|
|
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
|
|
|
std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
|
|
|
|
std::make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
|
|
|
|
std::make_pair("members", toJson(_node.members())),
|
|
|
|
std::make_pair("scope", idOrNull(_node.scope()))
|
2020-09-10 10:01:23 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
addIfSet(attributes,"canonicalName", _node.annotation().canonicalName);
|
|
|
|
|
|
|
|
setJsonNode(_node, "StructDefinition", std::move(attributes));
|
|
|
|
|
2017-03-20 18:06:17 +00:00
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(EnumDefinition const& _node)
|
2016-08-16 15:18:57 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("name", _node.name()),
|
|
|
|
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
|
|
|
std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
|
|
|
|
std::make_pair("members", toJson(_node.members()))
|
2020-09-10 10:01:23 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
addIfSet(attributes,"canonicalName", _node.annotation().canonicalName);
|
|
|
|
|
|
|
|
setJsonNode(_node, "EnumDefinition", std::move(attributes));
|
|
|
|
|
2017-03-20 18:06:17 +00:00
|
|
|
return false;
|
2016-08-16 15:18:57 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(EnumValue const& _node)
|
2016-08-16 15:38:24 +00:00
|
|
|
{
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "EnumValue", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("name", _node.name()),
|
|
|
|
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
2017-03-20 18:06:17 +00:00
|
|
|
});
|
|
|
|
return false;
|
2016-08-16 15:38:24 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(UserDefinedValueTypeDefinition const& _node)
|
2021-08-17 15:34:23 +00:00
|
|
|
{
|
|
|
|
solAssert(_node.underlyingType(), "");
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("name", _node.name()),
|
|
|
|
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
|
|
|
std::make_pair("underlyingType", toJson(*_node.underlyingType()))
|
2021-08-17 15:34:23 +00:00
|
|
|
};
|
2021-09-28 09:05:52 +00:00
|
|
|
addIfSet(attributes, "canonicalName", _node.annotation().canonicalName);
|
2021-08-17 15:34:23 +00:00
|
|
|
|
|
|
|
setJsonNode(_node, "UserDefinedValueTypeDefinition", std::move(attributes));
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(ParameterList const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "ParameterList", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("parameters", toJson(_node.parameters()))
|
2017-03-20 18:06:17 +00:00
|
|
|
});
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(OverrideSpecifier const& _node)
|
2019-11-21 14:47:10 +00:00
|
|
|
{
|
|
|
|
setJsonNode(_node, "OverrideSpecifier", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("overrides", toJson(_node.overrides()))
|
2019-11-21 14:47:10 +00:00
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(FunctionDefinition const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("name", _node.name()),
|
|
|
|
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
|
|
|
std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
|
|
|
|
std::make_pair("kind", _node.isFree() ? "freeFunction" : TokenTraits::toString(_node.kind())),
|
|
|
|
std::make_pair("stateMutability", stateMutabilityToString(_node.stateMutability())),
|
|
|
|
std::make_pair("virtual", _node.markedVirtual()),
|
|
|
|
std::make_pair("overrides", _node.overrides() ? toJson(*_node.overrides()) : Json::nullValue),
|
|
|
|
std::make_pair("parameters", toJson(_node.parameterList())),
|
|
|
|
std::make_pair("returnParameters", toJson(*_node.returnParameterList())),
|
|
|
|
std::make_pair("modifiers", toJson(_node.modifiers())),
|
|
|
|
std::make_pair("body", _node.isImplemented() ? toJson(_node.body()) : Json::nullValue),
|
|
|
|
std::make_pair("implemented", _node.isImplemented()),
|
|
|
|
std::make_pair("scope", idOrNull(_node.scope()))
|
2017-03-20 18:06:17 +00:00
|
|
|
};
|
2020-06-10 16:19:42 +00:00
|
|
|
|
2023-08-14 12:39:16 +00:00
|
|
|
std::optional<Visibility> visibility;
|
2020-07-08 20:08:50 +00:00
|
|
|
if (_node.isConstructor())
|
|
|
|
{
|
|
|
|
if (_node.annotation().contract)
|
|
|
|
visibility = _node.annotation().contract->abstract() ? Visibility::Internal : Visibility::Public;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
visibility = _node.visibility();
|
|
|
|
|
|
|
|
if (visibility)
|
|
|
|
attributes.emplace_back("visibility", Declaration::visibilityToString(*visibility));
|
|
|
|
|
|
|
|
if (_node.isPartOfExternalInterface() && m_stackState > CompilerStack::State::ParsedAndImported)
|
2019-12-09 00:26:23 +00:00
|
|
|
attributes.emplace_back("functionSelector", _node.externalIdentifierHex());
|
2019-12-05 02:17:28 +00:00
|
|
|
if (!_node.annotation().baseFunctions.empty())
|
2023-08-14 12:39:16 +00:00
|
|
|
attributes.emplace_back(std::make_pair("baseFunctions", getContainerIds(_node.annotation().baseFunctions, true)));
|
2023-03-15 13:38:03 +00:00
|
|
|
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "FunctionDefinition", std::move(attributes));
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(VariableDeclaration const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("name", _node.name()),
|
|
|
|
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
|
|
|
std::make_pair("typeName", toJson(_node.typeName())),
|
|
|
|
std::make_pair("constant", _node.isConstant()),
|
|
|
|
std::make_pair("mutability", VariableDeclaration::mutabilityToString(_node.mutability())),
|
|
|
|
std::make_pair("stateVariable", _node.isStateVariable()),
|
|
|
|
std::make_pair("storageLocation", location(_node.referenceLocation())),
|
|
|
|
std::make_pair("overrides", _node.overrides() ? toJson(*_node.overrides()) : Json::nullValue),
|
|
|
|
std::make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
|
|
|
|
std::make_pair("value", _node.value() ? toJson(*_node.value()) : Json::nullValue),
|
|
|
|
std::make_pair("scope", idOrNull(_node.scope())),
|
|
|
|
std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true))
|
2017-03-20 18:06:17 +00:00
|
|
|
};
|
2019-12-09 00:26:23 +00:00
|
|
|
if (_node.isStateVariable() && _node.isPublic())
|
|
|
|
attributes.emplace_back("functionSelector", _node.externalIdentifierHex());
|
2020-03-24 22:44:39 +00:00
|
|
|
if (_node.isStateVariable() && _node.documentation())
|
|
|
|
attributes.emplace_back("documentation", toJson(*_node.documentation()));
|
2017-03-13 14:19:41 +00:00
|
|
|
if (m_inEvent)
|
2018-12-10 18:02:39 +00:00
|
|
|
attributes.emplace_back("indexed", _node.isIndexed());
|
2019-12-11 14:32:28 +00:00
|
|
|
if (!_node.annotation().baseFunctions.empty())
|
2023-08-14 12:39:16 +00:00
|
|
|
attributes.emplace_back(std::make_pair("baseFunctions", getContainerIds(_node.annotation().baseFunctions, true)));
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "VariableDeclaration", std::move(attributes));
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(ModifierDefinition const& _node)
|
2016-08-17 14:23:20 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("name", _node.name()),
|
|
|
|
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
|
|
|
std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
|
|
|
|
std::make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
|
|
|
|
std::make_pair("parameters", toJson(_node.parameterList())),
|
|
|
|
std::make_pair("virtual", _node.markedVirtual()),
|
|
|
|
std::make_pair("overrides", _node.overrides() ? toJson(*_node.overrides()) : Json::nullValue),
|
|
|
|
std::make_pair("body", _node.isImplemented() ? toJson(_node.body()) : Json::nullValue)
|
2019-12-09 15:54:52 +00:00
|
|
|
};
|
|
|
|
if (!_node.annotation().baseFunctions.empty())
|
2023-08-14 12:39:16 +00:00
|
|
|
attributes.emplace_back(std::make_pair("baseModifiers", getContainerIds(_node.annotation().baseFunctions, true)));
|
2019-12-09 15:54:52 +00:00
|
|
|
setJsonNode(_node, "ModifierDefinition", std::move(attributes));
|
2017-03-20 18:06:17 +00:00
|
|
|
return false;
|
2016-08-17 14:23:20 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(ModifierInvocation const& _node)
|
2016-08-17 14:52:14 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes{
|
|
|
|
std::make_pair("modifierName", toJson(_node.name())),
|
|
|
|
std::make_pair("arguments", _node.arguments() ? toJson(*_node.arguments()) : Json::nullValue)
|
2021-03-11 13:39:27 +00:00
|
|
|
};
|
|
|
|
if (Declaration const* declaration = _node.name().annotation().referencedDeclaration)
|
|
|
|
{
|
|
|
|
if (dynamic_cast<ModifierDefinition const*>(declaration))
|
|
|
|
attributes.emplace_back("kind", "modifierInvocation");
|
2021-03-24 10:19:38 +00:00
|
|
|
else if (dynamic_cast<ContractDefinition const*>(declaration))
|
|
|
|
attributes.emplace_back("kind", "baseConstructorSpecifier");
|
2021-03-11 13:39:27 +00:00
|
|
|
}
|
2022-08-23 17:28:45 +00:00
|
|
|
setJsonNode(_node, "ModifierInvocation", std::move(attributes));
|
2017-03-20 18:06:17 +00:00
|
|
|
return false;
|
2016-08-17 14:52:14 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(EventDefinition const& _node)
|
2016-08-17 14:52:14 +00:00
|
|
|
{
|
2017-03-13 14:19:41 +00:00
|
|
|
m_inEvent = true;
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> _attributes = {
|
|
|
|
std::make_pair("name", _node.name()),
|
|
|
|
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
|
|
|
std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
|
|
|
|
std::make_pair("parameters", toJson(_node.parameterList())),
|
|
|
|
std::make_pair("anonymous", _node.isAnonymous())
|
2022-02-10 14:14:08 +00:00
|
|
|
};
|
2023-06-12 10:03:34 +00:00
|
|
|
if (m_stackState >= CompilerStack::State::AnalysisSuccessful)
|
2022-02-10 14:14:08 +00:00
|
|
|
_attributes.emplace_back(
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair(
|
2022-02-10 14:14:08 +00:00
|
|
|
"eventSelector",
|
2022-03-07 04:25:35 +00:00
|
|
|
toHex(u256(util::h256::Arith(util::keccak256(_node.functionType(true)->externalSignature()))))
|
2022-02-10 14:14:08 +00:00
|
|
|
));
|
|
|
|
|
|
|
|
setJsonNode(_node, "EventDefinition", std::move(_attributes));
|
2017-03-20 18:06:17 +00:00
|
|
|
return false;
|
2016-08-17 14:52:14 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(ErrorDefinition const& _node)
|
2021-01-28 11:56:22 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> _attributes = {
|
|
|
|
std::make_pair("name", _node.name()),
|
|
|
|
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
|
|
|
std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
|
|
|
|
std::make_pair("parameters", toJson(_node.parameterList()))
|
2022-02-10 14:14:08 +00:00
|
|
|
};
|
2023-06-12 10:03:34 +00:00
|
|
|
if (m_stackState >= CompilerStack::State::AnalysisSuccessful)
|
2023-08-14 12:39:16 +00:00
|
|
|
_attributes.emplace_back(std::make_pair("errorSelector", _node.functionType(true)->externalIdentifierHex()));
|
2022-02-10 14:14:08 +00:00
|
|
|
|
|
|
|
setJsonNode(_node, "ErrorDefinition", std::move(_attributes));
|
2021-01-28 11:56:22 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(ElementaryTypeName const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("name", _node.typeName().toString()),
|
|
|
|
std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true))
|
2018-09-10 10:49:15 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if (_node.stateMutability())
|
2023-08-14 12:39:16 +00:00
|
|
|
attributes.emplace_back(std::make_pair("stateMutability", stateMutabilityToString(*_node.stateMutability())));
|
2018-09-10 10:49:15 +00:00
|
|
|
|
|
|
|
setJsonNode(_node, "ElementaryTypeName", std::move(attributes));
|
2017-03-20 18:06:17 +00:00
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(UserDefinedTypeName const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "UserDefinedTypeName", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("pathNode", toJson(_node.pathNode())),
|
|
|
|
std::make_pair("referencedDeclaration", idOrNull(_node.pathNode().annotation().referencedDeclaration)),
|
|
|
|
std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true))
|
2015-10-06 10:35:10 +00:00
|
|
|
});
|
2017-03-20 18:06:17 +00:00
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(FunctionTypeName const& _node)
|
2016-09-27 19:37:32 +00:00
|
|
|
{
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "FunctionTypeName", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
|
|
|
|
std::make_pair("stateMutability", stateMutabilityToString(_node.stateMutability())),
|
|
|
|
std::make_pair("parameterTypes", toJson(*_node.parameterTypeList())),
|
|
|
|
std::make_pair("returnParameterTypes", toJson(*_node.returnParameterTypeList())),
|
|
|
|
std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true))
|
2017-03-20 18:06:17 +00:00
|
|
|
});
|
|
|
|
return false;
|
2016-09-27 19:37:32 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(Mapping const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "Mapping", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("keyType", toJson(_node.keyType())),
|
|
|
|
std::make_pair("keyName", _node.keyName()),
|
|
|
|
std::make_pair("keyNameLocation", sourceLocationToString(_node.keyNameLocation())),
|
|
|
|
std::make_pair("valueType", toJson(_node.valueType())),
|
|
|
|
std::make_pair("valueName", _node.valueName()),
|
|
|
|
std::make_pair("valueNameLocation", sourceLocationToString(_node.valueNameLocation())),
|
|
|
|
std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true))
|
2017-03-20 18:06:17 +00:00
|
|
|
});
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(ArrayTypeName const& _node)
|
2016-08-17 15:09:21 +00:00
|
|
|
{
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "ArrayTypeName", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("baseType", toJson(_node.baseType())),
|
|
|
|
std::make_pair("length", toJsonOrNull(_node.length())),
|
|
|
|
std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true))
|
2017-03-20 18:06:17 +00:00
|
|
|
});
|
|
|
|
return false;
|
2016-08-17 15:09:21 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(InlineAssembly const& _node)
|
2016-02-22 01:13:41 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> externalReferences;
|
2020-01-14 11:46:47 +00:00
|
|
|
|
2019-06-24 13:31:32 +00:00
|
|
|
for (auto const& it: _node.annotation().externalReferences)
|
2017-05-17 13:52:45 +00:00
|
|
|
if (it.first)
|
2023-08-14 12:39:16 +00:00
|
|
|
externalReferences.emplace_back(std::make_pair(
|
2019-10-15 10:38:12 +00:00
|
|
|
it.first->name.str(),
|
|
|
|
inlineAssemblyIdentifierToJson(it)
|
|
|
|
));
|
2020-01-14 11:46:47 +00:00
|
|
|
|
2019-10-15 10:38:12 +00:00
|
|
|
Json::Value externalReferencesJson = Json::arrayValue;
|
2020-01-14 11:46:47 +00:00
|
|
|
|
2022-08-14 00:07:01 +00:00
|
|
|
std::sort(externalReferences.begin(), externalReferences.end());
|
2021-08-24 17:08:18 +00:00
|
|
|
for (Json::Value& it: externalReferences | ranges::views::values)
|
|
|
|
externalReferencesJson.append(std::move(it));
|
2019-10-15 10:38:12 +00:00
|
|
|
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("AST", Json::Value(yul::AsmJsonConverter(sourceIndexFromLocation(_node.location()))(_node.operations()))),
|
|
|
|
std::make_pair("externalReferences", std::move(externalReferencesJson)),
|
|
|
|
std::make_pair("evmVersion", dynamic_cast<solidity::yul::EVMDialect const&>(_node.dialect()).evmVersion().name())
|
2022-02-14 12:21:15 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if (_node.flags())
|
|
|
|
{
|
|
|
|
Json::Value flags(Json::arrayValue);
|
|
|
|
for (auto const& flag: *_node.flags())
|
|
|
|
if (flag)
|
|
|
|
flags.append(*flag);
|
|
|
|
else
|
|
|
|
flags.append(Json::nullValue);
|
2023-08-14 12:39:16 +00:00
|
|
|
attributes.emplace_back(std::make_pair("flags", std::move(flags)));
|
2022-02-14 12:21:15 +00:00
|
|
|
}
|
2022-08-23 17:28:45 +00:00
|
|
|
setJsonNode(_node, "InlineAssembly", std::move(attributes));
|
2020-01-14 11:46:47 +00:00
|
|
|
|
2017-03-20 18:06:17 +00:00
|
|
|
return false;
|
2016-02-22 01:13:41 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(Block const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2020-07-22 08:28:04 +00:00
|
|
|
setJsonNode(_node, _node.unchecked() ? "UncheckedBlock" : "Block", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("statements", toJson(_node.statements()))
|
2017-03-20 18:06:17 +00:00
|
|
|
});
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(PlaceholderStatement const& _node)
|
2016-08-17 15:20:17 +00:00
|
|
|
{
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "PlaceholderStatement", {});
|
|
|
|
return false;
|
2016-08-17 15:20:17 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(IfStatement const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "IfStatement", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("condition", toJson(_node.condition())),
|
|
|
|
std::make_pair("trueBody", toJson(_node.trueStatement())),
|
|
|
|
std::make_pair("falseBody", toJsonOrNull(_node.falseStatement()))
|
2017-03-20 18:06:17 +00:00
|
|
|
});
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(TryCatchClause const& _node)
|
2019-09-02 14:17:02 +00:00
|
|
|
{
|
|
|
|
setJsonNode(_node, "TryCatchClause", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("errorName", _node.errorName()),
|
|
|
|
std::make_pair("parameters", toJsonOrNull(_node.parameters())),
|
|
|
|
std::make_pair("block", toJson(_node.block()))
|
2019-09-02 14:17:02 +00:00
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(TryStatement const& _node)
|
2019-09-02 14:17:02 +00:00
|
|
|
{
|
|
|
|
setJsonNode(_node, "TryStatement", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("externalCall", toJson(_node.externalCall())),
|
|
|
|
std::make_pair("clauses", toJson(_node.clauses()))
|
2019-09-02 14:17:02 +00:00
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(WhileStatement const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(
|
2016-07-30 07:13:05 +00:00
|
|
|
_node,
|
|
|
|
_node.isDoWhile() ? "DoWhileStatement" : "WhileStatement",
|
2017-03-20 18:06:17 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("condition", toJson(_node.condition())),
|
|
|
|
std::make_pair("body", toJson(_node.body()))
|
2017-03-20 18:06:17 +00:00
|
|
|
}
|
|
|
|
);
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(ForStatement const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2022-08-10 13:48:06 +00:00
|
|
|
|
2023-06-13 11:41:36 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("initializationExpression", toJsonOrNull(_node.initializationExpression())),
|
|
|
|
std::make_pair("condition", toJsonOrNull(_node.condition())),
|
|
|
|
std::make_pair("loopExpression", toJsonOrNull(_node.loopExpression())),
|
|
|
|
std::make_pair("body", toJson(_node.body()))
|
2022-08-10 13:48:06 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if (_node.annotation().isSimpleCounterLoop.set())
|
2023-06-13 11:41:36 +00:00
|
|
|
attributes.emplace_back(std::make_pair("isSimpleCounterLoop", *_node.annotation().isSimpleCounterLoop));
|
2022-08-10 13:48:06 +00:00
|
|
|
|
|
|
|
setJsonNode(_node, "ForStatement", std::move(attributes));
|
2017-03-20 18:06:17 +00:00
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(Continue const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "Continue", {});
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(Break const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "Break", {});
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(Return const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "Return", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("expression", toJsonOrNull(_node.expression())),
|
|
|
|
std::make_pair("functionReturnParameters", idOrNull(_node.annotation().functionReturnParameters))
|
2017-03-20 18:06:17 +00:00
|
|
|
});
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(Throw const& _node)
|
2015-09-15 14:33:14 +00:00
|
|
|
{
|
2018-02-16 15:55:21 +00:00
|
|
|
setJsonNode(_node, "Throw", {});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(EmitStatement const& _node)
|
2018-02-16 15:55:21 +00:00
|
|
|
{
|
|
|
|
setJsonNode(_node, "EmitStatement", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("eventCall", toJson(_node.eventCall()))
|
2018-02-16 15:55:21 +00:00
|
|
|
});
|
2017-03-20 18:06:17 +00:00
|
|
|
return false;
|
2015-09-15 14:33:14 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(RevertStatement const& _node)
|
2021-03-16 18:17:57 +00:00
|
|
|
{
|
|
|
|
setJsonNode(_node, "RevertStatement", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("errorCall", toJson(_node.errorCall()))
|
2021-03-16 18:17:57 +00:00
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(VariableDeclarationStatement const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2017-03-20 18:06:17 +00:00
|
|
|
Json::Value varDecs(Json::arrayValue);
|
2018-07-04 16:34:24 +00:00
|
|
|
for (auto const& v: _node.declarations())
|
|
|
|
appendMove(varDecs, idOrNull(v.get()));
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "VariableDeclarationStatement", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("assignments", std::move(varDecs)),
|
|
|
|
std::make_pair("declarations", toJson(_node.declarations())),
|
|
|
|
std::make_pair("initialValue", toJsonOrNull(_node.initialValue()))
|
2017-03-20 18:06:17 +00:00
|
|
|
});
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(ExpressionStatement const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "ExpressionStatement", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("expression", toJson(_node.expression()))
|
2017-03-20 18:06:17 +00:00
|
|
|
});
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(Conditional const& _node)
|
2015-12-22 16:47:00 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("condition", toJson(_node.condition())),
|
|
|
|
std::make_pair("trueExpression", toJson(_node.trueExpression())),
|
|
|
|
std::make_pair("falseExpression", toJson(_node.falseExpression()))
|
2017-03-20 18:06:17 +00:00
|
|
|
};
|
2017-04-25 16:47:11 +00:00
|
|
|
appendExpressionAttributes(attributes, _node.annotation());
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "Conditional", std::move(attributes));
|
|
|
|
return false;
|
2015-12-22 16:47:00 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(Assignment const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("operator", TokenTraits::toString(_node.assignmentOperator())),
|
|
|
|
std::make_pair("leftHandSide", toJson(_node.leftHandSide())),
|
|
|
|
std::make_pair("rightHandSide", toJson(_node.rightHandSide()))
|
2017-03-20 18:06:17 +00:00
|
|
|
};
|
2017-04-25 16:47:11 +00:00
|
|
|
appendExpressionAttributes(attributes, _node.annotation());
|
2020-07-08 20:08:50 +00:00
|
|
|
setJsonNode(_node, "Assignment", std::move(attributes));
|
2017-03-20 18:06:17 +00:00
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(TupleExpression const& _node)
|
2015-10-12 21:02:35 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("isInlineArray", Json::Value(_node.isInlineArray())),
|
|
|
|
std::make_pair("components", toJson(_node.components())),
|
2017-03-20 18:06:17 +00:00
|
|
|
};
|
2017-04-25 16:47:11 +00:00
|
|
|
appendExpressionAttributes(attributes, _node.annotation());
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "TupleExpression", std::move(attributes));
|
|
|
|
return false;
|
2015-10-12 21:02:35 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(UnaryOperation const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("prefix", _node.isPrefixOperation()),
|
|
|
|
std::make_pair("operator", TokenTraits::toString(_node.getOperator())),
|
|
|
|
std::make_pair("subExpression", toJson(_node.subExpression()))
|
2017-03-20 18:06:17 +00:00
|
|
|
};
|
2022-07-06 07:17:59 +00:00
|
|
|
// NOTE: This annotation is guaranteed to be set but only if we didn't stop at the parsing stage.
|
|
|
|
if (_node.annotation().userDefinedFunction.set() && *_node.annotation().userDefinedFunction != nullptr)
|
|
|
|
attributes.emplace_back("function", nodeId(**_node.annotation().userDefinedFunction));
|
2017-04-25 16:47:11 +00:00
|
|
|
appendExpressionAttributes(attributes, _node.annotation());
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "UnaryOperation", std::move(attributes));
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(BinaryOperation const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("operator", TokenTraits::toString(_node.getOperator())),
|
|
|
|
std::make_pair("leftExpression", toJson(_node.leftExpression())),
|
|
|
|
std::make_pair("rightExpression", toJson(_node.rightExpression())),
|
|
|
|
std::make_pair("commonType", typePointerToJson(_node.annotation().commonType)),
|
2017-03-20 18:06:17 +00:00
|
|
|
};
|
2022-07-06 07:17:59 +00:00
|
|
|
// NOTE: This annotation is guaranteed to be set but only if we didn't stop at the parsing stage.
|
|
|
|
if (_node.annotation().userDefinedFunction.set() && *_node.annotation().userDefinedFunction != nullptr)
|
|
|
|
attributes.emplace_back("function", nodeId(**_node.annotation().userDefinedFunction));
|
2017-04-25 16:47:11 +00:00
|
|
|
appendExpressionAttributes(attributes, _node.annotation());
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "BinaryOperation", std::move(attributes));
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(FunctionCall const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2017-03-20 18:06:17 +00:00
|
|
|
Json::Value names(Json::arrayValue);
|
|
|
|
for (auto const& name: _node.names())
|
|
|
|
names.append(Json::Value(*name));
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("expression", toJson(_node.expression())),
|
|
|
|
std::make_pair("names", std::move(names)),
|
|
|
|
std::make_pair("nameLocations", sourceLocationsToJson(_node.nameLocations())),
|
|
|
|
std::make_pair("arguments", toJson(_node.arguments())),
|
|
|
|
std::make_pair("tryCall", _node.annotation().tryCall)
|
2017-05-19 13:45:01 +00:00
|
|
|
};
|
2020-04-08 17:38:30 +00:00
|
|
|
|
2020-07-08 20:08:50 +00:00
|
|
|
if (_node.annotation().kind.set())
|
2017-05-19 13:45:01 +00:00
|
|
|
{
|
2020-07-08 20:08:50 +00:00
|
|
|
FunctionCallKind nodeKind = *_node.annotation().kind;
|
2020-11-20 14:35:53 +00:00
|
|
|
attributes.emplace_back("kind", functionCallKind(nodeKind));
|
2017-05-19 13:45:01 +00:00
|
|
|
}
|
2020-07-08 20:08:50 +00:00
|
|
|
|
2017-04-25 16:47:11 +00:00
|
|
|
appendExpressionAttributes(attributes, _node.annotation());
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "FunctionCall", std::move(attributes));
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(FunctionCallOptions const& _node)
|
2020-01-22 14:42:50 +00:00
|
|
|
{
|
|
|
|
Json::Value names(Json::arrayValue);
|
|
|
|
for (auto const& name: _node.names())
|
|
|
|
names.append(Json::Value(*name));
|
|
|
|
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("expression", toJson(_node.expression())),
|
|
|
|
std::make_pair("names", std::move(names)),
|
|
|
|
std::make_pair("options", toJson(_node.options())),
|
2020-01-22 14:42:50 +00:00
|
|
|
};
|
|
|
|
appendExpressionAttributes(attributes, _node.annotation());
|
|
|
|
|
|
|
|
setJsonNode(_node, "FunctionCallOptions", std::move(attributes));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(NewExpression const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("typeName", toJson(_node.typeName()))
|
2017-03-20 18:06:17 +00:00
|
|
|
};
|
2017-04-25 16:47:11 +00:00
|
|
|
appendExpressionAttributes(attributes, _node.annotation());
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "NewExpression", std::move(attributes));
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(MemberAccess const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("memberName", _node.memberName()),
|
|
|
|
std::make_pair("memberLocation", Json::Value(sourceLocationToString(_node.memberLocation()))),
|
|
|
|
std::make_pair("expression", toJson(_node.expression())),
|
|
|
|
std::make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)),
|
2017-03-20 18:06:17 +00:00
|
|
|
};
|
2017-04-25 16:47:11 +00:00
|
|
|
appendExpressionAttributes(attributes, _node.annotation());
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "MemberAccess", std::move(attributes));
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(IndexAccess const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("baseExpression", toJson(_node.baseExpression())),
|
|
|
|
std::make_pair("indexExpression", toJsonOrNull(_node.indexExpression())),
|
2017-03-20 18:06:17 +00:00
|
|
|
};
|
2017-04-25 16:47:11 +00:00
|
|
|
appendExpressionAttributes(attributes, _node.annotation());
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "IndexAccess", std::move(attributes));
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(IndexRangeAccess const& _node)
|
2019-09-03 16:30:00 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("baseExpression", toJson(_node.baseExpression())),
|
|
|
|
std::make_pair("startExpression", toJsonOrNull(_node.startExpression())),
|
|
|
|
std::make_pair("endExpression", toJsonOrNull(_node.endExpression())),
|
2019-09-03 16:30:00 +00:00
|
|
|
};
|
|
|
|
appendExpressionAttributes(attributes, _node.annotation());
|
|
|
|
setJsonNode(_node, "IndexRangeAccess", std::move(attributes));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(Identifier const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2017-03-20 18:06:17 +00:00
|
|
|
Json::Value overloads(Json::arrayValue);
|
|
|
|
for (auto const& dec: _node.annotation().overloadedDeclarations)
|
|
|
|
overloads.append(nodeId(*dec));
|
|
|
|
setJsonNode(_node, "Identifier", {
|
2023-08-14 12:39:16 +00:00
|
|
|
std::make_pair("name", _node.name()),
|
|
|
|
std::make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)),
|
|
|
|
std::make_pair("overloadedDeclarations", overloads),
|
|
|
|
std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)),
|
|
|
|
std::make_pair("argumentTypes", typePointerToJson(_node.annotation().arguments))
|
2017-03-20 18:06:17 +00:00
|
|
|
});
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(ElementaryTypeNameExpression const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("typeName", toJson(_node.type()))
|
2017-03-20 18:06:17 +00:00
|
|
|
};
|
2017-04-25 16:47:11 +00:00
|
|
|
appendExpressionAttributes(attributes, _node.annotation());
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "ElementaryTypeNameExpression", std::move(attributes));
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(Literal const& _node)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2016-09-01 22:21:39 +00:00
|
|
|
Json::Value value{_node.value()};
|
2019-12-11 16:31:36 +00:00
|
|
|
if (!util::validateUTF8(_node.value()))
|
2016-09-01 22:21:39 +00:00
|
|
|
value = Json::nullValue;
|
2018-10-22 14:48:21 +00:00
|
|
|
Token subdenomination = Token(_node.subDenomination());
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("kind", literalTokenKind(_node.token())),
|
|
|
|
std::make_pair("value", value),
|
|
|
|
std::make_pair("hexValue", util::toHex(util::asBytes(_node.value()))),
|
|
|
|
std::make_pair(
|
2016-09-01 22:21:39 +00:00
|
|
|
"subdenomination",
|
|
|
|
subdenomination == Token::Illegal ?
|
|
|
|
Json::nullValue :
|
2018-10-22 14:48:21 +00:00
|
|
|
Json::Value{TokenTraits::toString(subdenomination)}
|
2017-03-20 18:06:17 +00:00
|
|
|
)
|
|
|
|
};
|
2017-04-25 16:47:11 +00:00
|
|
|
appendExpressionAttributes(attributes, _node.annotation());
|
2017-03-20 18:06:17 +00:00
|
|
|
setJsonNode(_node, "Literal", std::move(attributes));
|
|
|
|
return false;
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
bool ASTJsonExporter::visit(StructuredDocumentation const& _node)
|
2020-01-29 22:27:21 +00:00
|
|
|
{
|
|
|
|
Json::Value text{*_node.text()};
|
2023-08-14 12:39:16 +00:00
|
|
|
std::vector<std::pair<std::string, Json::Value>> attributes = {
|
|
|
|
std::make_pair("text", text)
|
2020-01-29 22:27:21 +00:00
|
|
|
};
|
|
|
|
setJsonNode(_node, "StructuredDocumentation", std::move(attributes));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-17 14:52:14 +00:00
|
|
|
|
2022-06-16 16:05:51 +00:00
|
|
|
void ASTJsonExporter::endVisit(EventDefinition const&)
|
2016-08-17 14:52:14 +00:00
|
|
|
{
|
2017-03-13 14:19:41 +00:00
|
|
|
m_inEvent = false;
|
2015-01-28 07:50:53 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 12:39:16 +00:00
|
|
|
std::string ASTJsonExporter::location(VariableDeclaration::Location _location)
|
2017-03-13 14:19:41 +00:00
|
|
|
{
|
|
|
|
switch (_location)
|
|
|
|
{
|
2018-08-17 23:09:31 +00:00
|
|
|
case VariableDeclaration::Location::Unspecified:
|
2017-03-13 14:19:41 +00:00
|
|
|
return "default";
|
|
|
|
case VariableDeclaration::Location::Storage:
|
|
|
|
return "storage";
|
|
|
|
case VariableDeclaration::Location::Memory:
|
|
|
|
return "memory";
|
2018-05-23 04:31:20 +00:00
|
|
|
case VariableDeclaration::Location::CallData:
|
|
|
|
return "calldata";
|
2017-03-13 14:19:41 +00:00
|
|
|
}
|
2018-09-30 07:10:38 +00:00
|
|
|
// To make the compiler happy
|
|
|
|
return {};
|
2017-03-13 14:19:41 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 12:39:16 +00:00
|
|
|
std::string ASTJsonExporter::contractKind(ContractKind _kind)
|
2017-05-05 14:15:09 +00:00
|
|
|
{
|
|
|
|
switch (_kind)
|
|
|
|
{
|
2020-01-07 14:11:29 +00:00
|
|
|
case ContractKind::Interface:
|
2017-05-05 14:15:09 +00:00
|
|
|
return "interface";
|
2020-01-07 14:11:29 +00:00
|
|
|
case ContractKind::Contract:
|
2017-05-05 14:15:09 +00:00
|
|
|
return "contract";
|
2020-01-07 14:11:29 +00:00
|
|
|
case ContractKind::Library:
|
2017-05-05 14:15:09 +00:00
|
|
|
return "library";
|
2017-05-19 13:45:01 +00:00
|
|
|
}
|
2018-09-30 07:10:38 +00:00
|
|
|
|
|
|
|
// To make the compiler happy
|
|
|
|
return {};
|
2017-05-19 13:45:01 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 12:39:16 +00:00
|
|
|
std::string ASTJsonExporter::functionCallKind(FunctionCallKind _kind)
|
2017-05-19 13:45:01 +00:00
|
|
|
{
|
|
|
|
switch (_kind)
|
|
|
|
{
|
|
|
|
case FunctionCallKind::FunctionCall:
|
|
|
|
return "functionCall";
|
|
|
|
case FunctionCallKind::TypeConversion:
|
|
|
|
return "typeConversion";
|
|
|
|
case FunctionCallKind::StructConstructorCall:
|
|
|
|
return "structConstructorCall";
|
|
|
|
default:
|
2017-07-19 01:19:00 +00:00
|
|
|
solAssert(false, "Unknown kind of function call.");
|
2017-05-05 14:15:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-14 12:39:16 +00:00
|
|
|
std::string ASTJsonExporter::literalTokenKind(Token _token)
|
2017-05-30 17:07:47 +00:00
|
|
|
{
|
|
|
|
switch (_token)
|
|
|
|
{
|
2019-12-11 16:31:36 +00:00
|
|
|
case Token::Number:
|
2017-05-30 17:07:47 +00:00
|
|
|
return "number";
|
2019-12-11 16:31:36 +00:00
|
|
|
case Token::StringLiteral:
|
2017-05-30 17:07:47 +00:00
|
|
|
return "string";
|
2020-07-02 16:39:04 +00:00
|
|
|
case Token::UnicodeStringLiteral:
|
|
|
|
return "unicodeString";
|
2020-07-27 08:52:36 +00:00
|
|
|
case Token::HexStringLiteral:
|
|
|
|
return "hexString";
|
2019-12-11 16:31:36 +00:00
|
|
|
case Token::TrueLiteral:
|
|
|
|
case Token::FalseLiteral:
|
2017-05-30 17:07:47 +00:00
|
|
|
return "bool";
|
|
|
|
default:
|
2017-07-19 01:19:00 +00:00
|
|
|
solAssert(false, "Unknown kind of literal token.");
|
2017-05-30 17:07:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-14 12:39:16 +00:00
|
|
|
std::string ASTJsonExporter::type(Expression const& _expression)
|
2015-01-05 14:46:40 +00:00
|
|
|
{
|
2015-09-16 14:56:30 +00:00
|
|
|
return _expression.annotation().type ? _expression.annotation().type->toString() : "Unknown";
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 12:39:16 +00:00
|
|
|
std::string ASTJsonExporter::type(VariableDeclaration const& _varDecl)
|
2015-09-24 10:12:31 +00:00
|
|
|
{
|
|
|
|
return _varDecl.annotation().type ? _varDecl.annotation().type->toString() : "Unknown";
|
|
|
|
}
|
|
|
|
|
2015-01-05 14:46:40 +00:00
|
|
|
}
|