Skip to content

Commit

Permalink
fix(noVoidTypeReturn): accept void expression in returns
Browse files Browse the repository at this point in the history
  • Loading branch information
Conaclos committed Oct 7, 2024
1 parent 48affbb commit b9186c2
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 33 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b

Contributed by @Conaclos

- [noVoidTypeReturn](https://biomejs.dev/linter/rules/no-void-type-return/) now accept `void` expressions in return position ([#4173](https://github.com/biomejs/biome/issues/4173)).

The following code is now accepted:

```ts
function f(): void {
return void 0;
}
```

Contributed by @Conaclos

### Parser

#### Bug Fixes
Expand Down
69 changes: 38 additions & 31 deletions crates/biome_js_analyze/src/lint/correctness/no_void_type_return.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ use biome_analyze::context::RuleContext;
use biome_analyze::{declare_lint_rule, Ast, Rule, RuleDiagnostic};
use biome_console::markup;
use biome_js_syntax::{
AnyTsReturnType, JsArrowFunctionExpression, JsFunctionDeclaration,
AnyJsExpression, AnyTsReturnType, JsArrowFunctionExpression, JsFunctionDeclaration,
JsFunctionExportDefaultDeclaration, JsFunctionExpression, JsGetterClassMember,
JsGetterObjectMember, JsMethodClassMember, JsMethodObjectMember, JsReturnStatement,
JsSyntaxKind,
};
use biome_rowan::{declare_node_union, AstNode};

Expand Down Expand Up @@ -92,47 +93,28 @@ declare_lint_rule! {
}
}

declare_node_union! {
pub JsFunctionMethod = JsArrowFunctionExpression | JsFunctionDeclaration | JsFunctionExportDefaultDeclaration | JsFunctionExpression | JsGetterClassMember | JsGetterObjectMember | JsMethodClassMember | JsMethodObjectMember
}

pub(crate) fn return_type(func: &JsFunctionMethod) -> Option<AnyTsReturnType> {
match func {
JsFunctionMethod::JsArrowFunctionExpression(func) => {
func.return_type_annotation()?.ty().ok()
}
JsFunctionMethod::JsFunctionDeclaration(func) => func.return_type_annotation()?.ty().ok(),
JsFunctionMethod::JsFunctionExportDefaultDeclaration(func) => {
func.return_type_annotation()?.ty().ok()
}
JsFunctionMethod::JsFunctionExpression(func) => func.return_type_annotation()?.ty().ok(),
JsFunctionMethod::JsGetterClassMember(func) => {
Some(AnyTsReturnType::AnyTsType(func.return_type()?.ty().ok()?))
}
JsFunctionMethod::JsGetterObjectMember(func) => {
Some(AnyTsReturnType::AnyTsType(func.return_type()?.ty().ok()?))
}
JsFunctionMethod::JsMethodClassMember(func) => func.return_type_annotation()?.ty().ok(),
JsFunctionMethod::JsMethodObjectMember(func) => func.return_type_annotation()?.ty().ok(),
}
}

impl Rule for NoVoidTypeReturn {
type Query = Ast<JsReturnStatement>;
type State = JsFunctionMethod;
type State = AnyJsFunctionMethodWithReturnType;
type Signals = Option<Self::State>;
type Options = ();

fn run(ctx: &RuleContext<Self>) -> Self::Signals {
let ret = ctx.query();
// Do not take arg-less returns into account
let _arg = ret.argument()?;
// Ignore arg-less returns such as `return;`
let arg = ret.argument()?;
if let AnyJsExpression::JsUnaryExpression(expr) = arg {
if expr.operator_token().ok()?.kind() == JsSyntaxKind::VOID_KW {
// Ignore `return void <foo>;`
return None;
}
}
let func = ret
.syntax()
.ancestors()
.find(|x| AnyJsControlFlowRoot::can_cast(x.kind()))
.and_then(JsFunctionMethod::cast)?;
let ret_type = return_type(&func)?;
.and_then(AnyJsFunctionMethodWithReturnType::cast)?;
let ret_type = func.return_type()?;
ret_type.as_any_ts_type()?.as_ts_void_type().and(Some(func))
}

Expand All @@ -149,3 +131,28 @@ impl Rule for NoVoidTypeReturn {
))
}
}

declare_node_union! {
pub AnyJsFunctionMethodWithReturnType = JsArrowFunctionExpression | JsFunctionDeclaration | JsFunctionExportDefaultDeclaration | JsFunctionExpression | JsGetterClassMember | JsGetterObjectMember | JsMethodClassMember | JsMethodObjectMember
}

impl AnyJsFunctionMethodWithReturnType {
pub fn return_type(&self) -> Option<AnyTsReturnType> {
match self {
Self::JsArrowFunctionExpression(func) => func.return_type_annotation()?.ty().ok(),
Self::JsFunctionDeclaration(func) => func.return_type_annotation()?.ty().ok(),
Self::JsFunctionExportDefaultDeclaration(func) => {
func.return_type_annotation()?.ty().ok()
}
Self::JsFunctionExpression(func) => func.return_type_annotation()?.ty().ok(),
Self::JsGetterClassMember(func) => {
Some(AnyTsReturnType::AnyTsType(func.return_type()?.ty().ok()?))
}
Self::JsGetterObjectMember(func) => {
Some(AnyTsReturnType::AnyTsType(func.return_type()?.ty().ok()?))
}
Self::JsMethodClassMember(func) => func.return_type_annotation()?.ty().ok(),
Self::JsMethodObjectMember(func) => func.return_type_annotation()?.ty().ok(),
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ class B {
function f(): void {
return;
}

function g(): void {
return void 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ function f(): void {
return;
}

```

function g(): void {
return void 0;
}

```

0 comments on commit b9186c2

Please sign in to comment.