Merge pull request #11971 from ethereum/parseASTID

Parse ast-id
This commit is contained in:
chriseth 2021-09-16 18:07:17 +02:00 committed by GitHub
commit 2d75043051
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 188 additions and 8 deletions

View File

@ -29,6 +29,7 @@
#include <liblangutil/SourceLocation.h>
#include <memory>
#include <optional>
namespace solidity::yul
{
@ -37,12 +38,22 @@ using Type = YulString;
struct DebugData
{
explicit DebugData(langutil::SourceLocation _location): location(std::move(_location)) {}
langutil::SourceLocation location;
static std::shared_ptr<DebugData const> create(langutil::SourceLocation _location = {})
explicit DebugData(langutil::SourceLocation _location, std::optional<int64_t> _astID = {}):
location(std::move(_location)),
astID(std::move(_astID))
{}
static std::shared_ptr<DebugData const> create(
langutil::SourceLocation _location = {},
std::optional<int64_t> _astID = {}
)
{
return std::make_shared<DebugData const>(_location);
return std::make_shared<DebugData const>(std::move(_location), std::move(_astID));
}
langutil::SourceLocation location;
/// ID in the (Solidity) source AST.
std::optional<int64_t> astID;
};
struct TypedName { std::shared_ptr<DebugData const> debugData; YulString name; Type type; };

View File

@ -103,7 +103,7 @@ unique_ptr<Block> Parser::parseInline(std::shared_ptr<Scanner> const& _scanner)
try
{
m_scanner = _scanner;
if (m_sourceNames)
if (m_useSourceLocationFrom == UseSourceLocationFrom::Comments)
fetchDebugDataFromComment();
return make_unique<Block>(parseBlock());
}
@ -136,6 +136,8 @@ void Parser::fetchDebugDataFromComment()
match_results<string_view::const_iterator> match;
langutil::SourceLocation sourceLocation = m_debugDataOverride->location;
// Empty for each new node.
optional<int> astID;
while (regex_search(commentLiteral.cbegin(), commentLiteral.cend(), match, tagRegex))
{
@ -149,12 +151,19 @@ void Parser::fetchDebugDataFromComment()
else
break;
}
else if (match[1] == "@ast-id")
{
if (auto parseResult = parseASTIDComment(commentLiteral, m_scanner->currentCommentLocation()))
tie(commentLiteral, astID) = *parseResult;
else
break;
}
else
// Ignore unrecognized tags.
continue;
}
m_debugDataOverride = DebugData::create(sourceLocation);
m_debugDataOverride = DebugData::create(sourceLocation, astID);
}
optional<pair<string_view, SourceLocation>> Parser::parseSrcComment(
@ -222,6 +231,38 @@ optional<pair<string_view, SourceLocation>> Parser::parseSrcComment(
return {{tail, SourceLocation{}}};
}
optional<pair<string_view, optional<int>>> Parser::parseASTIDComment(
string_view _arguments,
langutil::SourceLocation const& _commentLocation
)
{
static regex const argRegex = regex(
R"~~(^(\d+)(?:\s|$))~~",
regex_constants::ECMAScript | regex_constants::optimize
);
match_results<string_view::const_iterator> match;
optional<int> astID;
bool matched = regex_search(_arguments.cbegin(), _arguments.cend(), match, argRegex);
string_view tail = _arguments;
if (matched)
{
solAssert(match.size() == 2, "");
tail = _arguments.substr(static_cast<size_t>(match.position() + match.length()));
astID = toInt(match[1].str());
}
if (!matched || !astID || *astID < 0 || static_cast<int64_t>(*astID) != *astID)
{
m_errorReporter.syntaxError(1749_error, _commentLocation, "Invalid argument for @ast-id.");
astID = nullopt;
}
if (matched)
return {{_arguments, astID}};
else
return nullopt;
}
Block Parser::parseBlock()
{
RecursionGuard recursionGuard(*this);

View File

@ -108,8 +108,12 @@ protected:
void fetchDebugDataFromComment();
std::optional<std::pair<std::string_view, langutil::SourceLocation>>
parseSrcComment(
std::optional<std::pair<std::string_view, langutil::SourceLocation>> parseSrcComment(
std::string_view _arguments,
langutil::SourceLocation const& _commentLocation
);
std::optional<std::pair<std::string_view, std::optional<int>>> parseASTIDComment(
std::string_view _arguments,
langutil::SourceLocation const& _commentLocation
);

View File

@ -193,6 +193,7 @@ def examine_id_coverage(top_dir, source_id_to_file_names, new_ids_only=False):
white_ids = {
"9804", # Tested in test/libyul/ObjectParser.cpp.
"1544",
"1749",
"2674",
"6367",
"8387",

View File

@ -804,6 +804,129 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_with_code_snippets_with_nested_locati
CHECK_LOCATION(literal128.debugData->location, "source1", 96, 165);
}
BOOST_AUTO_TEST_CASE(astid)
{
ErrorList errorList;
ErrorReporter reporter(errorList);
auto const sourceText = R"(
/// @src -1:-1:-1 @ast-id 7
{
/** @ast-id 2 */
function f(x) -> y {}
mstore(1, 2)
}
)";
EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{});
shared_ptr<Block> result = parse(sourceText, dialect, reporter);
BOOST_REQUIRE(!!result);
BOOST_CHECK(result->debugData->astID == int64_t(7));
auto const& funDef = get<FunctionDefinition>(result->statements.at(0));
BOOST_CHECK(funDef.debugData->astID == int64_t(2));
BOOST_CHECK(funDef.parameters.at(0).debugData->astID == nullopt);
BOOST_CHECK(debugDataOf(result->statements.at(1))->astID == nullopt);
}
BOOST_AUTO_TEST_CASE(astid_reset)
{
ErrorList errorList;
ErrorReporter reporter(errorList);
auto const sourceText = R"(
/// @src -1:-1:-1 @ast-id 7 @src 1:1:1
{
/** @ast-id 2 */
function f(x) -> y {}
mstore(1, 2)
}
)";
EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{});
shared_ptr<Block> result = parse(sourceText, dialect, reporter);
BOOST_REQUIRE(!!result);
BOOST_CHECK(result->debugData->astID == int64_t(7));
auto const& funDef = get<FunctionDefinition>(result->statements.at(0));
BOOST_CHECK(funDef.debugData->astID == int64_t(2));
BOOST_CHECK(funDef.parameters.at(0).debugData->astID == nullopt);
BOOST_CHECK(debugDataOf(result->statements.at(1))->astID == nullopt);
}
BOOST_AUTO_TEST_CASE(astid_multi)
{
ErrorList errorList;
ErrorReporter reporter(errorList);
auto const sourceText = R"(
/// @src -1:-1:-1 @ast-id 7 @src 1:1:1 @ast-id 8
{}
)";
EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{});
shared_ptr<Block> result = parse(sourceText, dialect, reporter);
BOOST_REQUIRE(!!result);
BOOST_CHECK(result->debugData->astID == int64_t(8));
}
BOOST_AUTO_TEST_CASE(astid_invalid)
{
ErrorList errorList;
ErrorReporter reporter(errorList);
auto const sourceText = R"(
/// @src -1:-1:-1 @ast-id abc @src 1:1:1
{}
)";
EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{});
shared_ptr<Block> result = parse(sourceText, dialect, reporter);
BOOST_REQUIRE(!!result);
BOOST_REQUIRE(errorList.size() == 1);
BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError);
BOOST_TEST(errorList[0]->errorId() == 1749_error);
CHECK_LOCATION(result->debugData->location, "", -1, -1);
}
BOOST_AUTO_TEST_CASE(astid_too_large)
{
ErrorList errorList;
ErrorReporter reporter(errorList);
auto const sourceText = R"(
/// @ast-id 9223372036854775808
{}
)";
EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{});
shared_ptr<Block> result = parse(sourceText, dialect, reporter);
BOOST_REQUIRE(!!result);
BOOST_REQUIRE(errorList.size() == 1);
BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError);
BOOST_TEST(errorList[0]->errorId() == 1749_error);
}
BOOST_AUTO_TEST_CASE(astid_way_too_large)
{
ErrorList errorList;
ErrorReporter reporter(errorList);
auto const sourceText = R"(
/// @ast-id 999999999999999999999999999999999999999
{}
)";
EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{});
shared_ptr<Block> result = parse(sourceText, dialect, reporter);
BOOST_REQUIRE(!!result);
BOOST_REQUIRE(errorList.size() == 1);
BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError);
BOOST_TEST(errorList[0]->errorId() == 1749_error);
}
BOOST_AUTO_TEST_CASE(astid_not_fully_numeric)
{
ErrorList errorList;
ErrorReporter reporter(errorList);
auto const sourceText = R"(
/// @ast-id 9x
{}
)";
EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{});
shared_ptr<Block> result = parse(sourceText, dialect, reporter);
BOOST_REQUIRE(!!result);
BOOST_REQUIRE(errorList.size() == 1);
BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError);
BOOST_TEST(errorList[0]->errorId() == 1749_error);
}
BOOST_AUTO_TEST_CASE(customSourceLocations_multiple_src_tags_on_one_line)
{
ErrorList errorList;