-
Notifications
You must be signed in to change notification settings - Fork 196
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(compiler): enforce super constructor call in derived class constructors #5354
Changes from all commits
e36dfb7
ae88d31
772d4fd
78f227d
4dae735
9182535
d40cebd
9f93a68
3bf64da
50a6a6d
1870ad9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,6 +56,7 @@ class A { | |
|
||
class B extends A { | ||
new(msg: str) { | ||
super(msg); | ||
this.message = msg; | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -424,6 +424,8 @@ impl<'s> Parser<'s> { | |
_ => Scope::empty(), | ||
}; | ||
|
||
self.report_missing_super_call(&root, &scope); | ||
|
||
// Module files can only have certain kinds of statements | ||
if !is_entrypoint_file(&self.source_name) { | ||
for stmt in &scope.statements { | ||
|
@@ -480,6 +482,84 @@ impl<'s> Parser<'s> { | |
} | ||
} | ||
|
||
fn report_missing_super_call(&self, node: &Node, scope: &Scope) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd change this logic. Instead of re-scanning the entire tree I'd just modify |
||
let mut cursor = node.walk(); | ||
let mut nodes = Vec::new(); | ||
for child in node.named_children(&mut cursor) { | ||
if child.is_extra() { | ||
continue; | ||
} | ||
match child.kind() { | ||
"class_definition" => { | ||
let mut cursor = child.walk(); | ||
let mut has_extends = false; | ||
child.children(&mut cursor).for_each(|child| { | ||
if child.kind() == "extends" { | ||
has_extends = true; | ||
} | ||
if child.kind() == "class_implementation" && has_extends { | ||
let mut cursor = child.walk(); | ||
child.children(&mut cursor).for_each(|child| { | ||
if child.kind() == "initializer" || child.kind() == "inflight_initializer" { | ||
nodes.push(child); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
_ => {} | ||
} | ||
} | ||
|
||
if nodes.len() == 0 { | ||
return; | ||
} | ||
let mut counter = 0; | ||
for stmt in &scope.statements { | ||
let stmt_kind = &stmt.kind; | ||
match stmt_kind { | ||
StmtKind::Class(class) => { | ||
if class.parent.is_some() { | ||
let mut super_call_present = false; | ||
let mut initializer_present = false; | ||
match &class.initializer.body { | ||
FunctionBody::Statements(statements) => { | ||
self.has_super_constructor(&statements, &mut initializer_present, &mut super_call_present); | ||
} | ||
_ => {} | ||
} | ||
match &class.inflight_initializer.body { | ||
FunctionBody::Statements(statements) => { | ||
self.has_super_constructor(&statements, &mut initializer_present, &mut super_call_present); | ||
} | ||
_ => {} | ||
} | ||
if !super_call_present && initializer_present { | ||
self.add_error("Super call missing in initializer of derived class", &nodes[counter]); | ||
} | ||
if initializer_present { | ||
counter += 1; | ||
} | ||
} | ||
} | ||
_ => {} | ||
} | ||
} | ||
} | ||
|
||
fn has_super_constructor(&self, scope: &Scope, initializer_present: &mut bool, super_call_present: &mut bool) { | ||
if &scope.statements.len() > &0 { | ||
*initializer_present = true; | ||
let first_statement = &scope.statements.first().unwrap().kind; | ||
match first_statement { | ||
StmtKind::SuperConstructor { arg_list: _ } => { | ||
*super_call_present = true; | ||
} | ||
_ => {} | ||
} | ||
} | ||
} | ||
|
||
fn node_text<'a>(&'a self, node: &Node) -> &'a str { | ||
return str::from_utf8(&self.source[node.byte_range()]).unwrap(); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be avoided? Not critical if it's a hassle
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was wondering about his change, it was generated after I added
super()
to the inflight constructor and I ran e2e tests. I don't know if this is critical, but seems suspicious to me, so I pushed it to see if somebody knows whats going on 🙂