Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import com.sonar.orchestrator.container.Server;
import com.sonar.orchestrator.junit4.OrchestratorRule;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -57,12 +56,9 @@ public static File homeDir() {
}

public static File pluginJar(String artifactId) {
return Iterables.getOnlyElement(Arrays.asList(new File(homeDir(), "plugins/" + artifactId + "/target/").listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".jar") && !name.endsWith("-sources.jar");
}
})));
return Iterables.getOnlyElement(Arrays.asList(new File(homeDir(), "plugins/" + artifactId + "/target/").listFiles(
(dir, name) -> name.endsWith(".jar") && !name.endsWith("-sources.jar")
)));
}

public static File projectDir(String projectName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,9 @@ private void checkArguments(Arguments arguments, CredentialMethod method) {
var secondaryLocations = new ArrayList<JavaFileScannerContext.Location>();
if (isExpressionDerivedFromPlainText(argument, secondaryLocations, new HashSet<>())) {
String value = ExpressionsHelper.getConstantValueAsString(argument).value();
if (value != null && SecretClassifier.isKnownNonSecret(value)) {
continue;
if (value == null || !SecretClassifier.isKnownNonSecret(value)) {
reportIssue(argument, ISSUE_MESSAGE, secondaryLocations, null);
}
reportIssue(argument, ISSUE_MESSAGE, secondaryLocations, null);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,26 +448,24 @@ void consolidateQuickFixes() {
List<JavaQuickFix> quickFixesForIssue = new ArrayList<>();

for (String quickFixId : entry.getValue()) {
if (NO_QUICK_FIX_ID.equals(quickFixId)) {
// When the id corresponds to the "no quick fix id", it means that we expect no quick fix for this issue.
continue;
if (!NO_QUICK_FIX_ID.equals(quickFixId)) {
allQuickFixIds.add(quickFixId);
String message = quickfixesMessages.get(quickFixId);
if (message == null) {
throw new AssertionError("Missing message for quick fix: " + quickFixId);
}
List<QuickFixEditComment> edits = quickfixesEdits.get(quickFixId);
if (edits == null) {
throw new AssertionError("Missing edits for quick fix: " + quickFixId);
}

JavaQuickFix javaQuickFix = JavaQuickFix.newQuickFix(message).addTextEdits(
edits.stream()
.map(edit -> getEdit(edit, issueTextSpan, quickFixId))
.toList()
).build();
quickFixesForIssue.add(javaQuickFix);
}
allQuickFixIds.add(quickFixId);
String message = quickfixesMessages.get(quickFixId);
if (message == null) {
throw new AssertionError("Missing message for quick fix: " + quickFixId);
}
List<QuickFixEditComment> edits = quickfixesEdits.get(quickFixId);
if (edits == null) {
throw new AssertionError("Missing edits for quick fix: " + quickFixId);
}

JavaQuickFix javaQuickFix = JavaQuickFix.newQuickFix(message).addTextEdits(
edits.stream()
.map(edit -> getEdit(edit, issueTextSpan, quickFixId))
.toList()
).build();
quickFixesForIssue.add(javaQuickFix);
}
quickFixes.put(issueTextSpan, quickFixesForIssue);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -659,18 +659,15 @@ public void accept(Set<AnalyzerMessage> issues) {
for (AnalyzerMessage issue : issues) {
AnalyzerMessage.TextSpan primaryLocation = issue.primaryLocation();
List<JavaQuickFix> expected = expectedQuickFixes.get(primaryLocation);
if (expected == null) {
// We don't have to always test quick fixes, we do nothing if there is no expected quick fix.
continue;
}
List<JavaQuickFix> actual = actualQuickFixes.get(primaryLocation);
if (expected.isEmpty()) {
if (actual != null && !actual.isEmpty()) {
throw new AssertionError(String.format("[Quick Fix] Issue on line %d contains quick fixes while none where expected", primaryLocation.startLine));
if (expected != null) {
List<JavaQuickFix> actual = actualQuickFixes.get(primaryLocation);
if (expected.isEmpty()) {
if (actual != null && !actual.isEmpty()) {
throw new AssertionError(String.format("[Quick Fix] Issue on line %d contains quick fixes while none where expected", primaryLocation.startLine));
}
} else {
validateIfSameSize(expected, actual, issue);
}
// Else: no issue in both expected and actual, nothing to do
} else {
validateIfSameSize(expected, actual, issue);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
import org.sonar.java.reporting.JavaQuickFix;
import org.sonar.java.reporting.JavaTextEdit;
import org.sonar.plugins.java.api.JavaFileScanner;
import org.sonar.plugins.java.api.JavaFileScannerContext;
import org.sonar.plugins.java.api.caching.CacheContext;
import org.sonar.plugins.java.api.caching.JavaReadCache;
import org.sonar.plugins.java.api.caching.JavaWriteCache;
Expand Down Expand Up @@ -245,12 +244,9 @@ void context_return_good_root_working_directory() {
assertThatCode(() -> {
JavaCheckVerifier.newInstance()
.onFile(TEST_FILE)
.withCheck(new JavaFileScanner() {
@Override
public void scanFile(JavaFileScannerContext context) {
assertThat(context.getRootProjectWorkingDirectory().getPath()).isEqualTo(rootWorkDir);
}
})
.withCheck((JavaFileScanner) context ->
assertThat(context.getRootProjectWorkingDirectory().getPath()).isEqualTo(rootWorkDir)
)
.withProjectLevelWorkDir(rootWorkDir)
.verifyNoIssues();
}).doesNotThrowAnyException();
Expand Down Expand Up @@ -432,13 +428,10 @@ void compilationUnitModifier_modify_tree() {
classTree.complete((ModifiersTreeImpl) classTree.modifiers(), classTree.declarationKeyword(), ident);
};

var check = new JavaFileScanner() {
@Override
public void scanFile(JavaFileScannerContext context) {
CompilationUnitTree tree = context.getTree();
ClassTreeImpl classTree = (ClassTreeImpl) tree.types().get(0);
assertThat(classTree.simpleName().name()).isEqualTo("Modified");
}
var check = (JavaFileScanner) context -> {
CompilationUnitTree tree = context.getTree();
ClassTreeImpl classTree = (ClassTreeImpl) tree.types().get(0);
assertThat(classTree.simpleName().name()).isEqualTo("Modified");
};

JavaCheckVerifier.newInstance()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,10 @@ private void analyzeCFG(Map<CFG.Block, Set<Symbol>> in, Map<CFG.Block, Set<Symbo
Set<Symbol> newIn = new HashSet<>(gen.get(block));
newIn.addAll(SetUtils.difference(blockOut, kill.get(block)));

if (newIn.equals(in.get(block))) {
continue;
if (!newIn.equals(in.get(block))) {
in.put(block, newIn);
block.predecessors().forEach(workList::addLast);
}
in.put(block, newIn);
block.predecessors().forEach(workList::addLast);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,20 +66,16 @@ private static List<File> collectJars(Path home, boolean isMac) {
List<File> rootFiles = new ArrayList<>();
Set<Path> duplicatePathFilter = new HashSet<>();
for (Path jarDir : collectJarDirs(home, isMac)) {
if (!Files.isDirectory(jarDir)) {
continue;
if (Files.isDirectory(jarDir)) {
listFiles(jarDir, JavaSdkUtil::isJarFile).stream()
.filter(JavaSdkUtil::isNotAlternativeImplementation)
.map(JavaSdkUtil::toRealPath).filter(Optional::isPresent).map(Optional::get)
.forEach(jarFile -> {
if (duplicatePathFilter.add(jarFile)) {
rootFiles.add(jarFile.toFile());
}
});
}
listFiles(jarDir, JavaSdkUtil::isJarFile).stream()
// filter out alternative implementations
.filter(JavaSdkUtil::isNotAlternativeImplementation)
// filter out duplicate (symbolically linked) .jar files commonly found in OS X JDK distributions
.map(JavaSdkUtil::toRealPath).filter(Optional::isPresent).map(Optional::get)
// make sure there is no duplicates
.forEach(jarFile -> {
if (duplicatePathFilter.add(jarFile)) {
rootFiles.add(jarFile.toFile());
}
});
}

return rootFiles;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import org.sonar.plugins.java.api.tree.Tree;
import org.sonar.plugins.java.api.tree.TreeVisitor;

public class InternalSyntaxTrivia extends JavaTree implements SyntaxTrivia {
public final class InternalSyntaxTrivia extends JavaTree implements SyntaxTrivia {


private final CommentKind commentKind;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,18 +157,14 @@ void findOverridesInParentTypes(Collection<MethodSymbol> accumulator, Predicate<

private void findOverridesInTypes(Collection<MethodSymbol> accumulator, Predicate<IMethodBinding> overridesCondition, ITypeBinding... types) {
for (ITypeBinding type : types) {
if (type == null) {
// Can happen for unknown reason.
continue;
if (type != null) {
Stream.of(type.getDeclaredMethods())
.filter(overridesCondition)
.findFirst()
.map(sema::methodSymbol)
.ifPresent(accumulator::add);
findOverridesInParentTypes(accumulator, overridesCondition, type);
}
// check current type
Stream.of(type.getDeclaredMethods())
.filter(overridesCondition)
.findFirst()
.map(sema::methodSymbol)
.ifPresent(accumulator::add);
// check other inheritance levels
findOverridesInParentTypes(accumulator, overridesCondition, type);
}
}

Expand Down
13 changes: 8 additions & 5 deletions java-frontend/src/main/java/org/sonar/java/model/JParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -976,9 +976,10 @@ private EnumConstantTreeImpl processEnumConstantDeclaration(EnumConstantDeclarat
final InternalSyntaxToken closeParToken;
if (tokenManager.get(openParTokenIndex).tokenType == TerminalToken.TokenNameLPAREN) {
openParToken = createSyntaxToken(openParTokenIndex);
closeParToken = e.arguments().isEmpty()
? firstTokenAfter(e.getName(), TerminalToken.TokenNameRPAREN)
: firstTokenAfter((ASTNode) e.arguments().get(e.arguments().size() - 1), TerminalToken.TokenNameRPAREN);
ASTNode closeParAnchor = e.arguments().isEmpty()
? e.getName()
: (ASTNode) e.arguments().get(e.arguments().size() - 1);
closeParToken = firstTokenAfter(closeParAnchor, TerminalToken.TokenNameRPAREN);
} else {
openParToken = null;
closeParToken = null;
Expand Down Expand Up @@ -2737,9 +2738,11 @@ private JavaTree.WildcardTreeImpl convertWildcardType(WildcardType e) {
if (bound == null) {
t = new JavaTree.WildcardTreeImpl(questionToken);
} else {
Tree.Kind wildcardKind = e.isUpperBound() ? Tree.Kind.EXTENDS_WILDCARD : Tree.Kind.SUPER_WILDCARD;
TerminalToken boundTokenType = e.isUpperBound() ? TerminalToken.TokenNameextends : TerminalToken.TokenNamesuper;
t = new JavaTree.WildcardTreeImpl(
e.isUpperBound() ? Tree.Kind.EXTENDS_WILDCARD : Tree.Kind.SUPER_WILDCARD,
e.isUpperBound() ? firstTokenBefore(bound, TerminalToken.TokenNameextends) : firstTokenBefore(bound, TerminalToken.TokenNamesuper),
wildcardKind,
firstTokenBefore(bound, boundTokenType),
convertType(bound)
).complete(questionToken);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -408,22 +408,19 @@ public List<AnnotationValue> values() {
}

private Object convertAnnotationValue(Object value) {
if (value instanceof IVariableBinding iVariableBinding) {
return sema.variableSymbol(iVariableBinding);
} else if (value instanceof ITypeBinding iTypeBinding) {
return sema.typeSymbol(iTypeBinding);
} else if (value instanceof IAnnotationBinding iAnnotationBinding) {
return sema.annotation(iAnnotationBinding);
} else if (value instanceof Object[] a) {
// Godin: probably better to not modify original array
Object[] result = new Object[a.length];
for (int i = 0; i < a.length; i++) {
result[i] = convertAnnotationValue(a[i]);
return switch (value) {
case IVariableBinding iVariableBinding -> sema.variableSymbol(iVariableBinding);
case ITypeBinding iTypeBinding -> sema.typeSymbol(iTypeBinding);
case IAnnotationBinding iAnnotationBinding -> sema.annotation(iAnnotationBinding);
case Object[] a -> {
Object[] result = new Object[a.length];
for (int i = 0; i < a.length; i++) {
result[i] = convertAnnotationValue(a[i]);
}
yield result;
}
return result;
} else {
return value;
}
case null, default -> value;
};
Comment on lines 410 to +423

@gitar-bot gitar-bot Bot Aug 27, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Quality: Redundant duplicate arms in convertAnnotationValue switch

case null -> value; and default -> value; are two labels with identical bodies; the null label is only needed to avoid the pattern-switch NPE, so both can be merged into a single case null, default -> value; arm. Behaviour is unchanged either way (the old if/else chain also returned value for null since null instanceof X is false), but the duplicated arm is exactly the kind of redundancy this cleanup PR targets.

Merge the null and default arms:

return switch (value) {
  case IVariableBinding iVariableBinding -> sema.variableSymbol(iVariableBinding);
  case ITypeBinding iTypeBinding -> sema.typeSymbol(iTypeBinding);
  case IAnnotationBinding iAnnotationBinding -> sema.annotation(iAnnotationBinding);
  case Object[] a -> {
    Object[] result = new Object[a.length];
    for (int i = 0; i < a.length; i++) {
      result[i] = convertAnnotationValue(a[i]);
    }
    yield result;
  }
  case null, default -> value;
};

Was this helpful? React with 👍 / 👎

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
* <p>
* We expect only single JSP stratum, with single FileSection and LineSection. Moreover only single file is expected in FileSection
*/
public class SmapFile {
public final class SmapFile {

private static final Pattern LINE_INFO = Pattern.compile("(?<inputStartLine>\\d+)" +
"(?:#(?<lineFileId>\\d+))?" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -451,13 +451,10 @@ void scanWithoutParsing_filters_out_the_files_that_could_be_successfully_scanned
@Test
void test_modifyCompilationUnit_modify_ast() {

var check = new JavaFileScanner() {
@Override
public void scanFile(JavaFileScannerContext context) {
CompilationUnitTree tree = context.getTree();
ClassTreeImpl classTree = (ClassTreeImpl) tree.types().get(0);
assertThat(classTree.simpleName().symbol().isUnknown()).isTrue();
}
var check = (JavaFileScanner) scannerContext -> {
CompilationUnitTree tree = scannerContext.getTree();
ClassTreeImpl classTree = (ClassTreeImpl) tree.types().get(0);
assertThat(classTree.simpleName().symbol().isUnknown()).isTrue();
};

VisitorsBridge visitorsBridge = new VisitorsBridge(
Expand Down
2 changes: 1 addition & 1 deletion java-jsp/src/main/java/org/sonar/java/jsp/Jasper.java
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ static Path outputDir(SensorContext sensorContext) {
/**
* Overloading log methods so messages are redirected to scanner log
*/
static class ServletContext extends JspCServletContext {
static final class ServletContext extends JspCServletContext {

public ServletContext(URL aResourceBaseURL, ClassLoader classLoader) throws JasperException {
super(/* not used */ null, aResourceBaseURL, classLoader, false, true);
Expand Down
Loading