ConditionalExprTest.java
/*
* Copyright (C) 2017-2024 The JavaParser Team.
*
* This file is part of JavaParser.
*
* JavaParser can be used either under the terms of
* a) the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* b) the terms of the Apache License
*
* You should have received a copy of both licenses in LICENCE.LGPL and
* LICENCE.APACHE. Please refer to those files for details.
*
* JavaParser 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
* GNU Lesser General Public License for more details.
*/
package com.github.javaparser.symbolsolver.resolution;
import static org.junit.jupiter.api.Assertions.assertEquals;
import com.github.javaparser.ParserConfiguration;
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.expr.ConditionalExpr;
import com.github.javaparser.resolution.types.ResolvedType;
import com.github.javaparser.symbolsolver.JavaSymbolSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class ConditionalExprTest extends AbstractResolutionTest {
@BeforeEach
void setup() {
ParserConfiguration config = new ParserConfiguration();
config.setSymbolResolver(new JavaSymbolSolver(new ReflectionTypeSolver(false)));
StaticJavaParser.setConfiguration(config);
}
@Test
void test_if_operands_have_the_same_type() {
String code = "class A { public void m() { Object o = true ? null : null;}}";
ResolvedType rt1 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("null", rt1.describe());
code = "class A { public void m() { Object o = true ? \"\" : \"\";}}";
ResolvedType rt2 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("java.lang.String", rt2.describe());
code = "class A { public void m() { Object o = true ? new A() : new A();}}";
ResolvedType rt3 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("A", rt3.describe());
}
@Test
void test_null_operand_in_conditional_expression() {
String code = "class A { public void m() { Object o = true ? \"\" : null;}}";
ResolvedType rt1 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("java.lang.String", rt1.describe());
code = "class A { public void m() { Object o = true ? null : \"\";}}";
ResolvedType rt2 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("java.lang.String", rt2.describe());
}
@Test
void test_boolean_conditional_expression() {
// If the second and third operands are both of type Boolean, the conditional expression has type Boolean.
String code = "class A { public void m() { boolean r = true ? Boolean.TRUE : Boolean.FALSE;}}";
ResolvedType rt1 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("java.lang.Boolean", rt1.describe());
// Otherwise, the conditional expression has type boolean.
code = "class A { public void m() { boolean r = true ? true : Boolean.FALSE;}}";
ResolvedType rt2 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("boolean", rt2.describe());
}
@Test
void test_numeric_conditional_expression() {
// If the second and third operands have the same type, then that is the type of the conditional expression.
String code = "class A { public void m() { int r = true ? 1 : 2;}}";
ResolvedType rt1 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("int", rt1.describe());
// If one of the second and third operands is of primitive type T, and the type of the other is the result of
// applying boxing conversion (��5.1.7) to T, then the type of the conditional expression is T.
code = "class A { public void m() { int r = true ? 1 : Integer.valueOf(2);}}";
ResolvedType rt2 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("int", rt2.describe());
// If one of the operands is of type byte or Byte and the other is of type short or Short, then the type of the
// conditional expression is short.
code = "class A { public void m() { short r = true ? Byte.MIN_VALUE : Short.MIN_VALUE;}}";
ResolvedType rt3 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("short", rt3.describe());
code = "class A { public void m() { short r = true ? Byte.MIN_VALUE : Short.valueOf(Short.MIN_VALUE);}}";
ResolvedType rt4 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("short", rt4.describe());
code = "class A { public void m() { short r = true ? Short.MIN_VALUE : Byte.valueOf(Byte.MIN_VALUE);}}";
ResolvedType rt5 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("short", rt5.describe());
code =
"class A { public void m() { short r = true ? Short.valueOf(Short.MIN_VALUE) : Byte.valueOf(Byte.MIN_VALUE);}}";
ResolvedType rt5b = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("short", rt5b.describe());
// If one of the operands is of type T where T is byte, short, or char, and the other operand is a constant
// expression (��15.28) of type int whose value is representable in type T, then the type of the conditional
// expression is T.
code = "class A { public void m() { byte r = true ? Byte.MIN_VALUE : 1;}}";
ResolvedType rt6 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("byte", rt6.describe());
code = "class A { public void m() { short r = true ? Short.MIN_VALUE : 1;}}";
ResolvedType rt7 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("short", rt7.describe());
code = "class A { public void m() { char r = true ? Character.MIN_VALUE : 1;}}";
ResolvedType rt8 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("char", rt8.describe());
// If one of the operands is of type T, where T is Byte, Short, or Character,
// and the other operand is a constant expression of type int whose value is
// representable in the type U which is the result of applying unboxing
// conversion to T, then the type of the conditional expression is U.
code = "class A { public void m() { byte r = true ? Byte.valueOf(Byte.MIN_VALUE) : 1;}}";
ResolvedType rt9 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("byte", rt9.describe());
code = "class A { public void m() { short r = true ? Short.valueOf(Short.MIN_VALUE) : 1;}}";
ResolvedType rt10 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("short", rt10.describe());
code = "class A { public void m() { char r = true ? Character.valueOf(Character.MIN_VALUE) : 1;}}";
ResolvedType rt11 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("char", rt11.describe());
// reverse position of the reference type parameter
code = "class A { public void m() { char r = true ? 1 : Character.valueOf(Character.MIN_VALUE);}}";
ResolvedType rt12 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("char", rt12.describe());
// Otherwise, binary numeric promotion (��5.6.2) is applied to the operand types,
// and the type of the conditional expression is the promoted type of the second
// and third operands.
code = "class A { public void m() { long r = true ? 1L : 1;}}";
ResolvedType rt13 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("long", rt13.describe());
code = "class A { public void m() { long r = true ? 1.0 : 1F;}}";
ResolvedType rt14 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("double", rt14.describe());
}
@Test
void test_reference_conditional_expression() {
// If the second and third operands have the same type, then that is the type of the conditional expression.
String code = "class A { public void m() { String r = true ? new String(\"new string\") : \"\";}}";
ResolvedType rt1 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("java.lang.String", rt1.describe());
// Otherwise, the second and third operands are of types S1 and S2 respectively. Let T1 be the type that
// results from applying boxing conversion to S1, and let T2 be the type that results from applying boxing
// conversion to S2. The type of the conditional expression is the result of applying capture conversion
// (��5.1.10) to lub(T1, T2).
code =
"class A { public void m() { java.util.List list = true ? java.util.Collections.emptyList() : java.util.Collections.emptyList();}}";
ResolvedType rt2 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("java.util.List<T>", rt2.describe());
code = "class A { public void m() { Class clazz = true ? String.class : StringBuilder.class;}}";
ResolvedType rt5 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("java.lang.Class<? extends java.io.Serializable>", rt5.describe());
code = "class A { public void m() { java.io.Serializable r = true ? Integer.valueOf(1) : \"\";}}";
ResolvedType rt6 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("java.io.Serializable", rt6.describe());
}
@Test
void test_reference_conditional_expression_with_type_variable() {
// require that type variable T in the returned type of this method call java.util.Collections.emptyList()
// can be translated into String type
String code =
"class A { public void m() { java.util.List list = true ? new java.util.ArrayList<String>() : java.util.Collections.emptyList();}}";
ResolvedType rt3 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("java.util.List<java.lang.String>", rt3.describe());
code =
"class A { public void m() { java.util.List list = true ? java.util.Collections.emptyList() : new java.util.ArrayList<String>();}}";
ResolvedType rt4 = StaticJavaParser.parse(code)
.findFirst(ConditionalExpr.class)
.get()
.calculateResolvedType();
assertEquals("java.util.List<java.lang.String>", rt4.describe());
}
}