Skip to content

Commit 4a02e9a

Browse files
authored
Merge pull request ethereum#11867 from ethereum/solidity-snippets-next-to-source-locations-in-ir
Solidity snippets next to source locations in IR
2 parents 49cde9d + 14639ef commit 4a02e9a

File tree

41 files changed

+1221
-352
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1221
-352
lines changed

libsolidity/ast/ASTJsonConverter.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
#include <libsolidity/ast/TypeProvider.h>
2727

2828
#include <libyul/AsmJsonConverter.h>
29-
#include <libyul/AsmPrinter.h>
3029
#include <libyul/AST.h>
3130
#include <libyul/backends/evm/EVMDialect.h>
3231

libsolidity/codegen/ir/Common.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,13 @@
2222

2323
#include <libsolutil/CommonIO.h>
2424

25+
#include <libyul/AsmPrinter.h>
26+
2527
using namespace std;
26-
using namespace solidity::util;
28+
using namespace solidity::langutil;
2729
using namespace solidity::frontend;
30+
using namespace solidity::util;
31+
using namespace solidity::yul;
2832

2933
namespace solidity::frontend
3034
{
@@ -131,12 +135,12 @@ string dispenseLocationComment(langutil::SourceLocation const& _location, IRGene
131135
{
132136
solAssert(_location.sourceName, "");
133137
_context.markSourceUsed(*_location.sourceName);
134-
return "/// @src "
135-
+ to_string(_context.sourceIndices().at(*_location.sourceName))
136-
+ ":"
137-
+ to_string(_location.start)
138-
+ ":"
139-
+ to_string(_location.end);
138+
return AsmPrinter::formatSourceLocationComment(
139+
_location,
140+
_context.sourceIndices(),
141+
true /* _statement */,
142+
_context.soliditySourceProvider()
143+
);
140144
}
141145

142146
string dispenseLocationComment(ASTNode const& _node, IRGenerationContext& _context)

libsolidity/codegen/ir/IRGenerationContext.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <libsolidity/codegen/MultiUseYulFunctionCollector.h>
3030
#include <libsolidity/codegen/ir/Common.h>
3131

32+
#include <liblangutil/CharStreamProvider.h>
3233
#include <liblangutil/EVMVersion.h>
3334

3435
#include <libsolutil/Common.h>
@@ -72,13 +73,15 @@ class IRGenerationContext
7273
ExecutionContext _executionContext,
7374
RevertStrings _revertStrings,
7475
OptimiserSettings _optimiserSettings,
75-
std::map<std::string, unsigned> _sourceIndices
76+
std::map<std::string, unsigned> _sourceIndices,
77+
langutil::CharStreamProvider const* _soliditySourceProvider
7678
):
7779
m_evmVersion(_evmVersion),
7880
m_executionContext(_executionContext),
7981
m_revertStrings(_revertStrings),
8082
m_optimiserSettings(std::move(_optimiserSettings)),
81-
m_sourceIndices(std::move(_sourceIndices))
83+
m_sourceIndices(std::move(_sourceIndices)),
84+
m_soliditySourceProvider(_soliditySourceProvider)
8285
{}
8386

8487
MultiUseYulFunctionCollector& functionCollector() { return m_functions; }
@@ -171,6 +174,8 @@ class IRGenerationContext
171174

172175
bool immutableRegistered(VariableDeclaration const& _varDecl) const { return m_immutableVariables.count(&_varDecl); }
173176

177+
langutil::CharStreamProvider const* soliditySourceProvider() const { return m_soliditySourceProvider; }
178+
174179
private:
175180
langutil::EVMVersion m_evmVersion;
176181
ExecutionContext m_executionContext;
@@ -214,6 +219,8 @@ class IRGenerationContext
214219
std::map<int64_t, uint64_t> m_functionIDs;
215220

216221
std::set<ContractDefinition const*, ASTNode::CompareByID> m_subObjects;
222+
223+
langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr;
217224
};
218225

219226
}

libsolidity/codegen/ir/IRGenerator.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@
4545

4646
using namespace std;
4747
using namespace solidity;
48-
using namespace solidity::util;
4948
using namespace solidity::frontend;
49+
using namespace solidity::langutil;
50+
using namespace solidity::util;
5051

