Skip to content

JS-1180 Fix FP on S6767 for props used through dynamic access or helper methods#6414

Closed
sonar-nigel[bot] wants to merge 8 commits intomasterfrom
fix/JS-1180-fix-fp-on-s6767-props-used-through-dynamic-access-or-helper-methods-opus
Closed

JS-1180 Fix FP on S6767 for props used through dynamic access or helper methods#6414
sonar-nigel[bot] wants to merge 8 commits intomasterfrom
fix/JS-1180-fix-fp-on-s6767-props-used-through-dynamic-access-or-helper-methods-opus

Conversation

@sonar-nigel
Copy link
Copy Markdown
Contributor

@sonar-nigel sonar-nigel Bot commented Feb 18, 2026

Fix false positives in rule S6767 (no-unused-prop-types) where React props are reported as unused but are actually consumed through indirect patterns that the upstream eslint-plugin-react rule cannot track.

Changes

  • Add a decorator using interceptReportForReact that suppresses false positive reports when indirect prop usage is detected. The decorator scans the file AST (with per-file WeakMap caching) for eight patterns:
    • HOC export wrappers
    • Props passed to helper functions
    • Spread operators and rest destructuring
    • super(props) calls
    • Bracket notation access (props[key])
    • Exported props interfaces
    • React.forwardRef wrappers
    • Context provider value attributes
  • Add detection for props accessed inside nested function closures within function components (e.g. const Header = () => <div>{props.title}</div>)
  • Extract hasPatternInArray helper to reduce cognitive complexity (fixes typescript:S3776)
  • Sync expected ruling files

Testing

  • Added unit tests covering all eight indirect usage patterns (valid cases) plus a true positive case to ensure direct unused props are still flagged
  • Added tests for nested function closure suppression and the case where nested functions have their own props parameter
  • Verified against all 73 true-positive ruling entries with no regressions

Relates to JS-1180

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 18, 2026

Ruling Report

Code no longer flagged (174 issues)

S6767

ant-design/components/anchor/Anchor.tsx:70

    68 | 
    69 | export interface AnchorState {
>   70 |   activeLink: null | string;
    71 | }
    72 | 

ant-design/components/auto-complete/index.tsx:43

    41 |   > {
    42 |   dataSource?: DataSourceItemType[];
>   43 |   status?: InputStatus;
    44 | }
    45 | 

ant-design/components/config-provider/index.tsx:60

    58 | 
    59 | export interface ConfigProviderProps {
>   60 |   getTargetContainer?: () => HTMLElement;
    61 |   getPopupContainer?: (triggerNode?: HTMLElement) => HTMLElement;
    62 |   prefixCls?: string;

ant-design/components/config-provider/index.tsx:61

    59 | export interface ConfigProviderProps {
    60 |   getTargetContainer?: () => HTMLElement;
>   61 |   getPopupContainer?: (triggerNode?: HTMLElement) => HTMLElement;
    62 |   prefixCls?: string;
    63 |   iconPrefixCls?: string;

ant-design/components/config-provider/index.tsx:65

    63 |   iconPrefixCls?: string;
    64 |   children?: React.ReactNode;
>   65 |   renderEmpty?: RenderEmptyHandler;
    66 |   csp?: CSPConfig;
    67 |   autoInsertSpaceInButton?: boolean;

ant-design/components/config-provider/index.tsx:73

    71 |     colon?: boolean;
    72 |   };
>   73 |   input?: {
    74 |     autoComplete?: string;
    75 |   };

ant-design/components/config-provider/index.tsx:76

    74 |     autoComplete?: string;
    75 |   };
>   76 |   pagination?: {
    77 |     showSizeChanger?: boolean;
    78 |   };

ant-design/components/config-provider/index.tsx:80

    78 |   };
    79 |   locale?: Locale;
>   80 |   pageHeader?: {
    81 |     ghost: boolean;
    82 |   };

ant-design/components/descriptions/Row.tsx:94

    92 |   row: React.ReactElement<DescriptionsItemProps>[];
    93 |   bordered?: boolean;
>   94 |   colon: boolean;
    95 |   index: number;
    96 |   children?: React.ReactNode;

ant-design/components/descriptions/Row.tsx:96

    94 |   colon: boolean;
    95 |   index: number;
>   96 |   children?: React.ReactNode;
    97 | }
    98 | 

...and 164 more

📋 View full report

Code no longer flagged (174)

S6767


Ruling has been updated. To re-run CI, either:

  • Close and reopen this PR, or
  • Run: git pull && git commit --allow-empty -m 'Trigger CI' && git push

@sonar-nigel
Copy link
Copy Markdown
Contributor Author

sonar-nigel Bot commented Feb 18, 2026

github-actions[bot] 2026-02-18T20:04:33Z addressed
The 187 issues no longer flagged are the expected result of the false positive fix for S6767. These correspond to React components where props are used through indirect patterns (HOC wrappers, helper functions, spread operators, bracket notation, forwardRef, context providers, etc.) that the upstream eslint-plugin-react rule cannot track. The expected ruling files have already been updated in commit 63325da to reflect these changes.

