Skip to content

Commit

Permalink
SONARJAVA-5015 Improve the tolerance to syntax errors when parsing sw…
Browse files Browse the repository at this point in the history
…itch expressions (#4926)
  • Loading branch information
alban-auzeill authored Nov 13, 2024
1 parent 3456a1c commit 353722c
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 1 deletion.
14 changes: 13 additions & 1 deletion java-frontend/src/main/java/org/sonar/java/model/JParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,19 @@ public class JParser {

private static final Logger LOG = LoggerFactory.getLogger(JParser.class);

private static final Predicate<IProblem> IS_SYNTAX_ERROR = error -> (error.getID() & IProblem.Syntax) != 0;
private static final Set<Integer> WRONGLY_CATEGORIZED_AS_SYNTAX_ERROR = Set.of(
// Accept missing default clause, it may be due to missing semantic information of the switch expression,
// in this case, an enum fully covered with the switch cases will be seen as something that is not an enum
// when it is unknown, and the parser will wrongly consider the missing default clause as a syntax error.
IProblem.SwitchExpressionsYieldMissingDefaultCase,
// Accept missing default clause, it may be due the switch expression being an enum from a wrong dependency.
// In this case, the parser will wrongly consider the missing default clause as a syntax error.
IProblem.SwitchExpressionsYieldMissingEnumConstantCase
);

private static final Predicate<IProblem> IS_SYNTAX_ERROR = error -> ((error.getID() & IProblem.Syntax) != 0) &&
!WRONGLY_CATEGORIZED_AS_SYNTAX_ERROR.contains(error.getID());

private static final Predicate<IProblem> IS_UNDEFINED_TYPE_ERROR = error -> (error.getID() & IProblem.UndefinedType) != 0;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
import org.sonar.plugins.java.api.tree.TypeCastTree;
import org.sonar.plugins.java.api.tree.TypeTree;
import org.sonar.plugins.java.api.tree.VariableTree;
import org.sonar.plugins.java.api.tree.YieldStatementTree;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
Expand Down Expand Up @@ -559,6 +560,36 @@ void expression_switch() {
}
}

@Test
void switch_expression_with_yield_of_unknown_identifier_without_default_clause() {
SwitchExpressionTreeImpl switchExpression = (SwitchExpressionTreeImpl) expression("switch (unknownIdentifier) { case A -> 0; case B -> 1; }");
assertThat(switchExpression.expression().symbolType().isUnknown()).isTrue();
// the expression type of the full switch expression the should have been int or unknown
// instead of java.lang.Object, it is probably a limitation in the JDT parser when it face a missing default clause error
assertThat(switchExpression.symbolType().isUnknown()).isFalse();
assertThat(switchExpression.symbolType().fullyQualifiedName()).isEqualTo("java.lang.Object");
assertThat(switchExpression.cases().get(0).body().get(0)).isInstanceOf(YieldStatementTree.class);
}

@Test
void switch_expression_of_unknown_identifier_without_default_clause() {
SwitchExpressionTreeImpl switchExpression = (SwitchExpressionTreeImpl) expression("switch (unknownIdentifier) { case A: return 0; case B: return 1; }");
assertThat(switchExpression.expression().symbolType().isUnknown()).isTrue();
assertThat(switchExpression.symbolType().isUnknown()).isTrue();
assertThat(switchExpression.cases().get(0).body().get(0)).isInstanceOf(ReturnStatementTree.class);
}

@Test
void switch_expression_of_enum_without_default_clause() {
CompilationUnitTree cu = test("class C { Object m(java.time.DayOfWeek x) { return switch (x) { case MONDAY: return 0; case TUESDAY: return 1; } ; } }");
ClassTree c = (ClassTree) cu.types().get(0);
MethodTree m = (MethodTree) c.members().get(0);
ReturnStatementTree s = (ReturnStatementTree) Objects.requireNonNull(m.block()).body().get(0);
SwitchExpressionTreeImpl switchExpression = (SwitchExpressionTreeImpl) s.expression();
assertThat(switchExpression.expression().symbolType().isUnknown()).isFalse();
assertThat(switchExpression.symbolType().isUnknown()).isTrue();
}

/**
* Pattern Matching for instanceof
* (Preview in Java 14) https://openjdk.java.net/jeps/305
Expand Down

0 comments on commit 353722c

Please sign in to comment.