Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,15 @@ jobs:
- SONAR_SERVER_VERSION: 9.9.3.79811
SONAR_PLUGIN_API_VERSION: 9.14.0.375
SONAR_PLUGIN_API_GROUPID: org.sonarsource.api.plugin
SONAR_JAVA_VERSION: 7.16.0.30901
SONAR_SERVER_JAVA_VERSION: 17
# 10.x
- SONAR_SERVER_VERSION: 10.4.0.87286
SONAR_PLUGIN_API_VERSION: 10.6.0.2114
SONAR_PLUGIN_API_GROUPID: org.sonarsource.api.plugin
SONAR_JAVA_VERSION: 7.30.1.34514
SONAR_SERVER_JAVA_VERSION: 17
- SONAR_SERVER_VERSION: 10.5.1.90531
- SONAR_SERVER_VERSION: 10.6.0.92116
SONAR_PLUGIN_API_VERSION: 10.7.0.2191
SONAR_PLUGIN_API_GROUPID: org.sonarsource.api.plugin
SONAR_JAVA_VERSION: 7.34.0.35958
SONAR_SERVER_JAVA_VERSION: 17
steps:
- uses: actions/checkout@v4
Expand All @@ -67,8 +64,7 @@ jobs:
mvn -B verify \
-Dsonar.server.version=${{ matrix.SONAR_SERVER_VERSION }} \
-Dsonar-plugin-api.version=${{ matrix.SONAR_PLUGIN_API_VERSION }} \
-Dsonar-plugin-api.groupId=${{ matrix.SONAR_PLUGIN_API_GROUPID }} \
-Dsonar-java.version=${{ matrix.SONAR_JAVA_VERSION }}
-Dsonar-plugin-api.groupId=${{ matrix.SONAR_PLUGIN_API_GROUPID }}
build:
name: Build
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
<sonar-plugin-api.version>9.14.0.375</sonar-plugin-api.version>
<sonar-plugin-api.groupId>org.sonarsource.api.plugin</sonar-plugin-api.groupId>
<sonar-commons-analyzers.version>1.10.2.456</sonar-commons-analyzers.version>
<sonar-java.version>6.0.0.20538</sonar-java.version>
<sonar-java-frontend.version>8.2.0.36672</sonar-java-frontend.version>
<sonar-orchestrator.version>4.7.0.1861</sonar-orchestrator.version>

<errorprone.version>2.26.1</errorprone.version>
Expand Down
5 changes: 2 additions & 3 deletions sonar-erroraway-sonar-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,8 @@
</dependency>
<dependency>
<groupId>org.sonarsource.java</groupId>
<artifactId>sonar-java-plugin</artifactId>
<version>${sonar-java.version}</version>
<scope>provided</scope>
<artifactId>java-frontend</artifactId>
<version>${sonar-java-frontend.version}</version>
</dependency>

<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
import org.sonar.api.config.Configuration;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.TempFolder;
import org.sonar.plugins.java.api.JavaResourceLocator;
import org.sonar.java.classpath.ClasspathForMain;

