Skip to content
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

feat(symbols): collect symbols for params #484

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 0 additions & 97 deletions src/fast_check/swc_helpers.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// Copyright 2018-2024 the Deno authors. MIT license.

use std::ops::ControlFlow;

use deno_ast::swc::ast::*;
use deno_ast::swc::common::DUMMY_SP;

Expand All @@ -20,101 +18,6 @@ pub fn ts_keyword_type(kind: TsKeywordTypeKind) -> TsType {
})
}

#[derive(Debug)]
pub enum ReturnStatementAnalysis {
/// There are no return statements in the function body.
None,
/// There are only return statements without arguments in the function body,
/// or if the function body is empty.
Void,
/// There is only a single return statement in the function body, and it has
/// an argument.
Single(ReturnStmt),
/// There are multiple return statements in the function body, and at least
/// one of them has an argument.
Multiple,
}

pub fn analyze_return_stmts_in_function_body(
body: &deno_ast::swc::ast::BlockStmt,
) -> ReturnStatementAnalysis {
if body.stmts.is_empty() {
ReturnStatementAnalysis::Void
} else {
let mut analysis = ReturnStatementAnalysis::None;
analyze_return_stmts_from_stmts(&body.stmts, &mut analysis);
analysis
}
}

fn analyze_return_stmts_from_stmts(
stmts: &[Stmt],
analysis: &mut ReturnStatementAnalysis,
) -> ControlFlow<(), ()> {
for stmt in stmts {
analyze_return_stmts_from_stmt(stmt, analysis)?;
}
ControlFlow::Continue(())
}

fn analyze_return_stmts_from_stmt(
stmt: &Stmt,
analysis: &mut ReturnStatementAnalysis,
) -> ControlFlow<(), ()> {
match stmt {
Stmt::Block(n) => analyze_return_stmts_from_stmts(&n.stmts, analysis),
Stmt::With(n) => analyze_return_stmts_from_stmt(&n.body, analysis),
Stmt::Return(n) => {
match (&n.arg, &*analysis) {
(None, ReturnStatementAnalysis::None) => {
*analysis = ReturnStatementAnalysis::Void;
}
(None, ReturnStatementAnalysis::Void) => {}
(Some(_), ReturnStatementAnalysis::None)
| (Some(_), ReturnStatementAnalysis::Void) => {
*analysis = ReturnStatementAnalysis::Single(n.clone());
}
(_, ReturnStatementAnalysis::Single(_)) => {
*analysis = ReturnStatementAnalysis::Multiple;
return ControlFlow::Break(());
}
(_, ReturnStatementAnalysis::Multiple) => unreachable!(), // we break early when analysis is Multiple
}
ControlFlow::Continue(())
}
Stmt::Labeled(n) => analyze_return_stmts_from_stmt(&n.body, analysis),
Stmt::If(n) => analyze_return_stmts_from_stmt(&n.cons, analysis),
Stmt::Switch(n) => {
for case in &n.cases {
analyze_return_stmts_from_stmts(&case.cons, analysis)?;
}
ControlFlow::Continue(())
}
Stmt::Try(n) => {
analyze_return_stmts_from_stmts(&n.block.stmts, analysis)?;
if let Some(n) = &n.handler {
analyze_return_stmts_from_stmts(&n.body.stmts, analysis)?;
}
if let Some(n) = &n.finalizer {
analyze_return_stmts_from_stmts(&n.stmts, analysis)?;
}
ControlFlow::Continue(())
}
Stmt::While(n) => analyze_return_stmts_from_stmt(&n.body, analysis),
Stmt::DoWhile(n) => analyze_return_stmts_from_stmt(&n.body, analysis),
Stmt::For(n) => analyze_return_stmts_from_stmt(&n.body, analysis),
Stmt::ForIn(n) => analyze_return_stmts_from_stmt(&n.body, analysis),
Stmt::ForOf(n) => analyze_return_stmts_from_stmt(&n.body, analysis),
Stmt::Break(_)
| Stmt::Continue(_)
| Stmt::Throw(_)
| Stmt::Debugger(_)
| Stmt::Decl(_)
| Stmt::Expr(_)
| Stmt::Empty(_) => ControlFlow::Continue(()),
}
}

pub fn is_void_type(return_type: &TsType) -> bool {
is_keyword_type(return_type, TsKeywordTypeKind::TsVoidKeyword)
}
Expand Down
16 changes: 3 additions & 13 deletions src/fast_check/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ use deno_ast::SourceRange;
use deno_ast::SourceRangedForSpanned;
use indexmap::IndexMap;

use crate::swc_helpers::analyze_return_stmts_in_function_body;
use crate::swc_helpers::FunctionKind;
use crate::swc_helpers::ReturnStatementAnalysis;
use crate::symbols::EsModuleInfo;
use crate::symbols::ExpandoPropertyRef;
use crate::symbols::Symbol;
Expand All @@ -34,13 +37,11 @@ use crate::ParserModuleAnalyzer;
use crate::WorkspaceMember;

