<p>PMD and all its modules are versioned together. PMD uses <ahref="https://semver.org/spec/v2.0.0.html">Semantic Versioning 2.0.0</a>.
This means, that each PMD version consists of MAJOR.MINOR.PATCH components:</p>
<ul>
<li>MAJOR version is incremented for incompatible API changes</li>
<li>MINOR version is incremented for added functionality in a backwards compatible way</li>
<li>PATCH version is incremented for backward compatible bug fixes</li>
</ul>
<p>Additional labels for release candidates might be used.</p>
<p>Incompatible API changes shouldn’t be introduced lightly. See
<ahref="https://semver.org/spec/v2.0.0.html#if-even-the-tiniest-backward-incompatible-changes-to-the-public-api-require-a-major-version-bump-wont-i-end-up-at-version-4200-very-rapidly">FAQ: If even the tiniest backward incompatible changes to the public API require a major version bump, won’t I end up at version 42.0.0 very rapidly?</a>.</p>
<h3id="project-structure-and-java-base-packages-names">Project structure and Java base packages names</h3>
<p>PMD is mainly developed in the Java programming language. The build tool is Maven and the PMD build consists
of several maven modules.</p>
<ul>
<li>All packages belonging to a given module should have a common package prefix.</li>
<li>Given a package name, it should be easy to figure out to which module this package belongs. There is a 1:1 mapping
between maven module and package. This rule helps to find the source code for any fully qualified (Java) class name.</li>
<li>Two modules must not define the same packages. That means, it is not allowed that any given package spans more than
one module. Otherwise, the mapping between module and package wouldn’t be unambiguous.</li>
<li>The base package for all PMD source code is <codeclass="language-plaintext highlighter-rouge">net.sourceforge.pmd</code>. There are many different sub packages.</li>
<li>The core module <codeclass="language-plaintext highlighter-rouge">pmd-core</code> uses directly the base package as the only module. All other modules must use
specific sub packages.</li>
<li>Language modules use the base package <codeclass="language-plaintext highlighter-rouge">net.sourceforge.pmd.lang.<language id></code>.
E.g. <codeclass="language-plaintext highlighter-rouge">pmd-java</code> uses the package <codeclass="language-plaintext highlighter-rouge">net.sourceforge.pmd.lang.java</code>.</li>
<li>All other modules use the base package <codeclass="language-plaintext highlighter-rouge">net.sourceforge.pmd.<module></code>,
E.g. <codeclass="language-plaintext highlighter-rouge">pmd-cli</code> uses the package <codeclass="language-plaintext highlighter-rouge">net.sourceforge.pmd.cli</code>.</li>
</ul>
<h3id="criteria-for-public-api">Criteria for public API</h3>
<p>Public API is</p>
<ul>
<li>API needed to execute PMD analysis
<ul>
<li>Renderers</li>
<li>RuleSet XML Schema</li>
<li>Configuration</li>
<li>Ant Tasks</li>
</ul>
</li>
<li>API needed to implement custom rules
<ul>
<li>AST structure and classes of languages (incl. AST structure for XPath rules)</li>
<li>XPath functions</li>
<li>Language Symbol Table / Metrics / Type Resolution (Not the implementation)</li>
</ul>
</li>
</ul>
<p><strong>Not</strong> public API is</p>
<ul>
<li>Anything in packages <codeclass="language-plaintext highlighter-rouge">internal</code> and <codeclass="language-plaintext highlighter-rouge">impl</code></li>
<li>Inheritance-specific members of AST related classes and interfaces. E.g. adding a member to an
interface shouldn’t be considered API breaking</li>
<li>Setters in AST classes are private. They are only used in the parser.</li>
</ul>
<h3id="separation-between-public-api-internal-and-implementation">Separation between public API, internal and implementation</h3>
<p>All packages are considered to be public API by default, with <strong>two exceptions</strong>:</p>
<ul>
<li>
<p>Any package that contains an <codeclass="language-plaintext highlighter-rouge">internal</code> segment is considered internal. E.g. <codeclass="language-plaintext highlighter-rouge">net.sourceforge.pmd.internal</code>.
<em>Internal API</em> is meant for use <em>only</em> by the main PMD codebase. Internal types and methods
may be modified in any way, or even removed, at any time without a MAJOR version change.</p>
<p>The <codeclass="language-plaintext highlighter-rouge">@InternalApi</code> annotation will be used for types that have to live outside of
these packages, e.g. methods of a public type that shouldn’t be used outside PMD (again,
these can be removed anytime).</p>
</li>
<li>
<p>Any package that contains an <codeclass="language-plaintext highlighter-rouge">impl</code> segment is considered internal. E.g. <codeclass="language-plaintext highlighter-rouge">net.sourceforge.pmd.lang.impl</code>.
These packages contain base classes that are needed for extending PMD (like adding a new language).
These can change at any time without a MAJOR version change.</p>
<p>In a later version, the <codeclass="language-plaintext highlighter-rouge">impl</code> packages could be promoted as a public API for implementing new
languages for PMD outside the main monorepo. In that sense, e.g. the module <codeclass="language-plaintext highlighter-rouge">pmd-java</code> is allowed
to depend on <codeclass="language-plaintext highlighter-rouge">impl</code> packages of <codeclass="language-plaintext highlighter-rouge">pmd-core</code>, but ideally it doesn’t depend on <codeclass="language-plaintext highlighter-rouge">internal</code> packages of
<codeclass="language-plaintext highlighter-rouge">pmd-core</code> (or any other module). However, for now, the <codeclass="language-plaintext highlighter-rouge">impl</code> packages are <strong>explicitly considered
internal</strong> until this decision is revised.</p>
</li>
</ul>
<h3id="deprecation-and-removing-of-old-apis">Deprecation and removing of old APIs</h3>
<ul>
<li>APIs can be deprecated at any time (even in PATCH versions). Deprecated APIs are marked with the
<li>Deprecations should be listed in the release notes.</li>
<li>Deprecated APIs can only be removed with a MAJOR version change.</li>
</ul>
<h3id="experimental-apis">Experimental APIs</h3>
<ul>
<li>New features often introduce new APIs. These new APIs can be marked with the annotation <codeclass="language-plaintext highlighter-rouge">@Experimental</code> at
the class or method level.</li>
<li>APIs marked with the <codeclass="language-plaintext highlighter-rouge">@Experimental</code> annotation are subject to change and are considered <strong>not stable</strong>.
They can be modified in any way, or even removed, at any time. You should not use or rely
on them in any production code. They are purely to allow broad testing and feedback.</li>
<li>Experimental APIs can be introduced or removed with at least a MINOR version change.
These experimental APIs should be listed in the release notes.</li>
<li>Experimental APIs can be promoted to Public APIs with at least a MINOR version change.</li>
</ul>
<h3id="guidelines-for-ast-classes">Guidelines for AST classes</h3>
<p>AST classes of the individual language modules are used by custom rule implementations and are considered
Public API in general. Rules only read the AST and do not need to modify it.</p>
<p>In order to minimize the public API surface of AST classes, the following guidelines apply:</p>
<ul>
<li>Concrete AST classes should be final, to avoid custom subclasses.</li>
<li>Concrete AST classes should only have a package private constructor to avoid manual instantiation.
Only the parser of the language (which lives in the same package) should be able to create new instances
of AST classes.</li>
<li>Concrete AST classes should not have public setters. All setters should be package private, so that
only the parser of the language can call the setters during AST construction.</li>
</ul>
<p>Non-concrete AST classes (like base classes or common interfaces) should follow similar guidelines:</p>
<ul>
<li>Only package private constructor</li>
<li>Only package private setters</li>
</ul>
<h3id="summary-of-the-annotations">Summary of the annotations</h3>
<p>API members marked with the <codeclass="language-plaintext highlighter-rouge">@Experimental</code> annotation at the class or method level are subject to change.
It is an indication that the feature is in experimental, unstable state.
The API members can be modified in any way, or even removed, at any time, without warning.
You should not use or rely on them in any production code. They are purely to allow broad testing and feedback.</p>
<p>API members marked with the <codeclass="language-plaintext highlighter-rouge">@Deprecated</code> annotation at the class or method level will remain supported
until the next major release, but it is recommended to stop using them. These members might be