deno_lint 0.37.0

lint for deno
Documentation
// Copyright 2020-2021 the Deno authors. All rights reserved. MIT license.
use super::{Context, LintRule};
use crate::handler::{Handler, Traverse};
use crate::swc_util::StringRepr;
use crate::{Program, ProgramRef};
use deno_ast::{view as ast_view, SourceRanged};
use derive_more::Display;
use std::collections::HashSet;
use std::sync::Arc;

#[derive(Debug)]
pub struct AdjacentOverloadSignatures;

const CODE: &str = "adjacent-overload-signatures";

#[derive(Display)]
enum AdjacentOverloadSignaturesMessage {
  #[display(fmt = "All `{}` signatures should be adjacent", _0)]
  ShouldBeAdjacent(String),
}

#[derive(Display)]
enum AdjacentOverloadSignaturesHint {
  #[display(fmt = "Make sure all overloaded signatures are grouped together")]
  GroupedTogether,
}

impl LintRule for AdjacentOverloadSignatures {
  fn new() -> Arc<Self> {
    Arc::new(AdjacentOverloadSignatures)
  }

  fn tags(&self) -> &'static [&'static str] {
    &["recommended"]
  }

  fn code(&self) -> &'static str {
    CODE
  }

  fn lint_program(&self, _context: &mut Context, _program: ProgramRef<'_>) {
    unreachable!();
  }

  fn lint_program_with_ast_view<'view>(
    &self,
    context: &mut Context,
    program: Program<'_>,
  ) {
    AdjacentOverloadSignaturesHandler.traverse(program, context);
  }

  #[cfg(feature = "docs")]
  fn docs(&self) -> &'static str {
    include_str!("../../docs/rules/adjacent_overload_signatures.md")
  }
}

struct AdjacentOverloadSignaturesHandler;

impl Handler for AdjacentOverloadSignaturesHandler {
  fn script(&mut self, script: &ast_view::Script, ctx: &mut Context) {
    check(&script.body, ctx);
  }

  fn module(&mut self, module: &ast_view::Module, ctx: &mut Context) {
    check(&module.body, ctx);
  }

  fn ts_module_block(
    &mut self,
    ts_module_block: &ast_view::TsModuleBlock,
    ctx: &mut Context,
  ) {
    check(&ts_module_block.body, ctx);
  }

  fn class(&mut self, class: &ast_view::Class, ctx: &mut Context) {
    check(&class.body, ctx);
  }

  fn ts_type_lit(
    &mut self,
    ts_type_lit: &ast_view::TsTypeLit,
    ctx: &mut Context,
  ) {
    check(&ts_type_lit.members, ctx);
  }

  fn ts_interface_body(
    &mut self,
    ts_interface_body: &ast_view::TsInterfaceBody,
    ctx: &mut Context,
  ) {
    check(&ts_interface_body.body, ctx);
  }
}

fn check<'a, T, U>(items: T, ctx: &'a mut Context)
where
  T: IntoIterator<Item = &'a U>,
  U: ExtractMethod + SourceRanged + 'a,
{
  let mut seen_methods = HashSet::new();
  let mut last_method = None;
  for item in items {
    if let Some(method) = item.get_method() {
      if seen_methods.contains(&method) && last_method.as_ref() != Some(&method)
      {
        ctx.add_diagnostic_with_hint(
          item.range(),
          CODE,
          AdjacentOverloadSignaturesMessage::ShouldBeAdjacent(
            method.to_string(),
          ),
          AdjacentOverloadSignaturesHint::GroupedTogether,
        );
      }

      seen_methods.insert(method.clone());
      last_method = Some(method);
    } else {
      last_method = None;
    }
  }
}

fn extract_ident_from_decl(decl: &ast_view::Decl) -> Option<String> {
  match decl {
    ast_view::Decl::Fn(ast_view::FnDecl { ident, .. }) => {
      Some(ident.sym().to_string())
    }
    _ => None,
  }
}