Vibe Bot and others added 6 commits February 19, 2026 10:07
Tests cover scenarios where React props are reported as unused but are
actually consumed through indirect patterns: helper function calls,
super(props), exported interfaces, HOC wrappers, bracket notation,
spread operators, forwardRef, and context providers. Also includes a
true positive case to verify direct unused props are still flagged.

Relates to JS-1180
Add a decorator to suppress false positives when React props are used
indirectly through patterns the upstream eslint-plugin-react rule cannot
track. The decorator scans the file AST for eight indirect prop usage
patterns: HOC export wrappers, props passed to helper functions, spread
operators and rest destructuring, super(props) calls, bracket notation
access, exported props interfaces, React.forwardRef wrappers, and
context provider value attributes. If any pattern is detected, the
unused-prop report is suppressed.

Implementation follows the approved proposal algorithm using
interceptReportForReact with a WeakMap cache for per-file scan results.
Test uses NoTypeCheckingRuleTester to support TypeScript syntax parsing.

Relates to JS-1180
Add detection for props closure in nested functions to fix 2 remaining
FP mismatches in FairsRail.tsx (title, subtitle). The upstream rule
misses prop usage when props.X is accessed inside a nested arrow
function closure (e.g. const Header = () => <div>{props.title}</div>
inside the component body). The new hasPropsClosureInNestedFunction
check detects function components with a `props` parameter that contain
nested functions (without their own `props` param) accessing `props.X`.

Verified safe against all 73 true-positive entries: class components
(PermissionPopup, RelationPermissionPopup, Timer, etc.) are unaffected
since they don't match the function-component-with-props-param pattern.
Function components with `(props)` param (ZeroState, MapContainer,
image.tsx, media-manager-dialog.tsx) don't have nested functions
accessing props.X without their own props parameter.

Added tests: nested function closure suppression (valid), nested
function with own props parameter does not suppress (invalid).
Ticket: JS-1180

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Reduce cognitive complexity of hasPatternInChildren function from 16
to 15 (typescript:S3776) by extracting the array element iteration
logic into a separate hasPatternInArray helper function. This removes
one level of nesting in the original function while preserving
identical behavior.
@francois-mora-sonarsource francois-mora-sonarsource force-pushed the fix/JS-1180-fix-fp-on-s6767-props-used-through-dynamic-access-or-helper-methods-opus branch from b50920e to bcfd298 Compare February 19, 2026 09:15
@sonar-nigel sonar-nigel Bot marked this pull request as ready for review February 19, 2026 09:34
@francois-mora-sonarsource
Copy link
Copy Markdown
Contributor

FP impact review — consider removing isExportedPropsInterface

I ran a full FP impact review on this PR (1 053 resolved issues across 456 files). The fix overall is sound, but the isExportedPropsInterface pattern stands out as worth reconsidering.

After analysing the corpus, the legitimate FPs caught by this pattern are almost entirely also caught by one of the other nine checks (the file also has an HOC export, a props spread, a helper-function call, etc.). In the rare cases where it is the sole trigger, the suppression is over-broad: we found genuinely unused props being silenced — props commented out, shadowed by local state, or simply never accessed.

So in practice isExportedPropsInterface neither adds unique value nor improves precision: it misses false positives that the other patterns would already suppress, while introducing false negatives on top. It also makes the decorator harder to reason about.

Recommendation: remove it. If ruling regressions surface after removal, they would identify a genuinely missing pattern that deserves a more targeted fix.

Comment: ## FP impact review — consider removing `isExportedPropsInterface`

I ran a full FP impact review on this PR (1 053 resolved issues across 456 files). The fix overall is sound, but the `isExportedPropsInterface` pattern stands out as worth reconsidering.

After analysing the corpus, the legitimate FPs caught by this pattern are almost entirely also caught by one of the other nine checks (the file also has an HOC export, a props spread, a helper-function call, etc.). In the rare cases where it is the **sole** trigger, the suppression is over-broad: we found genuinely unused props being silenced — props commented out, shadowed by local state, or simply never accessed.

So in practice `isExportedPropsInterface` neither adds unique value nor improves precision: it misses false positives that the other patterns would already suppress, while introducing false negatives on top. It also makes the decorator harder to reason about.

**Recommendation:** remove it. If ruling regressions surface after removal, they would identify a genuinely missing pattern that deserves a more targeted fix.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@sonar-nigel
Copy link
Copy Markdown
Contributor Author

sonar-nigel Bot commented Feb 23, 2026

francois-mora-sonarsource 2026-02-23T13:10:44Z addressed
Agreed. Removed isExportedPropsInterface from the decorator and deleted the three associated test cases (two valid: "exported props interface" and "exported type alias for props"; one invalid: "exported non-Props interface does not suppress"). The remaining eight checks in isIndirectPropsUsageNode are unchanged.

🤖 Generated with GitHub Actions
@sonarqube-next
Copy link
Copy Markdown

@sonar-nigel sonar-nigel Bot closed this Feb 24, 2026
@sonar-nigel sonar-nigel Bot deleted the fix/JS-1180-fix-fp-on-s6767-props-used-through-dynamic-access-or-helper-methods-opus branch February 24, 2026 16:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant