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
2 changes: 1 addition & 1 deletion its/scanner-integration-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.sonarsource.java</groupId>
<artifactId>java-its</artifactId>
<version>8.31.0-SNAPSHOT</version>
<version>8.32.0-SNAPSHOT</version>
</parent>

<artifactId>it-java-scanner-integration-tests</artifactId>
Expand Down
4 changes: 4 additions & 0 deletions java-frontend/src/main/java/org/sonar/java/JavaFrontend.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.sonar.java.filters.SonarJavaIssueFilter;
import org.sonar.java.model.JParserConfig;
import org.sonar.java.model.VisitorsBridge;
import org.sonar.java.model.springcontext.SpringContextModelGatherers;
import org.sonar.java.telemetry.Telemetry;
import org.sonar.java.telemetry.TelemetryKey;
import org.sonar.plugins.java.api.JavaCheck;
Expand Down Expand Up @@ -82,6 +83,9 @@ public JavaFrontend(JavaVersion javaVersion, SonarComponents sonarComponents, Me
List<JavaCheck> commonVisitors = new ArrayList<>();
commonVisitors.add(javaResourceLocator);
commonVisitors.add(new Java25FeaturesTelemetryVisitor(telemetry));
if (sonarComponents.getSpringContextModel() != null) {
commonVisitors.addAll(SpringContextModelGatherers.getAllGatherers());
}
if (postAnalysisIssueFilter != null) {
commonVisitors.add(postAnalysisIssueFilter);
}
Expand Down
44 changes: 27 additions & 17 deletions java-frontend/src/main/java/org/sonar/java/SonarComponents.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
import org.sonar.java.model.GeneratedFile;
import org.sonar.java.model.JProblem;
import org.sonar.java.model.LineUtils;
import org.sonar.java.model.springcontext.SpringContextModel;
import org.sonar.java.reporting.AnalyzerMessage;
import org.sonar.java.reporting.JavaIssue;
import org.sonar.java.utils.ModuleMetadataUtils;
Expand Down Expand Up @@ -136,21 +137,22 @@ public class SonarComponents extends CheckRegistrar.RegistrarContext {
private SensorContext context;
private UnaryOperator<List<JavaCheck>> checkFilter = UnaryOperator.identity();
private final Set<RuleKey> additionalAutoScanCompatibleRuleKeys;
private SpringContextModel springContextModel;
Comment thread
asya-vorobeva marked this conversation as resolved.

private boolean alreadyLoggedSkipStatus = false;

public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSystem fs,
ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath,
CheckFactory checkFactory, ActiveRules activeRules) {
ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath,
CheckFactory checkFactory, ActiveRules activeRules) {
this(fileLinesContextFactory, fs, javaClasspath, javaTestClasspath, checkFactory, activeRules, null, null, null);
}

/**
* Can be called in SonarLint context when custom rules are present.
*/
public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSystem fs,
ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
ActiveRules activeRules, @Nullable CheckRegistrar[] checkRegistrars) {
ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
ActiveRules activeRules, @Nullable CheckRegistrar[] checkRegistrars) {
this(fileLinesContextFactory, fs, javaClasspath, javaTestClasspath, checkFactory, activeRules, checkRegistrars, null, null);
}

Expand All @@ -164,8 +166,8 @@ public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSyst
* Thus, for this constructor, we can also assume the presence of {@code CheckRegistrar} instances.
*/
public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSystem fs,
ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
ActiveRules activeRules, @Nullable CheckRegistrar[] checkRegistrars, SonarLintCache sonarLintCache) {
ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
ActiveRules activeRules, @Nullable CheckRegistrar[] checkRegistrars, SonarLintCache sonarLintCache) {
this(fileLinesContextFactory, fs, javaClasspath, javaTestClasspath, checkFactory, activeRules, checkRegistrars, null, sonarLintCache);
}

Expand All @@ -174,18 +176,18 @@ public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSyst
* May be called in some SonarLint contexts, but not others, since ProjectDefinition might not be available.
*/
public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSystem fs,
ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
ActiveRules activeRules, @Nullable ProjectDefinition projectDefinition) {
ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
ActiveRules activeRules, @Nullable ProjectDefinition projectDefinition) {
this(fileLinesContextFactory, fs, javaClasspath, javaTestClasspath, checkFactory, activeRules, null, projectDefinition, null);
}