trait ExtractMethod {
  fn get_method(&self) -> Option<Method>;
}

impl<'a> ExtractMethod for ast_view::ExportDecl<'a> {
  fn get_method(&self) -> Option<Method> {
    let method_name = extract_ident_from_decl(&self.decl);
    method_name.map(Method::Method)
  }
}

impl<'a> ExtractMethod for ast_view::Stmt<'a> {
  fn get_method(&self) -> Option<Method> {
    let method_name = match self {
      ast_view::Stmt::Decl(ref decl) => extract_ident_from_decl(decl),
      _ => None,
    };
    method_name.map(Method::Method)
  }
}

impl<'a> ExtractMethod for ast_view::ModuleItem<'a> {
  fn get_method(&self) -> Option<Method> {
    use deno_ast::view::{ModuleDecl, ModuleItem};
    match self {
      ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(export_decl)) => {
        export_decl.get_method()
      }
      ModuleItem::Stmt(stmt) => stmt.get_method(),
      _ => None,
    }
  }
}

impl<'a> ExtractMethod for ast_view::ClassMember<'a> {
  fn get_method(&self) -> Option<Method> {
    use deno_ast::view::{ClassMember, ClassMethod};
    match self {
      ClassMember::Method(ClassMethod { inner, .. }) => {
        inner.key.string_repr().map(|k| {
          if inner.is_static {
            Method::Static(k)
          } else {
            Method::Method(k)
          }
        })
      }
      ClassMember::Constructor(_) => {
        Some(Method::Method("constructor".to_string()))
      }
      _ => None,
    }
  }
}

impl<'a> ExtractMethod for ast_view::TsTypeElement<'a> {
  fn get_method(&self) -> Option<Method> {
    use deno_ast::view::{Expr, Lit, TsMethodSignature, TsTypeElement};
    match self {
      TsTypeElement::TsMethodSignature(TsMethodSignature {
        ref key, ..
      }) => match key {
        Expr::Ident(ident) => Some(Method::Method(ident.sym().to_string())),
        Expr::Lit(Lit::Str(s)) => Some(Method::Method(s.value().to_string())),
        _ => None,
      },
      TsTypeElement::TsCallSignatureDecl(_) => Some(Method::CallSignature),
      TsTypeElement::TsConstructSignatureDecl(_) => {
        Some(Method::ConstructSignature)
      }
      _ => None,
    }
  }
}