5152
namespace
5253
{
@@ -115,7 +116,7 @@ pair<string, string> IRGenerator::run(
115116
" * !USE AT YOUR OWN RISK! *\n"
116117
" *=====================================================*/\n\n";
117118

118-
return {warning + ir, warning + asmStack.print()};
119+
return {warning + ir, warning + asmStack.print(m_context.soliditySourceProvider())};
119120
}
120121

121122
string IRGenerator::generate(
@@ -1064,7 +1065,14 @@ void IRGenerator::resetContext(ContractDefinition const& _contract, ExecutionCon
10641065
m_context.internalDispatchClean(),
10651066
"Reset internal dispatch map without consuming it."
10661067
);
1067-
IRGenerationContext newContext(m_evmVersion, _context, m_context.revertStrings(), m_optimiserSettings, m_context.sourceIndices());
1068+
IRGenerationContext newContext(
1069+
m_evmVersion,
1070+
_context,
1071+
m_context.revertStrings(),
1072+
m_optimiserSettings,
1073+
m_context.sourceIndices(),
1074+
m_context.soliditySourceProvider()
1075+
);
10681076
newContext.copyFunctionIDsFrom(m_context);
10691077
m_context = move(newContext);
10701078

libsolidity/codegen/ir/IRGenerator.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@
2828
#include <libsolidity/ast/CallGraph.h>
2929
#include <libsolidity/codegen/ir/IRGenerationContext.h>
3030
#include <libsolidity/codegen/YulUtilFunctions.h>
31+
32+
#include <liblangutil/CharStreamProvider.h>
3133
#include <liblangutil/EVMVersion.h>
34+
3235
#include <string>
3336

3437
namespace solidity::frontend
@@ -45,11 +48,19 @@ class IRGenerator
4548
langutil::EVMVersion _evmVersion,
4649
RevertStrings _revertStrings,
4750
OptimiserSettings _optimiserSettings,
48-
std::map<std::string, unsigned> _sourceIndices
51+
std::map<std::string, unsigned> _sourceIndices,
52+
langutil::CharStreamProvider const* _soliditySourceProvider
4953
):
5054
m_evmVersion(_evmVersion),
5155
m_optimiserSettings(_optimiserSettings),
52-
m_context(_evmVersion, ExecutionContext::Creation, _revertStrings, std::move(_optimiserSettings), std::move(_sourceIndices)),
56+
m_context(
57+
_evmVersion,
58+
ExecutionContext::Creation,
59+
_revertStrings,
60+
std::move(_optimiserSettings),
61+
std::move(_sourceIndices),
62+
_soliditySourceProvider
63+
),
5364
m_utils(_evmVersion, m_context.revertStrings(), m_context.functionCollector())
5465
{}
5566

libsolidity/interface/CompilerStack.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1329,7 +1329,7 @@ void CompilerStack::generateIR(ContractDefinition const& _contract)
13291329
for (auto const& pair: m_contracts)
13301330
otherYulSources.emplace(pair.second.contract, pair.second.yulIR);
13311331

1332-
IRGenerator generator(m_evmVersion, m_revertStrings, m_optimiserSettings, sourceIndices());
1332+
IRGenerator generator(m_evmVersion, m_revertStrings, m_optimiserSettings, sourceIndices(), this);
13331333
tie(compiledContract.yulIR, compiledContract.yulIROptimized) = generator.run(
13341334
_contract,
13351335
createCBORMetadata(compiledContract),

libyul/AsmParser.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ void Parser::fetchSourceLocationFromComment()
135135
regex_constants::ECMAScript | regex_constants::optimize
136136
);
137137
static regex const srcTagArgsRegex = regex(
138-
R"~~(^(-1|\d+):(-1|\d+):(-1|\d+)(?:\s+|$))~~", // index and location, e.g.: 1:234:-1
138+
R"~~(^(-1|\d+):(-1|\d+):(-1|\d+)(?:\s+|$))~~" // index and location, e.g.: 1:234:-1
139+
R"~~(("(?:[^"\\]|\\.)*"?)?)~~", // optional code snippet, e.g.: "string memory s = \"abc\";..."
139140
regex_constants::ECMAScript | regex_constants::optimize
140141
);
141142

@@ -164,9 +165,22 @@ void Parser::fetchSourceLocationFromComment()
164165
return;
165166
}
166167

