diff --git a/jdk-codemodel/src/main/java/build/codemodel/jdk/JdkExpressionConverter.java b/jdk-codemodel/src/main/java/build/codemodel/jdk/JdkExpressionConverter.java index 7a745fa..f5285ac 100644 --- a/jdk-codemodel/src/main/java/build/codemodel/jdk/JdkExpressionConverter.java +++ b/jdk-codemodel/src/main/java/build/codemodel/jdk/JdkExpressionConverter.java @@ -47,7 +47,9 @@ import build.codemodel.imperative.Block; import build.codemodel.imperative.Statement; import build.codemodel.jdk.expression.ArrayAccess; +import build.codemodel.jdk.expression.AssignmentOperator; import build.codemodel.jdk.expression.BitwiseBinary; +import build.codemodel.jdk.expression.BitwiseOperator; import build.codemodel.jdk.expression.CharLiteral; import build.codemodel.jdk.expression.CompoundAssignment; import build.codemodel.jdk.expression.FieldAccess; @@ -61,7 +63,9 @@ import build.codemodel.jdk.expression.NewObject; import build.codemodel.jdk.expression.NullLiteral; import build.codemodel.jdk.expression.Parenthesized; +import build.codemodel.jdk.expression.PostfixOperator; import build.codemodel.jdk.expression.PostfixUnary; +import build.codemodel.jdk.expression.PrefixOperator; import build.codemodel.jdk.expression.PrefixUnary; import build.codemodel.jdk.expression.SwitchExpression; import build.codemodel.jdk.expression.Ternary; @@ -326,15 +330,28 @@ public Expression visitConditionalExpression(final ConditionalExpressionTree t, @Override public Expression visitAssignment(final AssignmentTree t, final Void v) { - return CompoundAssignment.of(codeModel, "ASSIGNMENT", + return CompoundAssignment.of(codeModel, AssignmentOperator.ASSIGN, convert(t.getVariable()), convert(t.getExpression())); } @Override public Expression visitCompoundAssignment(final CompoundAssignmentTree t, final Void v) { - return CompoundAssignment.of(codeModel, - t.getKind().toString(), + final var op = switch (t.getKind()) { + case PLUS_ASSIGNMENT -> AssignmentOperator.PLUS; + case MINUS_ASSIGNMENT -> AssignmentOperator.MINUS; + case MULTIPLY_ASSIGNMENT -> AssignmentOperator.MULTIPLY; + case DIVIDE_ASSIGNMENT -> AssignmentOperator.DIVIDE; + case REMAINDER_ASSIGNMENT -> AssignmentOperator.REMAINDER; + case AND_ASSIGNMENT -> AssignmentOperator.AND; + case OR_ASSIGNMENT -> AssignmentOperator.OR; + case XOR_ASSIGNMENT -> AssignmentOperator.XOR; + case LEFT_SHIFT_ASSIGNMENT -> AssignmentOperator.LEFT_SHIFT; + case RIGHT_SHIFT_ASSIGNMENT -> AssignmentOperator.RIGHT_SHIFT; + case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT -> AssignmentOperator.UNSIGNED_RIGHT_SHIFT; + default -> throw new IllegalArgumentException("Unexpected compound assignment kind: " + t.getKind()); + }; + return CompoundAssignment.of(codeModel, op, convert(t.getVariable()), convert(t.getExpression())); } @@ -357,8 +374,12 @@ public Expression visitBinary(final BinaryTree t, final Void v) { case GREATER_THAN_EQUAL -> GreaterThanOrEqualTo.of(left, right); case CONDITIONAL_AND -> Conjunction.of(left, right); case CONDITIONAL_OR -> Disjunction.of(left, right); - case AND, OR, XOR, LEFT_SHIFT, RIGHT_SHIFT, UNSIGNED_RIGHT_SHIFT -> - BitwiseBinary.of(codeModel, t.getKind().toString(), left, right); + case AND -> BitwiseBinary.of(codeModel, BitwiseOperator.AND, left, right); + case OR -> BitwiseBinary.of(codeModel, BitwiseOperator.OR, left, right); + case XOR -> BitwiseBinary.of(codeModel, BitwiseOperator.XOR, left, right); + case LEFT_SHIFT -> BitwiseBinary.of(codeModel, BitwiseOperator.LEFT_SHIFT, left, right); + case RIGHT_SHIFT -> BitwiseBinary.of(codeModel, BitwiseOperator.RIGHT_SHIFT, left, right); + case UNSIGNED_RIGHT_SHIFT -> BitwiseBinary.of(codeModel, BitwiseOperator.UNSIGNED_RIGHT_SHIFT, left, right); default -> UnknownExpression.of(codeModel); }; } @@ -367,10 +388,12 @@ public Expression visitBinary(final BinaryTree t, final Void v) { public Expression visitUnary(final UnaryTree t, final Void v) { final var operand = convert(t.getExpression()); return switch (t.getKind()) { - case PREFIX_INCREMENT, PREFIX_DECREMENT, BITWISE_COMPLEMENT, UNARY_PLUS -> - PrefixUnary.of(codeModel, t.getKind().toString(), operand); - case POSTFIX_INCREMENT, POSTFIX_DECREMENT -> - PostfixUnary.of(codeModel, t.getKind().toString(), operand); + case PREFIX_INCREMENT -> PrefixUnary.of(codeModel, PrefixOperator.INCREMENT, operand); + case PREFIX_DECREMENT -> PrefixUnary.of(codeModel, PrefixOperator.DECREMENT, operand); + case BITWISE_COMPLEMENT -> PrefixUnary.of(codeModel, PrefixOperator.BITWISE_COMPLEMENT, operand); + case UNARY_PLUS -> PrefixUnary.of(codeModel, PrefixOperator.UNARY_PLUS, operand); + case POSTFIX_INCREMENT -> PostfixUnary.of(codeModel, PostfixOperator.INCREMENT, operand); + case POSTFIX_DECREMENT -> PostfixUnary.of(codeModel, PostfixOperator.DECREMENT, operand); case UNARY_MINUS -> Negative.of(operand); case LOGICAL_COMPLEMENT -> Negation.of(operand); default -> UnknownExpression.of(codeModel); diff --git a/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/AssignmentOperator.java b/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/AssignmentOperator.java new file mode 100644 index 0000000..7885d46 --- /dev/null +++ b/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/AssignmentOperator.java @@ -0,0 +1,54 @@ +package build.codemodel.jdk.expression; + +/*- + * #%L + * JDK Code Model + * %% + * Copyright (C) 2026 Workday, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +/** + * The operator of a {@link CompoundAssignment} expression. + * + * @author reed.vonredwitz + * @since Apr-2026 + */ +public enum AssignmentOperator { + /** Simple assignment: {@code x = y} */ + ASSIGN, + /** Addition assignment: {@code x += y} */ + PLUS, + /** Subtraction assignment: {@code x -= y} */ + MINUS, + /** Multiplication assignment: {@code x *= y} */ + MULTIPLY, + /** Division assignment: {@code x /= y} */ + DIVIDE, + /** Remainder assignment: {@code x %= y} */ + REMAINDER, + /** Bitwise AND assignment: {@code x &= y} */ + AND, + /** Bitwise OR assignment: {@code x |= y} */ + OR, + /** Bitwise XOR assignment: {@code x ^= y} */ + XOR, + /** Left shift assignment: {@code x <<= y} */ + LEFT_SHIFT, + /** Signed right shift assignment: {@code x >>= y} */ + RIGHT_SHIFT, + /** Unsigned right shift assignment: {@code x >>>= y} */ + UNSIGNED_RIGHT_SHIFT +} diff --git a/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/BitwiseBinary.java b/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/BitwiseBinary.java index baa4388..23469a2 100644 --- a/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/BitwiseBinary.java +++ b/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/BitwiseBinary.java @@ -9,9 +9,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -47,9 +47,9 @@ public final class BitwiseBinary extends AbstractExpression { /** - * The operator kind string (e.g. {@code "AND"}, {@code "LEFT_SHIFT"}). + * The operator. */ - private final String operator; + private final BitwiseOperator operator; /** * The left-hand-side operand. @@ -62,7 +62,7 @@ public final class BitwiseBinary private final Expression right; private BitwiseBinary(final CodeModel codeModel, - final String operator, + final BitwiseOperator operator, final Expression left, final Expression right) { super(codeModel); @@ -79,7 +79,7 @@ public BitwiseBinary(@Bound final CodeModel codeModel, final Marshalled left, final Marshalled right) { super(codeModel, marshaller, traits); - this.operator = operator; + this.operator = BitwiseOperator.valueOf(operator); this.left = marshaller.unmarshal(left); this.right = marshaller.unmarshal(right); } @@ -91,17 +91,17 @@ public void destructor(final Marshaller marshaller, final Out> left, final Out> right) { super.destructor(marshaller, traits); - operator.set(this.operator); + operator.set(this.operator.name()); left.set(marshaller.marshal(this.left)); right.set(marshaller.marshal(this.right)); } /** - * Obtains the operator kind string. + * Obtains the operator. * - * @return the operator kind string + * @return the {@link BitwiseOperator} */ - public String operator() { + public BitwiseOperator operator() { return this.operator; } @@ -126,7 +126,7 @@ public Expression right() { @Override public boolean equals(final Object object) { return object instanceof BitwiseBinary other - && Objects.equals(this.operator, other.operator) + && this.operator == other.operator && Objects.equals(this.left, other.left) && Objects.equals(this.right, other.right) && super.equals(other); @@ -136,13 +136,13 @@ public boolean equals(final Object object) { * Creates a {@link BitwiseBinary} expression. * * @param codeModel the {@link CodeModel} - * @param operator the operator kind string - * @param left the left-hand-side {@link Expression} - * @param right the right-hand-side {@link Expression} + * @param operator the {@link BitwiseOperator} + * @param left the left-hand-side {@link Expression} + * @param right the right-hand-side {@link Expression} * @return a new {@link BitwiseBinary} */ public static BitwiseBinary of(final CodeModel codeModel, - final String operator, + final BitwiseOperator operator, final Expression left, final Expression right) { return new BitwiseBinary(codeModel, operator, left, right); diff --git a/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/BitwiseOperator.java b/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/BitwiseOperator.java new file mode 100644 index 0000000..fdf772e --- /dev/null +++ b/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/BitwiseOperator.java @@ -0,0 +1,42 @@ +package build.codemodel.jdk.expression; + +/*- + * #%L + * JDK Code Model + * %% + * Copyright (C) 2026 Workday, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +/** + * The operator of a {@link BitwiseBinary} expression. + * + * @author reed.vonredwitz + * @since Apr-2026 + */ +public enum BitwiseOperator { + /** Bitwise AND: {@code a & b} */ + AND, + /** Bitwise OR: {@code a | b} */ + OR, + /** Bitwise XOR: {@code a ^ b} */ + XOR, + /** Left shift: {@code a << b} */ + LEFT_SHIFT, + /** Signed right shift: {@code a >> b} */ + RIGHT_SHIFT, + /** Unsigned right shift: {@code a >>> b} */ + UNSIGNED_RIGHT_SHIFT +} diff --git a/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/CompoundAssignment.java b/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/CompoundAssignment.java index e518f4e..4350cec 100644 --- a/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/CompoundAssignment.java +++ b/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/CompoundAssignment.java @@ -9,9 +9,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -37,8 +37,7 @@ import java.util.stream.Stream; /** - * A compound assignment expression: {@code var OP= value} (e.g. {@code x += 1}). - * Also used for simple assignment {@code var = value} when the operator is {@code "ASSIGNMENT"}. + * An assignment expression: simple {@code x = y} or compound {@code x += y}, {@code x <<= y}, etc. * * @author reed.vonredwitz * @since Mar-2026 @@ -47,9 +46,9 @@ public final class CompoundAssignment extends AbstractExpression { /** - * The operator kind string (e.g. {@code "PLUS_ASSIGNMENT"}, {@code "ASSIGNMENT"}). + * The operator. */ - private final String operator; + private final AssignmentOperator operator; /** * The left-hand-side variable expression. @@ -62,7 +61,7 @@ public final class CompoundAssignment private final Expression value; private CompoundAssignment(final CodeModel codeModel, - final String operator, + final AssignmentOperator operator, final Expression variable, final Expression value) { super(codeModel); @@ -79,7 +78,7 @@ public CompoundAssignment(@Bound final CodeModel codeModel, final Marshalled variable, final Marshalled value) { super(codeModel, marshaller, traits); - this.operator = operator; + this.operator = AssignmentOperator.valueOf(operator); this.variable = marshaller.unmarshal(variable); this.value = marshaller.unmarshal(value); } @@ -91,17 +90,17 @@ public void destructor(final Marshaller marshaller, final Out> variable, final Out> value) { super.destructor(marshaller, traits); - operator.set(this.operator); + operator.set(this.operator.name()); variable.set(marshaller.marshal(this.variable)); value.set(marshaller.marshal(this.value)); } /** - * Obtains the operator kind string. + * Obtains the operator. * - * @return the operator kind string + * @return the {@link AssignmentOperator} */ - public String operator() { + public AssignmentOperator operator() { return this.operator; } @@ -126,7 +125,7 @@ public Expression value() { @Override public boolean equals(final Object object) { return object instanceof CompoundAssignment other - && Objects.equals(this.operator, other.operator) + && this.operator == other.operator && Objects.equals(this.variable, other.variable) && Objects.equals(this.value, other.value) && super.equals(other); @@ -136,13 +135,13 @@ public boolean equals(final Object object) { * Creates a {@link CompoundAssignment} expression. * * @param codeModel the {@link CodeModel} - * @param operator the operator kind string - * @param variable the left-hand-side variable {@link Expression} - * @param value the right-hand-side value {@link Expression} + * @param operator the {@link AssignmentOperator} + * @param variable the left-hand-side variable {@link Expression} + * @param value the right-hand-side value {@link Expression} * @return a new {@link CompoundAssignment} */ public static CompoundAssignment of(final CodeModel codeModel, - final String operator, + final AssignmentOperator operator, final Expression variable, final Expression value) { return new CompoundAssignment(codeModel, operator, variable, value); diff --git a/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/PostfixOperator.java b/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/PostfixOperator.java new file mode 100644 index 0000000..8581b24 --- /dev/null +++ b/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/PostfixOperator.java @@ -0,0 +1,34 @@ +package build.codemodel.jdk.expression; + +/*- + * #%L + * JDK Code Model + * %% + * Copyright (C) 2026 Workday, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +/** + * The operator of a {@link PostfixUnary} expression. + * + * @author reed.vonredwitz + * @since Apr-2026 + */ +public enum PostfixOperator { + /** Post-increment: {@code x++} */ + INCREMENT, + /** Post-decrement: {@code x--} */ + DECREMENT +} diff --git a/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/PostfixUnary.java b/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/PostfixUnary.java index 2e12c1c..4231052 100644 --- a/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/PostfixUnary.java +++ b/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/PostfixUnary.java @@ -9,9 +9,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -46,9 +46,9 @@ public final class PostfixUnary extends AbstractExpression { /** - * The operator kind string (e.g. {@code "POSTFIX_INCREMENT"}). + * The operator. */ - private final String operator; + private final PostfixOperator operator; /** * The operand expression. @@ -56,7 +56,7 @@ public final class PostfixUnary private final Expression operand; private PostfixUnary(final CodeModel codeModel, - final String operator, + final PostfixOperator operator, final Expression operand) { super(codeModel); this.operator = Objects.requireNonNull(operator, "operator must not be null"); @@ -70,7 +70,7 @@ public PostfixUnary(@Bound final CodeModel codeModel, final String operator, final Marshalled operand) { super(codeModel, marshaller, traits); - this.operator = operator; + this.operator = PostfixOperator.valueOf(operator); this.operand = marshaller.unmarshal(operand); } @@ -80,16 +80,16 @@ public void destructor(final Marshaller marshaller, final Out operator, final Out> operand) { super.destructor(marshaller, traits); - operator.set(this.operator); + operator.set(this.operator.name()); operand.set(marshaller.marshal(this.operand)); } /** - * Obtains the operator kind string. + * Obtains the operator. * - * @return the operator kind string + * @return the {@link PostfixOperator} */ - public String operator() { + public PostfixOperator operator() { return this.operator; } @@ -105,7 +105,7 @@ public Expression operand() { @Override public boolean equals(final Object object) { return object instanceof PostfixUnary other - && Objects.equals(this.operator, other.operator) + && this.operator == other.operator && Objects.equals(this.operand, other.operand) && super.equals(other); } @@ -114,12 +114,12 @@ public boolean equals(final Object object) { * Creates a {@link PostfixUnary} expression. * * @param codeModel the {@link CodeModel} - * @param operator the operator kind string - * @param operand the operand {@link Expression} + * @param operator the {@link PostfixOperator} + * @param operand the operand {@link Expression} * @return a new {@link PostfixUnary} */ public static PostfixUnary of(final CodeModel codeModel, - final String operator, + final PostfixOperator operator, final Expression operand) { return new PostfixUnary(codeModel, operator, operand); } diff --git a/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/PrefixOperator.java b/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/PrefixOperator.java new file mode 100644 index 0000000..c0bb8e4 --- /dev/null +++ b/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/PrefixOperator.java @@ -0,0 +1,38 @@ +package build.codemodel.jdk.expression; + +/*- + * #%L + * JDK Code Model + * %% + * Copyright (C) 2026 Workday, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +/** + * The operator of a {@link PrefixUnary} expression. + * + * @author reed.vonredwitz + * @since Apr-2026 + */ +public enum PrefixOperator { + /** Pre-increment: {@code ++x} */ + INCREMENT, + /** Pre-decrement: {@code --x} */ + DECREMENT, + /** Bitwise complement: {@code ~x} */ + BITWISE_COMPLEMENT, + /** Unary plus: {@code +x} */ + UNARY_PLUS +} diff --git a/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/PrefixUnary.java b/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/PrefixUnary.java index dffabbd..e77101f 100644 --- a/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/PrefixUnary.java +++ b/jdk-codemodel/src/main/java/build/codemodel/jdk/expression/PrefixUnary.java @@ -9,9 +9,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -46,9 +46,9 @@ public final class PrefixUnary extends AbstractExpression { /** - * The operator kind string (e.g. {@code "PREFIX_INCREMENT"}, {@code "BITWISE_COMPLEMENT"}). + * The operator. */ - private final String operator; + private final PrefixOperator operator; /** * The operand expression. @@ -56,7 +56,7 @@ public final class PrefixUnary private final Expression operand; private PrefixUnary(final CodeModel codeModel, - final String operator, + final PrefixOperator operator, final Expression operand) { super(codeModel); this.operator = Objects.requireNonNull(operator, "operator must not be null"); @@ -70,7 +70,7 @@ public PrefixUnary(@Bound final CodeModel codeModel, final String operator, final Marshalled operand) { super(codeModel, marshaller, traits); - this.operator = operator; + this.operator = PrefixOperator.valueOf(operator); this.operand = marshaller.unmarshal(operand); } @@ -80,16 +80,16 @@ public void destructor(final Marshaller marshaller, final Out operator, final Out> operand) { super.destructor(marshaller, traits); - operator.set(this.operator); + operator.set(this.operator.name()); operand.set(marshaller.marshal(this.operand)); } /** - * Obtains the operator kind string. + * Obtains the operator. * - * @return the operator kind string + * @return the {@link PrefixOperator} */ - public String operator() { + public PrefixOperator operator() { return this.operator; } @@ -105,7 +105,7 @@ public Expression operand() { @Override public boolean equals(final Object object) { return object instanceof PrefixUnary other - && Objects.equals(this.operator, other.operator) + && this.operator == other.operator && Objects.equals(this.operand, other.operand) && super.equals(other); } @@ -114,12 +114,12 @@ public boolean equals(final Object object) { * Creates a {@link PrefixUnary} expression. * * @param codeModel the {@link CodeModel} - * @param operator the operator kind string - * @param operand the operand {@link Expression} + * @param operator the {@link PrefixOperator} + * @param operand the operand {@link Expression} * @return a new {@link PrefixUnary} */ public static PrefixUnary of(final CodeModel codeModel, - final String operator, + final PrefixOperator operator, final Expression operand) { return new PrefixUnary(codeModel, operator, operand); } diff --git a/jdk-codemodel/src/test/java/build/codemodel/jdk/ExpressionCaptureFidelityTests.java b/jdk-codemodel/src/test/java/build/codemodel/jdk/ExpressionCaptureFidelityTests.java index 0d914bf..886bdc4 100644 --- a/jdk-codemodel/src/test/java/build/codemodel/jdk/ExpressionCaptureFidelityTests.java +++ b/jdk-codemodel/src/test/java/build/codemodel/jdk/ExpressionCaptureFidelityTests.java @@ -24,9 +24,18 @@ import build.codemodel.foundation.usage.NamedTypeUsage; import build.codemodel.imperative.Return; import build.codemodel.jdk.descriptor.MethodBodyDescriptor; +import build.codemodel.jdk.expression.AssignmentOperator; +import build.codemodel.jdk.expression.BitwiseBinary; +import build.codemodel.jdk.expression.BitwiseOperator; +import build.codemodel.jdk.expression.CompoundAssignment; import build.codemodel.jdk.expression.InstanceOf; import build.codemodel.jdk.expression.NewArray; import build.codemodel.jdk.expression.NewObject; +import build.codemodel.jdk.expression.PostfixOperator; +import build.codemodel.jdk.expression.PostfixUnary; +import build.codemodel.jdk.expression.PrefixOperator; +import build.codemodel.jdk.expression.PrefixUnary; +import build.codemodel.jdk.statement.ExpressionStatement; import build.codemodel.jdk.statement.LocalVariableDeclaration; import build.codemodel.objectoriented.descriptor.MethodDescriptor; import com.google.testing.compile.JavaFileObjects; @@ -168,4 +177,96 @@ public String[] create(int n) { assertThat(newArray.elementType()).isInstanceOf(NamedTypeUsage.class); assertThat(((NamedTypeUsage) newArray.elementType()).typeName().canonicalName()).isEqualTo("java.lang.String"); } + + @Test + void shouldCaptureBitwiseOperator() { + final var source = JavaFileObjects.forSourceString( + "build.codemodel.jdk.example.Bits", """ + package build.codemodel.jdk.example; + public class Bits { + public int run(int a, int b) { return a << b; } + } + """); + + final var codeModel = JdkInitializerTests.runInternal( + new JdkInitializer(List.of(), List.of(), List.of(source))); + + final var typeName = codeModel.getNameProvider() + .getTypeName(Optional.empty(), "build.codemodel.jdk.example.Bits"); + final var body = codeModel.getTypeDescriptor(typeName).orElseThrow() + .traits(MethodDescriptor.class).findFirst().orElseThrow() + .getTrait(MethodBodyDescriptor.class).orElseThrow().body(); + final var bitwise = (BitwiseBinary) ((Return) body.statements().findFirst().orElseThrow()).expression(); + + assertThat(bitwise.operator()).isEqualTo(BitwiseOperator.LEFT_SHIFT); + } + + @Test + void shouldCapturePrefixOperator() { + final var source = JavaFileObjects.forSourceString( + "build.codemodel.jdk.example.Counter", """ + package build.codemodel.jdk.example; + public class Counter { + public int run(int x) { return ++x; } + } + """); + + final var codeModel = JdkInitializerTests.runInternal( + new JdkInitializer(List.of(), List.of(), List.of(source))); + + final var typeName = codeModel.getNameProvider() + .getTypeName(Optional.empty(), "build.codemodel.jdk.example.Counter"); + final var body = codeModel.getTypeDescriptor(typeName).orElseThrow() + .traits(MethodDescriptor.class).findFirst().orElseThrow() + .getTrait(MethodBodyDescriptor.class).orElseThrow().body(); + final var prefix = (PrefixUnary) ((Return) body.statements().findFirst().orElseThrow()).expression(); + + assertThat(prefix.operator()).isEqualTo(PrefixOperator.INCREMENT); + } + + @Test + void shouldCapturePostfixOperator() { + final var source = JavaFileObjects.forSourceString( + "build.codemodel.jdk.example.Postfix", """ + package build.codemodel.jdk.example; + public class Postfix { + public void run(int[] arr) { arr[0]--; } + } + """); + + final var codeModel = JdkInitializerTests.runInternal( + new JdkInitializer(List.of(), List.of(), List.of(source))); + + final var typeName = codeModel.getNameProvider() + .getTypeName(Optional.empty(), "build.codemodel.jdk.example.Postfix"); + final var body = codeModel.getTypeDescriptor(typeName).orElseThrow() + .traits(MethodDescriptor.class).findFirst().orElseThrow() + .getTrait(MethodBodyDescriptor.class).orElseThrow().body(); + final var postfix = (PostfixUnary) ((ExpressionStatement) body.statements().findFirst().orElseThrow()).expression(); + + assertThat(postfix.operator()).isEqualTo(PostfixOperator.DECREMENT); + } + + @Test + void shouldCaptureAssignmentOperator() { + final var source = JavaFileObjects.forSourceString( + "build.codemodel.jdk.example.Assigner", """ + package build.codemodel.jdk.example; + public class Assigner { + public void run(int[] arr) { arr[0] += 1; } + } + """); + + final var codeModel = JdkInitializerTests.runInternal( + new JdkInitializer(List.of(), List.of(), List.of(source))); + + final var typeName = codeModel.getNameProvider() + .getTypeName(Optional.empty(), "build.codemodel.jdk.example.Assigner"); + final var body = codeModel.getTypeDescriptor(typeName).orElseThrow() + .traits(MethodDescriptor.class).findFirst().orElseThrow() + .getTrait(MethodBodyDescriptor.class).orElseThrow().body(); + final var assign = (CompoundAssignment) ((ExpressionStatement) body.statements().findFirst().orElseThrow()).expression(); + + assertThat(assign.operator()).isEqualTo(AssignmentOperator.PLUS); + } }