diff --git a/java-frontend/src/main/java/org/sonar/java/model/JParser.java b/java-frontend/src/main/java/org/sonar/java/model/JParser.java index fd97a1322c8..329fe6bbd55 100644 --- a/java-frontend/src/main/java/org/sonar/java/model/JParser.java +++ b/java-frontend/src/main/java/org/sonar/java/model/JParser.java @@ -258,7 +258,19 @@ public class JParser { private static final Logger LOG = LoggerFactory.getLogger(JParser.class); - private static final Predicate IS_SYNTAX_ERROR = error -> (error.getID() & IProblem.Syntax) != 0; + private static final Set 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 IS_SYNTAX_ERROR = error -> ((error.getID() & IProblem.Syntax) != 0) && + !WRONGLY_CATEGORIZED_AS_SYNTAX_ERROR.contains(error.getID()); + private static final Predicate IS_UNDEFINED_TYPE_ERROR = error -> (error.getID() & IProblem.UndefinedType) != 0; /** diff --git a/java-frontend/src/test/java/org/sonar/java/model/JParserSemanticTest.java b/java-frontend/src/test/java/org/sonar/java/model/JParserSemanticTest.java index 9b1b7c67391..6894df04bcb 100644 --- a/java-frontend/src/test/java/org/sonar/java/model/JParserSemanticTest.java +++ b/java-frontend/src/test/java/org/sonar/java/model/JParserSemanticTest.java @@ -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; @@ -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