Skip to content

Parenthesized chained assertions not detected as unsafe_double_type_assertion #27

Description

@CodeDeficient

Finding

When a chained assertion is wrapped in parentheses — such as (value as unknown) as any — the detector does not classify it as unsafe_double_type_assertion. Instead it falls through to the generic single-assertion branch (or produces a different finding), because the outer AsExpression.expression is a ParenthesizedExpression, not an AsExpression.

Evidence

Reported by CodeRabbit review on PR #24 (commit 3a9b942): the visitor checks ts.isAsExpression(node.expression) which fails for parenthesized chains.

// This pattern is NOT detected as a chained assertion:
const x = (value as unknown) as any;
// AST: AsExpression → ParenthesizedExpression → AsExpression

Removing the parentheses makes it detectable:

// This pattern IS detected as a chained assertion:
const x = value as unknown as any;

Requirements

  • (value as X) as Y must be classified as unsafe_double_type_assertion with assertionForm: chained_as.
  • (value as X) as any must produce both unsafe_double_type_assertion and unsafe_type_assertion independently.
  • ((value as X) as Y) as Z (nested parens) must still be detected.
  • Non-chained parenthesized expressions must not be affected.
  • Existing chain-count tests must continue to pass.

Constraints

  • Do not change finding types or severity.
  • Do not affect non-chained single assertions.
  • Do not modify suppression behavior.
  • Do not exceed the existing per-AST-node finding-count semantics.
  • Do not add dependencies.

Validation

Add tests (RED before fix, GREEN after) for:

  1. (value as X) as Y → 1 finding, unsafe_double_type_assertion
  2. (value as unknown) as any → 2 findings (double + any)
  3. ((value as X) as Y) as Z → 2 findings
  4. (value) as any (unnecessary parens around expression, not chain) → 1 finding unsafe_type_assertion
  5. (value as X) as Y as Z → 2 findings (outer chain + inner chain)
  6. Existing 1-chain, 2-chain, 3-chain, 4-chain tests unchanged

Rollback

A reverted commit restores current parenthesized detection behavior.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions