Browse Source

Validation for PostFix (#1963)

* postfix increment and decrement operators can only be applied to reals

* Added validation rule for postfix only on variables
Andreas Mülder 7 years ago
parent
commit
f1ce94efbb

+ 13 - 11
plugins/org.yakindu.base.expressions/src/org/yakindu/base/expressions/inferrer/ExpressionsTypeInferrer.java

@@ -183,9 +183,11 @@ public class ExpressionsTypeInferrer extends AbstractTypeSystemInferrer implemen
 		}
 		return result1;
 	}
-	
+
 	public InferenceResult doInfer(PostFixUnaryExpression expression) {
-		return inferTypeDispatch(expression.getOperand());
+		InferenceResult result = inferTypeDispatch(expression.getOperand());
+		assertIsSubType(result, getResultFor(REAL), null);
+		return result;
 	}
 
 	public InferenceResult doInfer(TypeCastExpression e) {
@@ -254,22 +256,22 @@ public class ExpressionsTypeInferrer extends AbstractTypeSystemInferrer implemen
 		// resolve type parameter from operation call
 		List<InferenceResult> argumentTypes = getArgumentTypes(getOperationArguments(e));
 		List<Parameter> parameters = op.getParameters();
-		
+
 		List<InferenceResult> argumentsToInfer = new ArrayList<>();
 		List<Parameter> parametersToInfer = new ArrayList<>();
-		
-		for(int i = 0; i < parameters.size(); i++) {
-			if(!typeParameterMapping.containsKey(parameters.get(i).getType())) {
+
+		for (int i = 0; i < parameters.size(); i++) {
+			if (!typeParameterMapping.containsKey(parameters.get(i).getType())) {
 				parametersToInfer.add(parameters.get(i));
-				if(i < argumentTypes.size()) {
+				if (i < argumentTypes.size()) {
 					argumentsToInfer.add(argumentTypes.get(i));
 				}
-				
+
 			}
 		}
-		
-		typeParameterInferrer.inferTypeParametersFromOperationArguments(parametersToInfer, argumentsToInfer, typeParameterMapping,
-				acceptor);
+
+		typeParameterInferrer.inferTypeParametersFromOperationArguments(parametersToInfer, argumentsToInfer,
+				typeParameterMapping, acceptor);
 		validateParameters(typeParameterMapping, op, getOperationArguments(e), acceptor);
 		return inferReturnType(op, typeParameterMapping);
 	}

+ 42 - 28
plugins/org.yakindu.base.expressions/src/org/yakindu/base/expressions/validation/ExpressionsJavaValidator.java

@@ -28,6 +28,7 @@ import org.yakindu.base.expressions.expressions.ElementReferenceExpression;
 import org.yakindu.base.expressions.expressions.Expression;
 import org.yakindu.base.expressions.expressions.ExpressionsPackage;
 import org.yakindu.base.expressions.expressions.FeatureCall;
+import org.yakindu.base.expressions.expressions.PostFixUnaryExpression;
 import org.yakindu.base.types.AnnotatableElement;
 import org.yakindu.base.types.Annotation;
 import org.yakindu.base.types.ComplexType;
@@ -76,25 +77,28 @@ public class ExpressionsJavaValidator extends org.yakindu.base.expressions.valid
 
 	public static final String ERROR_DUPLICATE_PARAMETER_ASSIGNMENT_CODE = "ErrorDuplicateParameterAssignment";
 	public static final String ERROR_DUPLICATE_PARAMETER_ASSIGNMENT_MSG = "Duplicate assignment to parameter '%s'.";
-	
+
 	public static final String ERROR_ASSIGNMENT_TO_CONST_CODE = "AssignmentToConst";
 	public static final String ERROR_ASSIGNMENT_TO_CONST_MSG = "Assignment to constant not allowed.";
-	
+
 	public static final String ERROR_LEFT_HAND_ASSIGNMENT_CODE = "LeftHandAssignment";
 	public static final String ERROR_LEFT_HAND_ASSIGNMENT_MSG = "The left-hand side of an assignment must be a variable.";
-	
+
 	public static final String ERROR_WRONG_NUMBER_OF_ARGUMENTS_CODE = "WrongNrOfArgs";
 	public static final String ERROR_WRONG_NUMBER_OF_ARGUMENTS_MSG = "Wrong number of arguments, expected %s .";
-	
+
 	public static final String ERROR_VAR_ARGS_LAST_CODE = "VarArgsMustBeLast";
 	public static final String ERROR_VAR_ARGS_LAST_MSG = "The variable argument type must be the last argument.";
-	
+
 	public static final String ERROR_WRONG_ANNOTATION_TARGET_CODE = "WrongAnnotationTarget";
 	public static final String ERROR_WRONG_ANNOTATION_TARGET_MSG = "Annotation '%s' can not be applied on %s .";
-	
+
 	public static final String ERROR_OPTIONAL_MUST_BE_LAST_CODE = "OptionalParametersLast";
 	public static final String ERROR_OPTIONAL_MUST_BE_LAST_MSG = "Required parameters must not be defined after optional parameters.";
 
+	public static final String POSTFIX_ONLY_ON_VARIABLES_CODE = "PostfixOnlyOnVariables";
+	public static final String POSTFIX_ONLY_ON_VARIABLES_MSG = "Invalid argument to operator '++/--'";
+
 	@Inject
 	private GenericsPrettyPrinter printer;
 	@Inject
@@ -123,6 +127,14 @@ public class ExpressionsJavaValidator extends org.yakindu.base.expressions.valid
 		}
 	}
 
+	@Check
+	public void checkPostFixOperatorOnlyOnVariables(PostFixUnaryExpression expression) {
+		if (!(expression.getOperand() instanceof ElementReferenceExpression)
+				&& !(expression.getOperand() instanceof FeatureCall)) {
+			error(POSTFIX_ONLY_ON_VARIABLES_MSG, expression, null, POSTFIX_ONLY_ON_VARIABLES_CODE);
+		}
+	}
+
 	@Check
 	public void checkIsRaw(TypeSpecifier typedElement) {
 		Type type = typedElement.getType();
@@ -227,7 +239,7 @@ public class ExpressionsJavaValidator extends org.yakindu.base.expressions.valid
 			}
 		}
 	}
-	
+
 	@Check(CheckType.FAST)
 	public void checkAssignmentToFinalVariable(AssignmentExpression exp) {
 		Expression varRef = exp.getVarRef();
@@ -238,27 +250,31 @@ public class ExpressionsJavaValidator extends org.yakindu.base.expressions.valid
 			referencedObject = ((ElementReferenceExpression) varRef).getReference();
 		if (referencedObject instanceof Property) {
 			if (((Property) referencedObject).isConst()) {
-				error(ERROR_ASSIGNMENT_TO_CONST_MSG, ExpressionsPackage.Literals.ASSIGNMENT_EXPRESSION__VAR_REF, ERROR_ASSIGNMENT_TO_CONST_CODE);
+				error(ERROR_ASSIGNMENT_TO_CONST_MSG, ExpressionsPackage.Literals.ASSIGNMENT_EXPRESSION__VAR_REF,
+						ERROR_ASSIGNMENT_TO_CONST_CODE);
 			}
 		}
 	}
-	
+
 	@Check(CheckType.FAST)
 	public void checkLeftHandAssignment(final AssignmentExpression expression) {
 		Expression varRef = expression.getVarRef();
 		if (varRef instanceof FeatureCall) {
 			EObject referencedObject = ((FeatureCall) varRef).getFeature();
 			if (!(referencedObject instanceof Property)) {
-				error(ERROR_LEFT_HAND_ASSIGNMENT_MSG, ExpressionsPackage.Literals.ASSIGNMENT_EXPRESSION__VAR_REF, ERROR_LEFT_HAND_ASSIGNMENT_CODE);
+				error(ERROR_LEFT_HAND_ASSIGNMENT_MSG, ExpressionsPackage.Literals.ASSIGNMENT_EXPRESSION__VAR_REF,
+						ERROR_LEFT_HAND_ASSIGNMENT_CODE);
 			}
 		} else if (varRef instanceof ElementReferenceExpression) {
 			EObject referencedObject = ((ElementReferenceExpression) varRef).getReference();
-			if (!(referencedObject instanceof Property) && !(referencedObject  instanceof Parameter)) {
-				error(ERROR_LEFT_HAND_ASSIGNMENT_MSG, ExpressionsPackage.Literals.ASSIGNMENT_EXPRESSION__VAR_REF, ERROR_LEFT_HAND_ASSIGNMENT_CODE);
+			if (!(referencedObject instanceof Property) && !(referencedObject instanceof Parameter)) {
+				error(ERROR_LEFT_HAND_ASSIGNMENT_MSG, ExpressionsPackage.Literals.ASSIGNMENT_EXPRESSION__VAR_REF,
+						ERROR_LEFT_HAND_ASSIGNMENT_CODE);
 			}
 
 		} else {
-			error(ERROR_LEFT_HAND_ASSIGNMENT_MSG, ExpressionsPackage.Literals.ASSIGNMENT_EXPRESSION__VAR_REF, ERROR_LEFT_HAND_ASSIGNMENT_CODE);
+			error(ERROR_LEFT_HAND_ASSIGNMENT_MSG, ExpressionsPackage.Literals.ASSIGNMENT_EXPRESSION__VAR_REF,
+					ERROR_LEFT_HAND_ASSIGNMENT_CODE);
 		}
 	}
 
@@ -281,24 +297,22 @@ public class ExpressionsJavaValidator extends org.yakindu.base.expressions.valid
 	protected void assertOperationArguments(Operation operation, List<Expression> args) {
 		EList<Parameter> parameters = operation.getParameters();
 		List<Parameter> optionalParameters = filterOptionalParameters(parameters);
-		if (
-			(operation.isVariadic() && operation.getVarArgIndex() > args.size())
-			|| 
-			(!operation.isVariadic() &&
-					!(args.size() <= parameters.size() && args.size() >= parameters.size() - optionalParameters.size()))
-			) {
-			error(String.format(ERROR_WRONG_NUMBER_OF_ARGUMENTS_MSG, parameters), null, ERROR_WRONG_NUMBER_OF_ARGUMENTS_CODE);
+		if ((operation.isVariadic() && operation.getVarArgIndex() > args.size())
+				|| (!operation.isVariadic() && !(args.size() <= parameters.size()
+						&& args.size() >= parameters.size() - optionalParameters.size()))) {
+			error(String.format(ERROR_WRONG_NUMBER_OF_ARGUMENTS_MSG, parameters), null,
+					ERROR_WRONG_NUMBER_OF_ARGUMENTS_CODE);
 		}
 	}
-	
+
 	/**
 	 * @param parameters
 	 * @return
 	 */
 	protected List<Parameter> filterOptionalParameters(EList<Parameter> parameters) {
 		List<Parameter> optionalParameters = new ArrayList<>();
-		for(Parameter p : parameters) {
-			if(p.isOptional()) {
+		for (Parameter p : parameters) {
+			if (p.isOptional()) {
 				optionalParameters.add(p);
 			}
 		}
@@ -312,13 +326,13 @@ public class ExpressionsJavaValidator extends org.yakindu.base.expressions.valid
 					ERROR_VAR_ARGS_LAST_CODE);
 		}
 	}
-	
+
 	@Check(CheckType.FAST)
 	public void checkAnnotationTarget(final AnnotatableElement element) {
 		EList<Annotation> annotations = element.getAnnotations();
 		for (Annotation annotation : annotations) {
 			EList<EObject> targets = annotation.getType().getTargets();
-			if(targets.isEmpty())
+			if (targets.isEmpty())
 				continue;
 			boolean found = Iterables.any(targets, new Predicate<EObject>() {
 				@Override
@@ -328,12 +342,12 @@ public class ExpressionsJavaValidator extends org.yakindu.base.expressions.valid
 			});
 			if (!found) {
 				error(String.format(ERROR_WRONG_ANNOTATION_TARGET_MSG, annotation.getType().getName(),
-						element.eClass()), null,
-						element.getAnnotations().indexOf(annotation), ERROR_WRONG_ANNOTATION_TARGET_CODE);
+						element.eClass()), null, element.getAnnotations().indexOf(annotation),
+						ERROR_WRONG_ANNOTATION_TARGET_CODE);
 			}
 		}
 	}
-	
+
 	@Check(CheckType.FAST)
 	public void checkOptionalArgumentsAreLast(Operation op) {
 		boolean foundOptional = false;

File diff suppressed because it is too large
+ 1082 - 1064
test-plugins/org.yakindu.sct.model.stext.test/src/org/yakindu/sct/model/stext/test/TypeInferrerTest.java


+ 17 - 1
test-plugins/org.yakindu.sct.model.stext.test/src/org/yakindu/sct/model/stext/test/validation/STextJavaValidatorTest.java

@@ -35,6 +35,8 @@ import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.yakindu.base.expressions.expressions.Expression;
+import org.yakindu.base.expressions.terminals.ExpressionsValueConverterService;
+import org.yakindu.base.expressions.validation.ExpressionsJavaValidator;
 import org.yakindu.base.types.Operation;
 import org.yakindu.base.types.inferrer.ITypeSystemInferrer;
 import org.yakindu.base.types.typesystem.ITypeSystem;
@@ -76,7 +78,7 @@ public class STextJavaValidatorTest extends AbstractSTextValidationTest implemen
 
 	@Inject
 	TestCompletenessAssertions checkAvailable;
-
+	
 	/**
 	 * @see STextJavaValidator#checkVariableDefinition(org.yakindu.sct.model.stext.stext.VariableDefinition)
 	 */
@@ -400,6 +402,20 @@ public class STextJavaValidatorTest extends AbstractSTextValidationTest implemen
 		AssertableDiagnostics validationResult = tester.validate(model);
 		validationResult.assertOK();
 	}
+	
+	@Test
+	public void checkPostFixOperatorOnlyOnVariables() {
+		EObject model = super.parseExpression("ABC.intVar++", Expression.class.getSimpleName(), interfaceScope());
+		AssertableDiagnostics validationResult = tester.validate(model);
+		validationResult.assertOK();
+		model = super.parseExpression("intVar++", Expression.class.getSimpleName(), internalScope());
+		validationResult = tester.validate(model);
+		validationResult.assertOK();
+		model = super.parseExpression("5++", Expression.class.getSimpleName(), interfaceScope());
+		validationResult = tester.validate(model);
+		validationResult.assertError(ExpressionsJavaValidator.POSTFIX_ONLY_ON_VARIABLES_CODE);
+		
+	}
 
 	/**
 	 *