diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index a3aab07fba29..789900e0f63b 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -366,7 +366,6 @@ std::multimap const& ContractDefinition: }); } - TypeNameAnnotation& TypeName::annotation() const { return initAnnotation(); @@ -399,6 +398,13 @@ StructDeclarationAnnotation& StructDefinition::annotation() const return initAnnotation(); } +std::optional StructDefinition::ethdebug() const +{ + Json result = Json::object(); + result["kind"] = "struct"; + return result; +} + Type const* EnumValue::type() const { auto parentDef = dynamic_cast(scope()); @@ -416,6 +422,17 @@ TypeDeclarationAnnotation& EnumDefinition::annotation() const return initAnnotation(); } +std::optional EnumDefinition::ethdebug() const +{ + Json result = Json::object(); + result["kind"] = "enum"; + Json values = Json::array(); + for (auto const& value: members()) + values.push_back(value->name()); + result["values"] = values; + return result; +} + bool FunctionDefinition::libraryFunction() const { if (auto const* contractDef = dynamic_cast(scope())) @@ -543,6 +560,57 @@ FunctionDefinition const& FunctionDefinition::resolveVirtual( return *this; // not reached } +std::optional FunctionDefinition::ethdebug() const +{ + Json result = Json::object(); + if (isOrdinary()) + result["kind"] = "function"; + else if (isConstructor()) + result["kind"] = "constructor"; + else if (isFallback()) + result["kind"] = "fallback"; + else + solAssert(false); + + if (!noVisibilitySpecified()) + { + switch (visibility()) + { + case solidity::frontend::Visibility::Default: + case solidity::frontend::Visibility::Private: + case solidity::frontend::Visibility::Internal: + result["internal"] = true; + break; + case solidity::frontend::Visibility::Public: + case solidity::frontend::Visibility::External: + result["external"] = true; + break; + } + } + + Json definition = Json::object(); + definition["name"] = name(); + result["definition"] = definition; + + Json parameters = Json::array(); + for (auto const& param: this->parameters()) + { + solAssert(param->ethdebug().has_value()); + parameters.emplace_back(*param->ethdebug()); + } + result["parameters"] = parameters; + + Json returns = Json::array(); + for (auto const& param: returnParameters()) + { + solAssert(param->ethdebug().has_value()); + returns.emplace_back(*param->ethdebug()); + } + result["returns"] = returns; + + return result; +} + Type const* ModifierDefinition::type() const { return TypeProvider::modifier(*this); @@ -878,6 +946,15 @@ VariableDeclarationAnnotation& VariableDeclaration::annotation() const return initAnnotation(); } +std::optional VariableDeclaration::ethdebug() const +{ + solAssert(type()->ethdebug().has_value()); + Json result = Json::object(); + result["name"] = name(); + result["type"] = *type()->ethdebug(); + return result; +} + StatementAnnotation& Statement::annotation() const { return initAnnotation(); diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 727652f56000..32392cf14eaf 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -126,6 +126,8 @@ class ASTNode virtual bool experimentalSolidityOnly() const { return false; } + virtual std::optional ethdebug() const { return std::nullopt; } + protected: size_t const m_id = 0; @@ -753,6 +755,8 @@ class StructDefinition: public Declaration, public StructurallyDocumented, publi StructDeclarationAnnotation& annotation() const override; + std::optional ethdebug() const override; + private: std::vector> m_members; }; @@ -785,6 +789,8 @@ class EnumDefinition: public Declaration, public StructurallyDocumented, public TypeDeclarationAnnotation& annotation() const override; + std::optional ethdebug() const override; + private: std::vector> m_members; }; @@ -1036,6 +1042,8 @@ class FunctionDefinition: public CallableDeclaration, public StructurallyDocumen Expression const* experimentalReturnExpression() const { return m_experimentalReturnExpression.get(); } + std::optional ethdebug() const override; + private: StateMutability m_stateMutability; bool m_free; @@ -1156,6 +1164,8 @@ class VariableDeclaration: public Declaration, public StructurallyDocumented ASTPointer const& typeExpression() const { return m_typeExpression; } VariableDeclarationAnnotation& annotation() const override; + std::optional ethdebug() const override; + protected: Visibility defaultVisibility() const override { return Visibility::Internal; } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index f6e2a54138b3..a2d03b09ef00 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -414,6 +414,85 @@ std::set Type::operatorDefiniti return matchingDefinitions; } +std::optional Type::ethdebug() const +{ + Json result = Json::object(); + switch (category()) + { + case Category::Address: + result["kind"] = "address"; + break; + case Category::Integer: + { + auto integer = dynamic_cast(this); + if (integer->isSigned()) + result["kind"] = "int"; + else + result["kind"] = "uint"; + result["bits"] = integer->numBits(); + break; + } + case Category::RationalNumber: + result["kind"] = "rational"; + break; + case Category::StringLiteral: + result["kind"] = "string"; + break; + case Category::Bool: + result["kind"] = "bool"; + break; + case Category::FixedPoint: + result["kind"] = "fixed"; + break; + case Category::Array: + result["kind"] = "array"; + break; + case Category::ArraySlice: + result["kind"] = "slice"; + break; + case Category::FixedBytes: + result["kind"] = "bytes"; + break; + case Category::Contract: + result["kind"] = "contract"; + break; + case Category::Struct: + result["kind"] = "struct"; + break; + case Category::Function: + result["kind"] = "function"; + break; + case Category::Enum: + result["kind"] = "enum"; + break; + case Category::UserDefinedValueType: + result["kind"] = "udvt"; + break; + case Category::Tuple: + result["kind"] = "tuple"; + break; + case Category::Mapping: + result["kind"] = "mapping"; + break; + case Category::TypeType: + result["kind"] = "type-type"; + break; + case Category::Modifier: + result["kind"] = "modifier"; + break; + case Category::Magic: + result["kind"] = "magic"; + break; + case Category::Module: + result["kind"] = "module"; + break; + case Category::InaccessibleDynamic: + result["kind"] = "inaccessible-dynamic"; + break; + } + return result; +} + MemberList::MemberMap Type::attachedFunctions(Type const& _type, ASTNode const& _scope) { MemberList::MemberMap members; diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 5a5040c40dd2..32862609e372 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -23,14 +23,15 @@ #pragma once +#include #include #include #include -#include #include #include #include +#include #include #include @@ -409,6 +410,7 @@ class Type bool _unary ) const; + virtual std::optional ethdebug() const; private: /// @returns a member list containing all members added to this type by `using for` directives. static MemberList::MemberMap attachedFunctions(Type const& _type, ASTNode const& _scope); diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index a45e7173b651..031551f905b0 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -1105,11 +1105,33 @@ Json CompilerStack::ethdebug(Contract const& _contract) const solUnimplementedAssert(!isExperimentalSolidity()); return _contract.ethdebug.init([&] { Json result = Json::object(); - result["not yet implemented"] = true; + result["types"] = ethdebugTypes(_contract); return result; }); } +Json CompilerStack::ethdebugTypes(Contract const& _contract) const +{ + Json types = Json::object(); + ContractDefinition const& contract = *_contract.contract; + for (auto const& _enum: contract.definedEnums()) + { + solAssert(_enum->ethdebug().has_value()); + types[_enum->name()] = *_enum->ethdebug(); + } + for (auto const& _struct: contract.definedStructs()) + { + solAssert(_struct->ethdebug().has_value()); + types[_struct->name()] = *_struct->ethdebug(); + } + for (auto const& _function: contract.definedFunctions()) + { + solAssert(_function->ethdebug().has_value()); + types[_function->name()] = *_function->ethdebug(); + } + return types; +} + Json CompilerStack::runtimeEthdebug(std::string const& _contractName) const { solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful."); @@ -1123,7 +1145,7 @@ Json CompilerStack::runtimeEthdebug(Contract const& _contract) const solUnimplementedAssert(!isExperimentalSolidity()); return _contract.ethdebugRuntime.init([&] { Json result = Json::object(); - result["not yet implemented (runtime)"] = true; + result["types"] = ethdebugTypes(_contract); return result; }); } diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 7cc1c1268631..2a0a0f0b6fdc 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -433,6 +433,8 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac mutable std::optional runtimeSourceMapping; }; + Json ethdebugTypes(Contract const& _contract) const; + void createAndAssignCallGraphs(); void findAndReportCyclicContractDependencies();