Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 43 additions & 55 deletions libsolidity/interface/CompilerStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -855,40 +855,34 @@ Json CompilerStack::generatedSources(std::string const& _contractName, bool _run
solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");

Contract const& c = contract(_contractName);
util::LazyInit<Json const> const& sources =
_runtime ?
c.runtimeGeneratedSources :
c.generatedSources;
return sources.init([&]{
Json sources = Json::array();
// If there is no compiler, then no bytecode was generated and thus no
// sources were generated (or we compiled "via IR").
if (c.compiler)
Json sources = Json::array();
// If there is no compiler, then no bytecode was generated and thus no
// sources were generated (or we compiled "via IR").
if (c.compiler)
{
solAssert(!m_viaIR, "");
std::string source =
_runtime ?
c.compiler->runtimeGeneratedYulUtilityCode() :
c.compiler->generatedYulUtilityCode();
if (!source.empty())
{
solAssert(!m_viaIR, "");
std::string source =
_runtime ?
c.compiler->runtimeGeneratedYulUtilityCode() :
c.compiler->generatedYulUtilityCode();
if (!source.empty())
{
std::string sourceName = CompilerContext::yulUtilityFileName();
unsigned sourceIndex = sourceIndices()[sourceName];
ErrorList errors;
ErrorReporter errorReporter(errors);
CharStream charStream(source, sourceName);
yul::EVMDialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(m_evmVersion);
std::shared_ptr<yul::AST> parserResult = yul::Parser{errorReporter, dialect}.parse(charStream);
solAssert(parserResult, "");
sources[0]["ast"] = yul::AsmJsonConverter{sourceIndex}(parserResult->root());
sources[0]["name"] = sourceName;
sources[0]["id"] = sourceIndex;
sources[0]["language"] = "Yul";
sources[0]["contents"] = std::move(source);
}
std::string sourceName = CompilerContext::yulUtilityFileName();
unsigned sourceIndex = sourceIndices()[sourceName];
ErrorList errors;
ErrorReporter errorReporter(errors);
CharStream charStream(source, sourceName);
yul::EVMDialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(m_evmVersion);
std::shared_ptr<yul::AST> parserResult = yul::Parser{errorReporter, dialect}.parse(charStream);
solAssert(parserResult, "");
sources[0]["ast"] = yul::AsmJsonConverter{sourceIndex}(parserResult->root());
sources[0]["name"] = sourceName;
sources[0]["id"] = sourceIndex;
sources[0]["language"] = "Yul";
sources[0]["contents"] = std::move(source);
}
return sources;
});
}
return sources;
}

std::string const* CompilerStack::sourceMapping(std::string const& _contractName) const
Expand Down Expand Up @@ -961,8 +955,6 @@ Json CompilerStack::yulIRAst(std::string const& _contractName) const
solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
solUnimplementedAssert(!isExperimentalSolidity());

// NOTE: Intentionally not using LazyInit. The artifact can get very large and we don't want to
// keep it around when compiling a large project containing many contracts.
return loadGeneratedIR(contract(_contractName).yulIR).astJson();
}

Expand All @@ -971,8 +963,6 @@ Json CompilerStack::yulCFGJson(std::string const& _contractName) const
solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
solUnimplementedAssert(!isExperimentalSolidity());

// NOTE: Intentionally not using LazyInit. The artifact can get very large and we don't want to
// keep it around when compiling a large project containing many contracts.
return loadGeneratedIR(contract(_contractName).yulIR).cfgJson();
}

Expand All @@ -987,8 +977,6 @@ Json CompilerStack::yulIROptimizedAst(std::string const& _contractName) const
solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
solUnimplementedAssert(!isExperimentalSolidity());

// NOTE: Intentionally not using LazyInit. The artifact can get very large and we don't want to
// keep it around when compiling a large project containing many contracts.
return loadGeneratedIR(contract(_contractName).yulIROptimized).astJson();
}

Expand Down Expand Up @@ -1045,76 +1033,76 @@ std::map<std::string, unsigned> CompilerStack::sourceIndices() const
return indices;
}