/**
* May be called in some SonarLint contexts, but not others, since ProjectDefinition might not be available.
*/
public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSystem fs,
ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
ActiveRules activeRules, @Nullable CheckRegistrar[] checkRegistrars,
@Nullable ProjectDefinition projectDefinition) {
ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
ActiveRules activeRules, @Nullable CheckRegistrar[] checkRegistrars,
@Nullable ProjectDefinition projectDefinition) {
this(
fileLinesContextFactory,
fs,
Expand All @@ -208,9 +210,9 @@ public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSyst
* (because ProjectDefinition can be available in recent SonarLint versions, and DBD provides a CheckRegistrar.)
*/
public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSystem fs,
ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
ActiveRules activeRules, @Nullable CheckRegistrar[] checkRegistrars,
@Nullable ProjectDefinition projectDefinition, @Nullable SonarLintCache sonarLintCache) {
ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
ActiveRules activeRules, @Nullable CheckRegistrar[] checkRegistrars,
@Nullable ProjectDefinition projectDefinition, @Nullable SonarLintCache sonarLintCache) {
this.fileLinesContextFactory = fileLinesContextFactory;
this.fs = fs;
this.javaClasspath = javaClasspath;
Expand Down Expand Up @@ -293,7 +295,7 @@ public void registerMainChecks(String repositoryKey, Collection<?> javaCheckClas
}

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

Expand Down Expand Up @@ -339,7 +341,7 @@ private boolean hasAtLeastOneActiveRule(Collection<RuleKey> ruleKeys) {
return ruleKeys.stream().anyMatch(ruleKey -> activeRules.find(ruleKey) != null);
}

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

Expand Down Expand Up @@ -646,7 +648,7 @@ private void logUndefinedTypes(int maxLines) {
}

private static void logParserMessages(Stream<Map.Entry<JProblem, List<String>>> messages, int maxProblems, String warningMessage,
String debugMessage) {
String debugMessage) {
String problemDelimiter = System.lineSeparator() + "- ";
List<List<String>> messagesList = messages
.sorted(Comparator.comparing(entry -> entry.getKey().toString()))
Expand Down Expand Up @@ -692,4 +694,12 @@ public Configuration getConfiguration() {
return context.config();
}

public void setSpringContextModel(SpringContextModel springContextModel) {
this.springContextModel = springContextModel;
}

public SpringContextModel getSpringContextModel() {
return springContextModel;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.sonar.api.config.Configuration;
import org.sonar.java.SonarComponents;
import org.sonar.java.caching.CacheContextImpl;
import org.sonar.java.model.springcontext.SpringContextModel;
import org.sonar.java.reporting.AnalyzerMessage;
import org.sonar.plugins.java.api.JavaCheck;
import org.sonar.plugins.java.api.JavaVersion;
Expand Down Expand Up @@ -115,5 +116,8 @@ public Configuration getConfiguration() {
return sonarComponents.getConfiguration();
}

public SpringContextModel getSpringContextModel() {
return sonarComponents.getSpringContextModel();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
*/
package org.sonar.java.model.springcontext;

import org.sonar.api.scanner.ScannerSide;
import org.sonarsource.api.sonarlint.SonarLintSide;

/**
* Aggregates all Spring context information collected during project scanning.
*
Expand All @@ -28,48 +31,35 @@
* <li>{@link EntityClassToPropertiesIndex} — JPA {@code @Entity} class properties</li>
* </ul>
*/
@ScannerSide
Comment thread
gitar-bot[bot] marked this conversation as resolved.
@SonarLintSide
public class SpringContextModel {
/** Registry of all bean definitions discovered during scanning. */
private BeanDefinitionRegistry beanDefinitionRegistry;
private final BeanDefinitionRegistry beanDefinitionRegistry = new BeanDefinitionRegistry();

/** Packages registered for Spring component scanning, grouped by module. */
private ProjectPackageScan projectPackageScan;
private final ProjectPackageScan projectPackageScan = new ProjectPackageScan();

/** Index for resolving bean names by their fully-qualified type. */
private TypeToBeanNamesIndex typeToBeanNamesIndex;
private final TypeToBeanNamesIndex typeToBeanNamesIndex = new TypeToBeanNamesIndex();

/** Index of properties associated with Spring Data / Hibernate {@code @Entity} classes. */
private EntityClassToPropertiesIndex entityClassToPropertiesIndex;
private final EntityClassToPropertiesIndex entityClassToPropertiesIndex = new EntityClassToPropertiesIndex();

public BeanDefinitionRegistry getBeanDefinitionRegistry() {
return beanDefinitionRegistry;
}

public void setBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) {
this.beanDefinitionRegistry = beanDefinitionRegistry;
}

public ProjectPackageScan getProjectPackageScan() {
return projectPackageScan;
}

public void setProjectPackageScan(ProjectPackageScan projectPackageScan) {
this.projectPackageScan = projectPackageScan;
}

public TypeToBeanNamesIndex getTypeToBeanNamesIndex() {
return typeToBeanNamesIndex;
}

public void setTypeToBeanNamesIndex(TypeToBeanNamesIndex typeToBeanNamesIndex) {
this.typeToBeanNamesIndex = typeToBeanNamesIndex;
}

public EntityClassToPropertiesIndex getEntityClassToPropertiesIndex() {
return entityClassToPropertiesIndex;
}

public void setEntityClassToPropertiesIndex(EntityClassToPropertiesIndex entityClassToPropertiesIndex) {
this.entityClassToPropertiesIndex = entityClassToPropertiesIndex;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* SonarQube Java
* Copyright (C) SonarSource Sàrl
* mailto:info AT sonarsource DOT com
*
* You can redistribute and/or modify this program under the terms of
* the Sonar Source-Available License Version 1, as published by SonarSource Sàrl.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the Sonar Source-Available License for more details.
*
* You should have received a copy of the Sonar Source-Available License
* along with this program; if not, see https://sonarsource.com/license/ssal/
*/
package org.sonar.java.model.springcontext;

import org.sonar.java.ast.visitors.SubscriptionVisitor;
import org.sonar.java.model.DefaultModuleScannerContext;
import org.sonar.plugins.java.api.ModuleScannerContext;
import org.sonar.plugins.java.api.internal.EndOfAnalysis;

/**
* Base class for visitors that need to gather data in the SpringContextModel at the end of the analysis.
* Extending classes will have to implement the AST visitor pattern, gather relevant spring-related data, and store it
* in the SpringContextModel at the of a module analysis.
*/
public abstract class SpringContextModelGatherer extends SubscriptionVisitor implements EndOfAnalysis {

@Override
public final void endOfAnalysis(ModuleScannerContext context) {
var defaultModuleContext = (DefaultModuleScannerContext) context;
gatherSpringContextData(context, defaultModuleContext.getSpringContextModel());
}
Comment thread
leonardo-pilastri-sonarsource marked this conversation as resolved.

/**
* Method called at the end of the analysis of a module, allowing to store gathered data in the SpringContextModel.
*/
public abstract void gatherSpringContextData(ModuleScannerContext context, SpringContextModel springContextModel);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* SonarQube Java
* Copyright (C) SonarSource Sàrl
* mailto:info AT sonarsource DOT com
*
* You can redistribute and/or modify this program under the terms of
* the Sonar Source-Available License Version 1, as published by SonarSource Sàrl.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the Sonar Source-Available License for more details.
*
* You should have received a copy of the Sonar Source-Available License
* along with this program; if not, see https://sonarsource.com/license/ssal/
*/
package org.sonar.java.model.springcontext;

import java.util.List;
import org.sonar.plugins.java.api.JavaCheck;

public class SpringContextModelGatherers {

private SpringContextModelGatherers() {
// utility class, should not be instantiated
}

public static List<JavaCheck> getAllGatherers() {
return List.of(
// example: new SampleSpringContextModelGatherer()
);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* SonarQube Java
* Copyright (C) SonarSource Sàrl
* mailto:info AT sonarsource DOT com
*
* You can redistribute and/or modify this program under the terms of
* the Sonar Source-Available License Version 1, as published by SonarSource Sàrl.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the Sonar Source-Available License for more details.
*
* You should have received a copy of the Sonar Source-Available License
* along with this program; if not, see https://sonarsource.com/license/ssal/
*/
package org.sonar.java.model.springcontext;
Comment thread
gitar-bot[bot] marked this conversation as resolved.

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.sensor.internal.SensorContextTester;
import org.sonar.java.SonarComponents;
import org.sonar.java.TestUtils;
import org.sonar.java.model.JParserTestUtils;
import org.sonar.java.model.VisitorsBridge;
import org.sonar.plugins.java.api.JavaCheck;
import org.sonar.plugins.java.api.ModuleScannerContext;
import org.sonar.plugins.java.api.tree.Tree;

import static org.assertj.core.api.Assertions.assertThat;

class SpringContextModelGathererTest {

private final SpringContextModel model = new SpringContextModel();

@Test
void testGatherSpringContextData() {
getSpringModelAfterVisitingFile("src/test/files/model/SimpleClass.java", new SampleGatherer());
assertThat(model.getTypeToBeanNamesIndex().getNamesForType("com.example.MyService")).containsExactly("myServiceBean");
}

private void getSpringModelAfterVisitingFile(String filePath, JavaCheck check) {
File file = new File(filePath);
InputFile inputFile = TestUtils.inputFile(file);
var compilationUnit = JParserTestUtils.parse(file);
SensorContextTester sensorContextTester = SensorContextTester.create(new File(""));
var sonarComponents = new SonarComponents(null, null, null, null, null, null);
sonarComponents.setSensorContext(sensorContextTester);
sonarComponents.setSpringContextModel(model);

VisitorsBridge visitorsBridge = new VisitorsBridge(List.of(check), new ArrayList<>(), sonarComponents);
visitorsBridge.setCurrentFile(inputFile);
visitorsBridge.visitFile(compilationUnit, false);
visitorsBridge.endOfAnalysis();
}

class SampleGatherer extends SpringContextModelGatherer {

@Override
public void gatherSpringContextData(ModuleScannerContext context, SpringContextModel springContextModel) {
springContextModel.getTypeToBeanNamesIndex().addBeanForType("com.example.MyService", "myServiceBean");
}

@Override
public List<Tree.Kind> nodesToVisit() {
return List.of();
}
}

}
Loading
Loading