167-
solAssert(srcTagArgsMatch.size() == 4, "");
168+
solAssert(srcTagArgsMatch.size() == 5, "");
168169
position += srcTagArgsMatch.position() + srcTagArgsMatch.length();
169170

171+
if (srcTagArgsMatch[4].matched && (
172+
!boost::algorithm::ends_with(srcTagArgsMatch[4].str(), "\"") ||
173+
boost::algorithm::ends_with(srcTagArgsMatch[4].str(), "\\\"")
174+
))
175+
{
176+
m_errorReporter.syntaxError(
177+
1544_error,
178+
commentLocation,
179+
"Invalid code snippet in source location mapping. Quote is not terminated."
180+
);
181+
return;
182+
}
183+
170184
optional<int> const sourceIndex = toInt(srcTagArgsMatch[1].str());
171185
optional<int> const start = toInt(srcTagArgsMatch[2].str());
172186
optional<int> const end = toInt(srcTagArgsMatch[3].str());

libyul/AsmPrinter.cpp

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <libyul/Dialect.h>
2828

2929
#include <libsolutil/CommonData.h>
30+
#include <libsolutil/StringUtils.h>
3031

3132
#include <boost/algorithm/string.hpp>
3233
#include <boost/algorithm/string/replace.hpp>
@@ -38,6 +39,7 @@
3839

3940
using namespace std;
4041
using namespace solidity;
42+
using namespace solidity::langutil;
4143
using namespace solidity::util;
4244
using namespace solidity::yul;
4345

@@ -256,30 +258,63 @@ string AsmPrinter::appendTypeName(YulString _type, bool _isBoolLiteral) const
256258
return ":" + _type.str();
257259
}
258260

259-
string AsmPrinter::formatSourceLocationComment(shared_ptr<DebugData const> const& _debugData, bool _statement)
261+
string AsmPrinter::formatSourceLocationComment(
262+
SourceLocation const& _location,
263+
map<string, unsigned> const& _nameToSourceIndex,
264+
bool _statement,
265+
CharStreamProvider const* _soliditySourceProvider
266+
)
260267
{
261-
if (
262-
!_debugData ||
263-
m_lastLocation == _debugData->location ||
264-
m_nameToSourceIndex.empty()
265-
)
266-
return "";
267-
268-
m_lastLocation = _debugData->location;
268+
yulAssert(!_nameToSourceIndex.empty(), "");
269269

270270
string sourceIndex = "-1";
271-
if (_debugData->location.sourceName)
272-
sourceIndex = to_string(m_nameToSourceIndex.at(*_debugData->location.sourceName));
271+
string solidityCodeSnippet = "";
272+
if (_location.sourceName)
273+
{
274+
sourceIndex = to_string(_nameToSourceIndex.at(*_location.sourceName));
275+
276+
if (_soliditySourceProvider)
277+
{
278+
solidityCodeSnippet = escapeAndQuoteString(
279+
_soliditySourceProvider->charStream(*_location.sourceName).singleLineSnippet(_location)
280+
);
281+
282+
// On top of escaping quotes we also escape the slash inside any `*/` to guard against
283+
// it prematurely terminating multi-line comment blocks. We do not escape all slashes
284+
// because the ones without `*` are not dangerous and ignoring them reduces visual noise.
285+
boost::replace_all(solidityCodeSnippet, "*/", "*\\/");
286+
}
287+
}
273288

274289
string sourceLocation =
275290
"@src " +
276291
sourceIndex +
277292
":" +
278-
to_string(_debugData->location.start) +
293+
to_string(_location.start) +
279294
":" +
280-
to_string(_debugData->location.end);
295+
to_string(_location.end);
296+
281297
return
282298
_statement ?
283-
"/// " + sourceLocation + "\n" :
284-
"/** " + sourceLocation + " */ ";
299+
"/// " + joinHumanReadable(vector<string>{sourceLocation, solidityCodeSnippet}, " ") :
300+
"/** " + joinHumanReadable(vector<string>{sourceLocation, solidityCodeSnippet}, " ") + " */ ";
301+
}
302+
303+
string AsmPrinter::formatSourceLocationComment(shared_ptr<DebugData const> const& _debugData, bool _statement)
304+
{
305+
if (
306+
!_debugData ||
307+
m_lastLocation == _debugData->location ||
308+
m_nameToSourceIndex.empty()
309+
)
310+
return "";
311+
312+
m_lastLocation = _debugData->location;
313+
314+
return formatSourceLocationComment(
315+
_debugData->location,
316+
m_nameToSourceIndex,
317+
_statement,
318+
m_soliditySourceProvider
319+
) + (_statement ? "\n" : "");
285320
}

