feat(ast): Add to ChainExpression and ExpressionArrayElement to ASTKind (#785)

This commit is contained in:
u9g 2023-08-24 23:03:53 -04:00 committed by GitHub
parent 31d56698f7
commit 741aa8df1f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 54 additions and 32 deletions

View file

@ -60,6 +60,7 @@ pub enum AstKind<'a> {
AwaitExpression(&'a AwaitExpression<'a>), AwaitExpression(&'a AwaitExpression<'a>),
BinaryExpression(&'a BinaryExpression<'a>), BinaryExpression(&'a BinaryExpression<'a>),
CallExpression(&'a CallExpression<'a>), CallExpression(&'a CallExpression<'a>),
ChainExpression(&'a ChainExpression<'a>),
ConditionalExpression(&'a ConditionalExpression<'a>), ConditionalExpression(&'a ConditionalExpression<'a>),
LogicalExpression(&'a LogicalExpression<'a>), LogicalExpression(&'a LogicalExpression<'a>),
MemberExpression(&'a MemberExpression<'a>), MemberExpression(&'a MemberExpression<'a>),
@ -81,6 +82,7 @@ pub enum AstKind<'a> {
AssignmentTargetWithDefault(&'a AssignmentTargetWithDefault<'a>), AssignmentTargetWithDefault(&'a AssignmentTargetWithDefault<'a>),
ArrayExpressionElement(&'a ArrayExpressionElement<'a>), ArrayExpressionElement(&'a ArrayExpressionElement<'a>),
Elision(Span), Elision(Span),
ExpressionArrayElement(&'a Expression<'a>),
SpreadElement(&'a SpreadElement<'a>), SpreadElement(&'a SpreadElement<'a>),
RestElement(&'a RestElement<'a>), RestElement(&'a RestElement<'a>),
@ -292,6 +294,7 @@ impl<'a> GetSpan for AstKind<'a> {
Self::AwaitExpression(x) => x.span, Self::AwaitExpression(x) => x.span,
Self::BinaryExpression(x) => x.span, Self::BinaryExpression(x) => x.span,
Self::CallExpression(x) => x.span, Self::CallExpression(x) => x.span,
Self::ChainExpression(x) => x.span,
Self::ConditionalExpression(x) => x.span, Self::ConditionalExpression(x) => x.span,
Self::LogicalExpression(x) => x.span, Self::LogicalExpression(x) => x.span,
Self::MemberExpression(x) => x.span(), Self::MemberExpression(x) => x.span(),
@ -314,6 +317,7 @@ impl<'a> GetSpan for AstKind<'a> {
Self::AssignmentTargetWithDefault(x) => x.span, Self::AssignmentTargetWithDefault(x) => x.span,
Self::SpreadElement(x) => x.span, Self::SpreadElement(x) => x.span,
Self::Elision(span) => *span, Self::Elision(span) => *span,
Self::ExpressionArrayElement(x) => x.span(),
Self::RestElement(x) => x.span, Self::RestElement(x) => x.span,
Self::Function(x) => x.span, Self::Function(x) => x.span,
@ -444,6 +448,7 @@ impl<'a> AstKind<'a> {
Self::AwaitExpression(_) => "AwaitExpression".into(), Self::AwaitExpression(_) => "AwaitExpression".into(),
Self::BinaryExpression(b) => format!("BinaryExpression{}", b.operator.as_str()).into(), Self::BinaryExpression(b) => format!("BinaryExpression{}", b.operator.as_str()).into(),
Self::CallExpression(_) => "CallExpression".into(), Self::CallExpression(_) => "CallExpression".into(),
Self::ChainExpression(_) => "ChainExpression".into(),
Self::ConditionalExpression(_) => "ConditionalExpression".into(), Self::ConditionalExpression(_) => "ConditionalExpression".into(),
Self::LogicalExpression(_) => "LogicalExpression".into(), Self::LogicalExpression(_) => "LogicalExpression".into(),
Self::MemberExpression(_) => "MemberExpression".into(), Self::MemberExpression(_) => "MemberExpression".into(),
@ -466,6 +471,7 @@ impl<'a> AstKind<'a> {
Self::AssignmentTargetWithDefault(_) => "AssignmentTargetWithDefault".into(), Self::AssignmentTargetWithDefault(_) => "AssignmentTargetWithDefault".into(),
Self::SpreadElement(_) => "SpreadElement".into(), Self::SpreadElement(_) => "SpreadElement".into(),
Self::Elision(_) => "Elision".into(), Self::Elision(_) => "Elision".into(),
Self::ExpressionArrayElement(_) => "ExpressionArrayElement".into(),
Self::RestElement(_) => "RestElement".into(), Self::RestElement(_) => "RestElement".into(),
Self::Function(x) => format!( Self::Function(x) => format!(

View file

@ -530,7 +530,7 @@ pub trait Visit<'a>: Sized {
self.enter_node(kind); self.enter_node(kind);
match arg { match arg {
ArrayExpressionElement::SpreadElement(spread) => self.visit_spread_element(spread), ArrayExpressionElement::SpreadElement(spread) => self.visit_spread_element(spread),
ArrayExpressionElement::Expression(expr) => self.visit_expression(expr), ArrayExpressionElement::Expression(expr) => self.visit_expression_array_element(expr),
ArrayExpressionElement::Elision(span) => self.visit_elision(*span), ArrayExpressionElement::Elision(span) => self.visit_elision(*span),
} }
self.leave_node(kind); self.leave_node(kind);
@ -553,6 +553,13 @@ pub trait Visit<'a>: Sized {
self.leave_node(kind); self.leave_node(kind);
} }
fn visit_expression_array_element(&mut self, expr: &'a Expression<'a>) {
let kind = AstKind::ExpressionArrayElement(expr);
self.enter_node(kind);
self.visit_expression(expr);
self.leave_node(kind);
}
fn visit_elision(&mut self, span: Span) { fn visit_elision(&mut self, span: Span) {
let kind = AstKind::Elision(span); let kind = AstKind::Elision(span);
self.enter_node(kind); self.enter_node(kind);
@ -607,7 +614,10 @@ pub trait Visit<'a>: Sized {
} }
fn visit_chain_expression(&mut self, expr: &'a ChainExpression<'a>) { fn visit_chain_expression(&mut self, expr: &'a ChainExpression<'a>) {
let kind = AstKind::ChainExpression(expr);
self.enter_node(kind);
self.visit_chain_element(&expr.expression); self.visit_chain_element(&expr.expression);
self.leave_node(kind);
} }
fn visit_chain_element(&mut self, elem: &'a ChainElement<'a>) { fn visit_chain_element(&mut self, elem: &'a ChainElement<'a>) {

View file

@ -401,7 +401,7 @@ pub trait VisitMut<'a, 'b>: Sized {
fn visit_array_expression_element(&mut self, arg: &'b mut ArrayExpressionElement<'a>) { fn visit_array_expression_element(&mut self, arg: &'b mut ArrayExpressionElement<'a>) {
match arg { match arg {
ArrayExpressionElement::SpreadElement(spread) => self.visit_spread_element(spread), ArrayExpressionElement::SpreadElement(spread) => self.visit_spread_element(spread),
ArrayExpressionElement::Expression(expr) => self.visit_expression(expr), ArrayExpressionElement::Expression(expr) => self.visit_expression_array_element(expr),
ArrayExpressionElement::Elision(span) => self.visit_elision(*span), ArrayExpressionElement::Elision(span) => self.visit_elision(*span),
} }
} }
@ -417,6 +417,10 @@ pub trait VisitMut<'a, 'b>: Sized {
self.visit_expression(&mut elem.argument); self.visit_expression(&mut elem.argument);
} }
fn visit_expression_array_element(&mut self, expr: &'b mut Expression<'a>) {
self.visit_expression(expr);
}
fn visit_elision(&mut self, _span: Span) {} fn visit_elision(&mut self, _span: Span) {}
fn visit_assignment_expression(&mut self, expr: &'b mut AssignmentExpression<'a>) { fn visit_assignment_expression(&mut self, expr: &'b mut AssignmentExpression<'a>) {

View file

@ -151,7 +151,8 @@ pub fn get_array_method_name<'a>(
AstKind::LogicalExpression(_) AstKind::LogicalExpression(_)
| AstKind::ConditionalExpression(_) | AstKind::ConditionalExpression(_)
| AstKind::Argument(_) | AstKind::Argument(_)
| AstKind::ParenthesizedExpression(_) => { | AstKind::ParenthesizedExpression(_)
| AstKind::ChainExpression(_) => {
current_node = parent; current_node = parent;
} }

View file

@ -192,7 +192,10 @@ fn get_real_parent<'a, 'b>(node: &AstNode, ctx: &'a LintContext<'b>) -> Option<&
for (_, parent) in for (_, parent) in
ctx.nodes().iter_parents(node.id()).tuple_windows::<(&AstNode<'b>, &AstNode<'b>)>() ctx.nodes().iter_parents(node.id()).tuple_windows::<(&AstNode<'b>, &AstNode<'b>)>()
{ {
if let AstKind::Argument(_) | AstKind::ParenthesizedExpression(_) = parent.kind() { if let AstKind::Argument(_)
| AstKind::ParenthesizedExpression(_)
| AstKind::ChainExpression(_) = parent.kind()
{
continue; continue;
} }

View file

@ -4,7 +4,7 @@ use oxc_diagnostics::{
thiserror::Error, thiserror::Error,
}; };
use oxc_macros::declare_oxc_lint; use oxc_macros::declare_oxc_lint;
use oxc_span::Span; use oxc_span::{GetSpan, Span};
use crate::{context::LintContext, rule::Rule, AstNode}; use crate::{context::LintContext, rule::Rule, AstNode};
@ -42,38 +42,36 @@ impl Rule for NoVarRequires {
return; return;
} }
let AstKind::CallExpression(expr) = node.kind() else { return }; let AstKind::CallExpression(expr) = node.kind() else { return };
if expr.is_require_call() {
if ctx.scopes().get_bindings(node.scope_id()).contains_key("require") {
return;
}
if let Some(parent_node) = ctx.nodes().parent_node(node.id()) { if expr.is_require_call()
if let AstKind::Argument(_) = parent_node.kind() { && !ctx.scopes().get_bindings(node.scope_id()).contains_key("require")
if let Some(parent_node) = ctx.nodes().parent_node(parent_node.id()) { {
if is_target_node(&parent_node.kind()) { // If the parent is an expression statement => this is a top level require()
ctx.diagnostic(NoVarRequiresDiagnostic(expr.span)); // Or, if the parent is a chain expression (require?.()) and
} // the grandparent is an expression statement => this is a top level require()
} let is_expression_statement = {
} let parent_node = ctx.nodes().parent_node(node.id());
let grandparent_node = parent_node.and_then(|x| ctx.nodes().parent_node(x.id()));
if is_target_node(&parent_node.kind()) {
ctx.diagnostic(NoVarRequiresDiagnostic(expr.span));
}
}
}
}
}
fn is_target_node(node_kind: &AstKind<'_>) -> bool {
matches!( matches!(
node_kind, (
AstKind::CallExpression(_) parent_node.map(oxc_semantic::AstNode::kind),
| AstKind::MemberExpression(_) grandparent_node.map(oxc_semantic::AstNode::kind)
| AstKind::NewExpression(_) ),
| AstKind::TSAsExpression(_) (Some(AstKind::ExpressionStatement(_)), _)
| AstKind::TSTypeAssertion(_) | (
| AstKind::VariableDeclarator(_) Some(AstKind::ChainExpression(_)),
Some(AstKind::ExpressionStatement(_))
) )
)
};
// If this is an expression statement, it means the `require()`'s return value is unused.
// If the return value is unused, this isn't a problem.
if !is_expression_statement {
ctx.diagnostic(NoVarRequiresDiagnostic(node.kind().span()));
}
}
}
} }
#[test] #[test]