#[derive(PartialEq, Eq, Hash, Clone, Display)]
#[allow(clippy::enum_variant_names)]
enum Method {
  #[display(fmt = "{}", _0)]
  Method(String),
  #[display(fmt = "{}", _0)]
  Static(String),
  #[display(fmt = "call")]
  CallSignature,
  #[display(fmt = "new")]
  ConstructSignature,
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn adjacent_overload_signatures_valid() {
    assert_lint_ok! {
      AdjacentOverloadSignatures,
      r#"
function error(a: string);
function error(b: number);
function error(ab: string | number) {}
export { error };
      "#,
      r#"
import { connect } from 'react-redux';
export interface ErrorMessageModel {
  message: string;
}
function mapStateToProps() {}
function mapDispatchToProps() {}
export default connect(mapStateToProps, mapDispatchToProps)(ErrorMessage);
      "#,
      r#"
export const foo = 'a',
  bar = 'b';
export interface Foo {}
export class Foo {}
      "#,
      r#"
export interface Foo {}
export const foo = 'a',
  bar = 'b';
export class Foo {}
      "#,
      r#"
const foo = 'a',
  bar = 'b';
interface Foo {}
class Foo {}
      "#,
      r#"
interface Foo {}
const foo = 'a',
  bar = 'b';
class Foo {}
      "#,
      r#"
export class Foo {}
export class Bar {}
export type FooBar = Foo | Bar;
      "#,
      r#"
export interface Foo {}
export class Foo {}
export class Bar {}
export type FooBar = Foo | Bar;
      "#,
      r#"
export function foo(s: string);
export function foo(n: number);
export function foo(sn: string | number) {}
export function bar(): void {}
export function baz(): void {}
      "#,
      r#"
function foo(s: string);
function foo(n: number);
function foo(sn: string | number) {}
function bar(): void {}
function baz(): void {}
      "#,
      r#"
declare function foo(s: string);
declare function foo(n: number);
declare function foo(sn: string | number);
declare function bar(): void;
declare function baz(): void;
      "#,
      r#"
declare module 'Foo' {
  export function foo(s: string): void;
  export function foo(n: number): void;
  export function foo(sn: string | number): void;
  export function bar(): void;
  export function baz(): void;
}
      "#,
      r#"
declare namespace Foo {
  export function foo(s: string): void;
  export function foo(n: number): void;
  export function foo(sn: string | number): void;
  export function bar(): void;
  export function baz(): void;
}
      "#,
      r#"
type Foo = {
  foo(s: string): void;
  foo(n: number): void;
  foo(sn: string | number): void;
  bar(): void;
  baz(): void;
};
      "#,
      r#"
type Foo = {
  foo(s: string): void;
  ['foo'](n: number): void;
  foo(sn: string | number): void;
  bar(): void;
  baz(): void;
};
      "#,
      r#"
interface Foo {
  (s: string): void;
  (n: number): void;
  (sn: string | number): void;
  foo(n: number): void;
  bar(): void;
  baz(): void;
}
      "#,
      r#"
interface Foo {
  (s: string): void;
  (n: number): void;
  (sn: string | number): void;
  foo(n: number): void;
  bar(): void;
  baz(): void;
  call(): void;
}
      "#,
      r#"
interface Foo {
  foo(s: string): void;
  foo(n: number): void;
  foo(sn: string | number): void;
  bar(): void;
  baz(): void;
}
      "#,
      r#"
interface Foo {
  foo(s: string): void;
  ['foo'](n: number): void;
  foo(sn: string | number): void;
  bar(): void;
  baz(): void;
}
      "#,
      r#"
interface Foo {
  foo(): void;
  bar: {
    baz(s: string): void;
    baz(n: number): void;
    baz(sn: string | number): void;
  };
}
      "#,
      r#"
interface Foo {
  new (s: string);
  new (n: number);
  new (sn: string | number);
  foo(): void;
}
      "#,
      r#"
class Foo {
  constructor(s: string);
  constructor(n: number);
  constructor(sn: string | number) {}
  bar(): void {}
  baz(): void {}
}
    "#,
      r#"
class Foo {
  foo(s: string): void;
  foo(n: number): void;
  foo(sn: string | number): void {}
  bar(): void {}
  baz(): void {}
}
    "#,
      r#"
class Foo {
  foo(s: string): void;
  "foo"(n: number): void;
  foo(sn: string | number): void {}
  bar(): void {}
  baz(): void {}
}
    "#,
      r#"
class Foo {
  foo(s: string): void;
  ['foo'](n: number): void;
  foo(sn: string | number): void {}
  bar(): void {}
  baz(): void {}
}
      "#,
      r#"
class Foo {
  foo(s: string): void;
  [`foo`](n: number): void;
  foo(sn: string | number): void {}
  bar(): void {}
  baz(): void {}
}
      "#,
      r#"
class Foo {
  name: string;
  foo(s: string): void;
  foo(n: number): void;
  foo(sn: string | number): void {}
  bar(): void {}
  baz(): void {}
}
      "#,
      r#"
class Foo {
  name: string;
  static foo(s: string): void;
  static foo(n: number): void;
  static foo(sn: string | number): void {}
  bar(): void {}
  baz(): void {}
  foo() {}
}
      "#,
      r#"
class Test {
  static test() {}
  untest() {}
  test() {}
}
      "#,
      r#"export default function <T>(foo: T) {}"#,
      r#"export default function named<T>(foo: T) {}"#,
      r#"
interface Foo {
  [Symbol.toStringTag](): void;
  [Symbol.iterator](): void;
}
      "#,
    };
  }

  #[test]
  fn adjacent_overload_signatures_invalid() {
    assert_lint_err! {
      AdjacentOverloadSignatures,
      r#"
export function foo(s: string);
export function foo(n: number);
export function bar(): void {}
export function baz(): void {}
export function foo(sn: string | number) {}
      "#: [
            {
              line: 6,
              col: 0,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
export function foo(s: string);
export function foo(n: number);
export type bar = number;
export type baz = number | string;
export function foo(sn: string | number) {}
      "#: [
            {
              line: 6,
              col: 0,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
function foo(s: string);
function foo(n: number);
function bar(): void {}
function baz(): void {}
function foo(sn: string | number) {}
      "#: [
            {
              line: 6,
              col: 0,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
function foo(s: string);
function foo(n: number);
type bar = number;
type baz = number | string;
function foo(sn: string | number) {}
      "#: [
            {
              line: 6,
              col: 0,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
function foo(s: string) {}
function foo(n: number) {}
const a = '';
const b = '';
function foo(sn: string | number) {}
      "#: [
            {
              line: 6,
              col: 0,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
function foo(s: string) {}
function foo(n: number) {}
class Bar {}
function foo(sn: string | number) {}
      "#: [
            {
              line: 5,
              col: 0,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
function foo(s: string) {}
function foo(n: number) {}
function foo(sn: string | number) {}
class Bar {
  foo(s: string);
  foo(n: number);
  name: string;
  foo(sn: string | number) {}
}
      "#: [
            {
              line: 9,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
declare function foo(s: string);
declare function foo(n: number);
declare function bar(): void;
declare function baz(): void;
declare function foo(sn: string | number);
      "#: [
            {
              line: 6,
              col: 0,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
declare function foo(s: string);
declare function foo(n: number);
const a = '';
const b = '';
declare function foo(sn: string | number);
      "#: [
            {
              line: 6,
              col: 0,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
declare module 'Foo' {
  export function foo(s: string): void;
  export function foo(n: number): void;
  export function bar(): void;
  export function baz(): void;
  export function foo(sn: string | number): void;
}
      "#: [
            {
              line: 7,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
declare module 'Foo' {
  export function foo(s: string): void;
  export function foo(n: number): void;
  export function foo(sn: string | number): void;
  function baz(s: string): void;
  export function bar(): void;
  function baz(n: number): void;
  function baz(sn: string | number): void;
}
      "#: [
            {
              line: 8,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "baz"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
declare namespace Foo {
  export function foo(s: string): void;
  export function foo(n: number): void;
  export function bar(): void;
  export function baz(): void;
  export function foo(sn: string | number): void;
}
      "#: [
            {
              line: 7,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
declare namespace Foo {
  export function foo(s: string): void;
  export function foo(n: number): void;
  export function foo(sn: string | number): void;
  function baz(s: string): void;
  export function bar(): void;
  function baz(n: number): void;
  function baz(sn: string | number): void;
}
      "#: [
            {
              line: 8,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "baz"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
type Foo = {
  foo(s: string): void;
  foo(n: number): void;
  bar(): void;
  baz(): void;
  foo(sn: string | number): void;
};
      "#: [
            {
              line: 7,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
type Foo = {
  foo(s: string): void;
  ['foo'](n: number): void;
  bar(): void;
  baz(): void;
  foo(sn: string | number): void;
};
      "#: [
            {
              line: 7,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
type Foo = {
  foo(s: string): void;
  name: string;
  foo(n: number): void;
  foo(sn: string | number): void;
  bar(): void;
  baz(): void;
};
      "#: [
            {
              line: 5,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
interface Foo {
  (s: string): void;
  foo(n: number): void;
  (n: number): void;
  (sn: string | number): void;
  bar(): void;
  baz(): void;
}
      "#: [
            {
              line: 5,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "call"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
interface Foo {
  foo(s: string): void;
  foo(n: number): void;
  bar(): void;
  baz(): void;
  foo(sn: string | number): void;
}
      "#: [
            {
              line: 7,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
interface Foo {
  foo(s: string): void;
  ['foo'](n: number): void;
  bar(): void;
  baz(): void;
  foo(sn: string | number): void;
}
      "#: [
            {
              line: 7,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
interface Foo {
  foo(s: string): void;
  'foo'(n: number): void;
  bar(): void;
  baz(): void;
  foo(sn: string | number): void;
}
      "#: [
            {
              line: 7,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
interface Foo {
  foo(s: string): void;
  name: string;
  foo(n: number): void;
  foo(sn: string | number): void;
  bar(): void;
  baz(): void;
}
      "#: [
            {
              line: 5,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
interface Foo {
  foo(): void;
  bar: {
    baz(s: string): void;
    baz(n: number): void;
    foo(): void;
    baz(sn: string | number): void;
  };
}
      "#: [
            {
              line: 8,
              col: 4,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "baz"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
interface Foo {
  new (s: string);
  new (n: number);
  foo(): void;
  bar(): void;
  new (sn: string | number);
}
      "#: [
            {
              line: 7,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "new"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
interface Foo {
  new (s: string);
  foo(): void;
  new (n: number);
  bar(): void;
  new (sn: string | number);
}
      "#: [
            {
              line: 5,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "new"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            },
            {
              line: 7,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "new"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
class Foo {
  constructor(s: string);
  constructor(n: number);
  bar(): void {}
  baz(): void {}
  constructor(sn: string | number) {}
}
      "#: [
            {
              line: 7,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "constructor"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
class Foo {
  foo(s: string): void;
  foo(n: number): void;
  bar(): void {}
  baz(): void {}
  foo(sn: string | number): void {}
}
      "#: [
            {
              line: 7,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
class Foo {
  foo(s: string): void;
  ['foo'](n: number): void;
  bar(): void {}
  baz(): void {}
  foo(sn: string | number): void {}
}
      "#: [
            {
              line: 7,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
class Foo {
  // prettier-ignore
  "foo"(s: string): void;
  foo(n: number): void;
  bar(): void {}
  baz(): void {}
  foo(sn: string | number): void {}
}
      "#: [
            {
              line: 8,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
class Foo {
  constructor(s: string);
  name: string;
  constructor(n: number);
  constructor(sn: string | number) {}
  bar(): void {}
  baz(): void {}
}
      "#: [
            {
              line: 5,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "constructor"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
class Foo {
  foo(s: string): void;
  name: string;
  foo(n: number): void;
  foo(sn: string | number): void {}
  bar(): void {}
  baz(): void {}
}
      "#: [
            {
              line: 5,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
class Foo {
  static foo(s: string): void;
  name: string;
  static foo(n: number): void;
  static foo(sn: string | number): void {}
  bar(): void {}
  baz(): void {}
}
      "#: [
            {
              line: 5,
              col: 2,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "foo"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
class Foo {
  foo() {
    class Bar {
      bar(): void;
      baz() {}
      bar(s: string): void;
    }
  }
}
      "#: [
            {
              line: 7,
              col: 6,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "bar"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
class Foo {
  foo() {
    class Bar {
      bar(): void;
      baz() {}
      bar(s: string): void;
    }
  }
}
      "#: [
            {
              line: 7,
              col: 6,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "bar"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ],
r#"
type Foo = {
  foo(): void;
  bar: {
    baz(s: string): void;
    baz(n: number): void;
    foo(): void;
    baz(sn: string | number): void;
  };
}
      "#: [
            {
              line: 8,
              col: 4,
              message: variant!(AdjacentOverloadSignaturesMessage, ShouldBeAdjacent, "baz"),
              hint: AdjacentOverloadSignaturesHint::GroupedTogether,
            }
          ]
    };
  }
}