libyul/AsmPrinter.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
#include <libsolutil/CommonData.h>
3030

31+
#include <liblangutil/CharStreamProvider.h>
3132
#include <liblangutil/SourceLocation.h>
3233

3334
#include <map>
@@ -46,9 +47,11 @@ class AsmPrinter
4647
public:
4748
explicit AsmPrinter(
4849
Dialect const* _dialect = nullptr,
49-
std::optional<std::map<unsigned, std::shared_ptr<std::string const>>> _sourceIndexToName = {}
50+
std::optional<std::map<unsigned, std::shared_ptr<std::string const>>> _sourceIndexToName = {},
51+
langutil::CharStreamProvider const* _soliditySourceProvider = nullptr
5052
):
51-
m_dialect(_dialect)
53+
m_dialect(_dialect),
54+
m_soliditySourceProvider(_soliditySourceProvider)
5255
{
5356
if (_sourceIndexToName)
5457
for (auto&& [index, name]: *_sourceIndexToName)
@@ -58,8 +61,9 @@ class AsmPrinter
5861

5962
explicit AsmPrinter(
6063
Dialect const& _dialect,
61-
std::optional<std::map<unsigned, std::shared_ptr<std::string const>>> _sourceIndexToName = {}
62-
): AsmPrinter(&_dialect, _sourceIndexToName) {}
64+
std::optional<std::map<unsigned, std::shared_ptr<std::string const>>> _sourceIndexToName = {},
65+
langutil::CharStreamProvider const* _soliditySourceProvider = nullptr
66+
): AsmPrinter(&_dialect, _sourceIndexToName, _soliditySourceProvider) {}
6367

6468
std::string operator()(Literal const& _literal);
6569
std::string operator()(Identifier const& _identifier);
@@ -76,6 +80,13 @@ class AsmPrinter
7680
std::string operator()(Leave const& _continue);
7781
std::string operator()(Block const& _block);
7882

83+
static std::string formatSourceLocationComment(
84+
langutil::SourceLocation const& _location,
85+
std::map<std::string, unsigned> const& _nameToSourceIndex,
86+
bool _statement,
87+
langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr
88+
);
89+
7990
private:
8091
std::string formatTypedName(TypedName _variable);
8192
std::string appendTypeName(YulString _type, bool _isBoolLiteral = false) const;
@@ -88,8 +99,9 @@ class AsmPrinter
8899
}
89100

90101
Dialect const* const m_dialect = nullptr;
91-
std::map<std::string const, unsigned> m_nameToSourceIndex;
102+
std::map<std::string, unsigned> m_nameToSourceIndex;
92103
langutil::SourceLocation m_lastLocation = {};
104+
langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr;
93105
};
94106

95107
}

libyul/AssemblyStack.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,11 +314,11 @@ AssemblyStack::assembleEVMWithDeployed(optional<string_view> _deployName) const
314314
return {make_shared<evmasm::Assembly>(assembly), {}};
315315
}
316316

317-
string AssemblyStack::print() const
317+
string AssemblyStack::print(CharStreamProvider const* _soliditySourceProvider) const
318318
{
319319
yulAssert(m_parserResult, "");
320320
yulAssert(m_parserResult->code, "");
321-
return m_parserResult->toString(&languageToDialect(m_language, m_evmVersion)) + "\n";
321+
return m_parserResult->toString(&languageToDialect(m_language, m_evmVersion), _soliditySourceProvider) + "\n";
322322
}
323323

324324
shared_ptr<Object> AssemblyStack::parserResult() const

0 commit comments

Comments
 (0)