mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #14518 from ethereum/analysis-framework-refactor
`AnalysisFramework` refactor
This commit is contained in:
commit
cc7a14a61d
@ -22,6 +22,7 @@
|
|||||||
#include <test/libsolidity/AnalysisFramework.h>
|
#include <test/libsolidity/AnalysisFramework.h>
|
||||||
|
|
||||||
#include <test/libsolidity/util/Common.h>
|
#include <test/libsolidity/util/Common.h>
|
||||||
|
#include <test/libsolidity/util/SoltestErrors.h>
|
||||||
#include <test/Common.h>
|
#include <test/Common.h>
|
||||||
|
|
||||||
#include <libsolidity/interface/CompilerStack.h>
|
#include <libsolidity/interface/CompilerStack.h>
|
||||||
@ -41,36 +42,84 @@ using namespace solidity::langutil;
|
|||||||
using namespace solidity::frontend;
|
using namespace solidity::frontend;
|
||||||
using namespace solidity::frontend::test;
|
using namespace solidity::frontend::test;
|
||||||
|
|
||||||
std::pair<SourceUnit const*, ErrorList>
|
std::pair<SourceUnit const*, ErrorList> AnalysisFramework::runAnalysisAndExpectNoParsingErrors(
|
||||||
AnalysisFramework::parseAnalyseAndReturnError(
|
|
||||||
std::string const& _source,
|
std::string const& _source,
|
||||||
bool _reportWarnings,
|
bool _includeWarningsAndInfos,
|
||||||
bool _insertLicenseAndVersionPragma,
|
bool _addPreamble,
|
||||||
bool _allowMultipleErrors
|
bool _allowMultiple
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
compiler().reset();
|
runFramework(_addPreamble ? withPreamble(_source) : _source, PipelineStage::Analysis);
|
||||||
compiler().setSources({{"", _insertLicenseAndVersionPragma ? withPreamble(_source) : _source}});
|
|
||||||
compiler().setEVMVersion(solidity::test::CommonOptions::get().evmVersion());
|
|
||||||
if (!compiler().parse())
|
|
||||||
{
|
|
||||||
BOOST_FAIL("Parsing contract failed in analysis test suite:" + formatErrors(compiler().errors()));
|
|
||||||
}
|
|
||||||
|
|
||||||
compiler().analyze();
|
if (!stageSuccessful(PipelineStage::Parsing))
|
||||||
|
BOOST_FAIL("Parsing contract failed in analysis test suite:" + formatErrors(m_compiler->errors()));
|
||||||
|
|
||||||
ErrorList errors = filteredErrors(_reportWarnings);
|
ErrorList errors = filteredErrors(_includeWarningsAndInfos);
|
||||||
if (errors.size() > 1 && !_allowMultipleErrors)
|
if (errors.size() > 1 && !_allowMultiple)
|
||||||
BOOST_FAIL("Multiple errors found: " + formatErrors(errors));
|
BOOST_FAIL("Multiple errors found: " + formatErrors(errors));
|
||||||
|
|
||||||
return make_pair(&compiler().ast(""), std::move(errors));
|
return make_pair(&compiler().ast(""), std::move(errors));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AnalysisFramework::runFramework(StringMap _sources, PipelineStage _targetStage)
|
||||||
|
{
|
||||||
|
resetFramework();
|
||||||
|
m_targetStage = _targetStage;
|
||||||
|
soltestAssert(m_compiler);
|
||||||
|
|
||||||
|
m_compiler->setSources(std::move(_sources));
|
||||||
|
setupCompiler(*m_compiler);
|
||||||
|
executeCompilationPipeline();
|
||||||
|
return pipelineSuccessful();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalysisFramework::resetFramework()
|
||||||
|
{
|
||||||
|
compiler().reset();
|
||||||
|
m_targetStage = PipelineStage::Compilation;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<CompilerStack> AnalysisFramework::createStack() const
|
std::unique_ptr<CompilerStack> AnalysisFramework::createStack() const
|
||||||
{
|
{
|
||||||
return std::make_unique<CompilerStack>();
|
return std::make_unique<CompilerStack>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnalysisFramework::setupCompiler(CompilerStack& _compiler)
|
||||||
|
{
|
||||||
|
// These are just defaults based on the (global) CLI options.
|
||||||
|
// Technically, every TestCase should override these with values passed to it in TestCase::Config.
|
||||||
|
// In practice TestCase::Config always matches global config so most test cases don't care.
|
||||||
|
_compiler.setEVMVersion(solidity::test::CommonOptions::get().evmVersion());
|
||||||
|
_compiler.setEOFVersion(solidity::test::CommonOptions::get().eofVersion());
|
||||||
|
_compiler.setOptimiserSettings(solidity::test::CommonOptions::get().optimize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalysisFramework::executeCompilationPipeline()
|
||||||
|
{
|
||||||
|
soltestAssert(m_compiler);
|
||||||
|
|
||||||
|
// If you add a new stage, remember to handle it below.
|
||||||
|
soltestAssert(
|
||||||
|
m_targetStage == PipelineStage::Parsing ||
|
||||||
|
m_targetStage == PipelineStage::Analysis ||
|
||||||
|
m_targetStage == PipelineStage::Compilation
|
||||||
|
);
|
||||||
|
|
||||||
|
bool parsingSuccessful = m_compiler->parse();
|
||||||
|
soltestAssert(parsingSuccessful || !filteredErrors(false /* _includeWarningsAndInfos */).empty());
|
||||||
|
if (!parsingSuccessful || stageSuccessful(m_targetStage))
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool analysisSuccessful = m_compiler->analyze();
|
||||||
|
soltestAssert(analysisSuccessful || !filteredErrors(false /* _includeWarningsAndInfos */).empty());
|
||||||
|
if (!analysisSuccessful || stageSuccessful(m_targetStage))
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool compilationSuccessful = m_compiler->compile();
|
||||||
|
soltestAssert(compilationSuccessful || !filteredErrors(false /* _includeWarningsAndInfos */).empty());
|
||||||
|
soltestAssert(stageSuccessful(m_targetStage) == compilationSuccessful);
|
||||||
|
}
|
||||||
|
|
||||||
ErrorList AnalysisFramework::filterErrors(ErrorList const& _errorList, bool _includeWarningsAndInfos) const
|
ErrorList AnalysisFramework::filterErrors(ErrorList const& _errorList, bool _includeWarningsAndInfos) const
|
||||||
{
|
{
|
||||||
ErrorList errors;
|
ErrorList errors;
|
||||||
@ -113,28 +162,26 @@ ErrorList AnalysisFramework::filterErrors(ErrorList const& _errorList, bool _inc
|
|||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceUnit const* AnalysisFramework::parseAndAnalyse(std::string const& _source)
|
bool AnalysisFramework::stageSuccessful(PipelineStage _stage) const
|
||||||
{
|
{
|
||||||
auto sourceAndError = parseAnalyseAndReturnError(_source);
|
switch (_stage) {
|
||||||
BOOST_REQUIRE(!!sourceAndError.first);
|
case PipelineStage::Parsing: return compiler().state() >= CompilerStack::Parsed;
|
||||||
std::string message;
|
case PipelineStage::Analysis: return compiler().state() >= CompilerStack::AnalysisSuccessful;
|
||||||
if (!sourceAndError.second.empty())
|
case PipelineStage::Compilation: return compiler().state() >= CompilerStack::CompilationSuccessful;
|
||||||
message = "Unexpected error: " + formatErrors(compiler().errors());
|
}
|
||||||
BOOST_REQUIRE_MESSAGE(sourceAndError.second.empty(), message);
|
unreachable();
|
||||||
return sourceAndError.first;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AnalysisFramework::success(std::string const& _source)
|
ErrorList AnalysisFramework::runAnalysisAndExpectError(
|
||||||
|
std::string const& _source,
|
||||||
|
bool _includeWarningsAndInfos,
|
||||||
|
bool _allowMultiple
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return parseAnalyseAndReturnError(_source).second.empty();
|
auto [ast, errors] = runAnalysisAndExpectNoParsingErrors(_source, _includeWarningsAndInfos, true, _allowMultiple);
|
||||||
}
|
BOOST_REQUIRE(!errors.empty());
|
||||||
|
BOOST_REQUIRE_MESSAGE(ast, "Expected error, but no error happened.");
|
||||||
ErrorList AnalysisFramework::expectError(std::string const& _source, bool _warning, bool _allowMultiple)
|
return errors;
|
||||||
{
|
|
||||||
auto sourceAndErrors = parseAnalyseAndReturnError(_source, _warning, true, _allowMultiple);
|
|
||||||
BOOST_REQUIRE(!sourceAndErrors.second.empty());
|
|
||||||
BOOST_REQUIRE_MESSAGE(!!sourceAndErrors.first, "Expected error, but no error happened.");
|
|
||||||
return sourceAndErrors.second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AnalysisFramework::formatErrors(
|
std::string AnalysisFramework::formatErrors(
|
||||||
|
@ -39,22 +39,66 @@ using FunctionTypePointer = FunctionType const*;
|
|||||||
namespace solidity::frontend::test
|
namespace solidity::frontend::test
|
||||||
{
|
{
|
||||||
|
|
||||||
|
enum class PipelineStage {
|
||||||
|
Parsing,
|
||||||
|
Analysis,
|
||||||
|
Compilation,
|
||||||
|
};
|
||||||
|
|
||||||
class AnalysisFramework
|
class AnalysisFramework
|
||||||
{
|
{
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual std::pair<SourceUnit const*, langutil::ErrorList>
|
|
||||||
parseAnalyseAndReturnError(
|
|
||||||
std::string const& _source,
|
|
||||||
bool _reportWarnings = false,
|
|
||||||
bool _insertLicenseAndVersionPragma = true,
|
|
||||||
bool _allowMultipleErrors = false
|
|
||||||
);
|
|
||||||
virtual ~AnalysisFramework() = default;
|
virtual ~AnalysisFramework() = default;
|
||||||
|
|
||||||
SourceUnit const* parseAndAnalyse(std::string const& _source);
|
/// Runs analysis via runFramework() and returns either an AST or a filtered list of errors.
|
||||||
bool success(std::string const& _source);
|
/// Uses Boost test macros to fail if errors do not occur specifically at the analysis stage.
|
||||||
langutil::ErrorList expectError(std::string const& _source, bool _warning = false, bool _allowMultiple = false);
|
///
|
||||||
|
/// @deprecated This is a legacy helper. Use runFramework() directly in new tests.
|
||||||
|
///
|
||||||
|
/// @param _includeWarningsAndInfos Do not remove warning and info messages from the error list.
|
||||||
|
/// @param _addPreamble Apply withPreamble() to @p _source.
|
||||||
|
/// @param _allowMultiple When false, use Boost test macros to fail when there's more
|
||||||
|
/// than one item on the error list.
|
||||||
|
std::pair<SourceUnit const*, langutil::ErrorList> runAnalysisAndExpectNoParsingErrors(
|
||||||
|
std::string const& _source,
|
||||||
|
bool _includeWarningsAndInfos = false,
|
||||||
|
bool _addPreamble = true,
|
||||||
|
bool _allowMultiple = false
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Runs analysis via runAnalysisAndExpectNoParsingErrors() and returns the list of errors.
|
||||||
|
/// Uses Boost test macros to fail if there are no errors.
|
||||||
|
///
|
||||||
|
/// @deprecated This is a legacy helper. Use runFramework() directly in new tests.
|
||||||
|
///
|
||||||
|
/// @param _includeWarningsAndInfos Do not remove warning and info messages from the error list.
|
||||||
|
/// @param _allowMultiple When false, use Boost test macros to fail when there's more
|
||||||
|
/// than one item on the error list.
|
||||||
|
langutil::ErrorList runAnalysisAndExpectError(
|
||||||
|
std::string const& _source,
|
||||||
|
bool _includeWarningsAndInfos = false,
|
||||||
|
bool _allowMultiple = false
|
||||||
|
);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Runs the full compiler pipeline on specified sources. This is the main function of the
|
||||||
|
/// framework. Resets the stack, configures it and runs either until the first failed stage or
|
||||||
|
/// until the @p _targetStage is reached.
|
||||||
|
/// Afterwards the caller can inspect the stack via @p compiler(). The framework provides a few
|
||||||
|
/// convenience helpers to check the state and error list, in general the caller can freely
|
||||||
|
/// access the stack, including generating outputs if the compilation succeeded.
|
||||||
|
bool runFramework(StringMap _sources, PipelineStage _targetStage = PipelineStage::Compilation);
|
||||||
|
bool runFramework(std::string _source, PipelineStage _targetStage = PipelineStage::Compilation)
|
||||||
|
{
|
||||||
|
return runFramework({{"", std::move(_source)}}, _targetStage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetFramework();
|
||||||
|
|
||||||
|
PipelineStage targetStage() const { return m_targetStage; }
|
||||||
|
bool pipelineSuccessful() const { return stageSuccessful(m_targetStage); }
|
||||||
|
bool stageSuccessful(PipelineStage _stage) const;
|
||||||
|
|
||||||
std::string formatErrors(
|
std::string formatErrors(
|
||||||
langutil::ErrorList const& _errors,
|
langutil::ErrorList const& _errors,
|
||||||
@ -80,9 +124,6 @@ protected:
|
|||||||
return filterErrors(compiler().errors(), _includeWarningsAndInfos);
|
return filterErrors(compiler().errors(), _includeWarningsAndInfos);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> m_warningsToFilter = {"This is a pre-release compiler version"};
|
|
||||||
std::vector<std::string> m_messagesToCut = {"Source file requires different compiler version (current compiler is"};
|
|
||||||
|
|
||||||
/// @returns reference to lazy-instantiated CompilerStack.
|
/// @returns reference to lazy-instantiated CompilerStack.
|
||||||
solidity::frontend::CompilerStack& compiler()
|
solidity::frontend::CompilerStack& compiler()
|
||||||
{
|
{
|
||||||
@ -99,12 +140,25 @@ protected:
|
|||||||
return *m_compiler;
|
return *m_compiler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
/// Creates a new instance of @p CompilerStack. Override if your test case needs to pass in
|
/// Creates a new instance of @p CompilerStack. Override if your test case needs to pass in
|
||||||
/// custom constructor arguments.
|
/// custom constructor arguments.
|
||||||
virtual std::unique_ptr<CompilerStack> createStack() const;
|
virtual std::unique_ptr<CompilerStack> createStack() const;
|
||||||
|
|
||||||
|
/// Configures @p CompilerStack. The default implementation sets basic parameters based on
|
||||||
|
/// CLI options. Override if your test case needs extra configuration.
|
||||||
|
virtual void setupCompiler(CompilerStack& _compiler);
|
||||||
|
|
||||||
|
/// Executes the requested pipeline stages until @p m_targetStage is reached.
|
||||||
|
/// Stops at the first failed stage.
|
||||||
|
void executeCompilationPipeline();
|
||||||
|
|
||||||
|
std::vector<std::string> m_warningsToFilter = {"This is a pre-release compiler version"};
|
||||||
|
std::vector<std::string> m_messagesToCut = {"Source file requires different compiler version (current compiler is"};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable std::unique_ptr<solidity::frontend::CompilerStack> m_compiler;
|
mutable std::unique_ptr<solidity::frontend::CompilerStack> m_compiler;
|
||||||
|
PipelineStage m_targetStage = PipelineStage::Compilation;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Asserts that the compilation down to typechecking
|
// Asserts that the compilation down to typechecking
|
||||||
@ -112,15 +166,15 @@ private:
|
|||||||
#define CHECK_ALLOW_MULTI(text, expectations) \
|
#define CHECK_ALLOW_MULTI(text, expectations) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
ErrorList errors = expectError((text), true, true); \
|
ErrorList errors = runAnalysisAndExpectError((text), true, true); \
|
||||||
auto message = searchErrors(errors, (expectations)); \
|
auto message = searchErrors(errors, (expectations)); \
|
||||||
BOOST_CHECK_MESSAGE(message.empty(), message); \
|
BOOST_CHECK_MESSAGE(message.empty(), message); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
#define CHECK_ERROR_OR_WARNING(text, typ, substrings, warning, allowMulti) \
|
#define CHECK_ERROR_OR_WARNING(text, typ, substrings, includeWarningsAndInfos, allowMulti) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
ErrorList errors = expectError((text), (warning), (allowMulti)); \
|
ErrorList errors = runAnalysisAndExpectError((text), (includeWarningsAndInfos), (allowMulti)); \
|
||||||
std::vector<std::pair<Error::Type, std::string>> expectations; \
|
std::vector<std::pair<Error::Type, std::string>> expectations; \
|
||||||
for (auto const& str: substrings) \
|
for (auto const& str: substrings) \
|
||||||
expectations.emplace_back((Error::Type::typ), str); \
|
expectations.emplace_back((Error::Type::typ), str); \
|
||||||
@ -154,16 +208,19 @@ CHECK_ERROR_OR_WARNING(text, Warning, std::vector<std::string>{(substring)}, tru
|
|||||||
CHECK_ERROR_OR_WARNING(text, Warning, substrings, true, true)
|
CHECK_ERROR_OR_WARNING(text, Warning, substrings, true, true)
|
||||||
|
|
||||||
// [checkSuccess(text)] asserts that the compilation down to typechecking succeeds.
|
// [checkSuccess(text)] asserts that the compilation down to typechecking succeeds.
|
||||||
#define CHECK_SUCCESS(text) do { BOOST_CHECK(success((text))); } while(0)
|
#define CHECK_SUCCESS(text) do { \
|
||||||
|
auto [ast, errors] = runAnalysisAndExpectNoParsingErrors((text)); \
|
||||||
|
BOOST_CHECK(errors.empty()); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
#define CHECK_SUCCESS_NO_WARNINGS(text) \
|
#define CHECK_SUCCESS_NO_WARNINGS(text) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
auto sourceAndError = parseAnalyseAndReturnError((text), true); \
|
auto [ast, errors] = runAnalysisAndExpectNoParsingErrors((text), true); \
|
||||||
std::string message; \
|
std::string message; \
|
||||||
if (!sourceAndError.second.empty()) \
|
if (!errors.empty()) \
|
||||||
message = formatErrors(compiler().errors());\
|
message = formatErrors(errors);\
|
||||||
BOOST_CHECK_MESSAGE(sourceAndError.second.empty(), message); \
|
BOOST_CHECK_MESSAGE(errors.empty(), message); \
|
||||||
} \
|
} \
|
||||||
while(0)
|
while(0)
|
||||||
|
|
||||||
|
@ -97,13 +97,14 @@ void GasTest::printUpdatedExpectations(std::ostream& _stream, std::string const&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TestCase::TestResult GasTest::run(std::ostream& _stream, std::string const& _linePrefix, bool _formatted)
|
void GasTest::setupCompiler(CompilerStack& _compiler)
|
||||||
{
|
{
|
||||||
compiler().reset();
|
AnalysisFramework::setupCompiler(_compiler);
|
||||||
|
|
||||||
// Prerelease CBOR metadata varies in size due to changing version numbers and build dates.
|
// Prerelease CBOR metadata varies in size due to changing version numbers and build dates.
|
||||||
// This leads to volatile creation cost estimates. Therefore we force the compiler to
|
// This leads to volatile creation cost estimates. Therefore we force the compiler to
|
||||||
// release mode for testing gas estimates.
|
// release mode for testing gas estimates.
|
||||||
compiler().setMetadataFormat(CompilerStack::MetadataFormat::NoMetadata);
|
_compiler.setMetadataFormat(CompilerStack::MetadataFormat::NoMetadata);
|
||||||
OptimiserSettings settings = m_optimise ? OptimiserSettings::standard() : OptimiserSettings::minimal();
|
OptimiserSettings settings = m_optimise ? OptimiserSettings::standard() : OptimiserSettings::minimal();
|
||||||
if (m_optimiseYul)
|
if (m_optimiseYul)
|
||||||
{
|
{
|
||||||
@ -111,10 +112,16 @@ TestCase::TestResult GasTest::run(std::ostream& _stream, std::string const& _lin
|
|||||||
settings.optimizeStackAllocation = m_optimise;
|
settings.optimizeStackAllocation = m_optimise;
|
||||||
}
|
}
|
||||||
settings.expectedExecutionsPerDeployment = m_optimiseRuns;
|
settings.expectedExecutionsPerDeployment = m_optimiseRuns;
|
||||||
compiler().setOptimiserSettings(settings);
|
_compiler.setOptimiserSettings(settings);
|
||||||
compiler().setSources({{"", withPreamble(m_source)}});
|
|
||||||
|
|
||||||
if (!compiler().parseAndAnalyze() || !compiler().compile())
|
// Intentionally ignoring EVM version specified on the command line.
|
||||||
|
// Gas expectations are only valid for the default version.
|
||||||
|
_compiler.setEVMVersion(EVMVersion{});
|
||||||
|
}
|
||||||
|
|
||||||
|
TestCase::TestResult GasTest::run(std::ostream& _stream, std::string const& _linePrefix, bool _formatted)
|
||||||
|
{
|
||||||
|
if (!runFramework(withPreamble(m_source), PipelineStage::Compilation))
|
||||||
{
|
{
|
||||||
_stream << formatErrors(filteredErrors(), _formatted);
|
_stream << formatErrors(filteredErrors(), _formatted);
|
||||||
return TestResult::FatalError;
|
return TestResult::FatalError;
|
||||||
|
@ -44,6 +44,9 @@ public:
|
|||||||
void printSource(std::ostream &_stream, std::string const &_linePrefix = "", bool _formatted = false) const override;
|
void printSource(std::ostream &_stream, std::string const &_linePrefix = "", bool _formatted = false) const override;
|
||||||
void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override;
|
void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void setupCompiler(CompilerStack& _compiler) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void parseExpectations(std::istream& _stream);
|
void parseExpectations(std::istream& _stream);
|
||||||
|
|
||||||
|
@ -36,13 +36,17 @@ using namespace solidity::frontend;
|
|||||||
using namespace solidity::frontend::test;
|
using namespace solidity::frontend::test;
|
||||||
using namespace yul;
|
using namespace yul;
|
||||||
|
|
||||||
|
void MemoryGuardTest::setupCompiler(CompilerStack& _compiler)
|
||||||
|
{
|
||||||
|
AnalysisFramework::setupCompiler(_compiler);
|
||||||
|
|
||||||
|
_compiler.setViaIR(true);
|
||||||
|
_compiler.setOptimiserSettings(OptimiserSettings::none());
|
||||||
|
}
|
||||||
|
|
||||||
TestCase::TestResult MemoryGuardTest::run(std::ostream& _stream, std::string const& _linePrefix, bool _formatted)
|
TestCase::TestResult MemoryGuardTest::run(std::ostream& _stream, std::string const& _linePrefix, bool _formatted)
|
||||||
{
|
{
|
||||||
compiler().reset();
|
if (!runFramework(m_source, PipelineStage::Compilation))
|
||||||
compiler().setSources(StringMap{{"", m_source}});
|
|
||||||
compiler().setViaIR(true);
|
|
||||||
compiler().setOptimiserSettings(OptimiserSettings::none());
|
|
||||||
if (!compiler().compile())
|
|
||||||
{
|
{
|
||||||
_stream << formatErrors(filteredErrors(), _formatted);
|
_stream << formatErrors(filteredErrors(), _formatted);
|
||||||
return TestResult::FatalError;
|
return TestResult::FatalError;
|
||||||
|
@ -48,6 +48,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false) override;
|
TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void setupCompiler(CompilerStack& _compiler) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -126,11 +126,11 @@ SMTCheckerTest::SMTCheckerTest(std::string const& _filename): SyntaxTest(_filena
|
|||||||
m_modelCheckerSettings.bmcLoopIterations = std::optional<unsigned>{bmcLoopIterations};
|
m_modelCheckerSettings.bmcLoopIterations = std::optional<unsigned>{bmcLoopIterations};
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMTCheckerTest::setupCompiler()
|
void SMTCheckerTest::setupCompiler(CompilerStack& _compiler)
|
||||||
{
|
{
|
||||||
SyntaxTest::setupCompiler();
|
SyntaxTest::setupCompiler(_compiler);
|
||||||
|
|
||||||
compiler().setModelCheckerSettings(m_modelCheckerSettings);
|
_compiler.setModelCheckerSettings(m_modelCheckerSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMTCheckerTest::filterObtainedErrors()
|
void SMTCheckerTest::filterObtainedErrors()
|
||||||
|
@ -38,7 +38,7 @@ public:
|
|||||||
}
|
}
|
||||||
SMTCheckerTest(std::string const& _filename);
|
SMTCheckerTest(std::string const& _filename);
|
||||||
|
|
||||||
void setupCompiler() override;
|
void setupCompiler(CompilerStack& _compiler) override;
|
||||||
void filterObtainedErrors() override;
|
void filterObtainedErrors() override;
|
||||||
|
|
||||||
void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override;
|
void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override;
|
||||||
|
@ -28,7 +28,19 @@
|
|||||||
namespace solidity::frontend::test
|
namespace solidity::frontend::test
|
||||||
{
|
{
|
||||||
|
|
||||||
BOOST_FIXTURE_TEST_SUITE(SolidityCompiler, AnalysisFramework)
|
class SolidityCompilerFixture: protected AnalysisFramework
|
||||||
|
{
|
||||||
|
void setupCompiler(CompilerStack& _compiler) override
|
||||||
|
{
|
||||||
|
AnalysisFramework::setupCompiler(_compiler);
|
||||||
|
|
||||||
|
// FIXME: This test was probably supposed to respect CommonOptions::get().optimize but
|
||||||
|
// due to a bug it was always running with optimizer disabled and it does not pass with it.
|
||||||
|
_compiler.setOptimiserSettings(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_SUITE(SolidityCompiler, SolidityCompilerFixture)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(does_not_include_creation_time_only_internal_functions)
|
BOOST_AUTO_TEST_CASE(does_not_include_creation_time_only_internal_functions)
|
||||||
{
|
{
|
||||||
@ -39,12 +51,13 @@ BOOST_AUTO_TEST_CASE(does_not_include_creation_time_only_internal_functions)
|
|||||||
function f() internal { unchecked { for (uint i = 0; i < 10; ++i) x += 3 + i; } }
|
function f() internal { unchecked { for (uint i = 0; i < 10; ++i) x += 3 + i; } }
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
compiler().setOptimiserSettings(solidity::test::CommonOptions::get().optimize);
|
|
||||||
BOOST_REQUIRE(success(sourceCode));
|
runFramework(sourceCode, PipelineStage::Compilation);
|
||||||
BOOST_REQUIRE_MESSAGE(
|
BOOST_REQUIRE_MESSAGE(
|
||||||
compiler().compile(),
|
pipelineSuccessful(),
|
||||||
"Contract compilation failed:\n" + formatErrors(filteredErrors(), true /* _colored */)
|
"Contract compilation failed:\n" + formatErrors(filteredErrors(), true /* _colored */)
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes const& creationBytecode = solidity::test::bytecodeSansMetadata(compiler().object("C").bytecode);
|
bytes const& creationBytecode = solidity::test::bytecodeSansMetadata(compiler().object("C").bytecode);
|
||||||
bytes const& runtimeBytecode = solidity::test::bytecodeSansMetadata(compiler().runtimeObject("C").bytecode);
|
bytes const& runtimeBytecode = solidity::test::bytecodeSansMetadata(compiler().runtimeObject("C").bytecode);
|
||||||
BOOST_CHECK(creationBytecode.size() >= 90);
|
BOOST_CHECK(creationBytecode.size() >= 90);
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <test/libsolidity/AnalysisFramework.h>
|
#include <test/libsolidity/AnalysisFramework.h>
|
||||||
|
#include <test/libsolidity/util/SoltestErrors.h>
|
||||||
|
|
||||||
#include <test/Common.h>
|
#include <test/Common.h>
|
||||||
|
|
||||||
@ -41,13 +42,15 @@ BOOST_FIXTURE_TEST_SUITE(SolidityNameAndTypeResolution, AnalysisFramework)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(function_no_implementation)
|
BOOST_AUTO_TEST_CASE(function_no_implementation)
|
||||||
{
|
{
|
||||||
SourceUnit const* sourceUnit = nullptr;
|
|
||||||
char const* text = R"(
|
char const* text = R"(
|
||||||
abstract contract test {
|
abstract contract test {
|
||||||
function functionName(bytes32 input) public virtual returns (bytes32 out);
|
function functionName(bytes32 input) public virtual returns (bytes32 out);
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
sourceUnit = parseAndAnalyse(text);
|
auto [sourceUnit, errors] = runAnalysisAndExpectNoParsingErrors(text);
|
||||||
|
soltestAssert(sourceUnit);
|
||||||
|
soltestAssert(errors.empty(), "Unexpected error: " + formatErrors(errors));
|
||||||
|
|
||||||
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->nodes();
|
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->nodes();
|
||||||
ContractDefinition* contract = dynamic_cast<ContractDefinition*>(nodes[1].get());
|
ContractDefinition* contract = dynamic_cast<ContractDefinition*>(nodes[1].get());
|
||||||
BOOST_REQUIRE(contract);
|
BOOST_REQUIRE(contract);
|
||||||
@ -57,12 +60,14 @@ BOOST_AUTO_TEST_CASE(function_no_implementation)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(abstract_contract)
|
BOOST_AUTO_TEST_CASE(abstract_contract)
|
||||||
{
|
{
|
||||||
SourceUnit const* sourceUnit = nullptr;
|
|
||||||
char const* text = R"(
|
char const* text = R"(
|
||||||
abstract contract base { function foo() public virtual; }
|
abstract contract base { function foo() public virtual; }
|
||||||
contract derived is base { function foo() public override {} }
|
contract derived is base { function foo() public override {} }
|
||||||
)";
|
)";
|
||||||
sourceUnit = parseAndAnalyse(text);
|
auto [sourceUnit, errors] = runAnalysisAndExpectNoParsingErrors(text);
|
||||||
|
soltestAssert(sourceUnit);
|
||||||
|
soltestAssert(errors.empty(), "Unexpected error: " + formatErrors(errors));
|
||||||
|
|
||||||
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->nodes();
|
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->nodes();
|
||||||
ContractDefinition* base = dynamic_cast<ContractDefinition*>(nodes[1].get());
|
ContractDefinition* base = dynamic_cast<ContractDefinition*>(nodes[1].get());
|
||||||
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
|
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
|
||||||
@ -76,12 +81,14 @@ BOOST_AUTO_TEST_CASE(abstract_contract)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(abstract_contract_with_overload)
|
BOOST_AUTO_TEST_CASE(abstract_contract_with_overload)
|
||||||
{
|
{
|
||||||
SourceUnit const* sourceUnit = nullptr;
|
|
||||||
char const* text = R"(
|
char const* text = R"(
|
||||||
abstract contract base { function foo(bool) public virtual; }
|
abstract contract base { function foo(bool) public virtual; }
|
||||||
abstract contract derived is base { function foo(uint) public {} }
|
abstract contract derived is base { function foo(uint) public {} }
|
||||||
)";
|
)";
|
||||||
sourceUnit = parseAndAnalyse(text);
|
auto [sourceUnit, errors] = runAnalysisAndExpectNoParsingErrors(text);
|
||||||
|
soltestAssert(sourceUnit);
|
||||||
|
soltestAssert(errors.empty(), "Unexpected error: " + formatErrors(errors));
|
||||||
|
|
||||||
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->nodes();
|
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->nodes();
|
||||||
ContractDefinition* base = dynamic_cast<ContractDefinition*>(nodes[1].get());
|
ContractDefinition* base = dynamic_cast<ContractDefinition*>(nodes[1].get());
|
||||||
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
|
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
|
||||||
@ -93,12 +100,14 @@ BOOST_AUTO_TEST_CASE(abstract_contract_with_overload)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(implement_abstract_via_constructor)
|
BOOST_AUTO_TEST_CASE(implement_abstract_via_constructor)
|
||||||
{
|
{
|
||||||
SourceUnit const* sourceUnit = nullptr;
|
|
||||||
char const* text = R"(
|
char const* text = R"(
|
||||||
abstract contract base { function foo() public virtual; }
|
abstract contract base { function foo() public virtual; }
|
||||||
abstract contract foo is base { constructor() {} }
|
abstract contract foo is base { constructor() {} }
|
||||||
)";
|
)";
|
||||||
sourceUnit = parseAndAnalyse(text);
|
auto [sourceUnit, errors] = runAnalysisAndExpectNoParsingErrors(text);
|
||||||
|
soltestAssert(sourceUnit);
|
||||||
|
soltestAssert(errors.empty(), "Unexpected error: " + formatErrors(errors));
|
||||||
|
|
||||||
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->nodes();
|
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->nodes();
|
||||||
BOOST_CHECK_EQUAL(nodes.size(), 3);
|
BOOST_CHECK_EQUAL(nodes.size(), 3);
|
||||||
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
|
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
|
||||||
@ -108,7 +117,6 @@ BOOST_AUTO_TEST_CASE(implement_abstract_via_constructor)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(function_canonical_signature)
|
BOOST_AUTO_TEST_CASE(function_canonical_signature)
|
||||||
{
|
{
|
||||||
SourceUnit const* sourceUnit = nullptr;
|
|
||||||
char const* text = R"(
|
char const* text = R"(
|
||||||
contract Test {
|
contract Test {
|
||||||
function foo(uint256 arg1, uint64 arg2, bool arg3) public returns (uint256 ret) {
|
function foo(uint256 arg1, uint64 arg2, bool arg3) public returns (uint256 ret) {
|
||||||
@ -116,7 +124,10 @@ BOOST_AUTO_TEST_CASE(function_canonical_signature)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
sourceUnit = parseAndAnalyse(text);
|
auto [sourceUnit, errors] = runAnalysisAndExpectNoParsingErrors(text);
|
||||||
|
soltestAssert(sourceUnit);
|
||||||
|
soltestAssert(errors.empty(), "Unexpected error: " + formatErrors(errors));
|
||||||
|
|
||||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||||
{
|
{
|
||||||
@ -127,7 +138,6 @@ BOOST_AUTO_TEST_CASE(function_canonical_signature)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(function_canonical_signature_type_aliases)
|
BOOST_AUTO_TEST_CASE(function_canonical_signature_type_aliases)
|
||||||
{
|
{
|
||||||
SourceUnit const* sourceUnit = nullptr;
|
|
||||||
char const* text = R"(
|
char const* text = R"(
|
||||||
contract Test {
|
contract Test {
|
||||||
function boo(uint, bytes32, address) public returns (uint ret) {
|
function boo(uint, bytes32, address) public returns (uint ret) {
|
||||||
@ -135,7 +145,10 @@ BOOST_AUTO_TEST_CASE(function_canonical_signature_type_aliases)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
sourceUnit = parseAndAnalyse(text);
|
auto [sourceUnit, errors] = runAnalysisAndExpectNoParsingErrors(text);
|
||||||
|
soltestAssert(sourceUnit);
|
||||||
|
soltestAssert(errors.empty(), "Unexpected error: " + formatErrors(errors));
|
||||||
|
|
||||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||||
{
|
{
|
||||||
@ -148,7 +161,6 @@ BOOST_AUTO_TEST_CASE(function_canonical_signature_type_aliases)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(function_external_types)
|
BOOST_AUTO_TEST_CASE(function_external_types)
|
||||||
{
|
{
|
||||||
SourceUnit const* sourceUnit = nullptr;
|
|
||||||
char const* text = R"(
|
char const* text = R"(
|
||||||
contract C {
|
contract C {
|
||||||
uint a;
|
uint a;
|
||||||
@ -159,7 +171,10 @@ BOOST_AUTO_TEST_CASE(function_external_types)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
sourceUnit = parseAndAnalyse(text);
|
auto [sourceUnit, errors] = runAnalysisAndExpectNoParsingErrors(text);
|
||||||
|
soltestAssert(sourceUnit);
|
||||||
|
soltestAssert(errors.empty(), "Unexpected error: " + formatErrors(errors));
|
||||||
|
|
||||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||||
{
|
{
|
||||||
@ -172,7 +187,6 @@ BOOST_AUTO_TEST_CASE(function_external_types)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(enum_external_type)
|
BOOST_AUTO_TEST_CASE(enum_external_type)
|
||||||
{
|
{
|
||||||
SourceUnit const* sourceUnit = nullptr;
|
|
||||||
char const* text = R"(
|
char const* text = R"(
|
||||||
// test for bug #1801
|
// test for bug #1801
|
||||||
contract Test {
|
contract Test {
|
||||||
@ -182,7 +196,10 @@ BOOST_AUTO_TEST_CASE(enum_external_type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
sourceUnit = parseAndAnalyse(text);
|
auto [sourceUnit, errors] = runAnalysisAndExpectNoParsingErrors(text);
|
||||||
|
soltestAssert(sourceUnit);
|
||||||
|
soltestAssert(errors.empty(), "Unexpected error: " + formatErrors(errors));
|
||||||
|
|
||||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||||
{
|
{
|
||||||
@ -211,7 +228,7 @@ BOOST_AUTO_TEST_CASE(external_struct_signatures)
|
|||||||
// Ignore analysis errors. This test only checks that correct signatures
|
// Ignore analysis errors. This test only checks that correct signatures
|
||||||
// are generated for external structs, but they are not yet supported
|
// are generated for external structs, but they are not yet supported
|
||||||
// in code generation and therefore cause an error in the TypeChecker.
|
// in code generation and therefore cause an error in the TypeChecker.
|
||||||
SourceUnit const* sourceUnit = parseAnalyseAndReturnError(text, false, true, true).first;
|
SourceUnit const* sourceUnit = runAnalysisAndExpectNoParsingErrors(text, false, true, true).first;
|
||||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||||
{
|
{
|
||||||
@ -242,7 +259,7 @@ BOOST_AUTO_TEST_CASE(external_struct_signatures_in_libraries)
|
|||||||
// Ignore analysis errors. This test only checks that correct signatures
|
// Ignore analysis errors. This test only checks that correct signatures
|
||||||
// are generated for external structs, but calldata structs are not yet supported
|
// are generated for external structs, but calldata structs are not yet supported
|
||||||
// in code generation and therefore cause an error in the TypeChecker.
|
// in code generation and therefore cause an error in the TypeChecker.
|
||||||
SourceUnit const* sourceUnit = parseAnalyseAndReturnError(text, false, true, true).first;
|
SourceUnit const* sourceUnit = runAnalysisAndExpectNoParsingErrors(text, false, true, true).first;
|
||||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||||
{
|
{
|
||||||
@ -264,7 +281,10 @@ BOOST_AUTO_TEST_CASE(struct_with_mapping_in_library)
|
|||||||
function f(X storage x) external {}
|
function f(X storage x) external {}
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
SourceUnit const* sourceUnit = parseAndAnalyse(text);
|
auto [sourceUnit, errors] = runAnalysisAndExpectNoParsingErrors(text);
|
||||||
|
soltestAssert(sourceUnit);
|
||||||
|
soltestAssert(errors.empty(), "Unexpected error: " + formatErrors(errors));
|
||||||
|
|
||||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||||
{
|
{
|
||||||
@ -287,10 +307,12 @@ BOOST_AUTO_TEST_CASE(state_variable_accessors)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
|
||||||
SourceUnit const* source;
|
auto [sourceUnit, errors] = runAnalysisAndExpectNoParsingErrors(text);
|
||||||
|
soltestAssert(sourceUnit);
|
||||||
|
soltestAssert(errors.empty(), "Unexpected error: " + formatErrors(errors));
|
||||||
|
|
||||||
ContractDefinition const* contract;
|
ContractDefinition const* contract;
|
||||||
source = parseAndAnalyse(text);
|
BOOST_REQUIRE((contract = retrieveContractByName(*sourceUnit, "test")) != nullptr);
|
||||||
BOOST_REQUIRE((contract = retrieveContractByName(*source, "test")) != nullptr);
|
|
||||||
FunctionTypePointer function = retrieveFunctionBySignature(*contract, "foo()");
|
FunctionTypePointer function = retrieveFunctionBySignature(*contract, "foo()");
|
||||||
BOOST_REQUIRE(function && function->hasDeclaration());
|
BOOST_REQUIRE(function && function->hasDeclaration());
|
||||||
auto returnParams = function->returnParameterTypes();
|
auto returnParams = function->returnParameterTypes();
|
||||||
@ -327,9 +349,12 @@ BOOST_AUTO_TEST_CASE(private_state_variable)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
|
||||||
|
auto [sourceUnit, errors] = runAnalysisAndExpectNoParsingErrors(text);
|
||||||
|
soltestAssert(sourceUnit);
|
||||||
|
soltestAssert(errors.empty(), "Unexpected error: " + formatErrors(errors));
|
||||||
|
|
||||||
ContractDefinition const* contract;
|
ContractDefinition const* contract;
|
||||||
SourceUnit const* source = parseAndAnalyse(text);
|
BOOST_CHECK((contract = retrieveContractByName(*sourceUnit, "test")) != nullptr);
|
||||||
BOOST_CHECK((contract = retrieveContractByName(*source, "test")) != nullptr);
|
|
||||||
FunctionTypePointer function;
|
FunctionTypePointer function;
|
||||||
function = retrieveFunctionBySignature(*contract, "foo()");
|
function = retrieveFunctionBySignature(*contract, "foo()");
|
||||||
BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of a private variable should not exist");
|
BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of a private variable should not exist");
|
||||||
@ -345,7 +370,7 @@ BOOST_AUTO_TEST_CASE(string)
|
|||||||
function f(string calldata x) external { s = x; }
|
function f(string calldata x) external { s = x; }
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
BOOST_CHECK_NO_THROW(parseAndAnalyse(sourceCode));
|
CHECK_SUCCESS(sourceCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(dynamic_return_types_not_possible)
|
BOOST_AUTO_TEST_CASE(dynamic_return_types_not_possible)
|
||||||
@ -372,7 +397,7 @@ BOOST_AUTO_TEST_CASE(warn_nonpresent_pragma)
|
|||||||
// SPDX-License-Identifier: GPL-3.0
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
contract C {}
|
contract C {}
|
||||||
)";
|
)";
|
||||||
auto sourceAndError = parseAnalyseAndReturnError(text, true, false);
|
auto sourceAndError = runAnalysisAndExpectNoParsingErrors(text, true, false);
|
||||||
BOOST_REQUIRE(!sourceAndError.second.empty());
|
BOOST_REQUIRE(!sourceAndError.second.empty());
|
||||||
BOOST_REQUIRE(!!sourceAndError.first);
|
BOOST_REQUIRE(!!sourceAndError.first);
|
||||||
BOOST_CHECK(searchErrorMessage(*sourceAndError.second.front(), "Source file does not specify required compiler version!"));
|
BOOST_CHECK(searchErrorMessage(*sourceAndError.second.front(), "Source file does not specify required compiler version!"));
|
||||||
|
@ -49,53 +49,51 @@ SyntaxTest::SyntaxTest(
|
|||||||
m_optimiseYul = m_reader.boolSetting("optimize-yul", true);
|
m_optimiseYul = m_reader.boolSetting("optimize-yul", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SyntaxTest::setupCompiler()
|
void SyntaxTest::setupCompiler(CompilerStack& _compiler)
|
||||||
{
|
{
|
||||||
compiler().reset();
|
AnalysisFramework::setupCompiler(_compiler);
|
||||||
compiler().setSources(withPreamble(m_sources.sources));
|
|
||||||
compiler().setEVMVersion(m_evmVersion);
|
_compiler.setEVMVersion(m_evmVersion);
|
||||||
compiler().setOptimiserSettings(
|
_compiler.setOptimiserSettings(
|
||||||
m_optimiseYul ?
|
m_optimiseYul ?
|
||||||
OptimiserSettings::full() :
|
OptimiserSettings::full() :
|
||||||
OptimiserSettings::minimal()
|
OptimiserSettings::minimal()
|
||||||
);
|
);
|
||||||
compiler().setMetadataFormat(CompilerStack::MetadataFormat::NoMetadata);
|
_compiler.setMetadataFormat(CompilerStack::MetadataFormat::NoMetadata);
|
||||||
compiler().setMetadataHash(CompilerStack::MetadataHash::None);
|
_compiler.setMetadataHash(CompilerStack::MetadataHash::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SyntaxTest::parseAndAnalyze()
|
void SyntaxTest::parseAndAnalyze()
|
||||||
{
|
{
|
||||||
setupCompiler();
|
try
|
||||||
|
{
|
||||||
if (compiler().parse() && compiler().analyze())
|
runFramework(withPreamble(m_sources.sources), PipelineStage::Compilation);
|
||||||
try
|
if (!pipelineSuccessful() && stageSuccessful(PipelineStage::Analysis))
|
||||||
{
|
{
|
||||||
if (!compiler().compile())
|
ErrorList const& errors = compiler().errors();
|
||||||
{
|
auto codeGeneretionErrorCount = count_if(errors.cbegin(), errors.cend(), [](auto const& error) {
|
||||||
ErrorList const& errors = compiler().errors();
|
return error->type() == Error::Type::CodeGenerationError;
|
||||||
auto codeGeneretionErrorCount = count_if(errors.cbegin(), errors.cend(), [](auto const& error) {
|
|
||||||
return error->type() == Error::Type::CodeGenerationError;
|
|
||||||
});
|
|
||||||
auto errorCount = count_if(errors.cbegin(), errors.cend(), [](auto const& error) {
|
|
||||||
return Error::isError(error->type());
|
|
||||||
});
|
|
||||||
// failing compilation after successful analysis is a rare case,
|
|
||||||
// it assumes that errors contain exactly one error, and the error is of type Error::Type::CodeGenerationError
|
|
||||||
if (codeGeneretionErrorCount != 1 || errorCount != 1)
|
|
||||||
BOOST_THROW_EXCEPTION(runtime_error("Compilation failed even though analysis was successful."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (UnimplementedFeatureError const& _e)
|
|
||||||
{
|
|
||||||
m_errorList.emplace_back(SyntaxTestError{
|
|
||||||
"UnimplementedFeatureError",
|
|
||||||
nullopt,
|
|
||||||
errorMessage(_e),
|
|
||||||
"",
|
|
||||||
-1,
|
|
||||||
-1
|
|
||||||
});
|
});
|
||||||
|
auto errorCount = count_if(errors.cbegin(), errors.cend(), [](auto const& error) {
|
||||||
|
return Error::isError(error->type());
|
||||||
|
});
|
||||||
|
// failing compilation after successful analysis is a rare case,
|
||||||
|
// it assumes that errors contain exactly one error, and the error is of type Error::Type::CodeGenerationError
|
||||||
|
if (codeGeneretionErrorCount != 1 || errorCount != 1)
|
||||||
|
BOOST_THROW_EXCEPTION(runtime_error("Compilation failed even though analysis was successful."));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (UnimplementedFeatureError const& _e)
|
||||||
|
{
|
||||||
|
m_errorList.emplace_back(SyntaxTestError{
|
||||||
|
"UnimplementedFeatureError",
|
||||||
|
nullopt,
|
||||||
|
errorMessage(_e),
|
||||||
|
"",
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
filterObtainedErrors();
|
filterObtainedErrors();
|
||||||
}
|
}
|
||||||
@ -146,4 +144,3 @@ void SyntaxTest::filterObtainedErrors()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ public:
|
|||||||
);
|
);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void setupCompiler();
|
void setupCompiler(CompilerStack& _compiler) override;
|
||||||
void parseAndAnalyze() override;
|
void parseAndAnalyze() override;
|
||||||
virtual void filterObtainedErrors();
|
virtual void filterObtainedErrors();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user