Json const& CompilerStack::contractABI(std::string const& _contractName) const
Json CompilerStack::contractABI(std::string const& _contractName) const
{
solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
return contractABI(contract(_contractName));
}

Json const& CompilerStack::contractABI(Contract const& _contract) const
Json CompilerStack::contractABI(Contract const& _contract) const
{
solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
solAssert(_contract.contract);
solUnimplementedAssert(!isExperimentalSolidity());
return _contract.abi.init([&]{ return ABI::generate(*_contract.contract); });
return ABI::generate(*_contract.contract);
}

Json const& CompilerStack::storageLayout(std::string const& _contractName) const
Json CompilerStack::storageLayout(std::string const& _contractName) const
{
solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
return storageLayout(contract(_contractName));
}

Json const& CompilerStack::storageLayout(Contract const& _contract) const
Json CompilerStack::storageLayout(Contract const& _contract) const
{
solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
solAssert(_contract.contract);
solUnimplementedAssert(!isExperimentalSolidity());

return _contract.storageLayout.init([&]{ return StorageLayout().generate(*_contract.contract, DataLocation::Storage); });
return StorageLayout().generate(*_contract.contract, DataLocation::Storage);
}

Json const& CompilerStack::transientStorageLayout(std::string const& _contractName) const
Json CompilerStack::transientStorageLayout(std::string const& _contractName) const
{
solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
return transientStorageLayout(contract(_contractName));
}

Json const& CompilerStack::transientStorageLayout(Contract const& _contract) const
Json CompilerStack::transientStorageLayout(Contract const& _contract) const
{
solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
solAssert(_contract.contract);
solUnimplementedAssert(!isExperimentalSolidity());

return _contract.transientStorageLayout.init([&]{ return StorageLayout().generate(*_contract.contract, DataLocation::Transient); });
return StorageLayout().generate(*_contract.contract, DataLocation::Transient);
}

Json const& CompilerStack::natspecUser(std::string const& _contractName) const
Json CompilerStack::natspecUser(std::string const& _contractName) const
{
solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
return natspecUser(contract(_contractName));
}

Json const& CompilerStack::natspecUser(Contract const& _contract) const
Json CompilerStack::natspecUser(Contract const& _contract) const
{
solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
solAssert(_contract.contract);
solUnimplementedAssert(!isExperimentalSolidity());
return _contract.userDocumentation.init([&]{ return Natspec::userDocumentation(*_contract.contract); });
return Natspec::userDocumentation(*_contract.contract);
}

Json const& CompilerStack::natspecDev(std::string const& _contractName) const
Json CompilerStack::natspecDev(std::string const& _contractName) const
{
solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
return natspecDev(contract(_contractName));
}

Json const& CompilerStack::natspecDev(Contract const& _contract) const
Json CompilerStack::natspecDev(Contract const& _contract) const
{
solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
solAssert(_contract.contract);
solUnimplementedAssert(!isExperimentalSolidity());
return _contract.devDocumentation.init([&]{ return Natspec::devDocumentation(*_contract.contract); });
return Natspec::devDocumentation(*_contract.contract);
}

Json CompilerStack::interfaceSymbols(std::string const& _contractName) const
Expand Down Expand Up @@ -1153,12 +1141,12 @@ bytes CompilerStack::cborMetadata(std::string const& _contractName, bool _forIR)
return createCBORMetadata(contract(_contractName), _forIR);
}

std::string const& CompilerStack::metadata(Contract const& _contract) const
std::string CompilerStack::metadata(Contract const& _contract) const
{
solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
solAssert(_contract.contract);
solUnimplementedAssert(!isExperimentalSolidity());
return _contract.metadata.init([&]{ return createMetadata(_contract, m_viaIR); });
return createMetadata(_contract, m_viaIR);
}

CharStream const& CompilerStack::charStream(std::string const& _sourceName) const
Expand Down
33 changes: 12 additions & 21 deletions libsolidity/interface/CompilerStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@

#include <libsolutil/Common.h>
#include <libsolutil/FixedHash.h>
#include <libsolutil/LazyInit.h>
#include <libsolutil/JSON.h>

#include <libyul/ObjectOptimizer.h>
Expand Down Expand Up @@ -341,29 +340,29 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac

