8000 feat: report unused Java private members by renanfranca · Pull Request #165 · habit-hooks/habit-hooks · GitHub
[go: up one dir, main page]

Skip to content

feat: report unused Java private members - #165

Merged
devill merged 1 commit into
habit-hooks:mainfrom
renanfranca:164-java-unused-private-members
Sep 17, 2026
Merged

devill merged 1 commit into
habit-hooks:mainfrom
renanfranca:164-java-unused-private-members

Conversation

@renanfranca
@renanfranca renanfranca commented Sep 8, 2026 •
Copy link
Copy Markdown
Contributor

What this changes

This PR adds Java detection for unused private fields and methods. It enables PMD's UnusedPrivateField and UnusedPrivateMethod rules in the bundled fallback ruleset and maps both results to the existing unused-class-member smell.

The Java integration uses the source file as the issue key. The key and details.file fields identify that file. Each issue also preserves the line where PMD found the problem, the complete diagnostic message, and the distinct source pmd:UnusedPrivateField or pmd:UnusedPrivateMethod.

When a file contains several violations, they continue to share the snooze behavior for that entire file. PMD remains responsible for deciding whether a member is reachable, applying exclusions and properties, and producing custom messages. A ruleset supplied by the project still replaces the bundled fallback ruleset instead of being combined with it.

This PR also moves unused-class-member.md from the TypeScript plugin into generic. There is now one shared source of guidance that applies across programming languages. The guide covers fields, methods, properties, reflection, annotations and decorators, serialization, lifecycle hooks, and other uses that static analysis may not detect.

The guide asks readers to investigate the member before changing it. Depending on what they find, they can connect the intended caller, extract a cohesive unit, or remove a member that is confirmed to be unused. The guide does not suggest automatic deletion.

Why the guide selects name or message

Knip and PMD provide different data. Knip identifies the member through details.name. PMD provides the complete description in its JSON report, but it does not provide a separate field dedicated to the member name.

Extracting a name from PMD text would make custom messages fragile. It would also couple the adapter to wording that PMD does not guarantee as part of its detector contract.

The shared template therefore uses details.name when that field is defined. Otherwise, it uses details.message. If both fields are present, name takes precedence. The mapper does not inspect the programming language, interpret diagnostic text, or add another display field.

Moving the guide does not turn generic into a detector, and it does not enable generic automatically. When generic is omitted, language sensors still report the smell and the existing fallback without coaching remains in effect.

Documentation and decisions

The smell vocabulary now records both Java mappings, the behavior of the bundled fallback ruleset, and the authority of a ruleset supplied by the project. It also explains that Java issues identify the source file, while TypeScript issues identify the member by name.

The decision record preserves the previous ownership by the TypeScript plugin as historical context and explains why #164 moves the single shared guide to generic. The executable guide specifications demonstrate how the displayed value is selected, and the Java plugin specifications demonstrate the behavior of the real PMD integration.

Validation

  • Scenarios using PMD 7.26.0 cover unused and referenced members, exclusions controlled by PMD, project rulesets that omit or enable the rules, and customization through ignoredFieldNames.
  • The complete test suite passed: 1070 passed, 4 skipped.
  • The focused suite covering Java, the generic guide, Knip, mapper behavior, specifications, and packaging passed: 138 passed.
  • Tests of the installed wheels without access to the source tree passed: 7 passed. These tests include both Java rules and confirm that only the generic plugin packages the shared guide.
  • uv run ruff check --config pyproject.toml src tests plugins passed.
  • uv run habit-hooks --all completed with zero findings.
  • GitHub CI passed on Ubuntu and Windows.

The enforced severity remains unchanged. Projects that use the bundled Java fallback ruleset may now see unused private members that were not reported before. Projects that supply their own PMD ruleset retain full control, and this change never modifies a reported member automatically.

Closes #164

Any feedback on the contracts, examples, or guidance is very welcome.

@renanfranca
Copy link
Copy Markdown
Contributor Author

Hello @devill ,

I would like to let you know that this PR is ready to review when you have the time. 😀

@devill
devill commented Sep 9, 2026
Copy link
Copy Markdown
Collaborator

Thanks! I'll review this tomorrow.

@devill
devill commented Sep 11, 2026
Copy link
Copy Markdown
Collaborator

Sorry for the late response. This PR is a bit harder to review, because it seems to do more than one thing, and also surfaced pre existing issues. Some of the issues are pre existing anti-patterns that got repeated. I'll leave a few comments.

@devill devill left a comment
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please consider the suggestions.

Comment thread docs/guide-includes.spec.md Resolved
Comment thread docs/smell-vocabulary.md Resolved

The unused members:

{% for issue in issues -%}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should be using the line level issues include here. Seems like the plugins sensor isn't faithfully following the interface defined by core, making this custom template necessary. Please make sure the plugin follows the pre defined interface.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the guidance. In this pull request, I moved the unused-class-member guide from the TypeScript plugin to the generic plugin so that Java and TypeScript could share it. Following your feedback, the generic guide now uses includes/line_level_issues.md. I also updated both the PMD and Knip sensors to emit details.content, which allows both languages to follow the core interface. Is this the scope you intended? Or would you prefer that I restore the TypeScript guide and Knip sensor, and apply the interface change only to the Java PMD sensor?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yes, that is the scope I intended, thanks!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, that is the scope I intended, thanks!

Thank you too :)

Comment thread plugins/java/docs/java-plugin.spec.md Resolved
@renanfranca
renanfranca force-pushed the 164-java-unused-private-members branch from e10bc4a to ae9ad31 Compare September 13, 2026 22:27
@renanfranca
Copy link
Copy Markdown
Contributor Author

Please consider the suggestions.

Thank you. I addressed the suggestions. I asked a question here to better understand one of yours suggestions: #165 (comment)

Thank you for your time 😀

@devill
devill merged commit 09ce1af into habit-hooks:main Sep 17, 2026
3 checks passed
@devill
devill commented Sep 17, 2026
Copy link
Copy Markdown
Collaborator

PR merged, thanks for the contribution! (An sorry for the slow response. I've been taking time off)

renanfranca reacted with thumbs up emoji renanfranca reacted with rocket emoji

@renanfranca
Copy link
Copy Markdown
Contributor Author

PR merged, thanks for the contribution! (An sorry for the slow response. I've been taking time off)

You are welcome 😄 ! All good 👍

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.

Add Java detection for unused private members using the existing unused-class-member guide

2 participants

0