/src/solidity/libsolidity/interface/StorageLayout.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 | | #include <libsolidity/interface/StorageLayout.h> |
20 | | |
21 | | #include <libsolidity/ast/TypeProvider.h> |
22 | | |
23 | | using namespace std::literals; |
24 | | using namespace solidity; |
25 | | using namespace solidity::frontend; |
26 | | |
27 | | Json StorageLayout::generate(ContractDefinition const& _contractDef, DataLocation const _location) |
28 | 0 | { |
29 | 0 | solAssert(!m_contract, ""); |
30 | 0 | m_contract = &_contractDef; |
31 | 0 | m_types.clear(); |
32 | |
|
33 | 0 | auto typeType = dynamic_cast<TypeType const*>(_contractDef.type()); |
34 | 0 | solAssert(typeType, ""); |
35 | 0 | auto contractType = dynamic_cast<ContractType const*>(typeType->actualType()); |
36 | 0 | solAssert(contractType, ""); |
37 | | |
38 | 0 | Json variables = Json::array(); |
39 | 0 | for (auto [var, slot, offset]: contractType->linearizedStateVariables(_location)) |
40 | 0 | variables.emplace_back(generate(*var, slot, offset)); |
41 | |
|
42 | 0 | Json layout; |
43 | 0 | layout["storage"] = std::move(variables); |
44 | 0 | layout["types"] = std::move(m_types); |
45 | |
|
46 | 0 | return layout; |
47 | 0 | } |
48 | | |
49 | | Json StorageLayout::generate(VariableDeclaration const& _var, u256 const& _slot, unsigned _offset) |
50 | 0 | { |
51 | 0 | Json varEntry; |
52 | 0 | Type const* varType = _var.type(); |
53 | |
|
54 | 0 | varEntry["label"] = _var.name(); |
55 | 0 | varEntry["astId"] = static_cast<int>(_var.id()); |
56 | 0 | varEntry["contract"] = m_contract->fullyQualifiedName(); |
57 | 0 | varEntry["slot"] = _slot.str(); |
58 | 0 | varEntry["offset"] = _offset; |
59 | 0 | varEntry["type"] = typeKeyName(varType); |
60 | |
|
61 | 0 | generate(varType); |
62 | |
|
63 | 0 | return varEntry; |
64 | 0 | } |
65 | | |
66 | | void StorageLayout::generate(Type const* _type) |
67 | 0 | { |
68 | 0 | if (m_types.contains(typeKeyName(_type))) |
69 | 0 | return; |
70 | | |
71 | | // Register it now to cut recursive visits. |
72 | 0 | Json& typeInfo = m_types[typeKeyName(_type)]; |
73 | 0 | typeInfo["label"] = _type->toString(true); |
74 | 0 | typeInfo["numberOfBytes"] = u256(_type->storageBytes() * _type->storageSize()).str(); |
75 | |
|
76 | 0 | if (auto structType = dynamic_cast<StructType const*>(_type)) |
77 | 0 | { |
78 | 0 | Json members = Json::array(); |
79 | 0 | auto const& structDef = structType->structDefinition(); |
80 | 0 | for (auto const& member: structDef.members()) |
81 | 0 | { |
82 | 0 | auto const& offsets = structType->storageOffsetsOfMember(member->name()); |
83 | 0 | members.emplace_back(generate(*member, offsets.first, offsets.second)); |
84 | 0 | } |
85 | 0 | typeInfo["members"] = std::move(members); |
86 | 0 | typeInfo["encoding"] = "inplace"; |
87 | 0 | } |
88 | 0 | else if (auto mappingType = dynamic_cast<MappingType const*>(_type)) |
89 | 0 | { |
90 | 0 | typeInfo["key"] = typeKeyName(mappingType->keyType()); |
91 | 0 | typeInfo["value"] = typeKeyName(mappingType->valueType()); |
92 | 0 | generate(mappingType->keyType()); |
93 | 0 | generate(mappingType->valueType()); |
94 | 0 | typeInfo["encoding"] = "mapping"; |
95 | 0 | } |
96 | 0 | else if (auto arrayType = dynamic_cast<ArrayType const*>(_type)) |
97 | 0 | { |
98 | 0 | if (arrayType->isByteArrayOrString()) |
99 | 0 | typeInfo["encoding"] = "bytes"; |
100 | 0 | else |
101 | 0 | { |
102 | 0 | typeInfo["base"] = typeKeyName(arrayType->baseType()); |
103 | 0 | generate(arrayType->baseType()); |
104 | 0 | typeInfo["encoding"] = arrayType->isDynamicallySized() ? "dynamic_array" : "inplace"; |
105 | 0 | } |
106 | 0 | } |
107 | 0 | else |
108 | 0 | { |
109 | 0 | solAssert(_type->isValueType(), ""); |
110 | 0 | typeInfo["encoding"] = "inplace"; |
111 | 0 | } |
112 | | |
113 | 0 | solAssert(typeInfo.contains("encoding"), ""); |
114 | 0 | } |
115 | | |
116 | | std::string StorageLayout::typeKeyName(Type const* _type) |
117 | 0 | { |
118 | 0 | if (auto refType = dynamic_cast<ReferenceType const*>(_type)) |
119 | 0 | return TypeProvider::withLocationIfReference(refType->location(), _type)->richIdentifier(); |
120 | 0 | return _type->richIdentifier(); |
121 | 0 | } |