• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pmd / pmd / 4553

25 Apr 2025 06:55AM UTC coverage: 77.84% (+0.008%) from 77.832%
4553

push

github

adangel
[core] Support language dialects (#5438)

Merge pull request #5438 from Monits:lang-dialects

17661 of 23654 branches covered (74.66%)

Branch coverage included in aggregate %.

113 of 137 new or added lines in 12 files covered. (82.48%)

20 existing lines in 5 files now uncovered.

38710 of 48765 relevant lines covered (79.38%)

0.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

37.5
/pmd-core/src/main/java/net/sourceforge/pmd/lang/Language.java
1
/**
2
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3
 */
4

5
package net.sourceforge.pmd.lang;
6

7
import java.util.List;
8
import java.util.ServiceLoader;
9
import java.util.Set;
10

11
import org.checkerframework.checker.nullness.qual.NonNull;
12
import org.checkerframework.checker.nullness.qual.Nullable;
13

14
import net.sourceforge.pmd.annotation.Experimental;
15
import net.sourceforge.pmd.cpd.CpdCapableLanguage;
16
import net.sourceforge.pmd.util.AssertionUtil;
17

18
/**
19
 * Represents a language module, and provides access to language-specific
20
 * functionality. You can get a language instance from a {@link LanguageRegistry},
21
 * see {@link LanguageRegistry#PMD} for instance.
22
 *
23
 * <p>Language instances are extensions to the core of PMD. They can be
24
 * registered with a {@linkplain ServiceLoader service file} so that
25
 * PMD automatically finds them on the classpath.
26
 *
27
 * <p>Instances of this interface are stateless and immutable after construction.
28
 * They mostly provide metadata about the language, like ID, name and different
29
 * versions that are supported.
30
 *
31
 * <p>Languages should implement the interfaces {@link PmdCapableLanguage}
32
 * or {@link CpdCapableLanguage} to be usable by PMD or CPD, respectively.
33
 *
34
 * @see LanguageVersion
35
 */
36
public interface Language extends Comparable<Language> {
37

38

39
    /**
40
     * Returns the full name of this Language. This is generally the name of this
41
     * language without the use of acronyms, but possibly some capital letters,
42
     * eg {@code "Java"}. It's suitable for displaying in a GUI.
43
     *
44
     * @return The full name of this language.
45
     */
46
    String getName();
47

48
    /**
49
     * Returns the short name of this language. This is the commonly
50
     * used short form of this language's name, perhaps an acronym,
51
     * but possibly with special characters.
52
     *
53
     * @return The short name of this language.
54
     */
55
    String getShortName();
56

57
    /**
58
     * Returns the ID of this language. This is a short, alphanumeric,
59
     * lowercase name, eg {@code "java"}. It's used to identify the language
60
     * in the ruleset XML, and is also in the package name of the language
61
     * module.
62
     *
63
     * @return The ID of this language.
64
     */
65
    String getId();
66

67
    /**
68
     * If this is a dialect of another language, returns the base language.
69
     * Dialects are for example different flavors of XML. Dialects must share
70
     * the same AST as their base language. This makes it so that rules written
71
     * for the base language can be applied files of all dialects uniformly.
72
     * @experimental Since 7.13.0. See <a href="https://github.com/pmd/pmd/pull/5438">[core] Support language dialects #5438</a>.
73
     */
74
    @Experimental
75
    default @Nullable String getBaseLanguageId() {
NEW
76
        return null;
×
77
    }
78

79
    /**
80
     * Return true if this language is a dialect of the given language.
81
     *
82
     * @param language A language (not null)
83
     * @experimental Since 7.13.0. See <a href="https://github.com/pmd/pmd/pull/5438">[core] Support language dialects #5438</a>.
84
     */
85
    @Experimental
86
    @SuppressWarnings("PMD.SimplifyBooleanReturns")
87
    default boolean isDialectOf(Language language) {
88
        AssertionUtil.requireParamNotNull("language", language);
1✔
89
        String base = getBaseLanguageId();
1✔
90
        if (base == null) {
1✔
91
            return false;
1✔
92
        }
93
        return base.equals(language.getId());
1✔
94
    }
95

96
    /**
97
     * Returns the list of file extensions associated with this language.
98
     * This list is unmodifiable. Extensions do not have a '.' prefix.
99
     *
100
     * @return A list of file extensions.
101
     */
102
    List<String> getExtensions();
103

104
    /**
105
     * Returns whether this language handles the given file extension.
106
     * The comparison is done ignoring case.
107
     *
108
     * @param extensionWithoutDot A file extension (without '.' prefix)
109
     *
110
     * @return <code>true</code> if this language handles the extension,
111
     *     <code>false</code> otherwise.
112
     */
113
    default boolean hasExtension(String extensionWithoutDot) {
114
        return getExtensions().contains(extensionWithoutDot);
1✔
115
    }
116

117
    /**
118
     * Returns an ordered list of supported versions for this language.
119
     *
120
     * @return All supported language versions.
121
     */
122
    List<LanguageVersion> getVersions();
123

124
    /**
125
     * Returns the latest language version. May not be the
126
     * {@linkplain #getDefaultVersion() default}.
127
     *
128
     * @return The latest language version
129
     */
130
    default LanguageVersion getLatestVersion() {
131
        List<LanguageVersion> versions = getVersions();
×
132
        return versions.get(versions.size() - 1);
×
133
    }
134

135
    /**
136
     * Returns a complete set of supported version names for this language
137
     * including all aliases.
138
     *
139
     * @return All supported language version names and aliases.
140
     */
141
    Set<String> getVersionNamesAndAliases();
142

143
    /**
144
     * Returns true if a language version with the given {@linkplain LanguageVersion#getVersion() version string}
145
     * is registered. Then, {@link #getVersion(String) getVersion} will return a non-null value.
146
     *
147
     * @param version A version string
148
     *
149
     * @return True if the version string is known
150
     */
151
    default boolean hasVersion(String version) {
152
        return getVersion(version) != null;
×
153
    }
154

155
    /**
156
     * Returns the language version with the given {@linkplain LanguageVersion#getVersion() version string}.
157
     * Returns null if no such version exists.
158
     *
159
     * @param version A language version string.
160
     *
161
     * @return The corresponding LanguageVersion, {@code null} if the
162
     *     version string is not recognized.
163
     */
164
    default @Nullable LanguageVersion getVersion(String version) {
165
        for (LanguageVersion v : getVersions()) {
×
166
            if (v.getVersion().equals(version)) {
×
167
                return v;
×
168
            }
169
        }
×
170
        return null;
×
171
    }
172

173
    /**
174
     * Returns the default language version for this language.
175
     * This is an arbitrary choice made by the PMD product, and can change
176
     * between PMD releases. Every language has a default version.
177
     *
178
     * @return The current default language version for this language.
179
     */
180
    @NonNull LanguageVersion getDefaultVersion();
181

182

183
    /**
184
     * Creates a new bundle of properties that will serve to configure
185
     * the {@link LanguageProcessor} for this language. The returned
186
     * bundle must have all supported properties already declared. See
187
     * {@link PmdCapableLanguage} and {@link CpdCapableLanguage} for sites
188
     * where properties are passed back to the language with user-provided
189
     * values.
190
     *
191
     * @return A new set of properties
192
     */
193
    default LanguagePropertyBundle newPropertyBundle() {
194
        return new LanguagePropertyBundle(this);
1✔
195
    }
196

197

198
    /**
199
     * Returns a set of the IDs of languages that this language instance
200
     * depends on. Whenever this language is loaded into a {@link LanguageProcessorRegistry},
201
     * those dependencies need to be loaded as well.
202
     */
203
    Set<String> getDependencies();
204

205
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc