Skip to content

Commit 029e51f

Browse files
committed
fix: accept partial first sourcemap element
1 parent a92b406 commit 029e51f

File tree

2 files changed

+76
-28
lines changed

2 files changed

+76
-28
lines changed

crates/artifacts/solc/src/sourcemap.rs

Lines changed: 74 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,11 @@ impl From<std::num::TryFromIntError> for SyntaxError {
7878

7979
#[derive(PartialEq, Eq)]
8080
enum Token<'a> {
81+
/// Decimal number
8182
Number(&'a str),
83+
/// `;`
8284
Semicolon,
85+
/// `:`
8386
Colon,
8487
/// `i` which represents an instruction that goes into a function
8588
In,
@@ -175,7 +178,7 @@ pub type SourceMap = Vec<SourceElement>;
175178
/// A single element in a [`SourceMap`].
176179
///
177180
/// Solidity reference: <https://docs.soliditylang.org/en/latest/internals/source_mappings.html#source-mappings>
178-
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
181+
#[derive(Clone, PartialEq, Eq, Hash)]
179182
pub struct SourceElement {
180183
offset: u32,
181184
length: u32,
@@ -184,12 +187,37 @@ pub struct SourceElement {
184187
jump_and_modifier_depth: u32,
185188
}
186189

190+
impl fmt::Debug for SourceElement {
191+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192+
f.debug_struct("SourceElement")
193+
.field("offset", &self.offset())
194+
.field("length", &self.length())
195+
.field("index", &self.index_i32())
196+
.field("jump", &self.jump())
197+
.field("modifier_depth", &self.modifier_depth())
198+
.field("formatted", &format_args!("{self}"))
199+
.finish()
200+
}
201+
}
202+
203+
impl Default for SourceElement {
204+
fn default() -> Self {
205+
Self::new()
206+
}
207+
}
208+
187209
impl SourceElement {
188210
/// Creates a new source element with default values.
189-
pub fn new_invalid() -> Self {
211+
pub fn new() -> Self {
190212
Self { offset: 0, length: 0, index: -1, jump_and_modifier_depth: 0 }
191213
}
192214

215+
/// Creates a new source element with default values.
216+
#[deprecated = "use `new` instead"]
217+
pub fn new_invalid() -> Self {
218+
Self::new()
219+
}
220+
193221
/// The byte-offset to the start of the range in the source file.
194222
#[inline]
195223
pub fn offset(&self) -> u32 {
@@ -295,10 +323,10 @@ impl fmt::Display for SourceElementBuilder {
295323
}
296324

297325
if let Some(s) = self.offset {
298-
if self.index == Some(None) {
326+
if s == 0 && self.index == Some(None) {
299327
f.write_str("-1")?;
300328
} else {
301-
s.fmt(f)?;
329+
write!(f, "{s}")?;
302330
}
303331
}
304332
if self.length.is_none()
@@ -311,10 +339,10 @@ impl fmt::Display for SourceElementBuilder {
311339
f.write_char(':')?;
312340

313341
if let Some(s) = self.length {
314-
if self.index == Some(None) {
342+
if s == 0 && self.index == Some(None) {
315343
f.write_str("-1")?;
316344
} else {
317-
s.fmt(f)?;
345+
write!(f, "{s}")?;
318346
}
319347
}
320348
if self.index.is_none() && self.jump.is_none() && self.modifier_depth.is_none() {
@@ -324,15 +352,15 @@ impl fmt::Display for SourceElementBuilder {
324352

325353
if let Some(s) = self.index {
326354
let s = s.map(|s| s as i64).unwrap_or(-1);
327-
s.fmt(f)?;
355+
write!(f, "{s}")?;
328356
}
329357
if self.jump.is_none() && self.modifier_depth.is_none() {
330358
return Ok(());
331359
}
332360
f.write_char(':')?;
333361

334362
if let Some(s) = self.jump {
335-
s.fmt(f)?;
363+
write!(f, "{s}")?;
336364
}
337365
if self.modifier_depth.is_none() {
338366
return Ok(());
@@ -353,17 +381,11 @@ impl fmt::Display for SourceElementBuilder {
353381

354382
impl SourceElementBuilder {
355383
fn finish(self, prev: Option<SourceElement>) -> Result<SourceElement, SyntaxError> {
356-
let no_prev = prev.is_none();
357-
let mut element = prev.unwrap_or_else(SourceElement::new_invalid);
384+
let mut element = prev.unwrap_or_default();
358385
macro_rules! get_field {
359386
(| $field:ident | $e:expr) => {
360387
if let Some($field) = self.$field {
361388
$e;
362-
} else if no_prev {
363-
return Err(SyntaxError::new(
364-
None,
365-
format!("no previous {}", stringify!($field)),
366-
));
367389
}
368390
};
369391
}
@@ -498,9 +520,9 @@ impl<'input> Parser<'input> {
498520
#[cfg(test)]
499521
if let Some(out) = self.output.as_mut() {
500522
if self.last_element.is_some() {
501-
let _ = out.write_char(';');
523+
out.write_char(';').unwrap();
502524
}
503-
let _ = out.write_str(&builder.to_string());
525+
write!(out, "{builder}").unwrap();
504526
}
505527

506528
let element = builder.finish(self.last_element.take())?;
@@ -554,29 +576,53 @@ pub fn parse(input: &str) -> Result<SourceMap, SyntaxError> {
554576
mod tests {
555577
use super::*;
556578

579+
fn parse_test(input: &str) {
580+
match parse_test_(input) {
581+
Ok(_) => {}
582+
Err(e) => panic!("{e}"),
583+
}
584+
}
585+
586+
fn parse_test_(input: &str) -> Result<SourceMap, SyntaxError> {
587+
let mut s = String::new();
588+
let mut p = Parser::new(input);
589+
p.output = Some(&mut s);
590+
let sm = p.collect::<Result<SourceMap, _>>()?;
591+
if s != input {
592+
return Err(SyntaxError::new(
593+
None,
594+
format!("mismatched output:\n actual: {s:?}\n expected: {input:?}\n sm: {sm:#?}"),
595+
));
596+
}
597+
Ok(sm)
598+
}
599+
600+
#[test]
601+
fn empty() {
602+
parse_test("");
603+
}
604+
557605
#[test]
558-
fn can_parse_source_maps() {
606+
fn source_maps() {
559607
// all source maps from the compiler output test data
560608
let source_maps = include_str!("../../../../test-data/out-source-maps.txt");
561609

562610
for (line, s) in source_maps.lines().enumerate() {
563-
parse(s).unwrap_or_else(|e| panic!("Failed to parse line {line}: {e}"));
611+
let line = line + 1;
612+
parse_test_(s).unwrap_or_else(|e| panic!("Failed to parse line {line}: {e}\n{s:?}"));
564613
}
565614
}
566615

567616
#[test]
568-
fn can_parse_foundry_cheatcodes_sol_maps() {
617+
fn cheatcodes() {
569618
let s = include_str!("../../../../test-data/cheatcodes.sol-sourcemap.txt");
570-
let mut out = String::new();
571-
let mut parser = Parser::new(s);
572-
parser.output = Some(&mut out);
573-
let _map = parser.collect::<Result<SourceMap, _>>().unwrap();
574-
assert_eq!(out, s);
619+
parse_test(s);
575620
}
576621

622+
// https://github.com/foundry-rs/foundry/issues/8986
577623
#[test]
578-
fn can_parse_empty() {
579-
let s = Parser::new("").collect::<Result<SourceMap, _>>().unwrap();
580-
assert_eq!(s.len(), 0);
624+
fn univ4_deployer() {
625+
let s = ":::-:0;;1888:10801:91;2615:100;;;2679:3;2615:100;;;;2700:4;2615:100;;;;-1:-1:-1;2615:100:91;;;;2546:169;;;-1:-1:-1;;2546:169:91;;;;;;;;;;;2615:100;2546:169;;;2615:100;2797:101;;;;;;;;;-1:-1:-1;;2797:101:91;;;;;;;;2546:169;2721:177;;;;;;;;;;;;;;;;;;2957:101;1888:10801;2957:101;2797;2957;;;-1:-1:-1;;2957:101:91;;;;356:29:89;2957:101:91;;;;2904:154;;;-1:-1:-1;;2904:154:91;;;;;;;;;;;;-1:-1:-1;;;;;;2904:154:91;;;;;;;;4018:32;;;;;4048:2;4018:32;;;4056:74;;;-1:-1:-1;;;;;4056:74:91;;;;;;;;1888:10801;;;;;;;;;;;;;;;;";
626+
parse_test(s);
581627
}
582628
}

crates/compilers/src/report/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
1515
// <https://github.com/tokio-rs/tracing/blob/master/tracing-core/src/dispatch.rs>
1616

17+
#![allow(static_mut_refs)] // TODO
18+
1719
use foundry_compilers_artifacts::remappings::Remapping;
1820
use semver::Version;
1921
use std::{

0 commit comments

Comments
 (0)