Skip to content

Commit

Permalink
feat: Improve il2cpp line mapping parser (#595)
Browse files Browse the repository at this point in the history
* feat: Improve il2cpp line mapping parser

The parser will now look for the next non-comment line when it encounters
a source_info comment and take that as the cpp_line, instead of just taking
the source_info comment line itself.
  • Loading branch information
loewenheim committed Jun 13, 2022
1 parent ad84061 commit 9b26fc8
Showing 1 changed file with 143 additions and 9 deletions.
152 changes: 143 additions & 9 deletions symbolic-il2cpp/src/line_mapping/from_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ impl ObjectLineMapping {
}

/// An Il2cpp `source_info` record.
#[derive(Debug, PartialEq, Eq)]
struct SourceInfo<'data> {
/// The C++ source line the `source_info` was parsed from.
cpp_line: u32,
Expand All @@ -94,9 +95,10 @@ struct SourceInfo<'data> {

/// An iterator over Il2cpp `source_info` markers.
///
/// The Iterator yields `(file, line)` pairs.
/// The Iterator yields `SourceInfo`s.
struct SourceInfos<'data> {
lines: Enumerate<Lines<'data>>,
current: Option<(&'data str, u32)>,
}

impl<'data> SourceInfos<'data> {
Expand All @@ -107,24 +109,42 @@ impl<'data> SourceInfos<'data> {
.unwrap_or_default()
.lines()
.enumerate();
Self { lines }
Self {
lines,
current: None,
}
}
}

impl<'data> Iterator for SourceInfos<'data> {
type Item = SourceInfo<'data>;

fn next(&mut self) -> Option<Self::Item> {
for (cpp_line, cpp_src_line) in &mut self.lines {
for (cpp_line_nr, cpp_src_line) in &mut self.lines {
match parse_line(cpp_src_line) {
// A new source info record. Emit the previously found one, if there is one.
Some((cs_file, cs_line)) => {
return Some(SourceInfo {
cpp_line: (cpp_line + 1) as u32,
cs_file,
cs_line,
})
if let Some((cs_file, cs_line)) = self.current.replace((cs_file, cs_line)) {
return Some(SourceInfo {
cpp_line: cpp_line_nr as u32,
cs_file,
cs_line,
});
}
}

// A comment. Just continue.
None if cpp_src_line.trim_start().starts_with("//") => continue,
// A source line. Emit the previously found source info record, if there is one.
None => {
if let Some((cs_file, cs_line)) = self.current.take() {
return Some(SourceInfo {
cpp_line: (cpp_line_nr + 1) as u32,
cs_file,
cs_line,
});
}
}
None => continue,
}
}
None
Expand All @@ -143,3 +163,117 @@ fn parse_line(line: &str) -> Option<(&str, u32)> {
let line = line.parse().ok()?;
Some((file, line))
}

#[cfg(test)]
mod tests {
use super::{SourceInfo, SourceInfos};

#[test]
fn one_mapping() {
let cpp_source = b"
Lorem ipsum dolor sit amet
//<source_info:main.cs:17>
// some
// more
// comments
actual source code";

let source_infos: Vec<_> = SourceInfos::new(cpp_source).collect();

assert_eq!(
source_infos,
vec![SourceInfo {
cpp_line: 7,
cs_file: "main.cs",
cs_line: 17,
}]
)
}

#[test]
fn several_mappings() {
let cpp_source = b"
Lorem ipsum dolor sit amet
//<source_info:main.cs:17>
// some
// comments
actual source code 1
actual source code 2
//<source_info:main.cs:29>
actual source code 3
//<source_info:main.cs:46>
// more
// comments
actual source code 4";

let source_infos: Vec<_> = SourceInfos::new(cpp_source).collect();

assert_eq!(
source_infos,
vec![
SourceInfo {
cpp_line: 6,
cs_file: "main.cs",
cs_line: 17,
},
SourceInfo {
cpp_line: 10,
cs_file: "main.cs",
cs_line: 29,
},
SourceInfo {
cpp_line: 15,
cs_file: "main.cs",
cs_line: 46,
}
]
)
}

#[test]
fn missing_source_line() {
let cpp_source = b"
Lorem ipsum dolor sit amet
//<source_info:main.cs:17>
// some
// comments
//<source_info:main.cs:29>
actual source code";

let source_infos: Vec<_> = SourceInfos::new(cpp_source).collect();

// The first source info has no source line to attach to, so it should use the line
// immediately before the second source_info.
assert_eq!(
source_infos,
vec![
SourceInfo {
cpp_line: 5,
cs_file: "main.cs",
cs_line: 17,
},
SourceInfo {
cpp_line: 7,
cs_file: "main.cs",
cs_line: 29,
},
]
)
}

#[test]
fn broken() {
let cpp_source = b"
Lorem ipsum dolor sit amet
//<source_info:main.cs:17>
// some
// more
// comments";

// Since there is no non-comment line for the source info to attach to,
// no source infos should be returned.
assert_eq!(SourceInfos::new(cpp_source).count(), 0);
}
}

0 comments on commit 9b26fc8

Please sign in to comment.