net.sourceforge.pmd.lang.LanguageVersionDiscoverer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pmd-core Show documentation
Show all versions of pmd-core Show documentation
PMD is an extensible multilanguage static code analyzer. It finds common programming flaws like unused variables,
empty catch blocks, unnecessary object creation, and so forth. It's mainly concerned with Java and
Apex, but supports 16 other languages. It comes with 400+ built-in rules. It can be
extended with custom rules. It uses JavaCC and Antlr to parse source files into abstract syntax trees
(AST) and runs rules against them to find violations. Rules can be written in Java or using a XPath query.
Currently, PMD supports Java, JavaScript, Salesforce.com Apex and Visualforce,
Kotlin, Swift, Modelica, PLSQL, Apache Velocity, JSP, WSDL, Maven POM, HTML, XML and XSL.
Scala is supported, but there are currently no Scala rules available.
Additionally, it includes CPD, the copy-paste-detector. CPD finds duplicated code in
Coco, C/C++, C#, Dart, Fortran, Gherkin, Go, Groovy, HTML, Java, JavaScript, JSP, Julia, Kotlin,
Lua, Matlab, Modelica, Objective-C, Perl, PHP, PLSQL, Python, Ruby, Salesforce.com Apex and
Visualforce, Scala, Swift, T-SQL, Typescript, Apache Velocity, WSDL, XML and XSL.
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.util.AssertionUtil;
/**
* This class can discover the LanguageVersion of a source file. Further, every
* Language has a default LanguageVersion, which can be temporarily overridden
* here.
*/
public class LanguageVersionDiscoverer {
private LanguageRegistry languageRegistry;
private final Map languageToLanguageVersion = new HashMap<>();
private LanguageVersion forcedVersion;
/**
* Build a new instance.
*
* @param forcedVersion If non-null, all files should be assigned this version.
* The methods of this class still work as usual and do not
* care about the forced language version.
*/
public LanguageVersionDiscoverer(LanguageRegistry registry, LanguageVersion forcedVersion) {
this.languageRegistry = registry;
this.forcedVersion = forcedVersion;
}
/**
* Build a new instance with no forced version.
*/
public LanguageVersionDiscoverer(LanguageRegistry registry) {
this(registry, null);
}
/**
* Set the given LanguageVersion as the current default for it's Language.
*
* @param languageVersion
* The new default for the Language.
* @return The previous default version for the language.
*/
public LanguageVersion setDefaultLanguageVersion(LanguageVersion languageVersion) {
AssertionUtil.requireParamNotNull("languageVersion", languageVersion);
LanguageVersion currentLanguageVersion = languageToLanguageVersion.put(languageVersion.getLanguage(),
languageVersion);
if (currentLanguageVersion == null) {
currentLanguageVersion = languageVersion.getLanguage().getDefaultVersion();
}
return currentLanguageVersion;
}
/**
* Get the current default LanguageVersion for the given Language.
*
* @param language
* The Language.
* @return The current default version for the language.
*/
public LanguageVersion getDefaultLanguageVersion(Language language) {
Objects.requireNonNull(language);
LanguageVersion languageVersion = languageToLanguageVersion.get(language);
if (languageVersion == null) {
languageVersion = language.getDefaultVersion();
}
return languageVersion;
}
/**
* Get the default LanguageVersion for the first Language of a given source
* file.
*
* @param sourceFile
* The file.
* @return The currently configured LanguageVersion for the source file, or
* null
if there are no supported Languages for the
* file.
*/
public LanguageVersion getDefaultLanguageVersionForFile(File sourceFile) {
return getDefaultLanguageVersionForFile(sourceFile.getName());
}
/**
* Get the LanguageVersion for the first Language of a source file with the
* given name.
*
* @param fileName
* The file name.
* @return The currently configured LanguageVersion for the source file or
* null
if there are no supported Languages for the
* file.
*/
public @Nullable LanguageVersion getDefaultLanguageVersionForFile(String fileName) {
List languages = getLanguagesForFile(fileName);
LanguageVersion languageVersion = null;
if (!languages.isEmpty()) {
languageVersion = getDefaultLanguageVersion(languages.get(0));
}
return languageVersion;
}
public LanguageVersion getForcedVersion() {
return forcedVersion;
}
public void setForcedVersion(LanguageVersion forceLanguageVersion) {
this.forcedVersion = forceLanguageVersion;
}
/**
* Get the Languages of a given source file.
*
* @param fileName
* The file name.
* @return The Languages for the source file, may be empty.
*/
public List getLanguagesForFile(String fileName) {
String extension = getExtension(fileName);
return languageRegistry.getLanguages().stream()
.filter(it -> it.hasExtension(extension))
.collect(Collectors.toList());
}
// Get the extensions from a file
private String getExtension(String fileName) {
return StringUtils.substringAfterLast(fileName, ".");
}
/**
* Make it so that the only extensions that are considered are those
* of the given language. This is different from {@link #setForcedVersion(LanguageVersion)}.
* because that one will assign the given language version to all files
* irrespective of extension. This method, on the other hand, will
* ignore files that do not match the given language.
*
* @param lang A language
*/
public void onlyRecognizeLanguages(LanguageRegistry lang) {
this.languageRegistry = Objects.requireNonNull(lang);
}
@Override
public String toString() {
return "LanguageVersionDiscoverer(" + languageRegistry
+ (forcedVersion != null ? ",forcedVersion=" + forcedVersion : "")
+ ")";
}
}