diff --git a/doc/code_elements.md b/doc/code_elements.md index 94013311036..12892f2fa99 100644 --- a/doc/code_elements.md +++ b/doc/code_elements.md @@ -324,6 +324,18 @@ switch(x) { // <-- switch statement System.out.println("foo"); } ``` +### CtSwitchExpression +[(javadoc)](http://spoon.gforge.inria.fr/mvnsites/spoon-core/apidocs/spoon/reflect/code/CtSwitchExpression.html) + +```java + +int i = 0; +int x = switch(i) { // <-- switch expression + case 1 -> 10; + case 2 -> 20; + default -> 30; +}; +``` ### CtSynchronized [(javadoc)](http://spoon.gforge.inria.fr/mvnsites/spoon-core/apidocs/spoon/reflect/code/CtSynchronized.html) diff --git a/pom.xml b/pom.xml index 32c52041431..4f13da2ab97 100644 --- a/pom.xml +++ b/pom.xml @@ -40,7 +40,7 @@ org.eclipse.jdt org.eclipse.jdt.core - 3.16.0 + 3.18.0 org.eclipse.platform diff --git a/src/main/java/spoon/compiler/Environment.java b/src/main/java/spoon/compiler/Environment.java index ef2f928ee14..65a9eb73cb2 100644 --- a/src/main/java/spoon/compiler/Environment.java +++ b/src/main/java/spoon/compiler/Environment.java @@ -43,6 +43,17 @@ public interface Environment { */ void setComplianceLevel(int level); + /** + * Returns true if preview language features are enabled. + */ + boolean isPreviewFeaturesEnabled(); + + /** + * Set to true to enable latest preview language features. + * Note: compliance level should be set to the latest. + */ + void setPreviewFeaturesEnabled(boolean enabled); + /** * @return the kind of pretty-printing expected. * most robust: {@link PRETTY_PRINTING_MODE#DEBUG} diff --git a/src/main/java/spoon/compiler/builder/ComplianceOptions.java b/src/main/java/spoon/compiler/builder/ComplianceOptions.java index 4d424d35117..e9164bae9c8 100644 --- a/src/main/java/spoon/compiler/builder/ComplianceOptions.java +++ b/src/main/java/spoon/compiler/builder/ComplianceOptions.java @@ -19,4 +19,9 @@ public T compliance(int version) { return myself; } + + public T enablePreview() { + args.add("--enable-preview"); + return myself; + } } diff --git a/src/main/java/spoon/metamodel/Metamodel.java b/src/main/java/spoon/metamodel/Metamodel.java index b47178e3794..ad3ab7c8620 100644 --- a/src/main/java/spoon/metamodel/Metamodel.java +++ b/src/main/java/spoon/metamodel/Metamodel.java @@ -60,6 +60,7 @@ public static Set> getAllMetamodelInterfaces() { factory.getEnvironment().setLevel("INFO"); result.add(factory.Type().get(spoon.reflect.code.BinaryOperatorKind.class)); result.add(factory.Type().get(spoon.reflect.code.CtAbstractInvocation.class)); + result.add(factory.Type().get(spoon.reflect.code.CtAbstractSwitch.class)); result.add(factory.Type().get(spoon.reflect.code.CtAnnotationFieldAccess.class)); result.add(factory.Type().get(spoon.reflect.code.CtArrayAccess.class)); result.add(factory.Type().get(spoon.reflect.code.CtArrayRead.class)); @@ -107,6 +108,7 @@ public static Set> getAllMetamodelInterfaces() { result.add(factory.Type().get(spoon.reflect.code.CtStatementList.class)); result.add(factory.Type().get(spoon.reflect.code.CtSuperAccess.class)); result.add(factory.Type().get(spoon.reflect.code.CtSwitch.class)); + result.add(factory.Type().get(spoon.reflect.code.CtSwitchExpression.class)); result.add(factory.Type().get(spoon.reflect.code.CtSynchronized.class)); result.add(factory.Type().get(spoon.reflect.code.CtTargetedExpression.class)); result.add(factory.Type().get(spoon.reflect.code.CtThisAccess.class)); @@ -121,6 +123,7 @@ public static Set> getAllMetamodelInterfaces() { result.add(factory.Type().get(spoon.reflect.code.CtWhile.class)); result.add(factory.Type().get(spoon.reflect.code.UnaryOperatorKind.class)); result.add(factory.Type().get(spoon.reflect.code.LiteralBase.class)); + result.add(factory.Type().get(spoon.reflect.code.CaseKind.class)); result.add(factory.Type().get(spoon.reflect.declaration.CtAnnotatedElementType.class)); result.add(factory.Type().get(spoon.reflect.declaration.CtAnnotation.class)); result.add(factory.Type().get(spoon.reflect.declaration.CtAnnotationMethod.class)); diff --git a/src/main/java/spoon/reflect/ModelElementContainerDefaultCapacities.java b/src/main/java/spoon/reflect/ModelElementContainerDefaultCapacities.java index bef7b28b310..6d0ffcaa5e6 100644 --- a/src/main/java/spoon/reflect/ModelElementContainerDefaultCapacities.java +++ b/src/main/java/spoon/reflect/ModelElementContainerDefaultCapacities.java @@ -92,6 +92,9 @@ public final class ModelElementContainerDefaultCapacities { // > 1 very rarely public static final int TYPE_BOUNDS_CONTAINER_DEFAULT_CAPACITY = 1; + // > 1 allowed only since Java 12 + public static final int CASE_EXPRESSIONS_CONTAINER_DEFAULT_CAPACITY = 1; + private ModelElementContainerDefaultCapacities() { } } diff --git a/src/main/java/spoon/reflect/code/CaseKind.java b/src/main/java/spoon/reflect/code/CaseKind.java new file mode 100644 index 00000000000..a6223f741a6 --- /dev/null +++ b/src/main/java/spoon/reflect/code/CaseKind.java @@ -0,0 +1,11 @@ +/** + * Copyright (C) 2006-2019 INRIA and contributors + * + * Spoon is available either under the terms of the MIT License (see LICENSE-MIT.txt) of the Cecill-C License (see LICENSE-CECILL-C.txt). You as the user are entitled to choose the terms under which to adopt Spoon. + */ +package spoon.reflect.code; + +public enum CaseKind { + COLON, + ARROW, +} diff --git a/src/main/java/spoon/reflect/code/CtAbstractSwitch.java b/src/main/java/spoon/reflect/code/CtAbstractSwitch.java new file mode 100644 index 00000000000..57eed80fd69 --- /dev/null +++ b/src/main/java/spoon/reflect/code/CtAbstractSwitch.java @@ -0,0 +1,66 @@ +/** + * Copyright (C) 2006-2019 INRIA and contributors + * + * Spoon is available either under the terms of the MIT License (see LICENSE-MIT.txt) of the Cecill-C License (see LICENSE-CECILL-C.txt). You as the user are entitled to choose the terms under which to adopt Spoon. + */ +package spoon.reflect.code; + +import spoon.reflect.annotations.PropertyGetter; +import spoon.reflect.annotations.PropertySetter; +import spoon.reflect.declaration.CtElement; + +import java.util.List; + +import static spoon.reflect.path.CtRole.CASE; +import static spoon.reflect.path.CtRole.EXPRESSION; + +/** + * This code element defines an abstract switch + * (either switch statement or switch expression). + * + * @param + * the type of the selector expression + */ +public interface CtAbstractSwitch extends CtElement { + /** + * Gets the selector. The type of the Expression must be char, + * byte, short, int, + * Character, Byte, Short, + * Integer, or an enum type + */ + @PropertyGetter(role = EXPRESSION) + CtExpression getSelector(); + + /** + * Sets the selector. The type of the Expression must be char, + * byte, short, int, + * Character, Byte, Short, + * Integer, or an enum type + */ + @PropertySetter(role = EXPRESSION) + > T setSelector(CtExpression selector); + + /** + * Gets the list of cases defined for this switch. + */ + @PropertyGetter(role = CASE) + List> getCases(); + + /** + * Sets the list of cases defined for this switch. + */ + @PropertySetter(role = CASE) + > T setCases(List> cases); + + /** + * Adds a case; + */ + @PropertySetter(role = CASE) + > T addCase(CtCase c); + + /** + * Removes a case; + */ + @PropertySetter(role = CASE) + boolean removeCase(CtCase c); +} diff --git a/src/main/java/spoon/reflect/code/CtBreak.java b/src/main/java/spoon/reflect/code/CtBreak.java index 562e5ada69f..ba7bea74d54 100644 --- a/src/main/java/spoon/reflect/code/CtBreak.java +++ b/src/main/java/spoon/reflect/code/CtBreak.java @@ -5,6 +5,11 @@ */ package spoon.reflect.code; +import spoon.reflect.annotations.PropertyGetter; +import spoon.reflect.annotations.PropertySetter; + +import static spoon.reflect.path.CtRole.EXPRESSION; + /** * This code element defines a break statement. * Example: @@ -18,6 +23,22 @@ */ public interface CtBreak extends CtLabelledFlowBreak { + /** + * Gets the expression of the implicit brake with arrow syntax. + * Example: case 1 -> x = 10; (implicit brake with expression x = 10); + * (This syntax is available as a preview feature since Java 12) + */ + @PropertyGetter(role = EXPRESSION) + CtExpression getExpression(); + + /** + * Sets the expression of the implicit brake with arrow syntax. + * Example: case 1 -> x = 10; (implicit brake with expression x = 10); + * (This syntax is available as a preview feature since Java 12) + */ + @PropertySetter(role = EXPRESSION) + T setExpression(CtExpression expression); + @Override CtBreak clone(); } diff --git a/src/main/java/spoon/reflect/code/CtCase.java b/src/main/java/spoon/reflect/code/CtCase.java index 578c72fee34..a89bf91e5d2 100644 --- a/src/main/java/spoon/reflect/code/CtCase.java +++ b/src/main/java/spoon/reflect/code/CtCase.java @@ -8,6 +8,9 @@ import spoon.reflect.annotations.PropertyGetter; import spoon.reflect.annotations.PropertySetter; +import java.util.List; + +import static spoon.reflect.path.CtRole.CASE_KIND; import static spoon.reflect.path.CtRole.EXPRESSION; /** @@ -27,16 +30,53 @@ public interface CtCase extends CtStatement, CtStatementList { /** * Gets the case expression. + * Use {@link #getCaseExpressions()} since Java 12 */ @PropertyGetter(role = EXPRESSION) CtExpression getCaseExpression(); /** * Sets the case expression. + * Use {@link #setCaseExpressions(List)} since Java 12 */ @PropertySetter(role = EXPRESSION) > T setCaseExpression(CtExpression caseExpression); + /** + * Gets the case expressions. + * (Multiple case expressions are available as a preview feature since Java 12) + */ + @PropertyGetter(role = EXPRESSION) + List> getCaseExpressions(); + + /** + * Sets the case expressions. + * (Multiple case expressions are available as a preview feature since Java 12) + */ + @PropertySetter(role = EXPRESSION) + > T setCaseExpressions(List> caseExpressions); + + /** + * Adds case expression. + * (Multiple case expressions are available as a preview feature since Java 12) + */ + @PropertySetter(role = EXPRESSION) + > T addCaseExpression(CtExpression caseExpression); + + /** + * Gets the kind of this case - colon (:) or arrow (->) + * (Arrow syntax is available as a preview feature since Java 12) + */ + @PropertyGetter(role = CASE_KIND) + CaseKind getCaseKind(); + + /** + * Sets the kind of this case - colon (:) or arrow (->) + * (Arrow syntax is available as a preview feature since Java 12) + */ + @PropertySetter(role = CASE_KIND) + > T setCaseKind(CaseKind kind); + @Override CtCase clone(); } diff --git a/src/main/java/spoon/reflect/code/CtSwitch.java b/src/main/java/spoon/reflect/code/CtSwitch.java index 4b585e38080..be92372e60a 100644 --- a/src/main/java/spoon/reflect/code/CtSwitch.java +++ b/src/main/java/spoon/reflect/code/CtSwitch.java @@ -5,14 +5,6 @@ */ package spoon.reflect.code; -import spoon.reflect.annotations.PropertyGetter; -import spoon.reflect.annotations.PropertySetter; - -import java.util.List; - -import static spoon.reflect.path.CtRole.CASE; -import static spoon.reflect.path.CtRole.EXPRESSION; - /** * This code element defines a switch statement. * @@ -29,48 +21,7 @@ * type hierarchy, especially since the enums that make things even * worse!) */ -public interface CtSwitch extends CtStatement { - /** - * Gets the selector. The type of the Expression must be char, - * byte, short, int, - * Character, Byte, Short, - * Integer, or an enum type - */ - @PropertyGetter(role = EXPRESSION) - CtExpression getSelector(); - - /** - * Sets the selector. The type of the Expression must be char, - * byte, short, int, - * Character, Byte, Short, - * Integer, or an enum type - */ - @PropertySetter(role = EXPRESSION) - > T setSelector(CtExpression selector); - - /** - * Gets the list of cases defined for this switch. - */ - @PropertyGetter(role = CASE) - List> getCases(); - - /** - * Sets the list of cases defined for this switch. - */ - @PropertySetter(role = CASE) - > T setCases(List> cases); - - /** - * Adds a case; - */ - @PropertySetter(role = CASE) - > T addCase(CtCase c); - - /** - * Removes a case; - */ - @PropertySetter(role = CASE) - boolean removeCase(CtCase c); +public interface CtSwitch extends CtStatement, CtAbstractSwitch { @Override CtSwitch clone(); diff --git a/src/main/java/spoon/reflect/code/CtSwitchExpression.java b/src/main/java/spoon/reflect/code/CtSwitchExpression.java new file mode 100644 index 00000000000..50bb7285480 --- /dev/null +++ b/src/main/java/spoon/reflect/code/CtSwitchExpression.java @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2006-2019 INRIA and contributors + * + * Spoon is available either under the terms of the MIT License (see LICENSE-MIT.txt) of the Cecill-C License (see LICENSE-CECILL-C.txt). You as the user are entitled to choose the terms under which to adopt Spoon. + */ +package spoon.reflect.code; + +/** + * This code element defines a switch expression. + * + * Example:
+ * int i = 0;
+ * int x = switch(i) { // <-- switch expression
+ *     case 1 -> 10;
+ *     case 2 -> 20;
+ *     default -> 30;
+ * };
+ + * @param + * the type of the switch expression + * @param + * the type of the selector expression (it would be better to be able + * to define an upper bound, but it is not possible because of Java's + * type hierarchy, especially since the enums that make things even + * worse!) + */ +public interface CtSwitchExpression extends CtExpression, CtAbstractSwitch { + + @Override + CtSwitchExpression clone(); +} diff --git a/src/main/java/spoon/reflect/factory/CoreFactory.java b/src/main/java/spoon/reflect/factory/CoreFactory.java index 5cc9b83acb8..9f650eb28a2 100644 --- a/src/main/java/spoon/reflect/factory/CoreFactory.java +++ b/src/main/java/spoon/reflect/factory/CoreFactory.java @@ -43,6 +43,7 @@ import spoon.reflect.code.CtStatementList; import spoon.reflect.code.CtSuperAccess; import spoon.reflect.code.CtSwitch; +import spoon.reflect.code.CtSwitchExpression; import spoon.reflect.code.CtSynchronized; import spoon.reflect.code.CtThisAccess; import spoon.reflect.code.CtThrow; @@ -434,6 +435,11 @@ BodyHolderSourcePosition createBodyHolderSourcePosition( */ CtSwitch createSwitch(); + /** + * Creates a switch expression. + */ + CtSwitchExpression createSwitchExpression(); + /** * Creates a synchronized statement. */ diff --git a/src/main/java/spoon/reflect/factory/Factory.java b/src/main/java/spoon/reflect/factory/Factory.java index 5cc0d6aba64..f5f27c178aa 100644 --- a/src/main/java/spoon/reflect/factory/Factory.java +++ b/src/main/java/spoon/reflect/factory/Factory.java @@ -48,6 +48,7 @@ import spoon.reflect.code.CtStatementList; import spoon.reflect.code.CtSuperAccess; import spoon.reflect.code.CtSwitch; +import spoon.reflect.code.CtSwitchExpression; import spoon.reflect.code.CtSynchronized; import spoon.reflect.code.CtThisAccess; import spoon.reflect.code.CtThrow; @@ -408,6 +409,11 @@ public interface Factory { */ CtSwitch createSwitch(); + /** + * @see CoreFactory#createSwitchExpression() + */ + CtSwitchExpression createSwitchExpression(); + /** * @see CoreFactory#createEnum() */ diff --git a/src/main/java/spoon/reflect/factory/FactoryImpl.java b/src/main/java/spoon/reflect/factory/FactoryImpl.java index cdd3582c9bc..258f3f602a0 100644 --- a/src/main/java/spoon/reflect/factory/FactoryImpl.java +++ b/src/main/java/spoon/reflect/factory/FactoryImpl.java @@ -49,6 +49,7 @@ import spoon.reflect.code.CtStatementList; import spoon.reflect.code.CtSuperAccess; import spoon.reflect.code.CtSwitch; +import spoon.reflect.code.CtSwitchExpression; import spoon.reflect.code.CtSynchronized; import spoon.reflect.code.CtThisAccess; import spoon.reflect.code.CtThrow; @@ -671,6 +672,11 @@ public CtSwitch createSwitch() { return Core().createSwitch(); } + @Override + public CtSwitchExpression createSwitchExpression() { + return Core().createSwitchExpression(); + } + @Override public > CtEnum createEnum() { return Core().createEnum(); diff --git a/src/main/java/spoon/reflect/meta/impl/ModelRoleHandlers.java b/src/main/java/spoon/reflect/meta/impl/ModelRoleHandlers.java index 279fd9f56c3..0472a0d3aed 100644 --- a/src/main/java/spoon/reflect/meta/impl/ModelRoleHandlers.java +++ b/src/main/java/spoon/reflect/meta/impl/ModelRoleHandlers.java @@ -6,13 +6,16 @@ package spoon.reflect.meta.impl; import java.lang.annotation.Annotation; import spoon.reflect.code.BinaryOperatorKind; +import spoon.reflect.code.CaseKind; import spoon.reflect.code.CtAbstractInvocation; +import spoon.reflect.code.CtAbstractSwitch; import spoon.reflect.code.CtArrayAccess; import spoon.reflect.code.CtAssert; import spoon.reflect.code.CtAssignment; import spoon.reflect.code.CtBinaryOperator; import spoon.reflect.code.CtBlock; import spoon.reflect.code.CtBodyHolder; +import spoon.reflect.code.CtBreak; import spoon.reflect.code.CtCase; import spoon.reflect.code.CtCatch; import spoon.reflect.code.CtCatchVariable; @@ -37,7 +40,6 @@ import spoon.reflect.code.CtReturn; import spoon.reflect.code.CtStatement; import spoon.reflect.code.CtStatementList; -import spoon.reflect.code.CtSwitch; import spoon.reflect.code.CtSynchronized; import spoon.reflect.code.CtTargetedExpression; import spoon.reflect.code.CtThrow; @@ -107,7 +109,7 @@ class ModelRoleHandlers { private ModelRoleHandlers() { } - static final RoleHandler[] roleHandlers = new RoleHandler[]{ new CtTypeAccess_ACCESSED_TYPE_RoleHandler(), new CtClass_ANNONYMOUS_EXECUTABLE_RoleHandler(), new CtElement_ANNOTATION_RoleHandler(), new CtAnnotation_ANNOTATION_TYPE_RoleHandler(), new CtAbstractInvocation_ARGUMENT_RoleHandler(), new CtExecutableReference_ARGUMENT_TYPE_RoleHandler(), new CtAssignment_ASSIGNED_RoleHandler(), new CtRHSReceiver_ASSIGNMENT_RoleHandler(), new CtBodyHolder_BODY_RoleHandler(), new CtSynchronized_BODY_RoleHandler(), new CtIntersectionTypeReference_BOUND_RoleHandler(), new CtWildcardReference_BOUNDING_TYPE_RoleHandler(), new CtSwitch_CASE_RoleHandler(), new CtExpression_CAST_RoleHandler(), new CtTry_CATCH_RoleHandler(), new CtElement_COMMENT_RoleHandler(), new CtComment_COMMENT_CONTENT_RoleHandler(), new CtJavaDocTag_COMMENT_CONTENT_RoleHandler(), new CtJavaDoc_COMMENT_TAG_RoleHandler(), new CtComment_COMMENT_TYPE_RoleHandler(), new CtAssert_CONDITION_RoleHandler(), new CtConditional_CONDITION_RoleHandler(), new CtIf_CONDITION_RoleHandler(), new CtClass_CONSTRUCTOR_RoleHandler(), new CtPackage_CONTAINED_TYPE_RoleHandler(), new CtCompilationUnit_DECLARED_IMPORT_RoleHandler(), new CtCompilationUnit_DECLARED_MODULE_RoleHandler(), new CtCompilationUnit_DECLARED_MODULE_REF_RoleHandler(), new CtCompilationUnit_DECLARED_TYPE_RoleHandler(), new CtCompilationUnit_DECLARED_TYPE_REF_RoleHandler(), new CtExecutableReference_DECLARING_TYPE_RoleHandler(), new CtFieldReference_DECLARING_TYPE_RoleHandler(), new CtTypeReference_DECLARING_TYPE_RoleHandler(), new CtAnnotationMethod_DEFAULT_EXPRESSION_RoleHandler(), new CtVariable_DEFAULT_EXPRESSION_RoleHandler(), new CtNewArray_DIMENSION_RoleHandler(), new CtJavaDocTag_DOCUMENTATION_TYPE_RoleHandler(), new CtConditional_ELSE_RoleHandler(), new CtIf_ELSE_RoleHandler(), new CtModifiable_EMODIFIER_RoleHandler(), new CtAbstractInvocation_EXECUTABLE_REF_RoleHandler(), new CtExecutableReferenceExpression_EXECUTABLE_REF_RoleHandler(), new CtModule_EXPORTED_PACKAGE_RoleHandler(), new CtArrayAccess_EXPRESSION_RoleHandler(), new CtAssert_EXPRESSION_RoleHandler(), new CtCase_EXPRESSION_RoleHandler(), new CtDo_EXPRESSION_RoleHandler(), new CtFor_EXPRESSION_RoleHandler(), new CtForEach_EXPRESSION_RoleHandler(), new CtLambda_EXPRESSION_RoleHandler(), new CtNewArray_EXPRESSION_RoleHandler(), new CtReturn_EXPRESSION_RoleHandler(), new CtSwitch_EXPRESSION_RoleHandler(), new CtSynchronized_EXPRESSION_RoleHandler(), new CtThrow_EXPRESSION_RoleHandler(), new CtUnaryOperator_EXPRESSION_RoleHandler(), new CtWhile_EXPRESSION_RoleHandler(), new CtType_FIELD_RoleHandler(), new CtTry_FINALIZER_RoleHandler(), new CtForEach_FOREACH_VARIABLE_RoleHandler(), new CtFor_FOR_INIT_RoleHandler(), new CtFor_FOR_UPDATE_RoleHandler(), new CtProvidedService_IMPLEMENTATION_TYPE_RoleHandler(), new CtImport_IMPORT_REFERENCE_RoleHandler(), new CtType_INTERFACE_RoleHandler(), new CtTypeInformation_INTERFACE_RoleHandler(), new CtMethod_IS_DEFAULT_RoleHandler(), new CtFieldReference_IS_FINAL_RoleHandler(), new CtElement_IS_IMPLICIT_RoleHandler(), new CtLocalVariable_IS_INFERRED_RoleHandler(), new CtParameter_IS_INFERRED_RoleHandler(), new CtShadowable_IS_SHADOW_RoleHandler(), new CtExecutableReference_IS_STATIC_RoleHandler(), new CtFieldReference_IS_STATIC_RoleHandler(), new CtWildcardReference_IS_UPPER_RoleHandler(), new CtParameter_IS_VARARGS_RoleHandler(), new CtJavaDocTag_JAVADOC_TAG_VALUE_RoleHandler(), new CtStatement_LABEL_RoleHandler(), new CtBinaryOperator_LEFT_OPERAND_RoleHandler(), new CtLiteral_LITERAL_BASE_RoleHandler(), new CtType_METHOD_RoleHandler(), new CtModifiable_MODIFIER_RoleHandler(), new CtModule_MODIFIER_RoleHandler(), new CtModuleRequirement_MODIFIER_RoleHandler(), new CtTypeInformation_MODIFIER_RoleHandler(), new CtModule_MODULE_DIRECTIVE_RoleHandler(), new CtModuleRequirement_MODULE_REF_RoleHandler(), new CtPackageExport_MODULE_REF_RoleHandler(), new CtMultiTypedElement_MULTI_TYPE_RoleHandler(), new CtNamedElement_NAME_RoleHandler(), new CtReference_NAME_RoleHandler(), new CtNewClass_NESTED_TYPE_RoleHandler(), new CtType_NESTED_TYPE_RoleHandler(), new CtModule_OPENED_PACKAGE_RoleHandler(), new CtPackageExport_OPENED_PACKAGE_RoleHandler(), new CtBinaryOperator_OPERATOR_KIND_RoleHandler(), new CtOperatorAssignment_OPERATOR_KIND_RoleHandler(), new CtUnaryOperator_OPERATOR_KIND_RoleHandler(), new CtCompilationUnit_PACKAGE_DECLARATION_RoleHandler(), new CtPackageDeclaration_PACKAGE_REF_RoleHandler(), new CtPackageExport_PACKAGE_REF_RoleHandler(), new CtTypeReference_PACKAGE_REF_RoleHandler(), new CtCatch_PARAMETER_RoleHandler(), new CtExecutable_PARAMETER_RoleHandler(), new CtElement_POSITION_RoleHandler(), new CtModule_PROVIDED_SERVICE_RoleHandler(), new CtModule_REQUIRED_MODULE_RoleHandler(), new CtBinaryOperator_RIGHT_OPERAND_RoleHandler(), new CtModule_SERVICE_TYPE_RoleHandler(), new CtProvidedService_SERVICE_TYPE_RoleHandler(), new CtUsedService_SERVICE_TYPE_RoleHandler(), new CtCodeSnippet_SNIPPET_RoleHandler(), new CtStatementList_STATEMENT_RoleHandler(), new CtModule_SUB_PACKAGE_RoleHandler(), new CtPackage_SUB_PACKAGE_RoleHandler(), new CtType_SUPER_TYPE_RoleHandler(), new CtTypeInformation_SUPER_TYPE_RoleHandler(), new CtTargetedExpression_TARGET_RoleHandler(), new CtLabelledFlowBreak_TARGET_LABEL_RoleHandler(), new CtConditional_THEN_RoleHandler(), new CtIf_THEN_RoleHandler(), new CtExecutable_THROWN_RoleHandler(), new CtTryWithResource_TRY_RESOURCE_RoleHandler(), new CtArrayTypeReference_TYPE_RoleHandler(), new CtExecutableReference_TYPE_RoleHandler(), new CtTypedElement_TYPE_RoleHandler(), new CtVariableReference_TYPE_RoleHandler(), new CtActualTypeContainer_TYPE_ARGUMENT_RoleHandler(), new CtType_TYPE_MEMBER_RoleHandler(), new CtFormalTypeDeclarer_TYPE_PARAMETER_RoleHandler(), new CtTypeMemberWildcardImportReference_TYPE_REF_RoleHandler(), new CtAnnotation_VALUE_RoleHandler(), new CtEnum_VALUE_RoleHandler(), new CtLiteral_VALUE_RoleHandler(), new CtVariableAccess_VARIABLE_RoleHandler() }; + static final RoleHandler[] roleHandlers = new RoleHandler[]{ new CtTypeAccess_ACCESSED_TYPE_RoleHandler(), new CtClass_ANNONYMOUS_EXECUTABLE_RoleHandler(), new CtElement_ANNOTATION_RoleHandler(), new CtAnnotation_ANNOTATION_TYPE_RoleHandler(), new CtAbstractInvocation_ARGUMENT_RoleHandler(), new CtExecutableReference_ARGUMENT_TYPE_RoleHandler(), new CtAssignment_ASSIGNED_RoleHandler(), new CtRHSReceiver_ASSIGNMENT_RoleHandler(), new CtBodyHolder_BODY_RoleHandler(), new CtSynchronized_BODY_RoleHandler(), new CtIntersectionTypeReference_BOUND_RoleHandler(), new CtWildcardReference_BOUNDING_TYPE_RoleHandler(), new CtAbstractSwitch_CASE_RoleHandler(), new CtCase_CASE_KIND_RoleHandler(), new CtExpression_CAST_RoleHandler(), new CtTry_CATCH_RoleHandler(), new CtElement_COMMENT_RoleHandler(), new CtComment_COMMENT_CONTENT_RoleHandler(), new CtJavaDocTag_COMMENT_CONTENT_RoleHandler(), new CtJavaDoc_COMMENT_TAG_RoleHandler(), new CtComment_COMMENT_TYPE_RoleHandler(), new CtAssert_CONDITION_RoleHandler(), new CtConditional_CONDITION_RoleHandler(), new CtIf_CONDITION_RoleHandler(), new CtClass_CONSTRUCTOR_RoleHandler(), new CtPackage_CONTAINED_TYPE_RoleHandler(), new CtCompilationUnit_DECLARED_IMPORT_RoleHandler(), new CtCompilationUnit_DECLARED_MODULE_RoleHandler(), new CtCompilationUnit_DECLARED_MODULE_REF_RoleHandler(), new CtCompilationUnit_DECLARED_TYPE_RoleHandler(), new CtCompilationUnit_DECLARED_TYPE_REF_RoleHandler(), new CtExecutableReference_DECLARING_TYPE_RoleHandler(), new CtFieldReference_DECLARING_TYPE_RoleHandler(), new CtTypeReference_DECLARING_TYPE_RoleHandler(), new CtAnnotationMethod_DEFAULT_EXPRESSION_RoleHandler(), new CtVariable_DEFAULT_EXPRESSION_RoleHandler(), new CtNewArray_DIMENSION_RoleHandler(), new CtJavaDocTag_DOCUMENTATION_TYPE_RoleHandler(), new CtConditional_ELSE_RoleHandler(), new CtIf_ELSE_RoleHandler(), new CtModifiable_EMODIFIER_RoleHandler(), new CtAbstractInvocation_EXECUTABLE_REF_RoleHandler(), new CtExecutableReferenceExpression_EXECUTABLE_REF_RoleHandler(), new CtModule_EXPORTED_PACKAGE_RoleHandler(), new CtAbstractSwitch_EXPRESSION_RoleHandler(), new CtArrayAccess_EXPRESSION_RoleHandler(), new CtAssert_EXPRESSION_RoleHandler(), new CtBreak_EXPRESSION_RoleHandler(), new CtCase_EXPRESSION_RoleHandler(), new CtDo_EXPRESSION_RoleHandler(), new CtFor_EXPRESSION_RoleHandler(), new CtForEach_EXPRESSION_RoleHandler(), new CtLambda_EXPRESSION_RoleHandler(), new CtNewArray_EXPRESSION_RoleHandler(), new CtReturn_EXPRESSION_RoleHandler(), new CtSynchronized_EXPRESSION_RoleHandler(), new CtThrow_EXPRESSION_RoleHandler(), new CtUnaryOperator_EXPRESSION_RoleHandler(), new CtWhile_EXPRESSION_RoleHandler(), new CtType_FIELD_RoleHandler(), new CtTry_FINALIZER_RoleHandler(), new CtForEach_FOREACH_VARIABLE_RoleHandler(), new CtFor_FOR_INIT_RoleHandler(), new CtFor_FOR_UPDATE_RoleHandler(), new CtProvidedService_IMPLEMENTATION_TYPE_RoleHandler(), new CtImport_IMPORT_REFERENCE_RoleHandler(), new CtType_INTERFACE_RoleHandler(), new CtTypeInformation_INTERFACE_RoleHandler(), new CtMethod_IS_DEFAULT_RoleHandler(), new CtFieldReference_IS_FINAL_RoleHandler(), new CtElement_IS_IMPLICIT_RoleHandler(), new CtLocalVariable_IS_INFERRED_RoleHandler(), new CtParameter_IS_INFERRED_RoleHandler(), new CtShadowable_IS_SHADOW_RoleHandler(), new CtExecutableReference_IS_STATIC_RoleHandler(), new CtFieldReference_IS_STATIC_RoleHandler(), new CtWildcardReference_IS_UPPER_RoleHandler(), new CtParameter_IS_VARARGS_RoleHandler(), new CtJavaDocTag_JAVADOC_TAG_VALUE_RoleHandler(), new CtStatement_LABEL_RoleHandler(), new CtBinaryOperator_LEFT_OPERAND_RoleHandler(), new CtLiteral_LITERAL_BASE_RoleHandler(), new CtType_METHOD_RoleHandler(), new CtModifiable_MODIFIER_RoleHandler(), new CtModule_MODIFIER_RoleHandler(), new CtModuleRequirement_MODIFIER_RoleHandler(), new CtTypeInformation_MODIFIER_RoleHandler(), new CtModule_MODULE_DIRECTIVE_RoleHandler(), new CtModuleRequirement_MODULE_REF_RoleHandler(), new CtPackageExport_MODULE_REF_RoleHandler(), new CtMultiTypedElement_MULTI_TYPE_RoleHandler(), new CtNamedElement_NAME_RoleHandler(), new CtReference_NAME_RoleHandler(), new CtNewClass_NESTED_TYPE_RoleHandler(), new CtType_NESTED_TYPE_RoleHandler(), new CtModule_OPENED_PACKAGE_RoleHandler(), new CtPackageExport_OPENED_PACKAGE_RoleHandler(), new CtBinaryOperator_OPERATOR_KIND_RoleHandler(), new CtOperatorAssignment_OPERATOR_KIND_RoleHandler(), new CtUnaryOperator_OPERATOR_KIND_RoleHandler(), new CtCompilationUnit_PACKAGE_DECLARATION_RoleHandler(), new CtPackageDeclaration_PACKAGE_REF_RoleHandler(), new CtPackageExport_PACKAGE_REF_RoleHandler(), new CtTypeReference_PACKAGE_REF_RoleHandler(), new CtCatch_PARAMETER_RoleHandler(), new CtExecutable_PARAMETER_RoleHandler(), new CtElement_POSITION_RoleHandler(), new CtModule_PROVIDED_SERVICE_RoleHandler(), new CtModule_REQUIRED_MODULE_RoleHandler(), new CtBinaryOperator_RIGHT_OPERAND_RoleHandler(), new CtModule_SERVICE_TYPE_RoleHandler(), new CtProvidedService_SERVICE_TYPE_RoleHandler(), new CtUsedService_SERVICE_TYPE_RoleHandler(), new CtCodeSnippet_SNIPPET_RoleHandler(), new CtStatementList_STATEMENT_RoleHandler(), new CtModule_SUB_PACKAGE_RoleHandler(), new CtPackage_SUB_PACKAGE_RoleHandler(), new CtType_SUPER_TYPE_RoleHandler(), new CtTypeInformation_SUPER_TYPE_RoleHandler(), new CtTargetedExpression_TARGET_RoleHandler(), new CtLabelledFlowBreak_TARGET_LABEL_RoleHandler(), new CtConditional_THEN_RoleHandler(), new CtIf_THEN_RoleHandler(), new CtExecutable_THROWN_RoleHandler(), new CtTryWithResource_TRY_RESOURCE_RoleHandler(), new CtArrayTypeReference_TYPE_RoleHandler(), new CtExecutableReference_TYPE_RoleHandler(), new CtTypedElement_TYPE_RoleHandler(), new CtVariableReference_TYPE_RoleHandler(), new CtActualTypeContainer_TYPE_ARGUMENT_RoleHandler(), new CtType_TYPE_MEMBER_RoleHandler(), new CtFormalTypeDeclarer_TYPE_PARAMETER_RoleHandler(), new CtTypeMemberWildcardImportReference_TYPE_REF_RoleHandler(), new CtAnnotation_VALUE_RoleHandler(), new CtEnum_VALUE_RoleHandler(), new CtLiteral_VALUE_RoleHandler(), new CtVariableAccess_VARIABLE_RoleHandler() }; static class CtTypeAccess_ACCESSED_TYPE_RoleHandler extends SingleHandler> { private CtTypeAccess_ACCESSED_TYPE_RoleHandler() { @@ -313,9 +315,9 @@ public void setValue(T element, U value) { } } - static class CtSwitch_CASE_RoleHandler extends ListHandler> { - private CtSwitch_CASE_RoleHandler() { - super(CtRole.CASE, CtSwitch.class, CtCase.class); + static class CtAbstractSwitch_CASE_RoleHandler extends ListHandler> { + private CtAbstractSwitch_CASE_RoleHandler() { + super(CtRole.CASE, CtAbstractSwitch.class, CtCase.class); } @SuppressWarnings("unchecked") @@ -330,6 +332,23 @@ public void setValue(T element, U value) { } } + static class CtCase_CASE_KIND_RoleHandler extends SingleHandler { + private CtCase_CASE_KIND_RoleHandler() { + super(CtRole.CASE_KIND, CtCase.class, CaseKind.class); + } + + @SuppressWarnings("unchecked") + @Override + public U getValue(T element) { + return ((U) ((Object) (castTarget(element).getCaseKind()))); + } + + @Override + public void setValue(T element, U value) { + castTarget(element).setCaseKind(castValue(value)); + } + } + static class CtExpression_CAST_RoleHandler extends ListHandler> { private CtExpression_CAST_RoleHandler() { super(CtRole.CAST, CtExpression.class, CtTypeReference.class); @@ -825,6 +844,23 @@ public void setValue(T element, U value) { } } + static class CtAbstractSwitch_EXPRESSION_RoleHandler extends SingleHandler> { + private CtAbstractSwitch_EXPRESSION_RoleHandler() { + super(CtRole.EXPRESSION, CtAbstractSwitch.class, CtExpression.class); + } + + @SuppressWarnings("unchecked") + @Override + public U getValue(T element) { + return ((U) ((Object) (castTarget(element).getSelector()))); + } + + @Override + public void setValue(T element, U value) { + castTarget(element).setSelector(castValue(value)); + } + } + static class CtArrayAccess_EXPRESSION_RoleHandler extends SingleHandler> { private CtArrayAccess_EXPRESSION_RoleHandler() { super(CtRole.EXPRESSION, CtArrayAccess.class, CtExpression.class); @@ -859,7 +895,24 @@ public void setValue(T element, U value) { } } - static class CtCase_EXPRESSION_RoleHandler extends SingleHandler> { + static class CtBreak_EXPRESSION_RoleHandler extends SingleHandler> { + private CtBreak_EXPRESSION_RoleHandler() { + super(CtRole.EXPRESSION, CtBreak.class, CtExpression.class); + } + + @SuppressWarnings("unchecked") + @Override + public U getValue(T element) { + return ((U) ((Object) (castTarget(element).getExpression()))); + } + + @Override + public void setValue(T element, U value) { + castTarget(element).setExpression(castValue(value)); + } + } + + static class CtCase_EXPRESSION_RoleHandler extends ListHandler> { private CtCase_EXPRESSION_RoleHandler() { super(CtRole.EXPRESSION, CtCase.class, CtExpression.class); } @@ -867,12 +920,12 @@ private CtCase_EXPRESSION_RoleHandler() { @SuppressWarnings("unchecked") @Override public U getValue(T element) { - return ((U) ((Object) (castTarget(element).getCaseExpression()))); + return ((U) ((Object) (castTarget(element).getCaseExpressions()))); } @Override public void setValue(T element, U value) { - castTarget(element).setCaseExpression(castValue(value)); + castTarget(element).setCaseExpressions(castValue(value)); } } @@ -978,23 +1031,6 @@ public void setValue(T element, U value) { } } - static class CtSwitch_EXPRESSION_RoleHandler extends SingleHandler> { - private CtSwitch_EXPRESSION_RoleHandler() { - super(CtRole.EXPRESSION, CtSwitch.class, CtExpression.class); - } - - @SuppressWarnings("unchecked") - @Override - public U getValue(T element) { - return ((U) ((Object) (castTarget(element).getSelector()))); - } - - @Override - public void setValue(T element, U value) { - castTarget(element).setSelector(castValue(value)); - } - } - static class CtSynchronized_EXPRESSION_RoleHandler extends SingleHandler> { private CtSynchronized_EXPRESSION_RoleHandler() { super(CtRole.EXPRESSION, CtSynchronized.class, CtExpression.class); diff --git a/src/main/java/spoon/reflect/path/CtRole.java b/src/main/java/spoon/reflect/path/CtRole.java index 40ccad65854..e0385ee9c04 100644 --- a/src/main/java/spoon/reflect/path/CtRole.java +++ b/src/main/java/spoon/reflect/path/CtRole.java @@ -114,7 +114,8 @@ public enum CtRole { PROVIDED_SERVICE(MODULE_DIRECTIVE, obj -> obj instanceof CtProvidedService), IS_INFERRED, TYPE_REF, - LITERAL_BASE; + LITERAL_BASE, + CASE_KIND; private final CtRole superRole; private final List subRoles; diff --git a/src/main/java/spoon/reflect/visitor/CtAbstractVisitor.java b/src/main/java/spoon/reflect/visitor/CtAbstractVisitor.java index ab1cde44036..811b23603ff 100644 --- a/src/main/java/spoon/reflect/visitor/CtAbstractVisitor.java +++ b/src/main/java/spoon/reflect/visitor/CtAbstractVisitor.java @@ -43,6 +43,7 @@ import spoon.reflect.code.CtStatementList; import spoon.reflect.code.CtSuperAccess; import spoon.reflect.code.CtSwitch; +import spoon.reflect.code.CtSwitchExpression; import spoon.reflect.code.CtSynchronized; import spoon.reflect.code.CtThisAccess; import spoon.reflect.code.CtThrow; @@ -353,6 +354,11 @@ public void visitCtSwitch(CtSwitch switchStatement) { } + @Override + public void visitCtSwitchExpression(CtSwitchExpression switchExpression) { + + } + @Override public void visitCtSynchronized(CtSynchronized synchro) { diff --git a/src/main/java/spoon/reflect/visitor/CtBiScannerDefault.java b/src/main/java/spoon/reflect/visitor/CtBiScannerDefault.java index 2371adb44fb..e96788972db 100644 --- a/src/main/java/spoon/reflect/visitor/CtBiScannerDefault.java +++ b/src/main/java/spoon/reflect/visitor/CtBiScannerDefault.java @@ -43,7 +43,7 @@ public void biScan(spoon.reflect.path.CtRole role, spoon.reflect.declaration.CtE } protected void biScan(spoon.reflect.path.CtRole role, java.util.Collection elements, java.util.Collection others) { - for (java.util.Iterator firstIt = elements.iterator(), secondIt = others.iterator(); (firstIt.hasNext()) && (secondIt.hasNext());) { + for (java.util.Iterator firstIt = elements.iterator(), secondIt = others.iterator(); firstIt.hasNext() && secondIt.hasNext();) { biScan(role, firstIt.next(), secondIt.next()); } } @@ -172,6 +172,7 @@ public void visitCtBreak(final spoon.reflect.code.CtBreak breakStatement) { spoon.reflect.code.CtBreak other = ((spoon.reflect.code.CtBreak) (this.stack.peek())); enter(breakStatement); biScan(spoon.reflect.path.CtRole.ANNOTATION, breakStatement.getAnnotations(), other.getAnnotations()); + biScan(spoon.reflect.path.CtRole.EXPRESSION, breakStatement.getExpression(), other.getExpression()); biScan(spoon.reflect.path.CtRole.COMMENT, breakStatement.getComments(), other.getComments()); exit(breakStatement); } @@ -181,7 +182,7 @@ public void visitCtCase(final spoon.reflect.code.CtCase caseStatement) { spoon.reflect.code.CtCase other = ((spoon.reflect.code.CtCase) (this.stack.peek())); enter(caseStatement); biScan(spoon.reflect.path.CtRole.ANNOTATION, caseStatement.getAnnotations(), other.getAnnotations()); - biScan(spoon.reflect.path.CtRole.EXPRESSION, caseStatement.getCaseExpression(), other.getCaseExpression()); + biScan(spoon.reflect.path.CtRole.EXPRESSION, caseStatement.getCaseExpressions(), other.getCaseExpressions()); biScan(spoon.reflect.path.CtRole.STATEMENT, caseStatement.getStatements(), other.getStatements()); biScan(spoon.reflect.path.CtRole.COMMENT, caseStatement.getComments(), other.getComments()); exit(caseStatement); @@ -642,6 +643,19 @@ public void visitCtSwitch(final spoon.reflect.code.CtSwitch switchStateme exit(switchStatement); } + // autogenerated by CtBiScannerGenerator + public void visitCtSwitchExpression(final spoon.reflect.code.CtSwitchExpression switchExpression) { + spoon.reflect.code.CtSwitchExpression other = ((spoon.reflect.code.CtSwitchExpression) (this.stack.peek())); + enter(switchExpression); + biScan(spoon.reflect.path.CtRole.ANNOTATION, switchExpression.getAnnotations(), other.getAnnotations()); + biScan(spoon.reflect.path.CtRole.EXPRESSION, switchExpression.getSelector(), other.getSelector()); + biScan(spoon.reflect.path.CtRole.CASE, switchExpression.getCases(), other.getCases()); + biScan(spoon.reflect.path.CtRole.COMMENT, switchExpression.getComments(), other.getComments()); + biScan(spoon.reflect.path.CtRole.TYPE, switchExpression.getType(), other.getType()); + biScan(spoon.reflect.path.CtRole.CAST, switchExpression.getTypeCasts(), other.getTypeCasts()); + exit(switchExpression); + } + // autogenerated by CtBiScannerGenerator public void visitCtSynchronized(final spoon.reflect.code.CtSynchronized synchro) { spoon.reflect.code.CtSynchronized other = ((spoon.reflect.code.CtSynchronized) (this.stack.peek())); @@ -1006,4 +1020,3 @@ public void visitCtTypeMemberWildcardImportReference(spoon.reflect.reference.CtT exit(wildcardReference); } } - diff --git a/src/main/java/spoon/reflect/visitor/CtInheritanceScanner.java b/src/main/java/spoon/reflect/visitor/CtInheritanceScanner.java index 6cbee135271..be5cb8ca6d7 100644 --- a/src/main/java/spoon/reflect/visitor/CtInheritanceScanner.java +++ b/src/main/java/spoon/reflect/visitor/CtInheritanceScanner.java @@ -6,6 +6,7 @@ package spoon.reflect.visitor; import spoon.reflect.code.CtAbstractInvocation; +import spoon.reflect.code.CtAbstractSwitch; import spoon.reflect.code.CtAnnotationFieldAccess; import spoon.reflect.code.CtArrayAccess; import spoon.reflect.code.CtArrayRead; @@ -53,6 +54,7 @@ import spoon.reflect.code.CtStatementList; import spoon.reflect.code.CtSuperAccess; import spoon.reflect.code.CtSwitch; +import spoon.reflect.code.CtSwitchExpression; import spoon.reflect.code.CtSynchronized; import spoon.reflect.code.CtTargetedExpression; import spoon.reflect.code.CtThisAccess; @@ -180,6 +182,12 @@ public void scan(CtElement element) { public void scanCtAbstractInvocation(CtAbstractInvocation a) { } + /** + * Scans an abstract switch (either switch statement or switch expression). + */ + public void scanCtAbstractSwitch(CtAbstractSwitch a) { + } + /** * Scans an abstract control flow break. */ @@ -806,12 +814,22 @@ public void visitCtStatementList(CtStatementList e) { } public void visitCtSwitch(CtSwitch e) { + scanCtAbstractSwitch(e); scanCtStatement(e); scanCtCodeElement(e); scanCtElement(e); scanCtVisitable(e); } + public void visitCtSwitchExpression(CtSwitchExpression e) { + scanCtAbstractSwitch(e); + scanCtExpression(e); + scanCtCodeElement(e); + scanCtTypedElement(e); + scanCtElement(e); + scanCtVisitable(e); + } + public void visitCtSynchronized(CtSynchronized e) { scanCtStatement(e); scanCtCodeElement(e); diff --git a/src/main/java/spoon/reflect/visitor/CtScanner.java b/src/main/java/spoon/reflect/visitor/CtScanner.java index 3ec684c03ee..acb0a406473 100644 --- a/src/main/java/spoon/reflect/visitor/CtScanner.java +++ b/src/main/java/spoon/reflect/visitor/CtScanner.java @@ -49,6 +49,7 @@ import spoon.reflect.code.CtStatementList; import spoon.reflect.code.CtSuperAccess; import spoon.reflect.code.CtSwitch; +import spoon.reflect.code.CtSwitchExpression; import spoon.reflect.code.CtSynchronized; import spoon.reflect.code.CtThisAccess; import spoon.reflect.code.CtThrow; @@ -299,6 +300,7 @@ public void visitCtBlock(final CtBlock block) { public void visitCtBreak(final CtBreak breakStatement) { enter(breakStatement); scan(CtRole.ANNOTATION, breakStatement.getAnnotations()); + scan(CtRole.EXPRESSION, breakStatement.getExpression()); scan(CtRole.COMMENT, breakStatement.getComments()); exit(breakStatement); } @@ -306,7 +308,7 @@ public void visitCtBreak(final CtBreak breakStatement) { public void visitCtCase(final CtCase caseStatement) { enter(caseStatement); scan(CtRole.ANNOTATION, caseStatement.getAnnotations()); - scan(CtRole.EXPRESSION, caseStatement.getCaseExpression()); + scan(CtRole.EXPRESSION, caseStatement.getCaseExpressions()); scan(CtRole.STATEMENT, caseStatement.getStatements()); scan(CtRole.COMMENT, caseStatement.getComments()); exit(caseStatement); @@ -689,6 +691,17 @@ public void visitCtSwitch(final CtSwitch switchStatement) { exit(switchStatement); } + public void visitCtSwitchExpression(final CtSwitchExpression switchExpression) { + enter(switchExpression); + scan(CtRole.ANNOTATION, switchExpression.getAnnotations()); + scan(CtRole.EXPRESSION, switchExpression.getSelector()); + scan(CtRole.CASE, switchExpression.getCases()); + scan(CtRole.COMMENT, switchExpression.getComments()); + scan(CtRole.TYPE, switchExpression.getType()); + scan(CtRole.CAST, switchExpression.getTypeCasts()); + exit(switchExpression); + } + public void visitCtSynchronized(final CtSynchronized synchro) { enter(synchro); scan(CtRole.ANNOTATION, synchro.getAnnotations()); diff --git a/src/main/java/spoon/reflect/visitor/CtVisitor.java b/src/main/java/spoon/reflect/visitor/CtVisitor.java index ee8e5cd113c..cb0736dc928 100644 --- a/src/main/java/spoon/reflect/visitor/CtVisitor.java +++ b/src/main/java/spoon/reflect/visitor/CtVisitor.java @@ -43,6 +43,7 @@ import spoon.reflect.code.CtStatementList; import spoon.reflect.code.CtSuperAccess; import spoon.reflect.code.CtSwitch; +import spoon.reflect.code.CtSwitchExpression; import spoon.reflect.code.CtSynchronized; import spoon.reflect.code.CtThisAccess; import spoon.reflect.code.CtThrow; @@ -366,6 +367,11 @@ void visitCtOperatorAssignment( */ void visitCtSwitch(CtSwitch switchStatement); + /** + * Visits a switch expression. + */ + void visitCtSwitchExpression(CtSwitchExpression switchExpression); + /** * Visits a synchronized modifier. */ diff --git a/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java b/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java index 76c9a9d3324..a9e8cfa9d14 100644 --- a/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java +++ b/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java @@ -12,6 +12,8 @@ import spoon.experimental.CtUnresolvedImport; import spoon.processing.Processor; import spoon.reflect.code.BinaryOperatorKind; +import spoon.reflect.code.CaseKind; +import spoon.reflect.code.CtAbstractSwitch; import spoon.reflect.code.CtAnnotationFieldAccess; import spoon.reflect.code.CtArrayAccess; import spoon.reflect.code.CtArrayRead; @@ -53,6 +55,7 @@ import spoon.reflect.code.CtStatementList; import spoon.reflect.code.CtSuperAccess; import spoon.reflect.code.CtSwitch; +import spoon.reflect.code.CtSwitchExpression; import spoon.reflect.code.CtSynchronized; import spoon.reflect.code.CtTargetedExpression; import spoon.reflect.code.CtThisAccess; @@ -539,9 +542,17 @@ public void visitCtBlock(CtBlock block) { @Override public void visitCtBreak(CtBreak breakStatement) { enterCtStatement(breakStatement); - printer.writeKeyword("break"); - if (breakStatement.getTargetLabel() != null) { - printer.writeSpace().writeKeyword(breakStatement.getTargetLabel()); + if (!breakStatement.isImplicit()) { + printer.writeKeyword("break"); + if (breakStatement.getTargetLabel() != null) { + printer.writeSpace().writeKeyword(breakStatement.getTargetLabel()); + } else if (breakStatement.getExpression() != null) { + printer.writeSpace(); + scan(breakStatement.getExpression()); + } + } else { + // Arrow (->) syntax from Java 12 + scan(breakStatement.getExpression()); } exitCtStatement(breakStatement); } @@ -552,24 +563,32 @@ public void visitCtCase(CtCase caseStatement) { enterCtStatement(caseStatement); if (caseStatement.getCaseExpression() != null) { printer.writeKeyword("case").writeSpace(); - // writing enum case expression - if (caseStatement.getCaseExpression() instanceof CtFieldAccess) { - final CtFieldReference variable = ((CtFieldAccess) caseStatement.getCaseExpression()).getVariable(); - // In noclasspath mode, we don't have always the type of the declaring type. - if (variable.getType() != null - && variable.getDeclaringType() != null - && variable.getType().getQualifiedName().equals(variable.getDeclaringType().getQualifiedName())) { - printer.writeIdentifier(variable.getSimpleName()); + List> caseExpressions = caseStatement.getCaseExpressions(); + for (int i = 0; i < caseExpressions.size(); i++) { + CtExpression caseExpression = caseExpressions.get(i); + // writing enum case expression + if (caseExpression instanceof CtFieldAccess) { + final CtFieldReference variable = ((CtFieldAccess) caseExpression).getVariable(); + // In noclasspath mode, we don't have always the type of the declaring type. + if (variable.getType() != null + && variable.getDeclaringType() != null + && variable.getType().getQualifiedName().equals(variable.getDeclaringType().getQualifiedName())) { + printer.writeIdentifier(variable.getSimpleName()); + } else { + scan(caseExpression); + } } else { - scan(caseStatement.getCaseExpression()); + scan(caseExpression); + } + if (i != caseExpressions.size() - 1) { + printer.writeSeparator(",").writeSpace(); } - } else { - scan(caseStatement.getCaseExpression()); } } else { printer.writeKeyword("default"); } - printer.writeSpace().writeSeparator(":").incTab(); + String separator = caseStatement.getCaseKind() == CaseKind.ARROW ? "->" : ":"; + printer.writeSpace().writeSeparator(separator).incTab(); for (CtStatement statement : caseStatement.getStatements()) { printer.writeln(); @@ -1658,13 +1677,11 @@ public void visitCtStatementList(CtStatementList statements) { } } - @Override - public void visitCtSwitch(CtSwitch switchStatement) { - enterCtStatement(switchStatement); + private void writeSwitch(CtAbstractSwitch abstractSwitch) { printer.writeKeyword("switch").writeSpace().writeSeparator("("); - scan(switchStatement.getSelector()); + scan(abstractSwitch.getSelector()); printer.writeSeparator(")").writeSpace().writeSeparator("{").incTab(); - for (CtCase c : switchStatement.getCases()) { + for (CtCase c : abstractSwitch.getCases()) { printer.writeln(); scan(c); } @@ -1673,9 +1690,22 @@ public void visitCtSwitch(CtSwitch switchStatement) { } else { printer.decTab().writeln().writeSeparator("}"); } + } + + @Override + public void visitCtSwitch(CtSwitch switchStatement) { + enterCtStatement(switchStatement); + writeSwitch(switchStatement); exitCtStatement(switchStatement); } + @Override + public void visitCtSwitchExpression(CtSwitchExpression switchExpression) { + enterCtExpression(switchExpression); + writeSwitch(switchExpression); + exitCtExpression(switchExpression); + } + @Override public void visitCtSynchronized(CtSynchronized synchro) { enterCtStatement(synchro); diff --git a/src/main/java/spoon/support/DefaultCoreFactory.java b/src/main/java/spoon/support/DefaultCoreFactory.java index 9e2b549ea2d..7afc3b4f388 100644 --- a/src/main/java/spoon/support/DefaultCoreFactory.java +++ b/src/main/java/spoon/support/DefaultCoreFactory.java @@ -45,6 +45,7 @@ import spoon.reflect.code.CtStatementList; import spoon.reflect.code.CtSuperAccess; import spoon.reflect.code.CtSwitch; +import spoon.reflect.code.CtSwitchExpression; import spoon.reflect.code.CtSynchronized; import spoon.reflect.code.CtThisAccess; import spoon.reflect.code.CtThrow; @@ -136,6 +137,7 @@ import spoon.support.reflect.code.CtReturnImpl; import spoon.support.reflect.code.CtStatementListImpl; import spoon.support.reflect.code.CtSuperAccessImpl; +import spoon.support.reflect.code.CtSwitchExpressionImpl; import spoon.support.reflect.code.CtSwitchImpl; import spoon.support.reflect.code.CtSynchronizedImpl; import spoon.support.reflect.code.CtThisAccessImpl; @@ -595,6 +597,13 @@ public CtSwitch createSwitch() { return e; } + @Override + public CtSwitchExpression createSwitchExpression() { + CtSwitchExpression e = new CtSwitchExpressionImpl(); + e.setFactory(getMainFactory()); + return e; + } + @Override public CtSynchronized createSynchronized() { CtSynchronized e = new CtSynchronizedImpl(); @@ -918,6 +927,9 @@ public CtElement create(Class klass) { if (klass.equals(spoon.reflect.code.CtSwitch.class)) { return createSwitch(); } + if (klass.equals(spoon.reflect.code.CtSwitchExpression.class)) { + return createSwitchExpression(); + } if (klass.equals(spoon.reflect.code.CtSynchronized.class)) { return createSynchronized(); } diff --git a/src/main/java/spoon/support/StandardEnvironment.java b/src/main/java/spoon/support/StandardEnvironment.java index 32e31cd990d..e9bd2cb8d9b 100644 --- a/src/main/java/spoon/support/StandardEnvironment.java +++ b/src/main/java/spoon/support/StandardEnvironment.java @@ -111,6 +111,8 @@ public void setPrettyPrintingMode(PRETTY_PRINTING_MODE prettyPrintingMode) { private int complianceLevel = DEFAULT_CODE_COMPLIANCE_LEVEL; + private boolean previewFeaturesEnabled = false; + private transient OutputDestinationHandler outputDestinationHandler = new DefaultOutputDestinationHandler(new File(Launcher.OUTPUTDIR), this); private OutputType outputType = OutputType.CLASSES; @@ -348,6 +350,16 @@ public void setComplianceLevel(int level) { complianceLevel = level; } + @Override + public boolean isPreviewFeaturesEnabled() { + return previewFeaturesEnabled; + } + + @Override + public void setPreviewFeaturesEnabled(boolean previewFeaturesEnabled) { + this.previewFeaturesEnabled = previewFeaturesEnabled; + } + @Override public void setProcessorProperties(String processorName, ProcessorProperties prop) { processorProperties.put(processorName, prop); diff --git a/src/main/java/spoon/support/compiler/jdt/JDTBasedSpoonCompiler.java b/src/main/java/spoon/support/compiler/jdt/JDTBasedSpoonCompiler.java index e68f014f0ca..cbf92c0d724 100644 --- a/src/main/java/spoon/support/compiler/jdt/JDTBasedSpoonCompiler.java +++ b/src/main/java/spoon/support/compiler/jdt/JDTBasedSpoonCompiler.java @@ -143,15 +143,21 @@ public boolean compile(InputType... types) { JDTBatchCompiler batchCompiler = createBatchCompiler(types); - - final String[] args = new JDTBuilderImpl() // - .classpathOptions(new ClasspathOptions().encoding(this.getEnvironment().getEncoding().displayName()).classpath(getSourceClasspath()).binaries(getBinaryOutputDirectory())) // - .complianceOptions(new ComplianceOptions().compliance(javaCompliance)) // - .annotationProcessingOptions(new AnnotationProcessingOptions().compileProcessors()) // - .advancedOptions(new AdvancedOptions().preserveUnusedVars().continueExecution().enableJavadoc()) // - .sources(new SourceOptions().sources(sources.getAllJavaFiles())) // no sources, handled by the JDTBatchCompiler + ClasspathOptions classpathOptions = new ClasspathOptions().encoding(this.getEnvironment().getEncoding().displayName()).classpath(getSourceClasspath()).binaries(getBinaryOutputDirectory()); + ComplianceOptions complianceOptions = new ComplianceOptions().compliance(javaCompliance); + if (factory.getEnvironment().isPreviewFeaturesEnabled()) { + complianceOptions.enablePreview(); + } + AnnotationProcessingOptions annotationProcessingOptions = new AnnotationProcessingOptions().compileProcessors(); + AdvancedOptions advancedOptions = new AdvancedOptions().preserveUnusedVars().continueExecution().enableJavadoc(); + SourceOptions sourceOptions = new SourceOptions().sources(this.sources.getAllJavaFiles()); + final String[] args = new JDTBuilderImpl() + .classpathOptions(classpathOptions) + .complianceOptions(complianceOptions) + .annotationProcessingOptions(annotationProcessingOptions) + .advancedOptions(advancedOptions) + .sources(sourceOptions) // no sources, handled by the JDTBatchCompiler .build(); - getFactory().getEnvironment().debugMessage("compile args: " + Arrays.toString(args)); System.setProperty("jdt.compiler.useSingleThread", "true"); batchCompiler.compile(args); @@ -386,11 +392,18 @@ protected CompilationUnitDeclaration[] buildUnits(JDTBuilder jdtBuilder, SpoonFo String[] args; if (jdtBuilder == null) { - args = new JDTBuilderImpl() // - .classpathOptions(new ClasspathOptions().encoding(this.getEnvironment().getEncoding().displayName()).classpath(classpath)) // - .complianceOptions(new ComplianceOptions().compliance(javaCompliance)) // - .advancedOptions(new AdvancedOptions().preserveUnusedVars().continueExecution().enableJavadoc()) // - .sources(new SourceOptions().sources(sourceFiles)) // no sources, handled by the JDTBatchCompiler + ClasspathOptions classpathOptions = new ClasspathOptions().encoding(this.getEnvironment().getEncoding().displayName()).classpath(classpath); + ComplianceOptions complianceOptions = new ComplianceOptions().compliance(javaCompliance); + if (factory.getEnvironment().isPreviewFeaturesEnabled()) { + complianceOptions.enablePreview(); + } + AdvancedOptions advancedOptions = new AdvancedOptions().preserveUnusedVars().continueExecution().enableJavadoc(); + SourceOptions sourceOptions = new SourceOptions().sources(sourceFiles); + args = new JDTBuilderImpl() + .classpathOptions(classpathOptions) + .complianceOptions(complianceOptions) + .advancedOptions(advancedOptions) + .sources(sourceOptions) // no sources, handled by the JDTBatchCompiler .build(); } else { args = jdtBuilder.build(); diff --git a/src/main/java/spoon/support/compiler/jdt/JDTCommentBuilder.java b/src/main/java/spoon/support/compiler/jdt/JDTCommentBuilder.java index cba6b3b6954..d6cdb773ee4 100644 --- a/src/main/java/spoon/support/compiler/jdt/JDTCommentBuilder.java +++ b/src/main/java/spoon/support/compiler/jdt/JDTCommentBuilder.java @@ -11,6 +11,7 @@ import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; import spoon.SpoonException; +import spoon.reflect.code.CtAbstractSwitch; import spoon.reflect.code.CtBinaryOperator; import spoon.reflect.code.CtBlock; import spoon.reflect.code.CtBodyHolder; @@ -24,6 +25,7 @@ import spoon.reflect.code.CtStatement; import spoon.reflect.code.CtStatementList; import spoon.reflect.code.CtSwitch; +import spoon.reflect.code.CtSwitchExpression; import spoon.reflect.cu.CompilationUnit; import spoon.reflect.cu.SourcePosition; import spoon.reflect.cu.position.BodyHolderSourcePosition; @@ -348,11 +350,10 @@ public void scanCtVariable(CtVariable e) { e.addComment(comment); } - @Override - public void visitCtSwitch(CtSwitch e) { - List> cases = e.getCases(); + private void visitSwitch(CtAbstractSwitch e) { + List> cases = e.getCases(); CtCase previous = null; - for (CtCase ctCase : cases) { + for (CtCase ctCase : cases) { if (previous == null) { if (comment.getPosition().getSourceStart() < ctCase.getPosition().getSourceStart() && e.getPosition().getSourceStart() < comment.getPosition().getSourceStart()) { @@ -389,6 +390,16 @@ public void visitCtSwitch(CtSwitch e) { } } + @Override + public void visitCtSwitch(CtSwitch e) { + visitSwitch(e); + } + + @Override + public void visitCtSwitchExpression(CtSwitchExpression e) { + visitSwitch(e); + } + @Override public void visitCtIf(CtIf e) { CtStatement thenStatement = e.getThenStatement(); diff --git a/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilder.java b/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilder.java index fc0c0265f54..a04993a62a1 100644 --- a/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilder.java +++ b/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilder.java @@ -83,6 +83,7 @@ import org.eclipse.jdt.internal.compiler.ast.StringLiteral; import org.eclipse.jdt.internal.compiler.ast.StringLiteralConcatenation; import org.eclipse.jdt.internal.compiler.ast.SuperReference; +import org.eclipse.jdt.internal.compiler.ast.SwitchExpression; import org.eclipse.jdt.internal.compiler.ast.SwitchStatement; import org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement; import org.eclipse.jdt.internal.compiler.ast.ThisReference; @@ -713,6 +714,14 @@ public void endVisit(SwitchStatement switchStatement, BlockScope scope) { context.exit(switchStatement); } + @Override + public void endVisit(SwitchExpression switchExpression, BlockScope scope) { + if (context.stack.peek().node instanceof CaseStatement) { + context.exit(context.stack.peek().node); + } + context.exit(switchExpression); + } + @Override public void endVisit(SynchronizedStatement synchronizedStatement, BlockScope scope) { context.exit(synchronizedStatement); @@ -1663,6 +1672,12 @@ public boolean visit(SwitchStatement switchStatement, BlockScope scope) { return true; } + @Override + public boolean visit(SwitchExpression switchExpression, BlockScope blockScope) { + context.enter(factory.Core().createSwitchExpression(), switchExpression); + return true; + } + @Override public boolean visit(SynchronizedStatement synchronizedStatement, BlockScope scope) { context.enter(factory.Core().createSynchronized(), synchronizedStatement); diff --git a/src/main/java/spoon/support/compiler/jdt/ParentExiter.java b/src/main/java/spoon/support/compiler/jdt/ParentExiter.java index 0154e336340..6cff80ad164 100644 --- a/src/main/java/spoon/support/compiler/jdt/ParentExiter.java +++ b/src/main/java/spoon/support/compiler/jdt/ParentExiter.java @@ -12,6 +12,7 @@ import org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression; import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; +import org.eclipse.jdt.internal.compiler.ast.BreakStatement; import org.eclipse.jdt.internal.compiler.ast.CaseStatement; import org.eclipse.jdt.internal.compiler.ast.CastExpression; import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall; @@ -21,6 +22,7 @@ import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression; +import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.StringLiteralConcatenation; import org.eclipse.jdt.internal.compiler.ast.TypeParameter; @@ -30,6 +32,7 @@ import spoon.SpoonException; import spoon.reflect.code.BinaryOperatorKind; +import spoon.reflect.code.CaseKind; import spoon.reflect.code.CtArrayAccess; import spoon.reflect.code.CtArrayRead; import spoon.reflect.code.CtArrayWrite; @@ -37,6 +40,7 @@ import spoon.reflect.code.CtAssignment; import spoon.reflect.code.CtBinaryOperator; import spoon.reflect.code.CtBlock; +import spoon.reflect.code.CtBreak; import spoon.reflect.code.CtCase; import spoon.reflect.code.CtCatch; import spoon.reflect.code.CtCatchVariable; @@ -58,6 +62,7 @@ import spoon.reflect.code.CtStatement; import spoon.reflect.code.CtSuperAccess; import spoon.reflect.code.CtSwitch; +import spoon.reflect.code.CtSwitchExpression; import spoon.reflect.code.CtSynchronized; import spoon.reflect.code.CtTargetedExpression; import spoon.reflect.code.CtThisAccess; @@ -445,11 +450,30 @@ public void visitCtBlock(CtBlock block) { super.visitCtBlock(block); } + @Override + public void visitCtBreak(CtBreak b) { + if (child instanceof CtExpression) { + if (!(childJDT instanceof SingleNameReference && ((SingleNameReference) childJDT).isLabel)) { + b.setExpression((CtExpression) child); + ASTNode node = jdtTreeBuilder.getContextBuilder().stack.peek().node; + if (node instanceof BreakStatement) { + b.setImplicit(((BreakStatement) node).isImplicit); + } + return; + } + } + super.visitCtBreak(b); + } + @Override public void visitCtCase(CtCase caseStatement) { final ASTNode node = jdtTreeBuilder.getContextBuilder().stack.peek().node; - if (node instanceof CaseStatement && ((CaseStatement) node).constantExpression != null && caseStatement.getCaseExpression() == null && child instanceof CtExpression) { - caseStatement.setCaseExpression((CtExpression) child); + if (node instanceof CaseStatement) { + caseStatement.setCaseKind(((CaseStatement) node).isExpr ? CaseKind.ARROW : CaseKind.COLON); + } + if (node instanceof CaseStatement && ((CaseStatement) node).constantExpression != null && child instanceof CtExpression + && caseStatement.getCaseExpressions().size() < ((CaseStatement) node).constantExpressions.length) { + caseStatement.addCaseExpression((CtExpression) child); return; } else if (child instanceof CtStatement) { caseStatement.addStatement((CtStatement) child); @@ -869,6 +893,21 @@ public void visitCtSwitch(CtSwitch switchStatement) { super.visitCtSwitch(switchStatement); } + @Override + public void visitCtSwitchExpression(CtSwitchExpression switchExpression) { + if (switchExpression.getSelector() == null && child instanceof CtExpression) { + switchExpression.setSelector((CtExpression) child); + return; + } + if (child instanceof CtCase) { + switchExpression.addCase((CtCase) child); + //we have all statements of the case. Update source position now + child.setPosition(jdtTreeBuilder.getPositionBuilder().buildPosition((CtCase) child)); + return; + } + super.visitCtSwitchExpression(switchExpression); + } + @Override public void visitCtSynchronized(CtSynchronized synchro) { if (synchro.getExpression() == null && child instanceof CtExpression) { diff --git a/src/main/java/spoon/support/compiler/jdt/PositionBuilder.java b/src/main/java/spoon/support/compiler/jdt/PositionBuilder.java index 780cd47404a..07112543b4e 100644 --- a/src/main/java/spoon/support/compiler/jdt/PositionBuilder.java +++ b/src/main/java/spoon/support/compiler/jdt/PositionBuilder.java @@ -405,7 +405,11 @@ SourcePosition buildPositionCtElement(CtElement e, ASTNode node) { return handlePositionProblem("Unexpected end of file in CtCase on: " + sourceStart); } if (contents[sourceEnd] != ':') { - return handlePositionProblem("Unexpected character " + contents[sourceEnd] + " instead of \':\' in CtCase on: " + sourceEnd); + if (contents[sourceEnd] == '-' && contents.length > sourceEnd + 1 && contents[sourceEnd + 1] == '>') { + sourceEnd++; + } else { + return handlePositionProblem("Unexpected character " + contents[sourceEnd] + " instead of \':\' or \'->\' in CtCase on: " + sourceEnd); + } } } else if ((node instanceof AssertStatement)) { AssertStatement assert_ = (AssertStatement) node; diff --git a/src/main/java/spoon/support/reflect/code/CtBreakImpl.java b/src/main/java/spoon/support/reflect/code/CtBreakImpl.java index be43af0814b..c5ba4013b81 100644 --- a/src/main/java/spoon/support/reflect/code/CtBreakImpl.java +++ b/src/main/java/spoon/support/reflect/code/CtBreakImpl.java @@ -7,14 +7,17 @@ import spoon.reflect.annotations.MetamodelPropertyField; import spoon.reflect.code.CtBreak; +import spoon.reflect.code.CtExpression; import spoon.reflect.code.CtLabelledFlowBreak; import spoon.reflect.code.CtStatement; import spoon.reflect.declaration.CtElement; +import spoon.reflect.path.CtRole; import spoon.reflect.visitor.CtVisitor; import spoon.reflect.visitor.filter.ParentFunction; import java.util.List; +import static spoon.reflect.path.CtRole.EXPRESSION; import static spoon.reflect.path.CtRole.TARGET_LABEL; public class CtBreakImpl extends CtStatementImpl implements CtBreak { @@ -23,6 +26,9 @@ public class CtBreakImpl extends CtStatementImpl implements CtBreak { @MetamodelPropertyField(role = TARGET_LABEL) String targetLabel; + @MetamodelPropertyField(role = CtRole.EXPRESSION) + CtExpression expression; + @Override public void accept(CtVisitor visitor) { visitor.visitCtBreak(this); @@ -56,6 +62,21 @@ public CtStatement getLabelledStatement() { return null; } + @Override + public CtExpression getExpression() { + return expression; + } + + @Override + public T setExpression(CtExpression expression) { + if (expression != null) { + expression.setParent(this); + } + getFactory().getEnvironment().getModelChangeListener().onObjectUpdate(this, EXPRESSION, expression, this.expression); + this.expression = expression; + return (T) this; + } + @Override public CtBreak clone() { return (CtBreak) super.clone(); diff --git a/src/main/java/spoon/support/reflect/code/CtCaseImpl.java b/src/main/java/spoon/support/reflect/code/CtCaseImpl.java index 0fd4d3daae3..ded6247ae5b 100644 --- a/src/main/java/spoon/support/reflect/code/CtCaseImpl.java +++ b/src/main/java/spoon/support/reflect/code/CtCaseImpl.java @@ -7,6 +7,7 @@ import spoon.reflect.ModelElementContainerDefaultCapacities; import spoon.reflect.annotations.MetamodelPropertyField; +import spoon.reflect.code.CaseKind; import spoon.reflect.code.CtCase; import spoon.reflect.code.CtExpression; import spoon.reflect.code.CtStatement; @@ -27,9 +28,15 @@ public class CtCaseImpl extends CtStatementImpl implements CtCase { @MetamodelPropertyField(role = CtRole.EXPRESSION) CtExpression caseExpression; + @MetamodelPropertyField(role = CtRole.EXPRESSION) + List> caseExpressions = emptyList(); + @MetamodelPropertyField(role = CtRole.STATEMENT) List statements = emptyList(); + @MetamodelPropertyField(role = CtRole.CASE_KIND) + CaseKind caseKind = CaseKind.COLON; + @Override public void accept(CtVisitor visitor) { visitor.visitCtCase(this); @@ -55,6 +62,51 @@ public > T setCaseExpression(CtExpression caseExpression) return (T) this; } + @Override + public List> getCaseExpressions() { + return caseExpressions; + } + + @Override + public > T setCaseExpressions(List> caseExpressions) { + if (caseExpressions == null || caseExpressions.isEmpty()) { + this.caseExpressions = CtElementImpl.emptyList(); + return (T) this; + } + getFactory().getEnvironment().getModelChangeListener().onObjectUpdate(this, CtRole.CASE, caseExpressions, this.caseExpressions); + this.caseExpressions.clear(); + for (CtExpression expr : caseExpressions) { + addCaseExpression(expr); + } + return (T) this; + } + + @Override + public > T addCaseExpression(CtExpression caseExpression) { + if (caseExpression == null) { + return (T) this; + } + this.ensureModifiableCaseExpressionsList(); + if (getCaseExpression() == null) { + setCaseExpression(caseExpression); + } + getFactory().getEnvironment().getModelChangeListener().onObjectUpdate(this, CtRole.CASE, caseExpressions, this.caseExpressions); + this.caseExpressions.add(caseExpression); + return (T) this; + } + + @Override + public CaseKind getCaseKind() { + return caseKind; + } + + @Override + public > T setCaseKind(CaseKind kind) { + getFactory().getEnvironment().getModelChangeListener().onObjectUpdate(this, CtRole.CASE_KIND, kind, this.caseKind); + caseKind = kind; + return (T) this; + } + @Override public T setStatements(List statements) { if (statements == null || statements.isEmpty()) { @@ -80,6 +132,12 @@ private void ensureModifiableStatementsList() { } } + private void ensureModifiableCaseExpressionsList() { + if (this.caseExpressions == CtElementImpl.>emptyList()) { + this.caseExpressions = new ArrayList<>(ModelElementContainerDefaultCapacities.CASE_EXPRESSIONS_CONTAINER_DEFAULT_CAPACITY); + } + } + @Override public T addStatement(int index, CtStatement statement) { if (statement == null) { diff --git a/src/main/java/spoon/support/reflect/code/CtSwitchExpressionImpl.java b/src/main/java/spoon/support/reflect/code/CtSwitchExpressionImpl.java new file mode 100644 index 00000000000..aae6a4f1657 --- /dev/null +++ b/src/main/java/spoon/support/reflect/code/CtSwitchExpressionImpl.java @@ -0,0 +1,98 @@ +/** + * Copyright (C) 2006-2019 INRIA and contributors + * + * Spoon is available either under the terms of the MIT License (see LICENSE-MIT.txt) of the Cecill-C License (see LICENSE-CECILL-C.txt). You as the user are entitled to choose the terms under which to adopt Spoon. + */ +package spoon.support.reflect.code; + +import spoon.reflect.annotations.MetamodelPropertyField; +import spoon.reflect.code.CtAbstractSwitch; +import spoon.reflect.code.CtCase; +import spoon.reflect.code.CtExpression; +import spoon.reflect.code.CtSwitchExpression; +import spoon.reflect.visitor.CtVisitor; +import spoon.support.reflect.declaration.CtElementImpl; + +import java.util.ArrayList; +import java.util.List; + +import static spoon.reflect.ModelElementContainerDefaultCapacities.SWITCH_CASES_CONTAINER_DEFAULT_CAPACITY; +import static spoon.reflect.path.CtRole.CASE; +import static spoon.reflect.path.CtRole.EXPRESSION; + +public class CtSwitchExpressionImpl extends CtExpressionImpl implements CtSwitchExpression { + private static final long serialVersionUID = 1L; + + @MetamodelPropertyField(role = CASE) + List> cases = emptyList(); + + @MetamodelPropertyField(role = EXPRESSION) + CtExpression expression; + + @Override + public void accept(CtVisitor visitor) { + visitor.visitCtSwitchExpression(this); + } + + @Override + public List> getCases() { + return cases; + } + + @Override + public CtExpression getSelector() { + return expression; + } + + @Override + public > T setCases(List> cases) { + if (cases == null || cases.isEmpty()) { + this.cases = CtElementImpl.emptyList(); + return (T) this; + } + getFactory().getEnvironment().getModelChangeListener().onListDeleteAll(this, CASE, this.cases, new ArrayList<>(this.cases)); + this.cases.clear(); + for (CtCase aCase : cases) { + addCase(aCase); + } + return (T) this; + } + + @Override + public > T setSelector(CtExpression selector) { + if (selector != null) { + selector.setParent(this); + } + getFactory().getEnvironment().getModelChangeListener().onObjectUpdate(this, EXPRESSION, selector, this.expression); + this.expression = selector; + return (T) this; + } + + @Override + public > T addCase(CtCase c) { + if (c == null) { + return (T) this; + } + if (cases == CtElementImpl.>emptyList()) { + cases = new ArrayList<>(SWITCH_CASES_CONTAINER_DEFAULT_CAPACITY); + } + c.setParent(this); + getFactory().getEnvironment().getModelChangeListener().onListAdd(this, CASE, this.cases, c); + cases.add(c); + return (T) this; + } + + @Override + public boolean removeCase(CtCase c) { + if (cases == CtElementImpl.>emptyList()) { + return false; + } + getFactory().getEnvironment().getModelChangeListener().onListDelete(this, CASE, cases, cases.indexOf(c), c); + return cases.remove(c); + } + + @Override + public CtSwitchExpression clone() { + return (CtSwitchExpression) super.clone(); + } +} diff --git a/src/main/java/spoon/support/reflect/code/CtSwitchImpl.java b/src/main/java/spoon/support/reflect/code/CtSwitchImpl.java index 923af2862cf..5486d29d47e 100644 --- a/src/main/java/spoon/support/reflect/code/CtSwitchImpl.java +++ b/src/main/java/spoon/support/reflect/code/CtSwitchImpl.java @@ -6,6 +6,7 @@ package spoon.support.reflect.code; import spoon.reflect.annotations.MetamodelPropertyField; +import spoon.reflect.code.CtAbstractSwitch; import spoon.reflect.code.CtCase; import spoon.reflect.code.CtExpression; import spoon.reflect.code.CtSwitch; @@ -44,7 +45,7 @@ public CtExpression getSelector() { } @Override - public > T setCases(List> cases) { + public > T setCases(List> cases) { if (cases == null || cases.isEmpty()) { this.cases = CtElementImpl.emptyList(); return (T) this; @@ -58,7 +59,7 @@ public > T setCases(List> cases) { } @Override - public > T setSelector(CtExpression selector) { + public > T setSelector(CtExpression selector) { if (selector != null) { selector.setParent(this); } @@ -68,7 +69,7 @@ public > T setSelector(CtExpression selector) { } @Override - public > T addCase(CtCase c) { + public > T addCase(CtCase c) { if (c == null) { return (T) this; } diff --git a/src/main/java/spoon/support/visitor/clone/CloneBuilder.java b/src/main/java/spoon/support/visitor/clone/CloneBuilder.java index b9ad3829c76..fc237c04907 100644 --- a/src/main/java/spoon/support/visitor/clone/CloneBuilder.java +++ b/src/main/java/spoon/support/visitor/clone/CloneBuilder.java @@ -4,8 +4,6 @@ * Spoon is available either under the terms of the MIT License (see LICENSE-MIT.txt) of the Cecill-C License (see LICENSE-CECILL-C.txt). You as the user are entitled to choose the terms under which to adopt Spoon. */ package spoon.support.visitor.clone; - - /** * Used to set all data in the cloned element. * @@ -119,6 +117,12 @@ public void visitCtBreak(spoon.reflect.code.CtBreak e) { super.visitCtBreak(e); } + // auto-generated, see spoon.generating.CloneVisitorGenerator + public void visitCtCase(spoon.reflect.code.CtCase e) { + ((spoon.reflect.code.CtCase) (other)).setCaseKind(e.getCaseKind()); + super.visitCtCase(e); + } + // auto-generated, see spoon.generating.CloneVisitorGenerator public void visitCtConstructor(spoon.reflect.declaration.CtConstructor e) { ((spoon.reflect.declaration.CtConstructor) (other)).setModifiers(e.getModifiers()); @@ -289,4 +293,3 @@ public void visitCtCompilationUnit(spoon.reflect.declaration.CtCompilationUnit c super.visitCtCompilationUnit(compilationUnit); } } - diff --git a/src/main/java/spoon/support/visitor/clone/CloneVisitor.java b/src/main/java/spoon/support/visitor/clone/CloneVisitor.java index fbb794e57cf..4254faaf33d 100644 --- a/src/main/java/spoon/support/visitor/clone/CloneVisitor.java +++ b/src/main/java/spoon/support/visitor/clone/CloneVisitor.java @@ -160,6 +160,7 @@ public void visitCtBreak(final spoon.reflect.code.CtBreak breakStatement) { spoon.reflect.code.CtBreak aCtBreak = breakStatement.getFactory().Core().createBreak(); this.builder.copy(breakStatement, aCtBreak); aCtBreak.setAnnotations(this.cloneHelper.clone(breakStatement.getAnnotations())); + aCtBreak.setExpression(this.cloneHelper.clone(breakStatement.getExpression())); aCtBreak.setComments(this.cloneHelper.clone(breakStatement.getComments())); this.cloneHelper.tailor(breakStatement, aCtBreak); this.other = aCtBreak; @@ -170,7 +171,7 @@ public void visitCtCase(final spoon.reflect.code.CtCase caseStatement) { spoon.reflect.code.CtCase aCtCase = caseStatement.getFactory().Core().createCase(); this.builder.copy(caseStatement, aCtCase); aCtCase.setAnnotations(this.cloneHelper.clone(caseStatement.getAnnotations())); - aCtCase.setCaseExpression(this.cloneHelper.clone(caseStatement.getCaseExpression())); + aCtCase.setCaseExpressions(this.cloneHelper.clone(caseStatement.getCaseExpressions())); aCtCase.setStatements(this.cloneHelper.clone(caseStatement.getStatements())); aCtCase.setComments(this.cloneHelper.clone(caseStatement.getComments())); this.cloneHelper.tailor(caseStatement, aCtCase); @@ -671,6 +672,20 @@ public void visitCtSwitch(final spoon.reflect.code.CtSwitch switchStateme this.other = aCtSwitch; } + // auto-generated, see spoon.generating.CloneVisitorGenerator + public void visitCtSwitchExpression(final spoon.reflect.code.CtSwitchExpression switchExpression) { + spoon.reflect.code.CtSwitchExpression aCtSwitchExpression = switchExpression.getFactory().Core().createSwitchExpression(); + this.builder.copy(switchExpression, aCtSwitchExpression); + aCtSwitchExpression.setAnnotations(this.cloneHelper.clone(switchExpression.getAnnotations())); + aCtSwitchExpression.setSelector(this.cloneHelper.clone(switchExpression.getSelector())); + aCtSwitchExpression.setCases(this.cloneHelper.clone(switchExpression.getCases())); + aCtSwitchExpression.setComments(this.cloneHelper.clone(switchExpression.getComments())); + aCtSwitchExpression.setType(this.cloneHelper.clone(switchExpression.getType())); + aCtSwitchExpression.setTypeCasts(this.cloneHelper.clone(switchExpression.getTypeCasts())); + this.cloneHelper.tailor(switchExpression, aCtSwitchExpression); + this.other = aCtSwitchExpression; + } + // auto-generated, see spoon.generating.CloneVisitorGenerator public void visitCtSynchronized(final spoon.reflect.code.CtSynchronized synchro) { spoon.reflect.code.CtSynchronized aCtSynchronized = synchro.getFactory().Core().createSynchronized(); @@ -1066,4 +1081,3 @@ public void visitCtTypeMemberWildcardImportReference(spoon.reflect.reference.CtT this.other = aCtTypeMemberWildcardImportReference; } } - diff --git a/src/main/java/spoon/support/visitor/replace/ReplacementVisitor.java b/src/main/java/spoon/support/visitor/replace/ReplacementVisitor.java index f94e7b7586a..07b0afee0ff 100644 --- a/src/main/java/spoon/support/visitor/replace/ReplacementVisitor.java +++ b/src/main/java/spoon/support/visitor/replace/ReplacementVisitor.java @@ -305,16 +305,30 @@ public void set(java.util.List replace) { } // auto-generated, see spoon.generating.ReplacementVisitorGenerator - class CtCaseCaseExpressionReplaceListener implements spoon.support.visitor.replace.ReplaceListener { - private final spoon.reflect.code.CtCase element; + class CtBreakExpressionReplaceListener implements spoon.support.visitor.replace.ReplaceListener { + private final spoon.reflect.code.CtBreak element; - CtCaseCaseExpressionReplaceListener(spoon.reflect.code.CtCase element) { + CtBreakExpressionReplaceListener(spoon.reflect.code.CtBreak element) { this.element = element; } @java.lang.Override public void set(spoon.reflect.code.CtExpression replace) { - this.element.setCaseExpression(replace); + this.element.setExpression(replace); + } + } + + // auto-generated, see spoon.generating.ReplacementVisitorGenerator + class CtCaseCaseExpressionsReplaceListener implements spoon.support.visitor.replace.ReplaceListListener { + private final spoon.reflect.code.CtCase element; + + CtCaseCaseExpressionsReplaceListener(spoon.reflect.code.CtCase element) { + this.element = element; + } + + @java.lang.Override + public void set(java.util.List replace) { + this.element.setCaseExpressions(replace); } } @@ -879,10 +893,10 @@ public void set(spoon.reflect.code.CtExpression replace) { } // auto-generated, see spoon.generating.ReplacementVisitorGenerator - class CtSwitchSelectorReplaceListener implements spoon.support.visitor.replace.ReplaceListener { - private final spoon.reflect.code.CtSwitch element; + class CtAbstractSwitchSelectorReplaceListener implements spoon.support.visitor.replace.ReplaceListener { + private final spoon.reflect.code.CtAbstractSwitch element; - CtSwitchSelectorReplaceListener(spoon.reflect.code.CtSwitch element) { + CtAbstractSwitchSelectorReplaceListener(spoon.reflect.code.CtAbstractSwitch element) { this.element = element; } @@ -893,10 +907,10 @@ public void set(spoon.reflect.code.CtExpression replace) { } // auto-generated, see spoon.generating.ReplacementVisitorGenerator - class CtSwitchCasesReplaceListener implements spoon.support.visitor.replace.ReplaceListListener { - private final spoon.reflect.code.CtSwitch element; + class CtAbstractSwitchCasesReplaceListener implements spoon.support.visitor.replace.ReplaceListListener { + private final spoon.reflect.code.CtAbstractSwitch element; - CtSwitchCasesReplaceListener(spoon.reflect.code.CtSwitch element) { + CtAbstractSwitchCasesReplaceListener(spoon.reflect.code.CtAbstractSwitch element) { this.element = element; } @@ -1328,7 +1342,7 @@ public void set(spoon.reflect.reference.CtTypeReference replace) { public static void replace(spoon.reflect.declaration.CtElement original, spoon.reflect.declaration.CtElement replace) { try { - new spoon.support.visitor.replace.ReplacementVisitor(original, (replace == null ? EMPTY : new spoon.reflect.declaration.CtElement[]{ replace })).scan(original.getParent()); + new spoon.support.visitor.replace.ReplacementVisitor(original, replace == null ? spoon.support.visitor.replace.ReplacementVisitor.EMPTY : new spoon.reflect.declaration.CtElement[]{ replace }).scan(original.getParent()); } catch (spoon.support.visitor.replace.InvalidReplaceException e) { throw e; } @@ -1350,7 +1364,7 @@ public static void replace(spoon private ReplacementVisitor(spoon.reflect.declaration.CtElement original, spoon.reflect.declaration.CtElement... replace) { this.original = original; - this.replace = (replace == null) ? EMPTY : replace; + this.replace = (replace == null) ? spoon.support.visitor.replace.ReplacementVisitor.EMPTY : replace; } private void replaceInMapIfExist(java.util.Map mapProtected, spoon.support.visitor.replace.ReplaceMapListener listener) { @@ -1358,16 +1372,16 @@ private void replaceInMapIfEx V shouldBeDeleted = null; K key = null; for (java.util.Map.Entry entry : map.entrySet()) { - if ((entry.getValue()) == (original)) { + if (entry.getValue() == original) { shouldBeDeleted = entry.getValue(); key = entry.getKey(); break; } } if (shouldBeDeleted != null) { - if ((replace.length) > 0) { - if ((replace.length) > 1) { - throw new spoon.support.visitor.replace.InvalidReplaceException(("Cannot replace single value by multiple values in " + (listener.getClass().getSimpleName()))); + if (replace.length > 0) { + if (replace.length > 1) { + throw new spoon.support.visitor.replace.InvalidReplaceException("Cannot replace single value by multiple values in " + listener.getClass().getSimpleName()); } V val = ((V) (replace[0])); if (val != null) { @@ -1387,7 +1401,7 @@ private void replaceInSetIfExist java.util.Set set = new java.util.HashSet<>(setProtected); T shouldBeDeleted = null; for (T element : set) { - if (element == (original)) { + if (element == original) { shouldBeDeleted = element; break; } @@ -1408,8 +1422,8 @@ private void replaceInListIfExis java.util.List list = new java.util.ArrayList<>(listProtected); T shouldBeDeleted = null; int index = 0; - for (int i = 0; i < (list.size()); i++) { - if ((list.get(i)) == (original)) { + for (int i = 0; i < list.size(); i++) { + if (list.get(i) == original) { index = i; shouldBeDeleted = list.get(i); break; @@ -1417,7 +1431,7 @@ private void replaceInListIfExis } if (shouldBeDeleted != null) { list.remove(index); - if ((replace.length) > 0) { + if (replace.length > 0) { for (spoon.reflect.declaration.CtElement aReplace : replace) { T ele = ((T) (aReplace)); if (ele != null) { @@ -1432,11 +1446,11 @@ private void replaceInListIfExis } private void replaceElementIfExist(spoon.reflect.declaration.CtElement candidate, spoon.support.visitor.replace.ReplaceListener listener) { - if (candidate == (original)) { + if (candidate == original) { spoon.reflect.declaration.CtElement val = null; - if ((replace.length) > 0) { - if ((replace.length) > 1) { - throw new spoon.support.visitor.replace.InvalidReplaceException(("Cannot replace single value by multiple values in " + (listener.getClass().getSimpleName()))); + if (replace.length > 0) { + if (replace.length > 1) { + throw new spoon.support.visitor.replace.InvalidReplaceException("Cannot replace single value by multiple values in " + listener.getClass().getSimpleName()); } val = replace[0]; } @@ -1548,6 +1562,7 @@ public void visitCtBlock(final spoon.reflect.code.CtBlock block) { @java.lang.Override public void visitCtBreak(final spoon.reflect.code.CtBreak breakStatement) { replaceInListIfExist(breakStatement.getAnnotations(), new spoon.support.visitor.replace.ReplacementVisitor.CtElementAnnotationsReplaceListener(breakStatement)); + replaceElementIfExist(breakStatement.getExpression(), new spoon.support.visitor.replace.ReplacementVisitor.CtBreakExpressionReplaceListener(breakStatement)); replaceInListIfExist(breakStatement.getComments(), new spoon.support.visitor.replace.ReplacementVisitor.CtElementCommentsReplaceListener(breakStatement)); } @@ -1555,7 +1570,7 @@ public void visitCtBreak(final spoon.reflect.code.CtBreak breakStatement) { @java.lang.Override public void visitCtCase(final spoon.reflect.code.CtCase caseStatement) { replaceInListIfExist(caseStatement.getAnnotations(), new spoon.support.visitor.replace.ReplacementVisitor.CtElementAnnotationsReplaceListener(caseStatement)); - replaceElementIfExist(caseStatement.getCaseExpression(), new spoon.support.visitor.replace.ReplacementVisitor.CtCaseCaseExpressionReplaceListener(caseStatement)); + replaceInListIfExist(caseStatement.getCaseExpressions(), new spoon.support.visitor.replace.ReplacementVisitor.CtCaseCaseExpressionsReplaceListener(caseStatement)); replaceInListIfExist(caseStatement.getStatements(), new spoon.support.visitor.replace.ReplacementVisitor.CtStatementListStatementsReplaceListener(caseStatement)); replaceInListIfExist(caseStatement.getComments(), new spoon.support.visitor.replace.ReplacementVisitor.CtElementCommentsReplaceListener(caseStatement)); } @@ -1925,11 +1940,22 @@ public void visitCtStatementList(final spoon.reflect.code.CtStatementList st @java.lang.Override public void visitCtSwitch(final spoon.reflect.code.CtSwitch switchStatement) { replaceInListIfExist(switchStatement.getAnnotations(), new spoon.support.visitor.replace.ReplacementVisitor.CtElementAnnotationsReplaceListener(switchStatement)); - replaceElementIfExist(switchStatement.getSelector(), new spoon.support.visitor.replace.ReplacementVisitor.CtSwitchSelectorReplaceListener(switchStatement)); - replaceInListIfExist(switchStatement.getCases(), new spoon.support.visitor.replace.ReplacementVisitor.CtSwitchCasesReplaceListener(switchStatement)); + replaceElementIfExist(switchStatement.getSelector(), new spoon.support.visitor.replace.ReplacementVisitor.CtAbstractSwitchSelectorReplaceListener(switchStatement)); + replaceInListIfExist(switchStatement.getCases(), new spoon.support.visitor.replace.ReplacementVisitor.CtAbstractSwitchCasesReplaceListener(switchStatement)); replaceInListIfExist(switchStatement.getComments(), new spoon.support.visitor.replace.ReplacementVisitor.CtElementCommentsReplaceListener(switchStatement)); } + // auto-generated, see spoon.generating.ReplacementVisitorGenerator + @java.lang.Override + public void visitCtSwitchExpression(final spoon.reflect.code.CtSwitchExpression switchExpression) { + replaceInListIfExist(switchExpression.getAnnotations(), new spoon.support.visitor.replace.ReplacementVisitor.CtElementAnnotationsReplaceListener(switchExpression)); + replaceElementIfExist(switchExpression.getSelector(), new spoon.support.visitor.replace.ReplacementVisitor.CtAbstractSwitchSelectorReplaceListener(switchExpression)); + replaceInListIfExist(switchExpression.getCases(), new spoon.support.visitor.replace.ReplacementVisitor.CtAbstractSwitchCasesReplaceListener(switchExpression)); + replaceInListIfExist(switchExpression.getComments(), new spoon.support.visitor.replace.ReplacementVisitor.CtElementCommentsReplaceListener(switchExpression)); + replaceElementIfExist(switchExpression.getType(), new spoon.support.visitor.replace.ReplacementVisitor.CtTypedElementTypeReplaceListener(switchExpression)); + replaceInListIfExist(switchExpression.getTypeCasts(), new spoon.support.visitor.replace.ReplacementVisitor.CtExpressionTypeCastsReplaceListener(switchExpression)); + } + // auto-generated, see spoon.generating.ReplacementVisitorGenerator @java.lang.Override public void visitCtSynchronized(final spoon.reflect.code.CtSynchronized synchro) { diff --git a/src/test/java/spoon/generating/CloneVisitorGenerator.java b/src/test/java/spoon/generating/CloneVisitorGenerator.java index 6cb7f25e1e1..f541fd0f190 100644 --- a/src/test/java/spoon/generating/CloneVisitorGenerator.java +++ b/src/test/java/spoon/generating/CloneVisitorGenerator.java @@ -205,6 +205,7 @@ private CtInvocation createFactoryInvocation(CtVariableAccess element new CtScanner() { private final List excludesAST = Arrays.asList(// "spoon.support.reflect.declaration.CtTypeInformationImpl", "spoon.support.reflect.code.CtAbstractInvocationImpl", // + "spoon.support.reflect.declaration.CtTypeInformationImpl", "spoon.support.reflect.code.CtAbstractSwitchImpl", // "spoon.support.reflect.declaration.CtTypedElementImpl", "spoon.support.reflect.declaration.CtVariableImpl", // "spoon.support.reflect.reference.CtActualTypeContainerImpl", "spoon.support.reflect.code.CtCFlowBreakImpl", "spoon.support.reflect.code.CtLabelledFlowBreakImpl", // "spoon.support.reflect.declaration.CtCodeSnippetImpl", "spoon.support.reflect.declaration.CtFormalTypeDeclarerImpl", // diff --git a/src/test/java/spoon/test/api/Metamodel.java b/src/test/java/spoon/test/api/Metamodel.java index e3a717cd410..59596728f35 100644 --- a/src/test/java/spoon/test/api/Metamodel.java +++ b/src/test/java/spoon/test/api/Metamodel.java @@ -711,6 +711,18 @@ private static void initTypes(List types) { )); + types.add(new Type("CtSwitchExpression", spoon.reflect.code.CtSwitchExpression.class, spoon.support.reflect.code.CtSwitchExpressionImpl.class, fm -> fm + .field(CtRole.IS_IMPLICIT, false, false) + .field(CtRole.POSITION, false, false) + .field(CtRole.TYPE, false, false) + .field(CtRole.ANNOTATION, false, false) + .field(CtRole.EXPRESSION, false, false) + .field(CtRole.CASE, false, false) + .field(CtRole.COMMENT, false, false) + .field(CtRole.CAST, false, false) + + )); + types.add(new Type("CtTry", spoon.reflect.code.CtTry.class, spoon.support.reflect.code.CtTryImpl.class, fm -> fm .field(CtRole.IS_IMPLICIT, false, false) .field(CtRole.LABEL, false, false) @@ -961,6 +973,7 @@ private static void initTypes(List types) { types.add(new Type("CtCase", spoon.reflect.code.CtCase.class, spoon.support.reflect.code.CtCaseImpl.class, fm -> fm .field(CtRole.IS_IMPLICIT, false, false) .field(CtRole.LABEL, false, false) + .field(CtRole.CASE_KIND, false, false) .field(CtRole.POSITION, false, false) .field(CtRole.ANNOTATION, false, false) .field(CtRole.EXPRESSION, false, false) @@ -1192,6 +1205,7 @@ private static void initTypes(List types) { types.add(new Type("CtBreak", spoon.reflect.code.CtBreak.class, spoon.support.reflect.code.CtBreakImpl.class, fm -> fm .field(CtRole.IS_IMPLICIT, false, false) .field(CtRole.LABEL, false, false) + .field(CtRole.EXPRESSION, false, false) .field(CtRole.TARGET_LABEL, false, false) .field(CtRole.POSITION, false, false) .field(CtRole.ANNOTATION, false, false) diff --git a/src/test/java/spoon/test/comment/CommentTest.java b/src/test/java/spoon/test/comment/CommentTest.java index 4a6977d6df7..68d4b1e9471 100644 --- a/src/test/java/spoon/test/comment/CommentTest.java +++ b/src/test/java/spoon/test/comment/CommentTest.java @@ -803,7 +803,8 @@ public void testDocumentationContract() throws Exception { final Launcher launcher = new Launcher(); launcher.getEnvironment().setNoClasspath(true); launcher.getEnvironment().setCommentEnabled(true); - launcher.getEnvironment().setComplianceLevel(10); + launcher.getEnvironment().setComplianceLevel(12); + launcher.getEnvironment().setPreviewFeaturesEnabled(true); // interfaces. launcher.addInputResource("./src/main/java/spoon/reflect/"); launcher.addInputResource("./src/main/java/spoon/support/reflect/"); diff --git a/src/test/java/spoon/test/model/SwitchCaseTest.java b/src/test/java/spoon/test/model/SwitchCaseTest.java index 1cc7d57a464..2ada91b28ac 100644 --- a/src/test/java/spoon/test/model/SwitchCaseTest.java +++ b/src/test/java/spoon/test/model/SwitchCaseTest.java @@ -17,26 +17,180 @@ package spoon.test.model; import org.junit.Test; +import spoon.Launcher; +import spoon.reflect.CtModel; +import spoon.reflect.code.CaseKind; +import spoon.reflect.code.CtBreak; import spoon.reflect.code.CtCase; +import spoon.reflect.code.CtIf; import spoon.reflect.code.CtLiteral; +import spoon.reflect.code.CtLocalVariable; import spoon.reflect.code.CtStatement; import spoon.reflect.code.CtSwitch; +import spoon.reflect.code.CtSwitchExpression; import spoon.reflect.declaration.CtClass; +import spoon.reflect.declaration.CtElement; import spoon.reflect.declaration.CtMethod; +import spoon.reflect.declaration.CtType; import spoon.reflect.factory.Factory; import spoon.reflect.visitor.filter.TypeFilter; +import spoon.support.compiler.VirtualFile; import java.util.ArrayList; import java.util.List; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; import static spoon.testing.utils.ModelUtils.build; import static spoon.testing.utils.ModelUtils.createFactory; public class SwitchCaseTest { + private static String toSingleLineString(CtElement e) { + return e.toString().replace("\n", "").replace("\r", ""); + } + + @Test + public void testJava12ArrowCase() { + String arrow = "class A { public void f(int i) { int x; switch(i) { case 1 -> x = 10; case 2 -> x = 20; default -> x = 30; }; } }"; + String arrowWithBlock = "class B { public void f(int i) { int x; switch(i) { case 1 -> { x = 10; break; } case 2 -> x = 20; default -> x = 30; }; } }"; + String colon = "class C { public void f(int i) { int x; switch(i) { case 1: x = 10; x = 1; break; case 2: x = 20; break; default: x = 30; break; }; } }"; + + Launcher launcher = new Launcher(); + launcher.getEnvironment().setComplianceLevel(12); + launcher.getEnvironment().setPreviewFeaturesEnabled(true); + launcher.getEnvironment().setNoClasspath(true); + launcher.addInputResource(new VirtualFile(arrow)); + launcher.addInputResource(new VirtualFile(arrowWithBlock)); + launcher.addInputResource(new VirtualFile(colon)); + CtModel model = launcher.buildModel(); + + CtType classA = model.getAllTypes().stream().filter(c -> c.getSimpleName().equals("A")).findFirst().get(); + CtCase caseA1 = classA.getElements(new TypeFilter<>(CtCase.class)).get(0); + CtCase caseA2 = classA.getElements(new TypeFilter<>(CtCase.class)).get(1); + CtCase caseA3 = classA.getElements(new TypeFilter<>(CtCase.class)).get(2); + + // contract: we should print arrows like in the original source code + assertEquals("case 1 -> x = 10;", toSingleLineString(caseA1)); + assertEquals("case 2 -> x = 20;", toSingleLineString(caseA2)); + assertEquals("default -> x = 30;", toSingleLineString(caseA3)); + assertEquals(caseA1.getCaseKind(), CaseKind.ARROW); + assertEquals(caseA2.getCaseKind(), CaseKind.ARROW); + assertEquals(caseA3.getCaseKind(), CaseKind.ARROW); + + // contract: we should have implicit breaks (with expressions) for arrows + assertTrue(caseA1.getElements(new TypeFilter<>(CtBreak.class)).get(0).isImplicit()); + assertEquals("x = 10", caseA1.getElements(new TypeFilter<>(CtBreak.class)).get(0).getExpression().toString()); + assertTrue(caseA2.getElements(new TypeFilter<>(CtBreak.class)).get(0).isImplicit()); + assertEquals("x = 20", caseA2.getElements(new TypeFilter<>(CtBreak.class)).get(0).getExpression().toString()); + assertTrue(caseA3.getElements(new TypeFilter<>(CtBreak.class)).get(0).isImplicit()); + assertEquals("x = 30", caseA3.getElements(new TypeFilter<>(CtBreak.class)).get(0).getExpression().toString()); + + CtType classB = model.getAllTypes().stream().filter(c -> c.getSimpleName().equals("B")).findFirst().get(); + CtCase caseB1 = classB.getElements(new TypeFilter<>(CtCase.class)).get(0); + + // contract: explicit break (inside the block) should be printed + assertFalse(caseB1.getElements(new TypeFilter<>(CtBreak.class)).get(0).isImplicit()); + assertEquals("break", caseB1.getElements(new TypeFilter<>(CtBreak.class)).get(0).toString()); + + CtType classC = model.getAllTypes().stream().filter(c -> c.getSimpleName().equals("C")).findFirst().get(); + CtCase caseC1 = classC.getElements(new TypeFilter<>(CtCase.class)).get(0); + CtCase caseC2 = classC.getElements(new TypeFilter<>(CtCase.class)).get(1); + CtCase caseC3 = classC.getElements(new TypeFilter<>(CtCase.class)).get(2); + + // contract: old switch should work as usual + assertEquals("case 1 : x = 10; x = 1; break;", toSingleLineString(caseC1)); + assertEquals("case 2 : x = 20; break;", toSingleLineString(caseC2)); + assertEquals("default : x = 30; break;", toSingleLineString(caseC3)); + assertEquals(caseC1.getCaseKind(), CaseKind.COLON); + assertEquals(caseC2.getCaseKind(), CaseKind.COLON); + assertEquals(caseC3.getCaseKind(), CaseKind.COLON); + } + + @Test + public void testJava12MultipleCaseExpressions() { + // contract: we should handle multiple case expressions correctly + String code = "class A { public void f(int i) { int x; switch(i) { case 1,2,3 -> x = 10; case 4 -> x = 20; default -> x = 30; }; } }"; + Launcher launcher = new Launcher(); + launcher.getEnvironment().setComplianceLevel(12); + launcher.getEnvironment().setPreviewFeaturesEnabled(true); + launcher.getEnvironment().setNoClasspath(true); + launcher.addInputResource(new VirtualFile(code)); + CtModel model = launcher.buildModel(); + CtType classA = model.getAllTypes().stream().filter(c -> c.getSimpleName().equals("A")).findFirst().get(); + CtCase caseA1 = classA.getElements(new TypeFilter<>(CtCase.class)).get(0); + CtCase caseA2 = classA.getElements(new TypeFilter<>(CtCase.class)).get(1); + CtCase caseA3 = classA.getElements(new TypeFilter<>(CtCase.class)).get(2); + + assertEquals(3, caseA1.getCaseExpressions().size()); + assertEquals("1", caseA1.getCaseExpressions().get(0).toString()); + assertEquals("2", caseA1.getCaseExpressions().get(1).toString()); + assertEquals("3", caseA1.getCaseExpressions().get(2).toString()); + + assertEquals(1, caseA2.getCaseExpressions().size()); + assertEquals("4", caseA2.getCaseExpressions().get(0).toString()); + + assertEquals(0, caseA3.getCaseExpressions().size()); + assertEquals("default -> x = 30;", toSingleLineString(caseA3)); + } + + @Test + public void testJava12BreakExpression() { + // contract: we should properly handle explicit break with expression inside switch expression + String code = "class A { public void f(String s) { int result = switch (s) { case \"Foo\": break 1; case \"Bar\": break 2; default: break 0; }; }"; + Launcher launcher = new Launcher(); + launcher.getEnvironment().setComplianceLevel(12); + launcher.getEnvironment().setPreviewFeaturesEnabled(true); + launcher.getEnvironment().setNoClasspath(true); + launcher.addInputResource(new VirtualFile(code)); + CtModel model = launcher.buildModel(); + List breaks = model.getElements(new TypeFilter<>(CtBreak.class)); + + assertEquals("1", breaks.get(0).getExpression().toString()); + assertEquals("break 1", breaks.get(0).toString()); + assertNull(breaks.get(0).getLabel()); + + assertEquals("2", breaks.get(1).getExpression().toString()); + assertNull(breaks.get(1).getLabel()); + assertEquals("break 2", breaks.get(1).toString()); + + assertEquals("0", breaks.get(2).getExpression().toString()); + assertNull(breaks.get(2).getLabel()); + assertEquals("break 0", breaks.get(2).toString()); + } + + @Test + public void testJava12SwitchExpression() { + // contract: we should handle switch expressions properly + String code = "class A { public void f(int i) { int x = switch(i) { case 1 -> 10; case 2 -> 20; default -> 30; }; } }"; + Launcher launcher = new Launcher(); + launcher.getEnvironment().setComplianceLevel(12); + launcher.getEnvironment().setPreviewFeaturesEnabled(true); + launcher.getEnvironment().setNoClasspath(true); + launcher.addInputResource(new VirtualFile(code)); + CtModel model = launcher.buildModel(); + CtLocalVariable localVariable = model.getElements(new TypeFilter<>(CtLocalVariable.class)).get(0); + assertTrue(localVariable.getAssignment() instanceof CtSwitchExpression); + assertEquals("int x = switch (i) { case 1 -> 10; case 2 -> 20; default -> 30;}", toSingleLineString(localVariable)); + } + + @Test + public void testJava12SwitchExpressionInIf() { + // contract: just another test for switch expressions + String code = "class A { public void f(int i) { if (switch (i) { case 1, 2 -> true; default -> false; }) {} }; } }"; + Launcher launcher = new Launcher(); + launcher.getEnvironment().setComplianceLevel(12); + launcher.getEnvironment().setPreviewFeaturesEnabled(true); + launcher.getEnvironment().setNoClasspath(true); + launcher.addInputResource(new VirtualFile(code)); + CtModel model = launcher.buildModel(); + CtIf ctIf = model.getElements(new TypeFilter<>(CtIf.class)).get(0); + assertEquals("if (switch (i) { case 1, 2 -> true; default -> false;}) {}", toSingleLineString(ctIf)); + } + @Test public void testIterationStatements() { Factory factory = createFactory();