[compat6] Support other cpd languages like cs

This commit is contained in:
Andreas Dangel
2024-02-17 18:39:50 +01:00
parent 0f7dff6909
commit b223b1a672
7 changed files with 197 additions and 1 deletions

View File

@@ -0,0 +1,2 @@
invoker.goals = verify
invoker.buildResult = failure

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.sourceforge.pmd.pmd-compat6.it</groupId>
<artifactId>cpd-for-csharp</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>@maven-pmd-plugin.version.for.integrationtest@</version>
<executions>
<execution>
<id>csharp-cpd-check</id>
<goals>
<goal>cpd-check</goal>
</goals>
</execution>
</executions>
<configuration>
<language>cs</language>
<minimumTokens>10</minimumTokens>
<includes>
<include>**/*.cs</include>
</includes>
<compileSourceRoots>
<compileSourceRoot>${basedir}/src/main/cs</compileSourceRoot>
</compileSourceRoots>
<printFailingErrors>true</printFailingErrors>
<skipPmdError>false</skipPmdError>
</configuration>
<dependencies>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-compat6</artifactId>
<version>@project.version@</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-core</artifactId>
<version>@pmd.version.for.integrationtest@</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-java</artifactId>
<version>@pmd.version.for.integrationtest@</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-javascript</artifactId>
<version>@pmd.version.for.integrationtest@</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-jsp</artifactId>
<version>@pmd.version.for.integrationtest@</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-cs</artifactId>
<version>@pmd.version.for.integrationtest@</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,12 @@
class Foo {
void bar() {
var test = $@"test";
var test2 = @$"test";
String query =
@"SELECT foo, bar
FROM table
WHERE id = 42";
}
}

View File

@@ -0,0 +1,12 @@
class Foo {
void bar() {
var test = $@"test";
var test2 = @$"test";
String query =
@"SELECT foo, bar
FROM table
WHERE id = 42";
}
}

View File

@@ -0,0 +1,46 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
String readFile(File file) throws IOException {
StringBuilder content = new StringBuilder();
for (String line : Files.readAllLines(file.toPath(), StandardCharsets.UTF_8)) {
content.append(line).append(System.lineSeparator());
}
return content.toString();
}
File buildLogPath = new File(basedir, "build.log");
String buildLog = readFile(buildLogPath);
if (buildLog.contains("An API incompatibility was encountered while")) {
throw new RuntimeException("Executing failed due to API incompatibility");
}
if (!buildLog.contains("[INFO] CPD Failure: Found 12 lines of duplicated code at locations:")) {
throw new RuntimeException("No CPD failures detected, did CPD run?");
}
File classA = new File("cpd-for-csharp/src/main/cs/strings1.cs");
if (!buildLog.contains(classA + " line 1")) {
throw new RuntimeException("No CPD failures detected, did CPD run?");
}
File classB = new File("cpd-for-csharp/src/main/cs/strings2.cs");
if (!buildLog.contains(classA + " line 1")) {
throw new RuntimeException("No CPD failures detected, did CPD run?");
}
File cpdXmlReport = new File(basedir, "target/cpd.xml");
if (!cpdXmlReport.exists()) {
throw new FileNotFoundException("Could not find cpd xml report: " + cpdXmlReport);
}
String cpdXml = readFile(cpdXmlReport);
if (!cpdXml.contains("<duplication lines=\"12\" tokens=\"29\">")) {
throw new RuntimeException("Expected duplication has not been reported");
}
if (!cpdXml.contains(classA + "\"/>")) {
throw new RuntimeException("Expected duplication has not been reported");
}
if (!cpdXml.contains(classB + "\"/>")) {
throw new RuntimeException("Expected duplication has not been reported");
}

View File

@@ -295,6 +295,9 @@ public class CPDConfiguration extends AbstractConfiguration {
} else if (language instanceof JSPLanguage) {
filenameFilter = language.getFileFilter();
setForceLanguageVersion(JspLanguageModule.getInstance().getDefaultVersion());
} else if (language instanceof LanguageFactory.CpdLanguageAdapter) {
filenameFilter = language.getFileFilter();
setForceLanguageVersion(((LanguageFactory.CpdLanguageAdapter) language).getLanguage().getDefaultVersion());
} else {
throw new UnsupportedOperationException("Language " + language.getName() + " is not supported");
}

View File

@@ -10,6 +10,11 @@
package net.sourceforge.pmd.cpd;
import java.util.Properties;
import java.util.stream.Collectors;
import net.sourceforge.pmd.lang.LanguagePropertyBundle;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.properties.PropertyDescriptor;
public final class LanguageFactory {
private LanguageFactory() {
@@ -17,6 +22,44 @@ public final class LanguageFactory {
}
public static Language createLanguage(String name, Properties properties) {
throw new UnsupportedOperationException();
CpdCapableLanguage cpdLanguage = (CpdCapableLanguage) LanguageRegistry.CPD.getLanguageById(name);
if (cpdLanguage != null) {
return new CpdLanguageAdapter(cpdLanguage, properties);
}
throw new UnsupportedOperationException("Language " + name + " is not supported");
}
public static class CpdLanguageAdapter extends AbstractLanguage {
private CpdCapableLanguage language;
public CpdLanguageAdapter(CpdCapableLanguage cpdCapableLanguage, Properties properties) {
super(cpdCapableLanguage.getName(), cpdCapableLanguage.getId(), createLexer(cpdCapableLanguage, properties), convertExtensions(cpdCapableLanguage));
this.language = cpdCapableLanguage;
}
private static Tokenizer createLexer(CpdCapableLanguage cpdCapableLanguage, Properties properties) {
LanguagePropertyBundle propertyBundle = cpdCapableLanguage.newPropertyBundle();
for (String propName : properties.stringPropertyNames()) {
PropertyDescriptor<?> propertyDescriptor = propertyBundle.getPropertyDescriptor(propName);
if (propertyDescriptor != null) {
setProperty(propertyBundle, propertyDescriptor, properties.getProperty(propName));
}
}
CpdLexer cpdLexer = cpdCapableLanguage.createCpdLexer(propertyBundle);
return cpdLexer::tokenize;
}
private static <T> void setProperty(LanguagePropertyBundle propertyBundle, PropertyDescriptor<T> propertyDescriptor, String stringValue) {
T value = propertyDescriptor.serializer().fromString(stringValue);
propertyBundle.setProperty(propertyDescriptor, value);
}
private static String[] convertExtensions(CpdCapableLanguage cpdCapableLanguage) {
return cpdCapableLanguage.getExtensions().stream().map(s -> "." + s).collect(Collectors.toList()).toArray(new String[0]);
}
public CpdCapableLanguage getLanguage() {
return language;
}
}
}