Skip to content

Fix matching logic for complex pointcuts combined with || - #65

Merged
lisachenko merged 1 commit into
masterfrom
claude/issue-9-implementation-tests-pl8ds7
Jul 23, 2026
Merged

Fix matching logic for complex pointcuts combined with ||#65
lisachenko merged 1 commit into
masterfrom
claude/issue-9-implementation-tests-pl8ds7

Conversation

@lisachenko

Copy link
Copy Markdown
Member

Fixes #9

Problem

Combined pointcuts delegated matching to each sub-pointcut regardless of the element's join point kind. In an expression like

execution(public **->data*(*)) || access(public **->$id*)

the KIND_METHOD execution clause could match a field named dataMap purely by name pattern (and the access clause could match methods named id*), producing false-positive line markers. OrPointcut.getKind() is the union of the clause kinds and PointcutAdvisor gates only on that aggregate, so the wrong-kind element always reached the kind-blind clause. A related leak: ... || initialization(Foo) compiles the initialization branch to TruePointcut(KIND_CLASS) whose matches() is always true, so every member of a matching class matched through that OR branch.

Fix

Adds the matching context from goaop/framework#274 (the join-point kind) as a gate on sub-pointcut delegation:

  • New Set<KindFilter>.supports(element) extension in KindFilter.kt maps Method/Field/PhpClass elements to KIND_METHOD/KIND_PROPERTY/KIND_CLASS.
  • AndPointcut.isMatchesPointcut (shared by OrPointcut via inheritance) now skips sub-pointcuts whose kind set does not support the element — this also fixes the initialization() leak above.
  • SignaturePointcut.matches() now checks its own filterKind, consistent with how AttributePointcut already behaved.
  • AttributePointcut reuses the shared helper instead of its private canMatchElement (behavior unchanged).

Not touched: modifier matching (MemberAccessMatcherFilter + MemberStateMatcherFilter) already evaluates public|protected + static correctly as (public || protected) && static, so the goaop/framework#293 variant of this bug does not exist in the plugin.

Tests

  • New OrPointcutKindMatchingTest regression suite using real SignaturePointcuts that mirrors the issue scenario: cross-kind false positives are rejected while legitimate matches of each clause still work, TruePointcut(KIND_CLASS) no longer leaks members through an OR, and the OR kind stays the union (which PointcutAdvisor.getMatchedElements relies on).
  • Kind-gate unit tests in AndPointcutTest/OrPointcutTest verifying the gate short-circuits before the sub-pointcut is consulted, and that only the kind-compatible child is delegated to.
  • supports() coverage in KindFilterTest; kind-mismatch cases in SignaturePointcutTest.
  • Existing mocks tightened from bare PhpClassMember to Method so they represent real PSI elements and pass the stricter gate.

🤖 Generated with Claude Code

https://claude.ai/code/session_015GwCyE8P8udW5VMJHY4qGk


Generated by Claude Code

Combined pointcuts delegated matching to each sub-pointcut regardless of
the element's join point kind, so in an expression like
'execution(public **->data*(*)) || access(public **->$id*)' the
KIND_METHOD execution clause could match a field named 'dataMap' purely
by name pattern (and the access clause could match methods), producing
false-positive line markers.

Add the matching context from goaop/framework#274 as a kind gate:

- New Set<KindFilter>.supports(element) extension maps Method/Field/
  PhpClass elements to KIND_METHOD/KIND_PROPERTY/KIND_CLASS.
- AndPointcut.isMatchesPointcut (shared by OrPointcut) now skips
  sub-pointcuts whose kind set does not support the element, which also
  stops class-kind TruePointcut branches (initialization()) from leaking
  every member through an OR.
- SignaturePointcut.matches() now checks its own filterKind, consistent
  with AttributePointcut.
- AttributePointcut reuses the shared helper instead of its private
  canMatchElement.

Tests: new OrPointcutKindMatchingTest regression suite with real
SignaturePointcuts mirroring the issue scenario, kind-gate tests for
And/OrPointcut and SignaturePointcut, supports() coverage in
KindFilterTest, and existing mocks tightened from bare PhpClassMember to
Method so they pass the stricter gate realistically.

Fixes #9

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015GwCyE8P8udW5VMJHY4qGk
@github-actions

Copy link
Copy Markdown

Qodana for JVM

It seems all right 👌

No new problems were found according to the checks applied

💡 Qodana analysis was run in the pull request mode: only the changed files were checked

View the detailed Qodana report

To be able to view the detailed Qodana report, you can either:

To get *.log files or any other Qodana artifacts, run the action with upload-result option set to true,
so that the action will upload the files as the job artifacts:

      - name: 'Qodana Scan'
        uses: JetBrains/qodana-action@v2026.1.3
        with:
          upload-result: true
Contact Qodana team

Contact us at qodana-support@jetbrains.com

@lisachenko
lisachenko merged commit b221ee1 into master Jul 23, 2026
6 checks passed
@lisachenko lisachenko added this to the 2.0.0 milestone Jul 23, 2026
@lisachenko
lisachenko deleted the claude/issue-9-implementation-tests-pl8ds7 branch July 23, 2026 04:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

[PointcutAdvisor] Fix logic of matching for complex pointcuts

2 participants