Skip to content

Commit

Permalink
SONARJAVA-4975 Create custom rules plugin around symbolic execution e…
Browse files Browse the repository at this point in the history
…ngine (#4798)
  • Loading branch information
leonardo-pilastri-sonarsource authored Jun 5, 2024
1 parent d6f74cb commit 52c9272
Show file tree
Hide file tree
Showing 462 changed files with 17,802 additions and 550 deletions.
3 changes: 2 additions & 1 deletion .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ test_analyze_task:
<<: *COMMON_BUILD_DEFINITION
build_script:
- source cirrus-env BUILD
- PULL_REQUEST_SHA=$GIT_SHA1 regular_mvn_build_deploy_analyze -P-deploy-sonarsource,-release,-sign -Dmaven.deploy.skip=true -Dsonar.analysisCache.enabled=true
# ignore duplications in the SE engine plugin, as it will be moved away from sonar-java at some point
- PULL_REQUEST_SHA=$GIT_SHA1 regular_mvn_build_deploy_analyze -P-deploy-sonarsource,-release,-sign -Dmaven.deploy.skip=true -Dsonar.analysisCache.enabled=true -Dsonar.cpd.exclusions=java-symbolic-execution/**
- ./check-license-compliance.sh
cleanup_before_cache_script: cleanup_maven_repository

Expand Down
6 changes: 6 additions & 0 deletions its/autoscan/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.sonarsource.java</groupId>
<artifactId>java-symbolic-execution-plugin</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<profiles>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public class AutoScanTest {
.useDefaultAdminCredentialsForBuilds(true)
.setSonarVersion(System.getProperty("sonar.runtimeVersion", "LATEST_RELEASE"))
.addPlugin(FileLocation.of(TestClasspathUtils.findModuleJarPath("../../sonar-java-plugin").toFile()))
.addPlugin(FileLocation.of(TestClasspathUtils.findModuleJarPath("../../java-symbolic-execution/java-symbolic-execution-plugin").toFile()))
.addPlugin(MavenLocation.of("org.sonarsource.sonar-lits-plugin", "sonar-lits-plugin", "0.11.0.2659"))
.build();

Expand Down
6 changes: 6 additions & 0 deletions its/plugin/tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.sonarsource.java</groupId>
<artifactId>java-symbolic-execution-plugin</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.sonarsource.java</groupId>
<artifactId>java-custom-rules-example</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public class JavaTestSuite {
.useDefaultAdminCredentialsForBuilds(true)
.setSonarVersion(System.getProperty("sonar.runtimeVersion", "LATEST_RELEASE"))
.addPlugin(JAVA_PLUGIN_LOCATION)
.addPlugin(FileLocation.of(TestClasspathUtils.findModuleJarPath("../../../java-symbolic-execution/java-symbolic-execution-plugin").toFile()))
// for support of custom rules
.addPlugin(FileLocation.of(TestUtils.pluginJar("java-extension-plugin")))
// making sure the tutorial is still working
Expand Down
6 changes: 6 additions & 0 deletions its/ruling/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.sonarsource.java</groupId>
<artifactId>java-symbolic-execution-plugin</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<profiles>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ private static Orchestrator createOrchestrator() {
.useDefaultAdminCredentialsForBuilds(true)
.setSonarVersion(System.getProperty("sonar.runtimeVersion", "LATEST_RELEASE"))
.addPlugin(FileLocation.of(TestClasspathUtils.findModuleJarPath("../../sonar-java-plugin").toFile()))
.addPlugin(FileLocation.of(TestClasspathUtils.findModuleJarPath("../../java-symbolic-execution/java-symbolic-execution-plugin").toFile()))
.addPlugin(MavenLocation.of("org.sonarsource.sonar-lits-plugin", "sonar-lits-plugin", "0.11.0.2659"));

if (isCommunityEditionTestsOnly()) {
Expand Down

This file was deleted.

5 changes: 0 additions & 5 deletions java-checks/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,6 @@
<artifactId>java-checks-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>java-symbolic-execution</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.sonarsource.java</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
import org.sonar.plugins.java.api.tree.Tree;
import org.sonar.plugins.java.api.tree.VariableTree;

import static org.sonar.java.se.NullabilityDataUtils.nullabilityAsString;
import static org.sonar.java.checks.helpers.NullabilityDataUtils.nullabilityAsString;
import static org.sonar.plugins.java.api.semantic.SymbolMetadata.NullabilityLevel.PACKAGE;

@Rule(key = "S2638")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
import org.sonar.plugins.java.api.tree.VariableTree;
import org.sonarsource.analyzer.commons.collections.SetUtils;

import static org.sonar.java.se.NullabilityDataUtils.nullabilityAsString;
import static org.sonar.java.checks.helpers.NullabilityDataUtils.nullabilityAsString;


@Rule(key = "S2789")
public class NullShouldNotBeUsedWithOptionalCheck extends BaseTreeVisitor implements JavaFileScanner {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
import org.sonar.plugins.java.api.tree.VariableTree;

import static org.sonar.java.checks.helpers.QuickFixHelper.contentForRange;
import static org.sonar.java.se.ProgramState.isField;

/**
* Current implementation raises the issue only for the fields used in one method
Expand Down Expand Up @@ -198,7 +197,7 @@ static Set<Symbol> getFrom(Tree classTree) {
@Override
public void visitMemberSelectExpression(MemberSelectExpressionTree tree) {
Symbol symbol = tree.identifier().symbol();
if (isField(symbol) && !symbol.isStatic()) {
if (isField(symbol)) {
if (tree.expression().is(Kind.IDENTIFIER)) {
if (!ExpressionUtils.isThis(tree.expression())) {
fieldsReadOnAnotherInstance.add(symbol);
Expand All @@ -221,4 +220,10 @@ public void visitVariable(VariableTree tree) {
}
}

public static boolean isField(Symbol symbol) {
return symbol.isVariableSymbol()
&& !symbol.isStatic()
&& !symbol.owner().isMethodSymbol();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.java.se;
package org.sonar.java.checks.helpers;

import java.util.List;
import java.util.Locale;
Expand All @@ -26,6 +26,7 @@
import org.sonar.plugins.java.api.semantic.SymbolMetadata;

public class NullabilityDataUtils {

private NullabilityDataUtils() {
// Utility class
}
Expand Down Expand Up @@ -62,13 +63,12 @@ private static String annotationArguments(List<SymbolMetadata.AnnotationValue> v

private static String levelToString(SymbolMetadata.NullabilityLevel level) {
switch (level) {
case PACKAGE:
case CLASS:
case PACKAGE, CLASS:
return String.format(" at %s level", level.toString().toLowerCase(Locale.ROOT));
case METHOD:
case VARIABLE:
case METHOD, VARIABLE:
default:
return "";
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
*/
package org.sonar.java.filters;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
Expand Down Expand Up @@ -84,28 +85,30 @@ final void excludeLines(Set<Integer> lines, String ruleKey) {
}

final void excludeLines(@Nullable Tree tree, Class<? extends JavaCheck> rule) {
computeFilteredLinesForRule(tree, rule, true);
excludeLinesIfTrue(true, tree, rule);
}

@SafeVarargs
final void excludeLines(@Nullable Tree tree, Class<? extends JavaCheck>... rules) {
for (Class<? extends JavaCheck> rule : rules) {
computeFilteredLinesForRule(tree, rule, true);
excludeLinesIfTrue(true, tree, rules);
}
}

@SafeVarargs
final void excludeLinesIfTrue(boolean condition, Tree tree, Class<? extends JavaCheck>... rules) {
for (Class<? extends JavaCheck> rule : rules) {
computeFilteredLinesForRule(tree, rule, condition);
}
final void excludeLinesIfTrue(boolean condition, @Nullable Tree tree, Class<? extends JavaCheck>... rules) {
Arrays.stream(rules).forEach(rule -> excludeLinesIfTrue(condition, tree, rule));
}

final void excludeLinesIfTrue(boolean condition, @Nullable Tree tree, String ruleKey) {
computeFilteredLinesForRule(tree, ruleKey, condition);
}

final void excludeLinesIfTrue(boolean condition, Tree tree, Class<? extends JavaCheck> rule) {
computeFilteredLinesForRule(tree, rule, condition);
final void excludeLinesIfTrue(boolean condition, @Nullable Tree tree, Class<? extends JavaCheck> rule) {
computeFilteredLinesForRule(tree, rulesKeysByRulesClass.get(rule), condition);
}

private void computeFilteredLinesForRule(@Nullable Tree tree, Class<? extends JavaCheck> filteredRule, boolean excludeLine) {
private void computeFilteredLinesForRule(@Nullable Tree tree, String ruleKey, boolean excludeLine) {
if (tree == null) {
return;
}
Expand All @@ -115,7 +118,7 @@ private void computeFilteredLinesForRule(@Nullable Tree tree, Class<? extends Ja
Set<Integer> filteredLines = IntStream.rangeClosed(LineUtils.startLine(firstSyntaxToken), LineUtils.startLine(lastSyntaxToken))
.boxed()
.collect(Collectors.toSet());
computeFilteredLinesForRule(filteredLines, rulesKeysByRulesClass.get(filteredRule), excludeLine);
computeFilteredLinesForRule(filteredLines, ruleKey, excludeLine);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
import org.sonar.java.checks.spring.SpringComponentWithNonAutowiredMembersCheck;
import org.sonar.java.checks.tests.AssertionTypesCheck;
import org.sonar.java.checks.unused.UnusedPrivateFieldCheck;
import org.sonar.java.se.checks.XxeProcessingCheck;
import org.sonar.plugins.java.api.JavaCheck;
import org.sonar.plugins.java.api.semantic.Symbol;
import org.sonar.plugins.java.api.semantic.SymbolMetadata;
Expand Down Expand Up @@ -75,8 +74,10 @@ public class LombokFilter extends BaseTreeVisitorIssueFilter {
/* S2325 */ StaticMethodCheck.class,
/* S1068 */ UnusedPrivateFieldCheck.class,
/* S1128 */ UselessImportCheck.class,
/* S1118 */ UtilityClassWithPublicConstructorCheck.class,
/* S2755 */ XxeProcessingCheck.class);
/* S1118 */ UtilityClassWithPublicConstructorCheck.class
);

private static final String SE_XXE_PROCESSING_CHECK_RULEKEY = "java:S2755";

private static final String LOMBOK_BUILDER = "lombok.Builder";
private static final String LOMBOK_SUPER_BUILDER = "lombok.SuperBuilder";
Expand Down Expand Up @@ -172,13 +173,13 @@ public void visitClass(ClassTree tree) {

@Override
public void visitVariable(VariableTree tree) {
excludeLinesIfTrue(tree.symbol().type().is(LOMBOK_VAL) && tree.initializer() != null, tree.initializer(), XxeProcessingCheck.class);
excludeLinesIfTrue(tree.symbol().type().is(LOMBOK_VAL) && tree.initializer() != null, tree.initializer(), SE_XXE_PROCESSING_CHECK_RULEKEY);
super.visitVariable(tree);
}

@Override
public void visitAssignmentExpression(AssignmentExpressionTree tree) {
excludeLinesIfTrue(tree.variable().symbolType().is(LOMBOK_VAL), tree.expression(), XxeProcessingCheck.class);
excludeLinesIfTrue(tree.variable().symbolType().is(LOMBOK_VAL), tree.expression(), SE_XXE_PROCESSING_CHECK_RULEKEY);
super.visitAssignmentExpression(tree);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,16 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.java.se;

package org.sonar.java.checks.helpers;

import org.junit.jupiter.api.Test;
import org.sonar.java.model.JavaTree;
import org.sonar.java.se.utils.JParserTestUtils;
import org.sonar.plugins.java.api.semantic.SymbolMetadata;
import org.sonar.plugins.java.api.tree.ClassTree;
import org.sonar.plugins.java.api.tree.VariableTree;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.java.se.NullabilityDataUtils.nullabilityAsString;
import static org.sonar.java.checks.helpers.NullabilityDataUtils.nullabilityAsString;

class NullabilityDataUtilsTest {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.sonar.java.checks.verifier.TestUtils;
import org.sonar.java.model.InternalSyntaxToken;
import org.sonar.plugins.java.api.JavaFileScannerContext;
import org.sonar.plugins.java.api.semantic.Sema;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
Expand All @@ -51,7 +52,7 @@ public void setUp() {

context = mock(JavaFileScannerContext.class);
when(context.getInputFile()).thenReturn(INPUT_FILE);
when(context.getSemanticModel()).thenReturn(new Object());
when(context.getSemanticModel()).thenReturn(mock(Sema.class));

fakeIssue = mock(FilterableIssue.class);
when(fakeIssue.componentKey()).thenReturn("component");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,6 @@
import org.sonar.java.checks.unused.UnusedPrivateFieldCheck;
import org.sonar.java.checks.unused.UnusedPrivateMethodCheck;
import org.sonar.java.checks.unused.UnusedTypeParameterCheck;
import org.sonar.java.se.checks.ConditionalUnreachableCodeCheck;
import org.sonar.java.se.checks.DivisionByZeroCheck;
import org.sonar.java.se.checks.NullDereferenceCheck;
import org.sonar.java.se.checks.UnclosedResourcesCheck;

class SuppressWarningFilterTest {
/**
Expand All @@ -75,7 +71,6 @@ void verify() {
new CallToDeprecatedMethodCheck(),
new CallToDeprecatedCodeMarkedForRemovalCheck(),
new MissingDeprecatedCheck(),
new DivisionByZeroCheck(),
new EmptyBlockCheck(),
new EmptyStatementUsageCheck(),
new ReturnInFinallyCheck(),
Expand All @@ -93,9 +88,7 @@ void verify_2() {
new BoxedBooleanExpressionsCheck(),
new ImmediateReverseBoxingCheck(),
new TypeParametersShadowingCheck(),
new NullDereferenceCheck(),
new TryWithResourcesCheck(),
new UnclosedResourcesCheck(),
new SerialVersionUidCheck(),
new StaticFieldUpateCheck(),
new StaticMethodCheck(),
Expand All @@ -113,8 +106,7 @@ void verify_unused() {
new UnusedPrivateClassCheck(),
new UnusedTypeParameterCheck(),
new UnusedPrivateMethodCheck(),
new DeadStoreCheck(),
new ConditionalUnreachableCodeCheck()
new DeadStoreCheck()
);
}

Expand Down
17 changes: 12 additions & 5 deletions java-frontend/src/main/java/org/sonar/java/SonarComponents.java
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSyst
this.additionalAutoScanCompatibleRuleKeys = new TreeSet<>();
if (checkRegistrars != null) {
for (CheckRegistrar registrar : checkRegistrars) {
registrar.register(this);
registrar.register(this, checkFactory);
}
}
}
Expand Down Expand Up @@ -281,12 +281,17 @@ private static File findPluginJar() {

@Override
public void registerMainChecks(String repositoryKey, Collection<?> javaCheckClassesAndInstances) {
registerCheckClasses(mainChecks, repositoryKey, javaCheckClassesAndInstances);
registerCheckClasses(mainChecks, getCreatedCheckFromFactory(repositoryKey, javaCheckClassesAndInstances), javaCheckClassesAndInstances);
}

@Override
public void registerMainChecks(Checks<JavaCheck> checks, Collection<?> javaCheckClassesAndInstances){
registerCheckClasses(mainChecks, checks, javaCheckClassesAndInstances);
}

@Override
public void registerTestChecks(String repositoryKey, Collection<?> javaCheckClassesAndInstances) {
registerCheckClasses(testChecks, repositoryKey, javaCheckClassesAndInstances);
registerCheckClasses(testChecks, getCreatedCheckFromFactory(repositoryKey, javaCheckClassesAndInstances), javaCheckClassesAndInstances);
}

@Override
Expand Down Expand Up @@ -316,9 +321,11 @@ private boolean hasAtLeastOneActiveRule(Collection<RuleKey> ruleKeys) {
return ruleKeys.stream().anyMatch(ruleKey -> activeRules.find(ruleKey) != null);
}

private Checks<JavaCheck> getCreatedCheckFromFactory(String repositoryKey, Collection<?> javaCheckClassesAndInstances){
return checkFactory.<JavaCheck>create(repositoryKey).addAnnotatedChecks(javaCheckClassesAndInstances);
}

private void registerCheckClasses(List<JavaCheck> destinationList, String repositoryKey, Collection<?> javaCheckClassesAndInstances) {
Checks<JavaCheck> createdChecks = checkFactory.<JavaCheck>create(repositoryKey).addAnnotatedChecks(javaCheckClassesAndInstances);
private void registerCheckClasses(List<JavaCheck> destinationList, Checks<JavaCheck> createdChecks, Collection<?> javaCheckClassesAndInstances) {
allChecks.add(createdChecks);
Map<Class<? extends JavaCheck>, Integer> classIndexes = new HashMap<>();
int i = 0;
Expand Down
Loading

0 comments on commit 52c9272

Please sign in to comment.