Open planetA opened 6 months ago
Here is what is the result of parsing:
Node {
id: Id(0xac5738),
kind: Other,
inner: [
Node {
id: Id(0xb218d0),
kind: FunctionDecl(
FunctionDecl {
name: Some(
"c",
),
loc: Some(
SourceLocation {
spelling_loc: Some(
BareSourceLocation {
offset: 4,
file: "main.c",
line: 1,
presumed_file: None,
presumed_line: None,
col: 5,
tok_len: 1,
included_from: None,
is_macro_arg_expansion: false,
},
),
expansion_loc: Some(
BareSourceLocation {
offset: 4,
file: "main.c",
line: 1,
presumed_file: None,
presumed_line: None,
col: 5,
tok_len: 1,
included_from: None,
is_macro_arg_expansion: false,
},
),
},
),
range: Some(
SourceRange {
begin: SourceLocation {
spelling_loc: Some(
BareSourceLocation {
offset: 0,
file: "main.c",
line: 1,
presumed_file: None,
presumed_line: None,
col: 1,
tok_len: 3,
included_from: None,
is_macro_arg_expansion: false,
},
),
expansion_loc: Some(
BareSourceLocation {
offset: 0,
file: "main.c",
line: 1,
presumed_file: None,
presumed_line: None,
col: 1,
tok_len: 3,
included_from: None,
is_macro_arg_expansion: false,
},
),
},
end: SourceLocation {
spelling_loc: Some(
BareSourceLocation {
offset: 6,
file: "main.c",
line: 1,
presumed_file: None,
presumed_line: None,
col: 7,
tok_len: 1,
included_from: None,
is_macro_arg_expansion: false,
},
),
expansion_loc: Some(
BareSourceLocation {
offset: 6,
file: "main.c",
line: 1,
presumed_file: None,
presumed_line: None,
col: 7,
tok_len: 1,
included_from: None,
is_macro_arg_expansion: false,
},
),
},
},
),
inner: None,
},
),
inner: [],
},
Node {
id: Id(0xb219e8),
kind: FunctionDecl(
FunctionDecl {
name: Some(
"d",
),
loc: Some(
SourceLocation {
spelling_loc: Some(
BareSourceLocation {
offset: 13,
file: "main.c",
line: 2,
presumed_file: None,
presumed_line: None,
col: 5,
tok_len: 1,
included_from: None,
is_macro_arg_expansion: false,
},
),
expansion_loc: Some(
BareSourceLocation {
offset: 13,
file: "main.c",
line: 2,
presumed_file: None,
presumed_line: None,
col: 5,
tok_len: 1,
included_from: None,
is_macro_arg_expansion: false,
},
),
},
),
range: Some(
SourceRange {
begin: SourceLocation {
spelling_loc: Some(
BareSourceLocation {
offset: 9,
file: "main.c",
line: 2,
presumed_file: None,
presumed_line: None,
col: 1,
tok_len: 3,
included_from: None,
is_macro_arg_expansion: false,
},
),
expansion_loc: Some(
BareSourceLocation {
offset: 9,
file: "main.c",
line: 2,
presumed_file: None,
presumed_line: None,
col: 1,
tok_len: 3,
included_from: None,
is_macro_arg_expansion: false,
},
),
},
end: SourceLocation {
spelling_loc: Some(
BareSourceLocation {
offset: 40,
file: "main.c",
line: 4,
presumed_file: None,
presumed_line: None,
col: 1,
tok_len: 1,
included_from: None,
is_macro_arg_expansion: false,
},
),
expansion_loc: Some(
BareSourceLocation {
offset: 40,
file: "main.c",
line: 4,
presumed_file: None,
presumed_line: None,
col: 1,
tok_len: 1,
included_from: None,
is_macro_arg_expansion: false,
},
),
},
},
),
inner: None,
},
),
inner: [
Node {
id: Id(0xb21ba8),
kind: Other,
inner: [
Node {
id: Id(0xb21b90),
kind: Other,
inner: [
Node {
id: Id(0xb21aa8),
kind: Other,
inner: [
Node {
id: Id(0xb21b70),
kind: CallExpr(
CallExpr {
name: None,
loc: None,
range: Some(
SourceRange {
begin: SourceLocation {
spelling_loc: Some(
BareSourceLocation {
offset: 35,
file: "main.c",
line: 4,
presumed_file: None,
presumed_line: None,
col: 17,
tok_len: 1,
included_from: None,
is_macro_arg_expansion: false,
},
),
expansion_loc: Some(
BareSourceLocation {
offset: 35,
file: "main.c",
line: 4,
presumed_file: None,
presumed_line: None,
col: 17,
tok_len: 1,
included_from: None,
is_macro_arg_expansion: false,
},
),
},
end: SourceLocation {
spelling_loc: Some(
BareSourceLocation {
offset: 37,
file: "main.c",
line: 4,
presumed_file: None,
presumed_line: None,
col: 19,
tok_len: 1,
included_from: None,
is_macro_arg_expansion: false,
},
),
expansion_loc: Some(
BareSourceLocation {
offset: 37,
file: "main.c",
line: 4,
presumed_file: None,
presumed_line: None,
col: 19,
tok_len: 1,
included_from: None,
is_macro_arg_expansion: false,
},
),
},
},
),
},
),
inner: [
Node {
id: Id(0xb21b58),
kind: Other,
inner: [
Node {
id: Id(0xb21b10),
kind: DeclRefExpr(
DeclRefExpr {
name: None,
loc: None,
range: Some(
SourceRange {
begin: SourceLocation {
spelling_loc: Some(
BareSourceLocation {
offset: 35,
file: "main.c",
line: 4,
presumed_file: None,
presumed_line: None,
col: 17,
tok_len: 1,
included_from: None,
is_macro_arg_expansion: false,
},
),
expansion_loc: Some(
BareSourceLocation {
offset: 35,
file: "main.c",
line: 4,
presumed_file: None,
presumed_line: None,
col: 17,
tok_len: 1,
included_from: None,
is_macro_arg_expansion: false,
},
),
},
end: SourceLocation {
spelling_loc: Some(
BareSourceLocation {
offset: 35,
file: "main.c",
line: 4,
presumed_file: None,
presumed_line: None,
col: 17,
tok_len: 1,
included_from: None,
is_macro_arg_expansion: false,
},
),
expansion_loc: Some(
BareSourceLocation {
offset: 35,
file: "main.c",
line: 4,
presumed_file: None,
presumed_line: None,
col: 17,
tok_len: 1,
included_from: None,
is_macro_arg_expansion: false,
},
),
},
},
),
referenced_decl: Some(
Node {
id: Id(0xb218d0),
kind: FunctionDecl(
FunctionDecl {
name: Some(
"c",
),
loc: None,
range: None,
inner: None,
},
),
inner: [],
},
),
},
),
inner: [],
},
],
},
],
},
],
},
],
},
],
},
],
},
],
}
Looking at the code, I can say that LAST_LOC_FILENAME
and LAST_LOC_LINE
are fundamentally wrong, because the last used one, which is going to be the value stored for the end range. Instead, it should use the one from the parent.
I looked once again into the algorithm. Conceptually, I think you implemented it correctly. The problem happens, when some node do not have "loc" and "range" fields. Then these fields are going to be skipped for the purpose of setting LAST_LOC_FILENAME
and LAST_LOC_LINE
.
For example, by adding the following Other
struct, I could work around the problem:
#[derive(Deserialize, Debug)]
pub enum Clang {
FunctionDecl(FunctionDecl),
CallExpr(CallExpr),
DeclRefExpr(DeclRefExpr),
Other(Other),
}
// ...
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Other {
pub name: Option<String>,
pub loc: Option<clang_ast::SourceLocation>,
pub range: Option<clang_ast::SourceRange>,
}
I think it makes sense to make loc
and range
mandatory fields in the Node
struct. Or, loc
and range
should be accounted in NodeVisitor
. What do you think?
That's right, I think we need every variant to have loc
and range
if you're planning to look at the loc
or range
of any variant.
I experimented with a different approach in #35 where the Deserializer
would inject correct values of loc
and range
, rather than having the Deserialize
impl in charge of the bookkeeping. So for example if the input were:
{
"id": "0xb218d0",
"kind": "FunctionDecl",
"loc": {
"offset": 4,
"file": "main.c",
"line": 1,
"col": 5,
"tokLen": 1
},
"range": {"..."}
"inner": [
{
"id": "0xb21aa8",
"kind": "VarDecl",
"loc": {
"offset": 31,
"col": 13,
"tokLen": 1
},
"..."
then the Deserialize
impl would see the following in the inner node (whether or not it actually cares about deserializing loc
):
"id": "0xb21aa8",
"kind": "VarDecl",
"loc": {
"offset": 31,
"col": 13,
"tokLen": 1,
"file": "main.c",
"line": 1
},
I think it can work, but it needs some more effort to complete it.
Hello,
it seems that when parsing AST, sometimes, the lines are mapped incorrectly below is a small working example:
tests/lines.rs
:The problem is the referencedDecl should be line 3, but it parses to line 4, which is the end of the enclosing function. This AST is slightly shortened version of the following parsed code: