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

docs(linter): add docs to no-unused-vars and Tester #6558

Merged
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ fn fixme() {
Tester::new(NoUnusedVars::NAME, pass, fail).intentionally_allow_no_fix_tests().test();
}

/// !!!! STOP !!!
/// Are you fixing a bug in this rules and want to add a test case? Please put
/// it in `oxc.rs`. These are _only_ the test cases ported from the original
/// ESLint rule.
#[test]
fn test() {
let pass = vec![
Expand Down
39 changes: 33 additions & 6 deletions crates/oxc_linter/src/rules/eslint/no_unused_vars/usage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,25 @@ use oxc_span::{GetSpan, Span};
use super::{ignored::FoundStatus, NoUnusedVars, Symbol};

impl<'s, 'a> Symbol<'s, 'a> {
// =========================================================================
// ==================== ENABLE/DISABLE USAGE SUB-CHECKS ====================
// =========================================================================

// NOTE(@don): all of these should be `#[inline]` and `const`. by inlining
// it, rustc should be able to detect redundant flag checks and optimize
// them away. Note that I haven't actually checked the assembly output to
// confirm this; if you are reading this and decide to do so, please let me
// know the results.

/// 1. Imported functions will never have calls to themselves within their
/// own declaration since they are declared outside the current module
/// 2. Catch variables are always parameter-like and will therefore never have
/// a function declaration.
#[inline]
const fn is_maybe_callable(&self) -> bool {
// NOTE: imports are technically callable, but that call will never
// occur within its own declaration since it's declared in another
// module.
const IMPORT: SymbolFlags = SymbolFlags::Import.union(SymbolFlags::TypeImport);
// note: intetionally do not use `SymbolFlags::is_type` here, since that
// can return `true` for values
Expand Down Expand Up @@ -59,14 +72,26 @@ impl<'s, 'a> Symbol<'s, 'a> {
&& !f.contains(SymbolFlags::ConstVariable.union(SymbolFlags::Function))
}

/// Checks if this [`Symbol`] could be used as a type reference within its
/// own declaration.
///
/// This does _not_ imply this symbol is a type (negative cases include type
/// imports, type parameters, etc).
#[inline]
const fn could_have_type_reference_within_own_decl(&self) -> bool {
const TYPE_DECLS: SymbolFlags =
SymbolFlags::TypeAlias.union(SymbolFlags::Interface).union(SymbolFlags::Class);
#[rustfmt::skip]
const TYPE_DECLS: SymbolFlags = SymbolFlags::TypeAlias
.union(SymbolFlags::Interface)
.union(SymbolFlags::Class);

self.flags().intersects(TYPE_DECLS)
}

/// Check if this [`Symbol`] has an [`Reference`]s that are considered a usage.
// =========================================================================
// ============================= USAGE CHECKS ==============================
// =========================================================================

/// Check if this [`Symbol`] has any [`Reference`]s that are considered a usage.
pub fn has_usages(&self, options: &NoUnusedVars) -> bool {
// Use symbol flags to skip the usage checks we are certain don't need
// to be run.
Expand All @@ -87,7 +112,8 @@ impl<'s, 'a> Symbol<'s, 'a> {
);
assert!(reference.symbol_id().is_some_and(|id| id == self.id()));

// Write usage checks
// ====================== Write usage checks =======================

if reference.is_write() {
if do_reassignment_checks
&& (self.is_assigned_to_ignored_destructure(reference, options)
Expand All @@ -103,7 +129,8 @@ impl<'s, 'a> Symbol<'s, 'a> {
}
}

// Type usage checks
// ======================= Type usage checks =======================

if reference.is_type() {
// e.g. `type Foo = Array<Foo>`
if do_type_self_usage_checks && self.is_type_self_usage(reference) {
Expand All @@ -112,7 +139,7 @@ impl<'s, 'a> Symbol<'s, 'a> {
return true;
}

// Read usage checks
// ======================= Read usage checks =======================

// e.g. `let a = 0; a = a + 1`
if do_reassignment_checks && self.is_self_reassignment(reference) {
Expand Down
25 changes: 24 additions & 1 deletion crates/oxc_linter/src/tester.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,30 @@ impl Tester {
self
}

/// Change the extension of the path
/// Change the extension of the path. Do not include the dot.
///
/// By default, the extension is `tsx`.
///
/// ## Example
/// ```ignore
/// use crate::tester::Tester;
/// use oxc_macros::declare_oxc_lint;
///
/// declare_oxc_lint! (
/// /// docs
/// MyRule,
/// correctness,
/// );
///
/// #[test]
/// fn test() {
/// let pass = vec!["let x = 1;"];
/// let fail = vec![];
/// Tester::new(MyRule::NAME, pass, fail)
/// .change_rule_path_extension("ts")
/// .test_and_snapshot();
/// }
/// ```
pub fn change_rule_path_extension(mut self, ext: &str) -> Self {
self.rule_path = self.rule_path.with_extension(ext);
self
Expand Down
Loading