use super::range_finder::ModulePublicRanges;
use super::swc_helpers::analyze_return_stmts_in_function_body;
use super::swc_helpers::any_type_ann;
use super::swc_helpers::ident;
use super::swc_helpers::is_void_type;
use super::swc_helpers::maybe_lit_to_ts_type;
use super::swc_helpers::ts_keyword_type;
use super::swc_helpers::ReturnStatementAnalysis;
use super::transform_dts::FastCheckDtsDiagnostic;
use super::transform_dts::FastCheckDtsTransformer;
use super::FastCheckDiagnostic;
Expand Down Expand Up @@ -1898,17 +1899,6 @@ impl<'a> FastCheckTransformer<'a> {
}
}

enum FunctionKind {
/// function declarations, class method declarations (both class decl and class expr)
DeclarationLike,
/// function expressions, arrow functions, object method shorthand properties
ExpressionLike,
/// getters, both on classes and object literals
Getter,
/// setters, both on classes and object literals
Setter,
}

fn is_ts_private_computed_class_member(m: &ClassMember) -> bool {
match m {
ClassMember::Method(m) => {
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod fast_check;
pub mod packages;
pub mod source;
mod text_encoding;
mod swc_helpers;

use source::FileSystem;
use source::JsrUrlProvider;
Expand Down
112 changes: 112 additions & 0 deletions src/swc_helpers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Copyright 2018-2024 the Deno authors. MIT license.

use std::ops::ControlFlow;

use deno_ast::swc::ast::ReturnStmt;
use deno_ast::swc::ast::Stmt;

pub enum FunctionKind {
/// function declarations, class method declarations (both class decl and class expr)
DeclarationLike,
/// function expressions, arrow functions, object method shorthand properties
ExpressionLike,
/// getters, both on classes and object literals
Getter,
/// setters, both on classes and object literals
Setter,
}

#[derive(Debug)]
pub enum ReturnStatementAnalysis {
/// There are no return statements in the function body.
None,
/// There are only return statements without arguments in the function body,
/// or if the function body is empty.
Void,
/// There is only a single return statement in the function body, and it has
/// an argument.
Single(ReturnStmt),
/// There are multiple return statements in the function body, and at least
/// one of them has an argument.
Multiple,
}

pub fn analyze_return_stmts_in_function_body(
body: &deno_ast::swc::ast::BlockStmt,
) -> ReturnStatementAnalysis {
if body.stmts.is_empty() {
ReturnStatementAnalysis::Void
} else {
let mut analysis = ReturnStatementAnalysis::None;
analyze_return_stmts_from_stmts(&body.stmts, &mut analysis);
analysis
}
}

fn analyze_return_stmts_from_stmts(
stmts: &[Stmt],
analysis: &mut ReturnStatementAnalysis,
) -> ControlFlow<(), ()> {
for stmt in stmts {
analyze_return_stmts_from_stmt(stmt, analysis)?;
}
ControlFlow::Continue(())
}

fn analyze_return_stmts_from_stmt(
stmt: &Stmt,
analysis: &mut ReturnStatementAnalysis,
) -> ControlFlow<(), ()> {
match stmt {
Stmt::Block(n) => analyze_return_stmts_from_stmts(&n.stmts, analysis),
Stmt::With(n) => analyze_return_stmts_from_stmt(&n.body, analysis),
Stmt::Return(n) => {
match (&n.arg, &*analysis) {
(None, ReturnStatementAnalysis::None) => {
*analysis = ReturnStatementAnalysis::Void;
}
(None, ReturnStatementAnalysis::Void) => {}
(Some(_), ReturnStatementAnalysis::None)
| (Some(_), ReturnStatementAnalysis::Void) => {
*analysis = ReturnStatementAnalysis::Single(n.clone());
}
(_, ReturnStatementAnalysis::Single(_)) => {
*analysis = ReturnStatementAnalysis::Multiple;
return ControlFlow::Break(());
}
(_, ReturnStatementAnalysis::Multiple) => unreachable!(), // we break early when analysis is Multiple
}
ControlFlow::Continue(())
}
Stmt::Labeled(n) => analyze_return_stmts_from_stmt(&n.body, analysis),
Stmt::If(n) => analyze_return_stmts_from_stmt(&n.cons, analysis),
Stmt::Switch(n) => {
for case in &n.cases {
analyze_return_stmts_from_stmts(&case.cons, analysis)?;
}
ControlFlow::Continue(())
}
Stmt::Try(n) => {
analyze_return_stmts_from_stmts(&n.block.stmts, analysis)?;
if let Some(n) = &n.handler {
analyze_return_stmts_from_stmts(&n.body.stmts, analysis)?;
}
if let Some(n) = &n.finalizer {
analyze_return_stmts_from_stmts(&n.stmts, analysis)?;
}
ControlFlow::Continue(())
}
Stmt::While(n) => analyze_return_stmts_from_stmt(&n.body, analysis),
Stmt::DoWhile(n) => analyze_return_stmts_from_stmt(&n.body, analysis),
Stmt::For(n) => analyze_return_stmts_from_stmt(&n.body, analysis),
Stmt::ForIn(n) => analyze_return_stmts_from_stmt(&n.body, analysis),
Stmt::ForOf(n) => analyze_return_stmts_from_stmt(&n.body, analysis),
Stmt::Break(_)
| Stmt::Continue(_)
| Stmt::Throw(_)
| Stmt::Debugger(_)
| Stmt::Decl(_)
| Stmt::Expr(_)
| Stmt::Empty(_) => ControlFlow::Continue(()),
}
}
Loading
Loading