Skip to content

SONARPHP-1969 Account for dynamically accessed local variables - #1855

Merged
lijun-chen-sonarsource merged 2 commits into
lc/SONARPHP-1593from
lc/SONARPHP-1969
Oct 22, 2026
Merged

lijun-chen-sonarsource merged 2 commits into
lc/SONARPHP-1593from
lc/SONARPHP-1969

Conversation

@lijun-chen-sonarsource

@lijun-chen-sonarsource lijun-chen-sonarsource commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Stack created with GitHub Stacks CLI • Give Feedback 💬


Summary by Gitar

  • Dynamic variable reads:
    • Treats $$name, ${'literal'}, and unresolved dynamic reads as reads of locals in ReadWriteUsages
    • Excludes write-only dynamic targets, static members, and direct string interpolation from dynamic read tracking
  • Indirect local access:
    • Treats include, require, eval, extract, and get_defined_vars calls as reading all locals in their scope
  • Tests:
    • Added UnusedLocalVariableCheckDynamicReads.php fixture covering dynamic read and write scenarios
  • Static method names:
    • Tracks dynamic locals used as static method names, such as Example::$$name(), as reads

This will update automatically on new commits.

@hashicorp-vault-sonar-prod

hashicorp-vault-sonar-prod Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

SONARPHP-1969

Comment thread php-checks/src/main/java/org/sonar/php/checks/utils/ReadWriteUsages.java Outdated
@lijun-chen-sonarsource
lijun-chen-sonarsource force-pushed the lc/SONARPHP-1969 branch 2 times, most recently from d16192e to c180a18 Compare October 19, 2026 21:53

@asya-vorobeva asya-vorobeva left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔢

Resolve literal variable names precisely and treat unresolved dynamic reads
as possible reads of all locals in their scope.

Account for eval, extract, get_defined_vars, and included code that can
observe locals. Distinguish static property names from dynamic local
lookups in calls, callables, and instance members.
@sonarqube-next

Copy link
Copy Markdown

@gitar-bot

gitar-bot Bot commented Oct 20, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 1 closed / 1 findings

🟡 Medium risk · Expanding dynamic-read tracking may suppress unused-local findings for unrelated variables, hiding genuine dead code from PHP analysis.

Adds dynamic local variable read tracking so $$name, ${'literal'}, and indirect access via include, eval, extract, and get_defined_vars count as reads in ReadWriteUsages. Static method calls with a variable-variable name, such as Example::$$name(), are now tracked as reads, addressing the skipped-read finding. No open issues found.

✅ 1 closed
✅ Edge Case: Static method calls with a variable-variable name are skipped as reads

📄 php-checks/src/main/java/org/sonar/php/checks/utils/ReadWriteUsages.java:142 📄 php-checks/src/main/java/org/sonar/php/checks/utils/ReadWriteUsages.java:150 📄 php-checks/src/main/java/org/sonar/php/checks/utils/ReadWriteUsages.java:183-185
isStaticMemberName treats every $$name or ${$name} that is the member of a static MemberAccessTree as a static property name. That is only true for property access. In Example::$$name() or Example::${$name}() (the grammar's CLASS_MEMBER_ACCESS with VARIABLE_WITHOUT_OBJECTS as the member, called through a FunctionCallTree), PHP evaluates the whole member expression as the method name. So $$name reads the local named by $name, the same way Example::$method() reads the local $method. These calls are therefore never passed to visitDynamicRead. For example, in function f($name) { $method = 'foo'; return Example::$$name(); } the rule still reports $method as unused, which is the false positive this PR is meant to remove. Fix: exclude only static members that are not the callee of a function call (or treat the call case as a dynamic read), and add a test case.

Verification Rules 1/1 met PRs 2 inspected

Functional validation No results

Rules 1 passed 2 not applicable

✅ Repository license compliance

Broader impact PRs 2 inspected
Cross-PR 2 PRs inspected 0 open impacts

PR #1854: SONARPHP-1593 Track reads through sibling and nested closure references Inspected
PR #1853: SONARPHP-1972 Exempt underscore-prefixed unused local variables Inspected

Auto-approval Not enabled

Set up

For more verification details, comment gitar display:verbose.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing compact verification results.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@lijun-chen-sonarsource
lijun-chen-sonarsource merged commit 0c96f80 into master Oct 22, 2026
22 checks passed
@lijun-chen-sonarsource
lijun-chen-sonarsource deleted the lc/SONARPHP-1969 branch October 22, 2026 08:28
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.

2 participants