Skip to content

report dependencies from compiler-duplicated accesses only once - #1748

Open
sharanggupta wants to merge 1 commit into
TNG:mainfrom
sharanggupta:gh-1339-dedupe-dependencies-from-duplicated-finally-bytecode
Open

sharanggupta wants to merge 1 commit into
TNG:mainfrom
sharanggupta:gh-1339-dedupe-dependencies-from-duplicated-finally-bytecode

Conversation

@sharanggupta

Copy link
Copy Markdown
Contributor

The byte code of a finally block is emitted twice by the compiler, once for the regular and once for the exceptional path. A single method call in a finally block therefore results in two JavaMethodCall objects with the same origin, target and line number.

Up to 1.2.x those collapsed into a single Dependency, because Dependency defines equality by origin class, target class, line number and description. Since 771df06 Dependency.tryCreateFromAccess creates Dependency.FromAccess instances whose equals()/hashCode() delegated to the wrapped JavaAccess; as JavaAccess has identity equality only, both dependencies survived deduplication and noClasses().should().dependOnClassesThat()... reported the same violation twice.

This PR lets Dependency.FromAccess use the value-based equality of Dependency (explicitly, so the intent is documented and SpotBugs' EQ_DOESNT_OVERRIDE_EQUALS is satisfied). Converting such a dependency to its JavaAccess is unaffected. A unit test pins the equality contract and an end-to-end test with a finally block reproduces the issue. The design is deliberately minimal; happy to move the deduplication elsewhere (e.g. JavaAccess equality or import time) if preferred.

Out of scope but worth noting: access-based rules such as noClasses().should().accessClassesThat() still report the duplicated call twice, since accesses were never deduplicated.

Verified with :archunit:test (15804 tests), spotlessCheck, architectureTest and spotbugsMain.

Resolves #1339

The byte code of a `finally` block is emitted twice by the compiler, once for
the regular and once for the exceptional path. A single method call in a
`finally` block thus results in two `JavaMethodCall` objects with the same
origin, target and line number.

Up to 1.2.x those were collapsed into a single `Dependency`, because
`Dependency` defines equality by origin class, target class, line number and
description. Since `Dependency.tryCreateFromAccess` creates `Dependency.FromAccess`
instances, whose `equals()`/`hashCode()` delegated to the wrapped `JavaAccess`,
both survived deduplication, as `JavaAccess` has identity equality only.
Rules like `noClasses().should().dependOnClassesThat()...` consequently
reported the same violation twice.

We now let `Dependency.FromAccess` inherit the value-based equality of
`Dependency`, so indistinguishable accesses form a single dependency again.
The conversion of such a dependency to its `JavaAccess` is unaffected.

Resolves: TNG#1339
Signed-off-by: Sharang Gupta <sharang@sharanggupta.dev>
@sharanggupta
sharanggupta force-pushed the gh-1339-dedupe-dependencies-from-duplicated-finally-bytecode branch from fff809b to 67d9737 Compare October 8, 2026 10:48

This branch has not been deployed

No deployments
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.

Duplicate error messages for noClasses().should().dependOnClassesThat().resideInAPackage(...) when culprit is in finally clause

1 participant