@Check(CheckType.NORMAL) public void checkForImpureJavaCallsInCheckConstraints(CheckConstraint checkConstraint) { if (checkConstraint.getExpression() != null) { checkForImpureJavaCallsInternal(checkConstraint.getExpression()); } }
@Check public void checkRecursivePatternCall(PatternCall call) { Map<PatternCall, Set<PatternCall>> graph = cache.get(call.eResource(), call.eResource(), new CallGraphProvider(call.eResource())); LinkedList<PatternCall> result = dfsCheckCycle(call, graph); if (result != null) { StringBuilder buffer = new StringBuilder(); boolean first = true; for (PatternCall elem : result) { if (first) { first = false; } else { buffer.append(" -> "); } buffer.append(prettyPrintPatternCall(elem)); } if (isNegativePatternCall(call)) { error(String.format(RECURSIVE_PATTERN_CALL_NEGATIVE, buffer.toString()), call, PatternLanguagePackage.Literals.PATTERN_CALL__PATTERN_REF, IssueCodes.RECURSIVE_PATTERN_CALL); } else if (PatternLanguageHelper.isTransitive(call)) { error(String.format(RECURSIVE_PATTERN_CALL_TRANSITIVE, buffer.toString()), call, PatternLanguagePackage.Literals.PATTERN_CALL__PATTERN_REF, IssueCodes.RECURSIVE_PATTERN_CALL); } else { warning(String.format(RECURSIVE_PATTERN_CALL, buffer.toString()), call, PatternLanguagePackage.Literals.PATTERN_CALL__PATTERN_REF, IssueCodes.RECURSIVE_PATTERN_CALL); } } }
final int arity = expectedTypes.size(); if (2 != arity) { error(String.format(TRANSITIVE_CLOSURE_ARITY_IN_PATTERNCALL, getFormattedCall(call), arity), PatternLanguagePackage.Literals.CALLABLE_RELATION__TRANSITIVE, IssueCodes.TRANSITIVE_PATTERNCALL_ARITY); IInputKey type2 = expectedTypes.get(1); if (!typeSystem.isConformant(type1, type2) && !typeSystem.isConformant(type2, type1)) { error(String.format( "The parameter types %s and %s are not compatible, so no transitive references can exist in instance models.", typeSystem.typeString(type1), typeSystem.typeString(type2)), getParameterFeature(call), IssueCodes.TRANSITIVE_PATTERNCALL_TYPE); error(String.format( "Reflexive transitive closure is not supported over non enumerable type %s.", typeSystem.typeString(type1)), getParameterFeature(call), 0, IssueCodes.TRANSITIVE_PATTERNCALL_TYPE); || eContainer instanceof AggregatedValue) { error(String.format(TRANSITIVE_CLOSURE_ONLY_IN_POSITIVE_COMPOSITION, getFormattedCall(call)), PatternLanguagePackage.Literals.CALLABLE_RELATION__TRANSITIVE, IssueCodes.TRANSITIVE_PATTERNCALL_NOT_APPLICABLE);
@Check public void checkPatternBody(PatternBody body) { if (body.getConstraints().isEmpty()) { String bodyName = getName(body); if (bodyName == null) { Pattern pattern = ((Pattern) body.eContainer()); String patternName = pattern.getName(); error("A patternbody of " + patternName + " is empty", body, PatternLanguagePackage.Literals.PATTERN_BODY__CONSTRAINTS, IssueCodes.PATTERN_BODY_EMPTY); } else { error("The patternbody " + bodyName + " cannot be empty", body, PatternLanguagePackage.Literals.PATTERN_BODY__NAME, IssueCodes.PATTERN_BODY_EMPTY); } } }
@Check public void checkPrivatePatternCall(PatternCall call) { final Pattern calledPattern = call.getPatternRef(); if (calledPattern != null && calledPattern.getModifiers() != null) { if (PatternLanguageHelper.isPrivate(calledPattern) && calledPattern.eResource() != call.eResource()){ error(String.format("The pattern %s is not visible.", getFormattedPattern(calledPattern)), PatternLanguagePackage.Literals.PATTERN_CALL__PATTERN_REF, IssueCodes.PRIVATE_PATTERN_CALLED); } } }
@Check public void checkPatternCallParameters(PatternCall call) { if (call.getPatternRef() != null && call.getPatternRef().getName() != null && call.getParameters() != null) { final int definitionParameterSize = call.getPatternRef().getParameters().size(); final int callParameterSize = call.getParameters().size(); if (definitionParameterSize != callParameterSize) { error("The pattern " + getFormattedPattern(call.getPatternRef()) + " is not applicable for the arguments(" + getFormattedArgumentsList(call.getParameters()) + ")", PatternLanguagePackage.Literals.PATTERN_CALL__PATTERN_REF, IssueCodes.WRONG_NUMBER_PATTERNCALL_PARAMETER); } } }
private void executeDefaultAnnotationValidation(Annotation annotation, IPatternAnnotationValidator validator) { if (validator.isDeprecated()) { warning(String.format("Annotation %s is deprecated.", annotation.getName()), annotation, PatternLanguagePackage.Literals.ANNOTATION__NAME, IssueCodes.DEPRECATION); error(UNKNOWN_ANNOTATION_ATTRIBUTE + unknownParameter.getName(), unknownParameter, PatternLanguagePackage.Literals.ANNOTATION_PARAMETER__NAME, annotation.getParameters().indexOf(unknownParameter), IssueCodes.UNKNOWN_ANNOTATION_PARAMETER); error(MISSING_ANNOTATION_ATTRIBUTE + missingAttribute, annotation, PatternLanguagePackage.Literals.ANNOTATION__PARAMETERS, IssueCodes.MISSING_REQUIRED_ANNOTATION_PARAMETER); warning(String.format("Annotation parameter %s is deprecated.", parameter.getName()), parameter, PatternLanguagePackage.Literals.ANNOTATION_PARAMETER__NAME, IssueCodes.DEPRECATION); if (expectedParameterType != null && parameter.getValue() != null && !expectedParameterType.isAssignableFrom(parameter.getValue().getClass())) { error(String.format(ANNOTATION_PARAMETER_TYPE_ERROR, getTypeName(parameter.getValue().getClass()), getTypeName(expectedParameterType)), parameter, PatternLanguagePackage.Literals.ANNOTATION_PARAMETER__NAME, annotation.getParameters().indexOf(parameter), IssueCodes.MISTYPED_ANNOTATION_PARAMETER); VariableReference reference = (VariableReference) parameter.getValue(); if (reference.getVariable() == null) { error(String.format("Unknown variable %s", reference.getVar()), parameter, PatternLanguagePackage.Literals.ANNOTATION_PARAMETER__VALUE, annotation.getParameters().indexOf(parameter), for (VariableReference reference : Iterables.filter(listValue.getValues(), VariableReference.class)) {
private void checkEvalInCompare(CompareConstraint constraint, VariableReference reference, FunctionEvaluationValue eval) { List<Variable> evalInputVariables = PatternLanguageHelper.getUsedVariables(eval.getExpression(), EcoreUtil2 .getContainerOfType(constraint, PatternBody.class).getVariables()); if (evalInputVariables.contains(reference.getVariable())) { if (constraint.getFeature() == CompareFeature.EQUALITY) { error("Return value of an eval expression cannot be stored in one of its parameters.", reference, PatternLanguagePackage.Literals.VARIABLE_REFERENCE__VAR, IssueCodes.EVAL_INCORRECT_RETURNVALUE); } else { warning("Return value of an eval expression should not be compared with one of its parameters.", reference, PatternLanguagePackage.Literals.VARIABLE_REFERENCE__VAR, IssueCodes.EVAL_INCORRECT_RETURNVALUE); } } }
@Check(CheckType.NORMAL) public void checkAnnotation(Annotation annotation) { if (annotationProvider.hasValidator(annotation.getName())) { IPatternAnnotationValidator validator = annotationProvider.getValidator(annotation.getName()); executeDefaultAnnotationValidation(annotation, validator); // Execute extra validation validator.getAdditionalValidator() .ifPresent(v -> v.executeAdditionalValidation(annotation, this)); } else { warning("Unknown annotation " + annotation.getName(), PatternLanguagePackage.Literals.ANNOTATION__NAME, IssueCodes.UNKNOWN_ANNOTATION); } }
warning("Both operands are constants - constraint is always true or always false.", PatternLanguagePackage.Literals.COMPARE_CONSTRAINT__LEFT_OPERAND, IssueCodes.CONSTANT_COMPARE_CONSTRAINT); warning("Both operands are constants - constraint is always true or always false.", PatternLanguagePackage.Literals.COMPARE_CONSTRAINT__RIGHT_OPERAND, IssueCodes.CONSTANT_COMPARE_CONSTRAINT); VariableReference op2v = (VariableReference) op2; if (op1v.getVar().equals(op2v.getVar())) { warning("Comparing a variable with itself.", PatternLanguagePackage.Literals.COMPARE_CONSTRAINT__LEFT_OPERAND, IssueCodes.SELF_COMPARE_CONSTRAINT); warning("Comparing a variable with itself.", PatternLanguagePackage.Literals.COMPARE_CONSTRAINT__RIGHT_OPERAND, IssueCodes.SELF_COMPARE_CONSTRAINT); checkEvalInCompare(constraint, (VariableReference) op2, (FunctionEvaluationValue) op1); } else if (op2Eval && op1Variable) { checkEvalInCompare(constraint, (VariableReference) op1, (FunctionEvaluationValue) op2);
@Check public void checkPackageDeclaration(PatternModel model) { String declaredPackage = packageNameProvider.getExpectedPackageName(model); String actualPackage = model.getPackageName(); if (declaredPackage != null && !Strings.equal(actualPackage, declaredPackage)) { error(String.format("The package declaration '%s' does not match the container '%s'", Strings.emptyIfNull(declaredPackage), Strings.emptyIfNull(actualPackage)), PatternLanguagePackage.Literals.PATTERN_MODEL__PACKAGE_NAME, IssueCodes.PACKAGE_NAME_MISMATCH); } if (actualPackage != null && !actualPackage.equals(actualPackage.toLowerCase())) { error("Only lowercase package names supported", PatternLanguagePackage.Literals.PATTERN_MODEL__PACKAGE_NAME, IssueCodes.PACKAGE_NAME_MISMATCH); } }
private LinkedList<PatternCall> dfsCheckCycle(PatternCall source, Map<PatternCall, Set<PatternCall>> graph) { LinkedList<PatternCall> path = new LinkedList<>(); path.add(source); return dfsCheckCycle(source, path, new HashSet<PatternCall>(), graph); }
private String getFormattedCall(CallableRelation relation) { if (relation instanceof PatternCall) { return getFormattedPattern(((PatternCall) relation).getPatternRef()); } else { return ASTStringProvider.INSTANCE.doSwitch(relation); } }
private String getConstantAsString(ValueReference ref) { if (ref instanceof NumberValue) { return numberLiterals.toJavaLiteral(((NumberValue) ref).getValue()); } else if (ref instanceof BoolValue) { return Boolean.toString(PatternLanguageHelper.getValue(ref, Boolean.class)); } else if (ref instanceof StringValue) { return "\"" + ((StringValue) ref).getValue() + "\""; } else if (ref instanceof ListValue) { StringBuilder sb = new StringBuilder(); sb.append("{ "); for (Iterator<ValueReference> iter = ((ListValue) ref).getValues().iterator(); iter.hasNext();) { sb.append(getConstantAsString(iter.next())); if (iter.hasNext()) { sb.append(", "); } } sb.append("}"); return sb.toString(); } else if (ref instanceof VariableReference) { return ((VariableReference) ref).getVar(); } return "UNDEFINED"; }
@Check public void checkPatternParameters(Pattern pattern) { if (pattern.getParameters().isEmpty()) { warning("Parameterless patterns can only be used to check for existence of a condition.", PatternLanguagePackage.Literals.PATTERN__NAME, IssueCodes.MISSING_PATTERN_PARAMETERS); // As no duplicate parameters are available, returning now return; } for (int i = 0; i < pattern.getParameters().size(); ++i) { String leftParameterName = pattern.getParameters().get(i).getName(); for (int j = i + 1; j < pattern.getParameters().size(); ++j) { if (Strings.equal(leftParameterName, pattern.getParameters().get(j).getName())) { error(DUPLICATE_VARIABLE_MESSAGE + leftParameterName, PatternLanguagePackage.Literals.PATTERN__PARAMETERS, i, IssueCodes.DUPLICATE_PATTERN_PARAMETER_NAME); error(DUPLICATE_VARIABLE_MESSAGE + leftParameterName, PatternLanguagePackage.Literals.PATTERN__PARAMETERS, j, IssueCodes.DUPLICATE_PATTERN_PARAMETER_NAME); } } } }
/** * Checks if an aggregate {@link VariableReference} is used only in the right context, that is, in an * {@link AggregatedValue} with an aggregator requiring aggregator parameters. * * @param value * the {@link VariableReference} instance * @since 1.4 */ @Check public void checkValueReference(VariableReference value) { if (value.isAggregator()) { AggregatedValue container = EcoreUtil2.getContainerOfType(value, AggregatedValue.class); if (container == null) { error(INVALID_AGGREGATE_MESSAGE, PatternLanguagePackage.Literals.VARIABLE_REFERENCE__AGGREGATOR, IssueCodes.INVALID_AGGREGATE_CONTEXT); } } }
/** * Contract: (1) path is the current path from source to the last element in path (2) the first element of path is * source (3) seen is maintained globally within the recursive calls of dfsCheckCycle */ private LinkedList<PatternCall> dfsCheckCycle(PatternCall source, LinkedList<PatternCall> path, Set<PatternCall> seen, Map<PatternCall, Set<PatternCall>> graph) { PatternCall current = path.getLast(); if (!seen.contains(current)) { seen.add(current); for (PatternCall target : graph.get(current)) { path.add(target); if (target == source) { return path; } LinkedList<PatternCall> intermediate = dfsCheckCycle(source, path, seen, graph); if (intermediate != null) { return intermediate; } else { path.removeLast(); } } } // this means that no cycle has been found return null; }
@Check(CheckType.NORMAL) public void checkVariableNames(PatternBody body) { for (Variable var1 : body.getVariables()) { Variable otherVar = null; for (Variable var2 : body.getVariables()) { if (PatternLanguageHelper.isNamedSingleUse(var1) && var1.getName().substring(1).equals(var2.getName())) { otherVar = var2; } } if (otherVar != null) { boolean isAggregate = PatternLanguageHelper.hasAggregateReference(var1); // Local variables do not have source location if (isAggregate) { error(String.format(VARIABLE_NAME_DUBIUS_REUSE_MESSAGE_AGGREGATE, var1.getName(), otherVar.getName()), PatternLanguageHelper.getReferences(var1).findAny().get(), PatternLanguagePackage.Literals.VARIABLE_REFERENCE__VARIABLE, IssueCodes.DUBIUS_VARIABLE_NAME); } else { warning(String.format(VARIABLE_NAME_DUBIUS_REUSE_MESSAGE_SINGLEUSE, var1.getName(), otherVar.getName()), PatternLanguageHelper.getReferences(var1).findAny().get(), PatternLanguagePackage.Literals.VARIABLE_REFERENCE__VARIABLE, IssueCodes.DUBIUS_VARIABLE_NAME); } } } }
error(String.format("%s is not an aggregator definition.", aggregator.getSimpleName()), PatternLanguagePackage.Literals.AGGREGATED_VALUE__AGGREGATOR, IssueCodes.INVALID_AGGREGATOR); return; if (AggregatorUtil.mustHaveAggregatorVariables(expression)) { if (references.isEmpty()) { error(String.format(MISSING_AGGREGATE_MESSAGE, aggregator.getSimpleName()), expression, PatternLanguagePackage.Literals.AGGREGATED_VALUE__CALL, IssueCodes.INVALID_AGGREGATOR_PARAMETER); error(String.format(EXACTLY_ONE_AGGREGATE_MESSAGE, aggregator.getSimpleName()), reference, null, IssueCodes.INVALID_AGGREGATOR_PARAMETER); error(String.format(UNEXPECTED_AGGREGATE_MESSAGE, reference.getVar(), aggregator.getSimpleName()), reference, null, IssueCodes.INVALID_AGGREGATOR_PARAMETER);
@Check(CheckType.NORMAL) public void checkForImpureJavaCallsInEvalExpressions(FunctionEvaluationValue eval) { if (eval.getExpression() != null) { checkForImpureJavaCallsInternal(eval.getExpression()); } }