/// @returns a JSON representing the contract ABI.
/// Prerequisite: Successful call to parse or compile.
Json const& contractABI(std::string const& _contractName) const;
Json contractABI(std::string const& _contractName) const;

/// @returns a JSON representing the storage layout of the contract.
/// Prerequisite: Successful call to parse or compile.
Json const& storageLayout(std::string const& _contractName) const;
Json storageLayout(std::string const& _contractName) const;

/// @returns a JSON representing the transient storage layout of the contract.
/// Prerequisite: Successful call to parse or compile.
Json const& transientStorageLayout(std::string const& _contractName) const;
Json transientStorageLayout(std::string const& _contractName) const;

/// @returns a JSON representing the contract's user documentation.
/// Prerequisite: Successful call to parse or compile.
Json const& natspecUser(std::string const& _contractName) const;
Json natspecUser(std::string const& _contractName) const;

/// @returns a JSON representing the contract's developer documentation.
/// Prerequisite: Successful call to parse or compile.
Json const& natspecDev(std::string const& _contractName) const;
Json natspecDev(std::string const& _contractName) const;

/// @returns a JSON object with the three members ``methods``, ``events``, ``errors``. Each is a map, mapping identifiers (hashes) to function names.
Json interfaceSymbols(std::string const& _contractName) const;

/// @returns the Contract Metadata matching the pipeline selected using the viaIR setting.
std::string const& metadata(std::string const& _contractName) const { return metadata(contract(_contractName)); }
std::string metadata(std::string const& _contractName) const { return metadata(contract(_contractName)); }

/// @returns the CBOR-encoded metadata matching the pipeline selected using the viaIR setting.
bytes cborMetadata(std::string const& _contractName) const { return cborMetadata(_contractName, m_viaIR); }
Expand Down Expand Up @@ -416,14 +415,6 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac
evmasm::LinkerObject runtimeObject; ///< Runtime object.
std::string yulIR; ///< Yul IR code straight from the code generator.
std::string yulIROptimized; ///< Reparsed and possibly optimized Yul IR code.
util::LazyInit<std::string const> metadata; ///< The metadata json that will be hashed into the chain.
util::LazyInit<Json const> abi;
util::LazyInit<Json const> storageLayout;
util::LazyInit<Json const> transientStorageLayout;
util::LazyInit<Json const> userDocumentation;
util::LazyInit<Json const> devDocumentation;
util::LazyInit<Json const> generatedSources;
util::LazyInit<Json const> runtimeGeneratedSources;
mutable std::optional<std::string const> sourceMapping;
mutable std::optional<std::string const> runtimeSourceMapping;
};
Expand Down Expand Up @@ -515,27 +506,27 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac

/// @returns the contract ABI as a JSON object.
/// This will generate the JSON object and store it in the Contract object if it is not present yet.
Json const& contractABI(Contract const&) const;
Json contractABI(Contract const&) const;

/// @returns the storage layout of the contract as a JSON object.
/// This will generate the JSON object and store it in the Contract object if it is not present yet.
Json const& storageLayout(Contract const&) const;
Json storageLayout(Contract const&) const;

/// @returns the transient storage layout of the contract as a JSON object.
/// This will generate the JSON object and store it in the Contract object if it is not present yet.
Json const& transientStorageLayout(Contract const&) const;
Json transientStorageLayout(Contract const&) const;

/// @returns the Natspec User documentation as a JSON object.
/// This will generate the JSON object and store it in the Contract object if it is not present yet.
Json const& natspecUser(Contract const&) const;
Json natspecUser(Contract const&) const;

/// @returns the Natspec Developer documentation as a JSON object.
/// This will generate the JSON object and store it in the Contract object if it is not present yet.
Json const& natspecDev(Contract const&) const;
Json natspecDev(Contract const&) const;

/// @returns the Contract Metadata matching the pipeline selected using the viaIR setting.
/// This will generate the metadata and store it in the Contract object if it is not present yet.
std::string const& metadata(Contract const& _contract) const;
std::string metadata(Contract const& _contract) const;

/// @returns the offset of the entry point of the given function into the list of assembly items
/// or zero if it is not found or does not exist.
Expand Down