Commit 89318d0b authored by Daniel Honsel's avatar Daniel Honsel
Browse files

check over specific functions

parent 90268b35
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -402,7 +402,7 @@ FunctionInstance:
// ext ref ok?
// usage / semantic of PreDefFunctionIdentifier?
FunctionRef:
	FunctionDef | ExtFunctionDef | BaseTemplate;
	FunctionDef | ExtFunctionDef | BaseTemplate | AltstepDef;
	//(IDENTIFIER DOT)? IDENTIFIER;

FunctionActualParList:
+181 −0
Original line number Diff line number Diff line
@@ -99,6 +99,9 @@ import java.util.Collection
import org.eclipse.emf.ecore.util.EcoreUtil.UsageCrossReferencer
import org.eclipse.emf.ecore.util.EcoreUtil.ExternalCrossReferencer
import de.ugoe.cs.swe.tTCN3.InLineTemplate
import de.ugoe.cs.swe.tTCN3.RunsOnSpec
import de.ugoe.cs.swe.tTCN3.FunctionInstance
import de.ugoe.cs.swe.tTCN3.AltstepInstance

class CheckDefinitionComeFirstParameter {
	public boolean hasOtherDefinitions
@@ -1157,6 +1160,184 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		);
	}

	@Check
	def checkNoOverSpecificRunsOnClauses(RunsOnSpec runsOn) {
		if (!activeProfile.checkNoOverSpecificRunsOnClauses)
			return;

		//As of v1.0.3, test cases are not considered in this check
		val parent = runsOn.eContainer
		var ComponentDef component = null
		var isUnreferenced = false
		val ArrayList<TTCN3Reference> consideredAltOrFunc = newArrayList
		if (parent instanceof AltstepDef) {
			component = parent.spec.component
			if (!parent.specifiedComponentResolved(component)) {
				return;
			}
		} else if (parent instanceof FunctionDef) {
			component = parent.runsOn.component
			if (!parent.specifiedComponentResolved(component)) {
				return;
			}
		} else {
			return;
		}

		val overSpecifiedFirstLevel = !component.isReferencedComponentSpec(parent)
		val message = "Definition for \"" + (parent as TTCN3Reference).name +
			"\" contains an over specific runs on clause!"
		val INode node = NodeModelUtils.getNode(parent)

		if (overSpecifiedFirstLevel) {
			var overSpecified = true
			if (activeProfile.recursionInCheckNoOverSpecificRunsOnClauses) {
				consideredAltOrFunc.add(parent as TTCN3Reference)
				overSpecified = !(parent as TTCN3Reference).isReferencedInHierarchy(consideredAltOrFunc)
			}

			if (overSpecified) {
				warning(
					message,
					null, //TODO: EStructuralFeature
					MessageClass.STYLE.toString,
					node.startLine.toString,
					node.endLine.toString,
					"6.13, " + MiscTools.getMethodName()
				);
			}
		}

	}

	private def boolean specifiedComponentResolved(TTCN3Reference parent, ComponentDef component) {
		if (Strings.isNullOrEmpty(component.name)) {
			val message = "" + "Runs on component reference of \"" + parent.name +
				"\" cannot be resolved. It may not be possible to determine whether construct has an over-specific runs on clause!"
			val INode node = NodeModelUtils.getNode(parent)
			info(
				message,
				null,
				MessageClass.STYLE.toString,
				node.startLine.toString,
				node.endLine.toString,
				"6.13, " + MiscTools.getMethodName(),
				LogLevel.INFORMATION.toString
			);
			return false
		}
		return true
	}

	private def ArrayList<TTCN3Reference> nextLevelFunctionsOrAltsteps(TTCN3Reference parent,
		ArrayList<TTCN3Reference> consideredAltOrFunc) {
		val ArrayList<TTCN3Reference> nextLevelCheck = newArrayList

		for (f : parent.getAllContentsOfType(FunctionInstance).map[it.ref]) {
			if (consideredAltOrFunc.contains(f)) {
				val message = "" + "Possible cyclic call sequence: \"" + f.name + "\". Skipping..."
				val INode node = NodeModelUtils.getNode(f)
				info(
					message,
					null,
					MessageClass.STYLE.toString,
					node.startLine.toString,
					node.endLine.toString,
					"6.13, " + MiscTools.getMethodName(),
					LogLevel.INFORMATION.toString
				);
			} else {
				nextLevelCheck.add(f)
			}
		}

		for (a : parent.getAllContentsOfType(AltstepInstance).map[it.ref]) {
			if (consideredAltOrFunc.contains(a)) {
				val message = "" + "Possible cyclic call sequence: \"" + a.name + "\". Skipping..."
				val INode node = NodeModelUtils.getNode(a)
				info(
					message,
					null,
					MessageClass.STYLE.toString,
					node.startLine.toString,
					node.endLine.toString,
					"6.13, " + MiscTools.getMethodName(),
					LogLevel.INFORMATION.toString
				);
			} else {
				nextLevelCheck.add(a)
			}
		}
		return nextLevelCheck
	}

	private def boolean isReferencedInHierarchy(TTCN3Reference parent, ArrayList<TTCN3Reference> consideredAltOrFunc) {
		var ArrayList<TTCN3Reference> nextLevelCheck = parent.nextLevelFunctionsOrAltsteps(consideredAltOrFunc)

		do {
			for (o : nextLevelCheck) {
				if (o instanceof FunctionDef) {
					if (o.runsOn != null) {
						if (o.specifiedComponentResolved(o.runsOn.component)) {
							if (o.runsOn.component.isReferencedComponentSpec(o))
								return true
						}
					} else {
						//TODO: error message?
					}
				} else if (o instanceof AltstepDef) {
					if (o.spec != null) {
						if (o.specifiedComponentResolved(o.spec.component)) {
							if (o.spec.component.isReferencedComponentSpec(o))
								return true
						}
					} else {
						// TODO: error message?
					}
				}
				nextLevelCheck = o.nextLevelFunctionsOrAltsteps(consideredAltOrFunc)
			}
		} while (!nextLevelCheck.empty)

		return false
	}

	private def boolean isReferencedComponentSpec(ComponentDef component, EObject parent) {
		for (d : component.defs) {
			val element = d.element
			if (element.port != null) {
				for (p : element.port.instances) {
					if (!p.isUnreferenced(parent))
						return true
				}
			} else if (element.const != null) {
				for (c : element.const.defs.list) {
					if (!c.isUnreferenced(parent))
						return true
				}
			} else if (element.timer != null) {
				for (t : element.timer.list.variables) {
					if (!t.isUnreferenced(parent))
						return true
				}
			} else if (element.variable != null) {
				if (element.variable.list != null) {
					for (v : element.variable.list.variables) {
						if (!v.isUnreferenced(parent))
							return true
					}
				}
				if (element.variable.tempList != null) {
					for (tv : element.variable.tempList.variables) {
						if (!tv.isUnreferenced(parent))
							return true
					}
				}
			}
		}
		false
	}

/**
	  * END: Code Style ------------------------------------------------------------------------------
	  */