import com.github.erroraway.ErrorAwayException;
import com.github.erroraway.rules.ErrorAwayRulesMapping;
Expand All @@ -64,12 +64,10 @@
public class ErrorAwaySensor implements Sensor {
private static final Logger LOGGER = LoggerFactory.getLogger(ErrorAwaySensor.class);

private JavaResourceLocator javaResourceLocator;
private ErrorAwayDependencyManager dependencyManager;
private TempFolder tempFolder;

public ErrorAwaySensor(JavaResourceLocator javaResourceLocator, ErrorAwayDependencyManager dependencyManager, TempFolder tempFolder) {
this.javaResourceLocator = javaResourceLocator;
public ErrorAwaySensor(ErrorAwayDependencyManager dependencyManager, TempFolder tempFolder) {
this.dependencyManager = dependencyManager;
this.tempFolder = tempFolder;
}
Expand Down Expand Up @@ -106,13 +104,13 @@ public void execute(SensorContext context) {
Iterable<String> classes = Collections.emptyList();

FileSystem fs = context.fileSystem();

LOGGER.info("Starting project analysis with encoding {} and base dir {}, plugin version is: {}, java version is {}", fs.encoding(), fs.baseDir(), getVersion(), Runtime.version());

try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnosticListener, Locale.getDefault(), fs.encoding())) {
Iterable<? extends JavaFileObject> compilationUnits = buildCompilationUnits(context);
configureClasspath(fileManager, context.config());

configureClasspath(fileManager, context.config(), fs);
configureAnnotationProcessors(fileManager, context.config());
configureOutputFolders(fileManager);

Expand All @@ -132,7 +130,7 @@ private ErrorProneOptions buildErrorProneOptions(SensorContext context) {
if (context.activeRules().find(RuleKey.of("nullaway", "NullAway")) != null) {
throw new ErrorAwayException("The " + NullAwayOption.ANNOTATED_PACKAGES.getKey() + " option must be set when the NullAway rule is enabled");
}

// When some annotation processors are enabled com.google.errorprone.ErrorPronePlugins turns on plugin
// scanning and tries to instanciate NullAway
if (configuration.hasKey(ErrorAwayPlugin.ANNOTATION_PROCESSORS_MAVEN_COORDINATES)) {
Expand Down Expand Up @@ -187,8 +185,9 @@ private Iterable<? extends JavaFileObject> buildCompilationUnits(SensorContext c
return paths;
}

private void configureClasspath(StandardJavaFileManager fileManager, Configuration configuration) throws IOException {
Collection<File> classpath = new ArrayList<>(javaResourceLocator.classpath());
private void configureClasspath(StandardJavaFileManager fileManager, Configuration configuration, FileSystem fs) throws IOException {
ClasspathForMain classpathForMain = new ClasspathForMain(configuration, fs);
Collection<File> classpath = new ArrayList<>(classpathForMain.getElements());
if (configuration.hasKey(ErrorAwayPlugin.CLASS_PATH_MAVEN_COORDINATES)) {
String[] coordinates = configuration.getStringArray(ErrorAwayPlugin.CLASS_PATH_MAVEN_COORDINATES);
classpath.addAll(dependencyManager.downloadDependencies(coordinates));
Expand Down Expand Up @@ -224,7 +223,7 @@ public void describe(SensorDescriptor descriptor) {
for (String repository : ErrorAwayRulesMapping.REPOSITORIES) {
descriptor.createIssuesForRuleRepository(repository);
}

descriptor.onlyOnLanguage("java");
descriptor.name("Errorprone sensor");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@
import java.io.File;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Collectors;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand All @@ -54,7 +52,6 @@
import org.sonar.api.testfixtures.log.LogAndArguments;
import org.sonar.api.testfixtures.log.LogTesterJUnit5;
import org.sonar.api.utils.TempFolder;
import org.sonar.plugins.java.api.JavaResourceLocator;

import com.github.erroraway.ErrorAwayException;
import com.github.erroraway.rules.ErrorAwayRulesMapping;
Expand All @@ -76,7 +73,6 @@ class ErrorAwaySensorTest {
private SensorContext context;
private ActiveRules activeRules;
private FilePredicates filePredicates;
private JavaResourceLocator javaResourceLocator;
private TempFolder tempFolder;
private NewIssue newIssue;
private NewIssueLocation location;
Expand Down Expand Up @@ -108,27 +104,25 @@ void setup() {
void setup(Path relativePath) {
Path path = Path.of("src/test/resources/samples");
Charset charset = Charset.forName("UTF-8");

// Mocked dependencies
fs = mock(FileSystem.class);
context = mock(SensorContext.class);
activeRules = mock(ActiveRules.class);
filePredicates = mock(FilePredicates.class);
javaResourceLocator = mock(JavaResourceLocator.class);
newIssue = mock(NewIssue.class);
location = mock(NewIssueLocation.class);
analisysError = mock(NewAnalysisError.class);

dependencyManager = new ErrorAwayDependencyManager(tempFolder, configuration);

// Sample data
FilePredicate javaFilePredicate = inputFile -> inputFile.filename().endsWith("java");
FilePredicate mainFilePredicate = inputFile -> inputFile.type() == Type.MAIN;
mainJavaFilePredicate = inputFile -> javaFilePredicate.apply(inputFile) && mainFilePredicate.apply(inputFile);
uriFilePredicate = inputFile -> inputFile.uri().equals(inputFile.uri());
FilePredicate javaFilePredicate = file -> file.filename().endsWith("java");
FilePredicate mainFilePredicate = file -> file.type() == Type.MAIN;
mainJavaFilePredicate = file -> javaFilePredicate.apply(file) && mainFilePredicate.apply(file);
uriFilePredicate = file -> file.uri().equals(file.uri());
inputFile = new TestInputFile(path.resolve(relativePath), relativePath, charset, Type.MAIN);
Iterable<InputFile> inputFiles = Collections.singleton(inputFile);
Collection<File> classpath = Collections.singleton(new File(System.getProperty("java.home") + "/lib/jrt-fs.jar"));

// Mock some methods
when(context.config()).thenReturn(configuration);
Expand All @@ -139,13 +133,12 @@ void setup(Path relativePath) {
when(fs.predicates()).thenReturn(filePredicates);
when(fs.inputFiles(mainJavaFilePredicate)).thenReturn(inputFiles);
when(fs.inputFile(uriFilePredicate)).thenReturn(inputFile);

when(filePredicates.hasLanguage("java")).thenReturn(javaFilePredicate);
when(filePredicates.hasType(Type.MAIN)).thenReturn(mainFilePredicate);
when(filePredicates.and(mainFilePredicate, javaFilePredicate)).thenReturn(mainJavaFilePredicate);
when(filePredicates.hasURI(inputFile.uri())).thenReturn(uriFilePredicate);
when(javaResourceLocator.classpath()).thenReturn(classpath);


when(context.newIssue()).thenReturn(newIssue);
when(context.newAnalysisError()).thenReturn(analisysError);

Expand All @@ -170,7 +163,7 @@ void analyzeWithErrorProneRule() {
enableRule(RuleKey.of("errorprone", "DurationTemporalUnit"));

// Call the sensor
ErrorAwaySensor sensor = new ErrorAwaySensor(javaResourceLocator, dependencyManager, tempFolder);
ErrorAwaySensor sensor = new ErrorAwaySensor(dependencyManager, tempFolder);
sensor.execute(context);

verify(context, times(1)).newIssue();
Expand All @@ -182,12 +175,12 @@ void analyzeWithAnnotationProcessor() {
setConfigurationStringArray(ErrorAwayPlugin.ANNOTATION_PROCESSORS_MAVEN_COORDINATES, new String[]{"com.google.auto.value:auto-value:1.9"});
setConfigurationBoolean(ErrorAwayPlugin.MAVEN_USE_TEMP_LOCAL_REPOSITORY, true);
setConfigurationStringArray(ErrorAwayPlugin.MAVEN_REPOSITORIES, new String[]{"https://repo1.maven.org/maven2/"});

setup(Path.of("com/bug/AutoValueSamples.java"));
enableRule(RuleKey.of("errorprone", "DurationTemporalUnit"));

// Call the sensor
ErrorAwaySensor sensor = new ErrorAwaySensor(javaResourceLocator, dependencyManager, tempFolder);
ErrorAwaySensor sensor = new ErrorAwaySensor(dependencyManager, tempFolder);
sensor.execute(context);

verify(context, times(1)).newIssue();
Expand All @@ -199,7 +192,7 @@ void missingDependencies() {
enableRule(RuleKey.of("errorprone", "DurationTemporalUnit"));

// Call the sensor
ErrorAwaySensor sensor = new ErrorAwaySensor(javaResourceLocator, dependencyManager, tempFolder);
ErrorAwaySensor sensor = new ErrorAwaySensor(dependencyManager, tempFolder);
// Javac wraps our exception in a RuntimeException
assertThrowsExactly(RuntimeException.class, () -> sensor.execute(context));

Expand All @@ -215,11 +208,11 @@ void missingDependencies() {
void analyzeWithNullAway() {
setup(Path.of("com/bug/BugSamples.java"));
when(activeRules.find(RuleKey.of("nullaway", "NullAway"))).thenReturn(mock(ActiveRule.class));

setConfigurationStringArray(NullAwayOption.ANNOTATED_PACKAGES.getKey(), new String[] { "foo", "com.bug", "bar" });

// Call the sensor
ErrorAwaySensor sensor = new ErrorAwaySensor(javaResourceLocator, dependencyManager, tempFolder);
ErrorAwaySensor sensor = new ErrorAwaySensor(dependencyManager, tempFolder);
sensor.execute(context);

verify(context, times(1)).newIssue();
Expand All @@ -231,26 +224,26 @@ void analyzeWithNullAwayWithoutAnnotatedPackageOption() {
when(activeRules.find(RuleKey.of("nullaway", "NullAway"))).thenReturn(mock(ActiveRule.class));

// Call the sensor
ErrorAwaySensor sensor = new ErrorAwaySensor(javaResourceLocator, dependencyManager, tempFolder);
ErrorAwaySensor sensor = new ErrorAwaySensor(dependencyManager, tempFolder);
assertThrows(ErrorAwayException.class, () -> sensor.execute(context));
}
@Test
void analyzeWithErrorProneSlf4j() {
setConfigurationStringArray(ErrorAwayPlugin.MAVEN_REPOSITORIES, new String[] {"https://repo1.maven.org/maven2/"});
setup(Path.of("com/bug/Slf4jSamples.java"));

@Test
void analyzeWithErrorProneSlf4j() {
setConfigurationStringArray(ErrorAwayPlugin.MAVEN_REPOSITORIES, new String[] {"https://repo1.maven.org/maven2/"});
setup(Path.of("com/bug/Slf4jSamples.java"));

RuleKey ruleKey = RuleKey.of("errorprone-slf4j", "Slf4jPlaceholderMismatch");
enableRule(ruleKey);
setConfigurationStringArray(ErrorAwayPlugin.CLASS_PATH_MAVEN_COORDINATES, new String[]{"org.slf4j:slf4j-api:1.7.36"});
// Call the sensor
ErrorAwaySensor sensor = new ErrorAwaySensor(javaResourceLocator, dependencyManager, tempFolder);
sensor.execute(context);
setConfigurationStringArray(ErrorAwayPlugin.CLASS_PATH_MAVEN_COORDINATES, new String[]{"org.slf4j:slf4j-api:1.7.36"});

// Call the sensor
ErrorAwaySensor sensor = new ErrorAwaySensor(dependencyManager, tempFolder);
sensor.execute(context);

verify(context, times(1)).newIssue();
verify(context, times(1)).newIssue();
verify(newIssue, times(1)).forRule(ruleKey);
}
}

@Test
void analyzeWithPicnicErrorProneSupport() {
Expand All @@ -264,36 +257,36 @@ void analyzeWithPicnicErrorProneSupport() {
new String[]{"com.google.guava:guava:31.1-jre"});

// Call the sensor
ErrorAwaySensor sensor = new ErrorAwaySensor(javaResourceLocator, dependencyManager, tempFolder);
ErrorAwaySensor sensor = new ErrorAwaySensor(dependencyManager, tempFolder);
sensor.execute(context);

verify(context, times(1)).newIssue();
verify(newIssue, times(1)).forRule(ruleKey);
}

@Test
void analyzeManyBugs() {
setup(Path.of("com/bug/ManyBugs.java"));
enableRule(RuleKey.of("errorprone", "BadShiftAmount"));
enableRule(RuleKey.of("errorprone", "ComparingThisWithNull"));
enableRule(RuleKey.of("errorprone", "EqualsNaN"));
enableRule(RuleKey.of("errorprone", "NullTernary"));
// Call the sensor
ErrorAwaySensor sensor = new ErrorAwaySensor(javaResourceLocator, dependencyManager, tempFolder);
sensor.execute(context);

verify(context, times(256)).newIssue();
}
@Test
void analyzeManyBugs() {
setup(Path.of("com/bug/ManyBugs.java"));

enableRule(RuleKey.of("errorprone", "BadShiftAmount"));
enableRule(RuleKey.of("errorprone", "ComparingThisWithNull"));
enableRule(RuleKey.of("errorprone", "EqualsNaN"));
enableRule(RuleKey.of("errorprone", "NullTernary"));

// Call the sensor
ErrorAwaySensor sensor = new ErrorAwaySensor(dependencyManager, tempFolder);
sensor.execute(context);

verify(context, times(256)).newIssue();
}

@Test
void compilerWarning() {
setup(Path.of("com/bug/VarArgsArray.java"));
enableRule(RuleKey.of("errorprone", "DurationTemporalUnit"));

// Call the sensor
ErrorAwaySensor sensor = new ErrorAwaySensor(javaResourceLocator, dependencyManager, tempFolder);
ErrorAwaySensor sensor = new ErrorAwaySensor(dependencyManager, tempFolder);
sensor.execute(context);

if (JRE.currentVersion().compareTo(JRE.JAVA_21) < 0) {
Expand All @@ -312,33 +305,33 @@ void missingInputFile() {
when(fs.inputFile(uriFilePredicate)).thenReturn(null);

// Call the sensor
ErrorAwaySensor sensor = new ErrorAwaySensor(javaResourceLocator, dependencyManager, tempFolder);
ErrorAwaySensor sensor = new ErrorAwaySensor(dependencyManager, tempFolder);
sensor.execute(context);

assertThat(logTester.getLogs(Level.WARN).stream().map(LogAndArguments::getRawMsg).collect(Collectors.toList())).contains("Could not file input file for source {}");
assertThat(logTester.getLogs(Level.WARN).stream().map(LogAndArguments::getRawMsg).toList()).contains("Could not file input file for source {}");
}

@Test
void describe() {
setup(Path.of("com/bug/BugSamples.java"));
SensorDescriptor descriptor = mock(SensorDescriptor.class);

ErrorAwaySensor sensor = new ErrorAwaySensor(javaResourceLocator, dependencyManager, tempFolder);
ErrorAwaySensor sensor = new ErrorAwaySensor(dependencyManager, tempFolder);
sensor.describe(descriptor);

verify(descriptor, times(1)).onlyOnLanguage("java");
}

@Test
void getVersion() {
ErrorAwaySensor sensor = new ErrorAwaySensor(javaResourceLocator, dependencyManager, tempFolder);
ErrorAwaySensor sensor = new ErrorAwaySensor(dependencyManager, tempFolder);

assertThat(sensor.getVersion()).doesNotStartWith("UNKNOWN");
}

@Test
void getVersionError() {
ErrorAwaySensor sensor = new ErrorAwaySensor(javaResourceLocator, dependencyManager, tempFolder);
ErrorAwaySensor sensor = new ErrorAwaySensor(dependencyManager, tempFolder);

assertThat(sensor.getVersion("/foo/bar.properties")).startsWith("UNKNOWN");
}
Expand Down
Loading