mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Support multiple sources for syntax tests.
This commit is contained in:
parent
95d426bd88
commit
6ed219ebe8
@ -62,11 +62,15 @@ bool TestCase::validateSettings(langutil::EVMVersion)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pair<string, size_t> TestCase::parseSourceAndSettingsWithLineNumbers(istream& _stream)
|
pair<map<string, string>, size_t> TestCase::parseSourcesAndSettingsWithLineNumbers(istream& _stream)
|
||||||
{
|
{
|
||||||
string source;
|
map<string, string> sources;
|
||||||
|
string currentSourceName;
|
||||||
|
string currentSource;
|
||||||
string line;
|
string line;
|
||||||
size_t lineNumber = 1;
|
size_t lineNumber = 1;
|
||||||
|
static string const sourceDelimiterStart("==== Source:");
|
||||||
|
static string const sourceDelimiterEnd("====");
|
||||||
static string const comment("// ");
|
static string const comment("// ");
|
||||||
static string const settingsDelimiter("// ====");
|
static string const settingsDelimiter("// ====");
|
||||||
static string const delimiter("// ----");
|
static string const delimiter("// ----");
|
||||||
@ -80,7 +84,22 @@ pair<string, size_t> TestCase::parseSourceAndSettingsWithLineNumbers(istream& _s
|
|||||||
else if (boost::algorithm::starts_with(line, settingsDelimiter))
|
else if (boost::algorithm::starts_with(line, settingsDelimiter))
|
||||||
sourcePart = false;
|
sourcePart = false;
|
||||||
else if (sourcePart)
|
else if (sourcePart)
|
||||||
source += line + "\n";
|
{
|
||||||
|
if (boost::algorithm::starts_with(line, sourceDelimiterStart) && boost::algorithm::ends_with(line, sourceDelimiterEnd))
|
||||||
|
{
|
||||||
|
if (!(currentSourceName.empty() && currentSource.empty()))
|
||||||
|
sources[currentSourceName] = std::move(currentSource);
|
||||||
|
currentSource = {};
|
||||||
|
currentSourceName = boost::trim_copy(line.substr(
|
||||||
|
sourceDelimiterStart.size(),
|
||||||
|
line.size() - sourceDelimiterEnd.size() - sourceDelimiterStart.size()
|
||||||
|
));
|
||||||
|
if (sources.count(currentSourceName))
|
||||||
|
throw runtime_error("Multiple definitions of test source \"" + currentSourceName + "\".");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
currentSource += line + "\n";
|
||||||
|
}
|
||||||
else if (boost::algorithm::starts_with(line, comment))
|
else if (boost::algorithm::starts_with(line, comment))
|
||||||
{
|
{
|
||||||
size_t colon = line.find(':');
|
size_t colon = line.find(':');
|
||||||
@ -95,12 +114,26 @@ pair<string, size_t> TestCase::parseSourceAndSettingsWithLineNumbers(istream& _s
|
|||||||
else
|
else
|
||||||
throw runtime_error(string("Expected \"//\" or \"// ---\" to terminate settings and source."));
|
throw runtime_error(string("Expected \"//\" or \"// ---\" to terminate settings and source."));
|
||||||
}
|
}
|
||||||
return make_pair(source, lineNumber);
|
sources[currentSourceName] = currentSource;
|
||||||
|
return {sources, lineNumber};
|
||||||
|
}
|
||||||
|
|
||||||
|
map<string, string> TestCase::parseSourcesAndSettings(istream& _stream)
|
||||||
|
{
|
||||||
|
return get<0>(parseSourcesAndSettingsWithLineNumbers(_stream));
|
||||||
|
}
|
||||||
|
|
||||||
|
pair<string, size_t> TestCase::parseSourceAndSettingsWithLineNumbers(istream& _stream)
|
||||||
|
{
|
||||||
|
auto [sourceMap, lineOffset] = parseSourcesAndSettingsWithLineNumbers(_stream);
|
||||||
|
if (sourceMap.size() != 1)
|
||||||
|
BOOST_THROW_EXCEPTION(runtime_error("Expected single source definition, but got multiple sources."));
|
||||||
|
return {std::move(sourceMap.begin()->second), lineOffset};
|
||||||
}
|
}
|
||||||
|
|
||||||
string TestCase::parseSourceAndSettings(istream& _stream)
|
string TestCase::parseSourceAndSettings(istream& _stream)
|
||||||
{
|
{
|
||||||
return get<0>(parseSourceAndSettingsWithLineNumbers(_stream));
|
return parseSourceAndSettingsWithLineNumbers(_stream).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
string TestCase::parseSimpleExpectations(std::istream& _file)
|
string TestCase::parseSimpleExpectations(std::istream& _file)
|
||||||
|
@ -80,6 +80,8 @@ public:
|
|||||||
virtual bool validateSettings(langutil::EVMVersion /*_evmVersion*/);
|
virtual bool validateSettings(langutil::EVMVersion /*_evmVersion*/);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
std::pair<std::map<std::string, std::string>, std::size_t> parseSourcesAndSettingsWithLineNumbers(std::istream& _file);
|
||||||
|
std::map<std::string, std::string> parseSourcesAndSettings(std::istream& _file);
|
||||||
std::pair<std::string, std::size_t> parseSourceAndSettingsWithLineNumbers(std::istream& _file);
|
std::pair<std::string, std::size_t> parseSourceAndSettingsWithLineNumbers(std::istream& _file);
|
||||||
std::string parseSourceAndSettings(std::istream& _file);
|
std::string parseSourceAndSettings(std::istream& _file);
|
||||||
static void expect(std::string::iterator& _it, std::string::iterator _end, std::string::value_type _c);
|
static void expect(std::string::iterator& _it, std::string::iterator _end, std::string::value_type _c);
|
||||||
|
@ -108,6 +108,9 @@ TestCase::TestResult SMTCheckerTest::run(ostream& _stream, string const& _linePr
|
|||||||
BOOST_THROW_EXCEPTION(runtime_error("Error must have a SourceLocation with start and end."));
|
BOOST_THROW_EXCEPTION(runtime_error("Error must have a SourceLocation with start and end."));
|
||||||
int start = location["start"].asInt();
|
int start = location["start"].asInt();
|
||||||
int end = location["end"].asInt();
|
int end = location["end"].asInt();
|
||||||
|
std::string sourceName;
|
||||||
|
if (location.isMember("source") && location["source"].isString())
|
||||||
|
sourceName = location["source"].asString();
|
||||||
if (start >= static_cast<int>(versionPragma.size()))
|
if (start >= static_cast<int>(versionPragma.size()))
|
||||||
start -= versionPragma.size();
|
start -= versionPragma.size();
|
||||||
if (end >= static_cast<int>(versionPragma.size()))
|
if (end >= static_cast<int>(versionPragma.size()))
|
||||||
@ -115,6 +118,7 @@ TestCase::TestResult SMTCheckerTest::run(ostream& _stream, string const& _linePr
|
|||||||
m_errorList.emplace_back(SyntaxTestError{
|
m_errorList.emplace_back(SyntaxTestError{
|
||||||
error["type"].asString(),
|
error["type"].asString(),
|
||||||
error["message"].asString(),
|
error["message"].asString(),
|
||||||
|
sourceName,
|
||||||
start,
|
start,
|
||||||
end
|
end
|
||||||
});
|
});
|
||||||
@ -141,13 +145,20 @@ vector<string> SMTCheckerTest::hashesFromJson(Json::Value const& _jsonObj, strin
|
|||||||
Json::Value SMTCheckerTest::buildJson(string const& _extra)
|
Json::Value SMTCheckerTest::buildJson(string const& _extra)
|
||||||
{
|
{
|
||||||
string language = "\"language\": \"Solidity\"";
|
string language = "\"language\": \"Solidity\"";
|
||||||
string sourceName = "\"A\"";
|
string sources = " \"sources\": { ";
|
||||||
string sourceContent = "\"" + _extra + m_source + "\"";
|
bool first = true;
|
||||||
string sourceObj = "{ \"content\": " + sourceContent + "}";
|
for (auto [sourceName, sourceContent]: m_sources)
|
||||||
string sources = " \"sources\": { " + sourceName + ": " + sourceObj + "}";
|
{
|
||||||
|
string sourceObj = "{ \"content\": \"" + _extra + sourceContent + "\"}";
|
||||||
|
if (!first)
|
||||||
|
sources += ", ";
|
||||||
|
sources += "\"" + sourceName + "\": " + sourceObj;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
sources += "}";
|
||||||
string input = "{" + language + ", " + sources + "}";
|
string input = "{" + language + ", " + sources + "}";
|
||||||
Json::Value source;
|
Json::Value source;
|
||||||
if (!jsonParse(input, source))
|
if (!jsonParse(input, source))
|
||||||
BOOST_THROW_EXCEPTION(runtime_error("Could not build JSON from string."));
|
BOOST_THROW_EXCEPTION(runtime_error("Could not build JSON from string: " + input));
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,8 @@ SyntaxTest::SyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion
|
|||||||
BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\"."));
|
BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\"."));
|
||||||
file.exceptions(ios::badbit);
|
file.exceptions(ios::badbit);
|
||||||
|
|
||||||
m_source = parseSourceAndSettings(file);
|
m_sources = parseSourcesAndSettings(file);
|
||||||
|
|
||||||
if (m_settings.count("optimize-yul"))
|
if (m_settings.count("optimize-yul"))
|
||||||
{
|
{
|
||||||
m_optimiseYul = true;
|
m_optimiseYul = true;
|
||||||
@ -74,7 +75,10 @@ TestCase::TestResult SyntaxTest::run(ostream& _stream, string const& _linePrefix
|
|||||||
{
|
{
|
||||||
string const versionPragma = "pragma solidity >=0.0;\n";
|
string const versionPragma = "pragma solidity >=0.0;\n";
|
||||||
compiler().reset();
|
compiler().reset();
|
||||||
compiler().setSources({{"", versionPragma + m_source}});
|
auto sourcesWithPragma = m_sources;
|
||||||
|
for (auto& source: sourcesWithPragma)
|
||||||
|
source.second = versionPragma + source.second;
|
||||||
|
compiler().setSources(sourcesWithPragma);
|
||||||
compiler().setEVMVersion(m_evmVersion);
|
compiler().setEVMVersion(m_evmVersion);
|
||||||
compiler().setParserErrorRecovery(m_parserErrorRecovery);
|
compiler().setParserErrorRecovery(m_parserErrorRecovery);
|
||||||
compiler().setOptimiserSettings(
|
compiler().setOptimiserSettings(
|
||||||
@ -94,6 +98,7 @@ TestCase::TestResult SyntaxTest::run(ostream& _stream, string const& _linePrefix
|
|||||||
m_errorList.emplace_back(SyntaxTestError{
|
m_errorList.emplace_back(SyntaxTestError{
|
||||||
"UnimplementedFeatureError",
|
"UnimplementedFeatureError",
|
||||||
errorMessage(_e),
|
errorMessage(_e),
|
||||||
|
"",
|
||||||
-1,
|
-1,
|
||||||
-1
|
-1
|
||||||
});
|
});
|
||||||
@ -102,6 +107,7 @@ TestCase::TestResult SyntaxTest::run(ostream& _stream, string const& _linePrefix
|
|||||||
for (auto const& currentError: filterErrors(compiler().errors(), true))
|
for (auto const& currentError: filterErrors(compiler().errors(), true))
|
||||||
{
|
{
|
||||||
int locationStart = -1, locationEnd = -1;
|
int locationStart = -1, locationEnd = -1;
|
||||||
|
string sourceName;
|
||||||
if (auto location = boost::get_error_info<errinfo_sourceLocation>(*currentError))
|
if (auto location = boost::get_error_info<errinfo_sourceLocation>(*currentError))
|
||||||
{
|
{
|
||||||
// ignore the version pragma inserted by the testing tool when calculating locations.
|
// ignore the version pragma inserted by the testing tool when calculating locations.
|
||||||
@ -109,10 +115,13 @@ TestCase::TestResult SyntaxTest::run(ostream& _stream, string const& _linePrefix
|
|||||||
locationStart = location->start - versionPragma.size();
|
locationStart = location->start - versionPragma.size();
|
||||||
if (location->end >= static_cast<int>(versionPragma.size()))
|
if (location->end >= static_cast<int>(versionPragma.size()))
|
||||||
locationEnd = location->end - versionPragma.size();
|
locationEnd = location->end - versionPragma.size();
|
||||||
|
if (location->source)
|
||||||
|
sourceName = location->source->name();
|
||||||
}
|
}
|
||||||
m_errorList.emplace_back(SyntaxTestError{
|
m_errorList.emplace_back(SyntaxTestError{
|
||||||
currentError->typeName(),
|
currentError->typeName(),
|
||||||
errorMessage(*currentError),
|
errorMessage(*currentError),
|
||||||
|
sourceName,
|
||||||
locationStart,
|
locationStart,
|
||||||
locationEnd
|
locationEnd
|
||||||
});
|
});
|
||||||
@ -137,17 +146,26 @@ bool SyntaxTest::printExpectationAndError(ostream& _stream, string const& _lineP
|
|||||||
|
|
||||||
void SyntaxTest::printSource(ostream& _stream, string const& _linePrefix, bool _formatted) const
|
void SyntaxTest::printSource(ostream& _stream, string const& _linePrefix, bool _formatted) const
|
||||||
{
|
{
|
||||||
if (_formatted)
|
|
||||||
{
|
if (m_sources.empty())
|
||||||
if (m_source.empty())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
vector<char const*> sourceFormatting(m_source.length(), formatting::RESET);
|
bool outputSourceNames = true;
|
||||||
for (auto const& error: m_errorList)
|
if (m_sources.size() == 1 && m_sources.begin()->first.empty())
|
||||||
if (error.locationStart >= 0 && error.locationEnd >= 0)
|
outputSourceNames = false;
|
||||||
|
|
||||||
|
if (_formatted)
|
||||||
{
|
{
|
||||||
assert(static_cast<size_t>(error.locationStart) <= m_source.length());
|
for (auto const& [name, source]: m_sources)
|
||||||
assert(static_cast<size_t>(error.locationEnd) <= m_source.length());
|
{
|
||||||
|
if (outputSourceNames)
|
||||||
|
_stream << _linePrefix << formatting::CYAN << "==== Source: " << name << " ====" << formatting::RESET << endl;
|
||||||
|
vector<char const*> sourceFormatting(source.length(), formatting::RESET);
|
||||||
|
for (auto const& error: m_errorList)
|
||||||
|
if (error.sourceName == name && error.locationStart >= 0 && error.locationEnd >= 0)
|
||||||
|
{
|
||||||
|
assert(static_cast<size_t>(error.locationStart) <= source.length());
|
||||||
|
assert(static_cast<size_t>(error.locationEnd) <= source.length());
|
||||||
bool isWarning = error.type == "Warning";
|
bool isWarning = error.type == "Warning";
|
||||||
for (int i = error.locationStart; i < error.locationEnd; i++)
|
for (int i = error.locationStart; i < error.locationEnd; i++)
|
||||||
if (isWarning)
|
if (isWarning)
|
||||||
@ -159,25 +177,30 @@ void SyntaxTest::printSource(ostream& _stream, string const& _linePrefix, bool _
|
|||||||
sourceFormatting[i] = formatting::RED_BACKGROUND;
|
sourceFormatting[i] = formatting::RED_BACKGROUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
_stream << _linePrefix << sourceFormatting.front() << m_source.front();
|
_stream << _linePrefix << sourceFormatting.front() << source.front();
|
||||||
for (size_t i = 1; i < m_source.length(); i++)
|
for (size_t i = 1; i < source.length(); i++)
|
||||||
{
|
{
|
||||||
if (sourceFormatting[i] != sourceFormatting[i - 1])
|
if (sourceFormatting[i] != sourceFormatting[i - 1])
|
||||||
_stream << sourceFormatting[i];
|
_stream << sourceFormatting[i];
|
||||||
if (m_source[i] != '\n')
|
if (source[i] != '\n')
|
||||||
_stream << m_source[i];
|
_stream << source[i];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_stream << formatting::RESET << endl;
|
_stream << formatting::RESET << endl;
|
||||||
if (i + 1 < m_source.length())
|
if (i + 1 < source.length())
|
||||||
_stream << _linePrefix << sourceFormatting[i];
|
_stream << _linePrefix << sourceFormatting[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_stream << formatting::RESET;
|
_stream << formatting::RESET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
for (auto const& [name, source]: m_sources)
|
||||||
{
|
{
|
||||||
stringstream stream(m_source);
|
if (outputSourceNames)
|
||||||
|
_stream << _linePrefix << "==== Source: " + name << " ====" << endl;
|
||||||
|
stringstream stream(source);
|
||||||
string line;
|
string line;
|
||||||
while (getline(stream, line))
|
while (getline(stream, line))
|
||||||
_stream << _linePrefix << line << endl;
|
_stream << _linePrefix << line << endl;
|
||||||
@ -201,9 +224,11 @@ void SyntaxTest::printErrorList(
|
|||||||
_stream << _linePrefix;
|
_stream << _linePrefix;
|
||||||
_stream << error.type << ": ";
|
_stream << error.type << ": ";
|
||||||
}
|
}
|
||||||
if (error.locationStart >= 0 || error.locationEnd >= 0)
|
if (!error.sourceName.empty() || error.locationStart >= 0 || error.locationEnd >= 0)
|
||||||
{
|
{
|
||||||
_stream << "(";
|
_stream << "(";
|
||||||
|
if (!error.sourceName.empty())
|
||||||
|
_stream << error.sourceName << ":";
|
||||||
if (error.locationStart >= 0)
|
if (error.locationStart >= 0)
|
||||||
_stream << error.locationStart;
|
_stream << error.locationStart;
|
||||||
_stream << "-";
|
_stream << "-";
|
||||||
@ -248,10 +273,19 @@ vector<SyntaxTestError> SyntaxTest::parseExpectations(istream& _stream)
|
|||||||
|
|
||||||
int locationStart = -1;
|
int locationStart = -1;
|
||||||
int locationEnd = -1;
|
int locationEnd = -1;
|
||||||
|
std::string sourceName;
|
||||||
|
|
||||||
if (it != line.end() && *it == '(')
|
if (it != line.end() && *it == '(')
|
||||||
{
|
{
|
||||||
++it;
|
++it;
|
||||||
|
if (it != line.end() && !isdigit(*it))
|
||||||
|
{
|
||||||
|
auto sourceNameStart = it;
|
||||||
|
while (it != line.end() && *it != ':')
|
||||||
|
++it;
|
||||||
|
sourceName = std::string(sourceNameStart, it);
|
||||||
|
expect(it, line.end(), ':');
|
||||||
|
}
|
||||||
locationStart = parseUnsignedInteger(it, line.end());
|
locationStart = parseUnsignedInteger(it, line.end());
|
||||||
expect(it, line.end(), '-');
|
expect(it, line.end(), '-');
|
||||||
locationEnd = parseUnsignedInteger(it, line.end());
|
locationEnd = parseUnsignedInteger(it, line.end());
|
||||||
@ -265,6 +299,7 @@ vector<SyntaxTestError> SyntaxTest::parseExpectations(istream& _stream)
|
|||||||
expectations.emplace_back(SyntaxTestError{
|
expectations.emplace_back(SyntaxTestError{
|
||||||
move(errorType),
|
move(errorType),
|
||||||
move(errorMessage),
|
move(errorMessage),
|
||||||
|
move(sourceName),
|
||||||
locationStart,
|
locationStart,
|
||||||
locationEnd
|
locationEnd
|
||||||
});
|
});
|
||||||
|
@ -38,12 +38,14 @@ struct SyntaxTestError
|
|||||||
{
|
{
|
||||||
std::string type;
|
std::string type;
|
||||||
std::string message;
|
std::string message;
|
||||||
|
std::string sourceName;
|
||||||
int locationStart;
|
int locationStart;
|
||||||
int locationEnd;
|
int locationEnd;
|
||||||
bool operator==(SyntaxTestError const& _rhs) const
|
bool operator==(SyntaxTestError const& _rhs) const
|
||||||
{
|
{
|
||||||
return type == _rhs.type &&
|
return type == _rhs.type &&
|
||||||
message == _rhs.message &&
|
message == _rhs.message &&
|
||||||
|
sourceName == _rhs.sourceName &&
|
||||||
locationStart == _rhs.locationStart &&
|
locationStart == _rhs.locationStart &&
|
||||||
locationEnd == _rhs.locationEnd;
|
locationEnd == _rhs.locationEnd;
|
||||||
}
|
}
|
||||||
@ -85,7 +87,7 @@ protected:
|
|||||||
|
|
||||||
static std::vector<SyntaxTestError> parseExpectations(std::istream& _stream);
|
static std::vector<SyntaxTestError> parseExpectations(std::istream& _stream);
|
||||||
|
|
||||||
std::string m_source;
|
std::map<std::string, std::string> m_sources;
|
||||||
std::vector<SyntaxTestError> m_expectations;
|
std::vector<SyntaxTestError> m_expectations;
|
||||||
std::vector<SyntaxTestError> m_errorList;
|
std::vector<SyntaxTestError> m_errorList;
|
||||||
bool m_optimiseYul = false;
|
bool m_optimiseYul = false;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
==== Source: A ====
|
||||||
pragma experimental SMTChecker;
|
pragma experimental SMTChecker;
|
||||||
|
|
||||||
contract C
|
contract C
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
==== Source: A ====
|
||||||
pragma experimental SMTChecker;
|
pragma experimental SMTChecker;
|
||||||
|
|
||||||
contract C
|
contract C
|
||||||
|
10
test/libsolidity/syntaxTests/multiSource/error_in_first.sol
Normal file
10
test/libsolidity/syntaxTests/multiSource/error_in_first.sol
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
==== Source: A ====
|
||||||
|
contract A {
|
||||||
|
function g() public { x; }
|
||||||
|
}
|
||||||
|
==== Source: B ====
|
||||||
|
contract B {
|
||||||
|
function f() public { }
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// DeclarationError: (A:36-37): Undeclared identifier.
|
12
test/libsolidity/syntaxTests/multiSource/import.sol
Normal file
12
test/libsolidity/syntaxTests/multiSource/import.sol
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
==== Source: A ====
|
||||||
|
contract A {
|
||||||
|
function g(uint256 x) public view returns(uint256) { return x; }
|
||||||
|
}
|
||||||
|
==== Source: B ====
|
||||||
|
import "A";
|
||||||
|
contract B is A {
|
||||||
|
function f(uint256 x) public view returns(uint256) { return x; }
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// Warning: (A:14-78): Function state mutability can be restricted to pure
|
||||||
|
// Warning: (B:31-95): Function state mutability can be restricted to pure
|
@ -0,0 +1,5 @@
|
|||||||
|
==== Source: a ====
|
||||||
|
import "b";
|
||||||
|
contract C {}
|
||||||
|
// ----
|
||||||
|
// ParserError: (a:0-11): Source "b" not found: File not supplied initially.
|
10
test/libsolidity/syntaxTests/multiSource/no_import.sol
Normal file
10
test/libsolidity/syntaxTests/multiSource/no_import.sol
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
==== Source: A ====
|
||||||
|
contract A {
|
||||||
|
function g(uint256 x) public view returns(uint256) { return x; }
|
||||||
|
}
|
||||||
|
==== Source: B ====
|
||||||
|
contract B is A {
|
||||||
|
function f(uint256 x) public view returns(uint256) { return x; }
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// DeclarationError: (B:14-15): Identifier not found or not unique.
|
7
test/libsolidity/syntaxTests/multiSource/one_source.sol
Normal file
7
test/libsolidity/syntaxTests/multiSource/one_source.sol
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
==== Source: SourceName ====
|
||||||
|
contract A {
|
||||||
|
uint256 x;
|
||||||
|
function f() public pure { x = 42; }
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError: (SourceName:53-54): Function declared as pure, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable.
|
11
test/libsolidity/syntaxTests/multiSource/warning_in_both.sol
Normal file
11
test/libsolidity/syntaxTests/multiSource/warning_in_both.sol
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
==== Source: A ====
|
||||||
|
contract A {
|
||||||
|
function g(uint256 x) public view returns(uint256) { return x; }
|
||||||
|
}
|
||||||
|
==== Source: B ====
|
||||||
|
contract B {
|
||||||
|
function f(uint256 x) public view returns(uint256) { return x; }
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// Warning: (A:14-78): Function state mutability can be restricted to pure
|
||||||
|
// Warning: (B:14-78): Function state mutability can be restricted to pure
|
Loading…
Reference in New Issue
Block a user