Commit 90268b35 authored by Daniel Honsel's avatar Daniel Honsel
Browse files

more code style validations

parent 70557686
Loading
Loading
Loading
Loading
+447 −24
Original line number Diff line number Diff line
package de.ugoe.cs.swe.validation

import com.google.common.base.Strings
import de.ugoe.cs.swe.TTCN3Configuration.QualityCheckProfile
import de.ugoe.cs.swe.common.ConfigTools
import de.ugoe.cs.swe.common.MiscTools
import de.ugoe.cs.swe.common.logging.LoggingInterface.LogLevel
import de.ugoe.cs.swe.common.logging.LoggingInterface.MessageClass
import de.ugoe.cs.swe.tTCN3.AllOrSignatureList
import de.ugoe.cs.swe.tTCN3.AllOrTypeList
import de.ugoe.cs.swe.tTCN3.AltConstruct
import de.ugoe.cs.swe.tTCN3.AltstepDef
import de.ugoe.cs.swe.tTCN3.AltstepLocalDef
import de.ugoe.cs.swe.tTCN3.AltstepLocalDefList
import de.ugoe.cs.swe.tTCN3.BaseTemplate
import de.ugoe.cs.swe.tTCN3.ComponentDef
import de.ugoe.cs.swe.tTCN3.ComponentDefList
import de.ugoe.cs.swe.tTCN3.ComponentElementDef
import de.ugoe.cs.swe.tTCN3.ConstDef
import de.ugoe.cs.swe.tTCN3.ConstList
import de.ugoe.cs.swe.tTCN3.ControlStatementOrDefList
@@ -23,21 +33,29 @@ import de.ugoe.cs.swe.tTCN3.FunctionDef
import de.ugoe.cs.swe.tTCN3.FunctionDefList
import de.ugoe.cs.swe.tTCN3.FunctionFormalPar
import de.ugoe.cs.swe.tTCN3.FunctionFormalParList
import de.ugoe.cs.swe.tTCN3.GotoStatement
import de.ugoe.cs.swe.tTCN3.GroupDef
import de.ugoe.cs.swe.tTCN3.ImportDef
import de.ugoe.cs.swe.tTCN3.Initial
import de.ugoe.cs.swe.tTCN3.LabelStatement
import de.ugoe.cs.swe.tTCN3.MatchingSymbol
import de.ugoe.cs.swe.tTCN3.ModuleControlPart
import de.ugoe.cs.swe.tTCN3.ModuleDefinition
import de.ugoe.cs.swe.tTCN3.ModuleDefinitionsList
import de.ugoe.cs.swe.tTCN3.ModulePar
import de.ugoe.cs.swe.tTCN3.ModuleParDef
import de.ugoe.cs.swe.tTCN3.ModuleParameter
import de.ugoe.cs.swe.tTCN3.PermutationMatch
import de.ugoe.cs.swe.tTCN3.PortDef
import de.ugoe.cs.swe.tTCN3.PortInstance
import de.ugoe.cs.swe.tTCN3.ProcOrTypeList
import de.ugoe.cs.swe.tTCN3.RecordDefNamed
import de.ugoe.cs.swe.tTCN3.RecordOfDefNamed
import de.ugoe.cs.swe.tTCN3.RefValue
import de.ugoe.cs.swe.tTCN3.ReferencedType
import de.ugoe.cs.swe.tTCN3.SetDefNamed
import de.ugoe.cs.swe.tTCN3.SetOfDefNamed
import de.ugoe.cs.swe.tTCN3.Signature
import de.ugoe.cs.swe.tTCN3.SignatureDef
import de.ugoe.cs.swe.tTCN3.SingleConstDef
import de.ugoe.cs.swe.tTCN3.SingleTempVarInstance
@@ -45,6 +63,8 @@ import de.ugoe.cs.swe.tTCN3.SingleVarInstance
import de.ugoe.cs.swe.tTCN3.StatementBlock
import de.ugoe.cs.swe.tTCN3.StructDefBody
import de.ugoe.cs.swe.tTCN3.StructFieldDef
import de.ugoe.cs.swe.tTCN3.StructuredTypeDef
import de.ugoe.cs.swe.tTCN3.SubTypeDef
import de.ugoe.cs.swe.tTCN3.SubTypeDefNamed
import de.ugoe.cs.swe.tTCN3.TTCN3Module
import de.ugoe.cs.swe.tTCN3.TTCN3Package
@@ -53,12 +73,19 @@ import de.ugoe.cs.swe.tTCN3.TemplateDef
import de.ugoe.cs.swe.tTCN3.TemplateOrValueFormalPar
import de.ugoe.cs.swe.tTCN3.TemplateOrValueFormalParList
import de.ugoe.cs.swe.tTCN3.TestcaseDef
import de.ugoe.cs.swe.tTCN3.TimerInstance
import de.ugoe.cs.swe.tTCN3.Type
import de.ugoe.cs.swe.tTCN3.TypeDef
import de.ugoe.cs.swe.tTCN3.TypeDefBody
import de.ugoe.cs.swe.tTCN3.UnionDefNamed
import de.ugoe.cs.swe.tTCN3.VarInstance
import java.util.ArrayList
import java.util.List
import java.util.Map
import java.util.concurrent.ConcurrentHashMap
import java.util.regex.Matcher
import java.util.regex.Pattern
import org.eclipse.emf.ecore.EClass
import org.eclipse.emf.ecore.EObject
import org.eclipse.emf.ecore.EStructuralFeature
import org.eclipse.xtext.nodemodel.INode
@@ -67,30 +94,19 @@ import org.eclipse.xtext.validation.Check

import static extension de.ugoe.cs.swe.common.TTCN3ScopeHelper.*
import static extension org.eclipse.xtext.EcoreUtil2.*
import de.ugoe.cs.swe.tTCN3.TimerInstance
import de.ugoe.cs.swe.tTCN3.ComponentElementDef
import de.ugoe.cs.swe.common.ConfigTools
import de.ugoe.cs.swe.TTCN3Configuration.QualityCheckProfile
import de.ugoe.cs.swe.common.logging.LoggingInterface.LogLevel
import de.ugoe.cs.swe.common.logging.LoggingInterface.MessageClass
import de.ugoe.cs.swe.tTCN3.BaseTemplate
import de.ugoe.cs.swe.common.MiscTools
import de.ugoe.cs.swe.tTCN3.MatchingSymbol
import de.ugoe.cs.swe.tTCN3.StructuredTypeDef
import de.ugoe.cs.swe.tTCN3.SubTypeDef
import java.util.List
import de.ugoe.cs.swe.tTCN3.Type
import de.ugoe.cs.swe.tTCN3.Signature
import de.ugoe.cs.swe.tTCN3.ProcOrTypeList
import de.ugoe.cs.swe.tTCN3.AllOrSignatureList
import de.ugoe.cs.swe.tTCN3.AllOrTypeList
import de.ugoe.cs.swe.tTCN3.GotoStatement
import de.ugoe.cs.swe.tTCN3.LabelStatement
import de.ugoe.cs.swe.tTCN3.AltConstruct
import de.ugoe.cs.swe.tTCN3.PermutationMatch
import de.ugoe.cs.swe.tTCN3.impl.TTCN3PackageImpl
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

class CheckDefinitionComeFirstParameter {
	public boolean hasOtherDefinitions
	public int previousLocalDefinitionsOrderLevel
}

class TTCN3Validator extends AbstractTTCN3Validator {
	val static Map<String, ArrayList<String>> moduleLevelIdentifiersMap = new ConcurrentHashMap<String, ArrayList<String>>();
	val ConfigTools configTools = ConfigTools.getInstance;
	var QualityCheckProfile activeProfile = null;

@@ -738,9 +754,415 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		}
	}

	@Check
	def checkLocalDefinitionsComeFirst(ModuleDefinition moduleDefinition) {
		if (!activeProfile.checkLocalDefinitionsComeFirst)
			return;

		val definition = moduleDefinition.def

		if (definition instanceof FunctionDef) {
			definition.statement.checkLocalDefinitionsComeFirstStatemanet
		} else if (definition instanceof TestcaseDef) {
			definition.statement.checkLocalDefinitionsComeFirstStatemanet
		} else if (definition instanceof AltstepDef) {
			definition.checkLocalDefinitionsComeFirstAltstepDef
		} else if (definition instanceof TypeDef) {
			if (definition.body.structured != null && definition.body.structured.component != null) {
				definition.body.structured.component.checkLocalDefinitionsComeFirstComponent
			}
		}

	}

	private def checkLocalDefinitionsComeFirstStatemanet(StatementBlock statement) {
		val CheckDefinitionComeFirstParameter params = new CheckDefinitionComeFirstParameter
		for (d : statement.def) {
			if (d.locDef != null && d.locDef.constDef != null) {
				d.locDef.constDef.checkLocalDefinitionsComeFirstOrder(params)
			} else if (d.locInst != null && d.locInst.timer != null) {
				d.locInst.timer.checkLocalDefinitionsComeFirstOrder(params)
			} else if (d.locInst != null && d.locInst.variable != null) {
				d.locInst.variable.checkLocalDefinitionsComeFirstOrder(params)
			}
		}
		for (s : statement.stat) {
			s.checkLocalDefinitionsComeFirstOther
		}
	}

	private def checkLocalDefinitionsComeFirstAltstepDef(AltstepDef altstep) {
		val CheckDefinitionComeFirstParameter params = new CheckDefinitionComeFirstParameter
		for (d : altstep.local.defs) {
			if (d.variable != null) {
				d.variable.checkLocalDefinitionsComeFirstOrder(params)
			} else if (d.timer != null) {
				d.timer.checkLocalDefinitionsComeFirstOrder(params)
			} else if (d.const != null) {
				d.const.checkLocalDefinitionsComeFirstOrder(params)
			}
		}
		altstep.guard.checkLocalDefinitionsComeFirstOther
	}

	private def checkLocalDefinitionsComeFirstComponent(ComponentDef component) {
		val CheckDefinitionComeFirstParameter params = new CheckDefinitionComeFirstParameter
		for (d : component.defs) {
			if (d.element.port != null)
				d.element.port.checkLocalDefinitionsComeFirstOrder(params)
			else if (d.element.variable != null)
				d.element.variable.checkLocalDefinitionsComeFirstOrder(params)
			else if (d.element.timer != null)
				d.element.timer.checkLocalDefinitionsComeFirstOrder(params)
			else if (d.element.const != null)
				d.element.const.checkLocalDefinitionsComeFirstOrder(params)
		}
	}

	private def checkLocalDefinitionsComeFirstOther(EObject parent) {
		val configuredOrder = localDefOrderClasses
		val List<EObject> foundChilds = newArrayList
		for (t : configuredOrder) {

			// TODO: find a way to get the Class<EObject> to fix the hack
			if (t.instanceClassName.contains("VarInstance")) {
				foundChilds.addAll(parent.getAllContentsOfType(VarInstance))
			} else if (t.instanceClassName.contains("ConstDef")) {
				foundChilds.addAll(parent.getAllContentsOfType(ConstDef))
			} else if (t.instanceClassName.contains("TimerInstance")) {
				foundChilds.addAll(parent.getAllContentsOfType(TimerInstance))
			} else if (t.instanceClassName.contains("PortInstance")) {
				foundChilds.addAll(parent.getAllContentsOfType(PortInstance))
			}
		}
		for (c : foundChilds) {
			val message = "Local definition is not at the beginning!"
			val INode node = NodeModelUtils.getNode(c)
			warning(
				message,
				null, //TODO: struct feature
				MessageClass.STYLE.toString,
				node.startLine.toString,
				node.endLine.toString,
				"6.8, " + "checkLocalDefinitionsComeFirst"
			);
		}
	}

	private def checkLocalDefinitionsComeFirstOrder(EObject o, CheckDefinitionComeFirstParameter params) {
		val configuredOrder = localDefOrderClasses
		val int currentLocalDefinitionTypeOrderLevel = configuredOrder.indexOf(o.eClass);
		val INode node = NodeModelUtils.getNode(o)
		if (configuredOrder.contains(o.eClass)) {
			if (params.hasOtherDefinitions) {
				val message = "Local definition is not at the beginning!"
				warning(
					message,
					null, //TODO: struct feature
					MessageClass.STYLE.toString,
					node.startLine.toString,
					node.endLine.toString,
					"6.8, " + "checkLocalDefinitionsComeFirst"
				);
			} else {
				if ((currentLocalDefinitionTypeOrderLevel < params.previousLocalDefinitionsOrderLevel)) {
					val message = "Local definition order is not maintained as configured (" +
						configuredOrder.eClassesToString + ")!"
					warning(
						message,
						null, //TODO: struct feature
						MessageClass.STYLE.toString,
						node.startLine.toString,
						node.endLine.toString,
						"6.8, " + "checkLocalDefinitionsComeFirst"
					);

				} else {
					params.previousLocalDefinitionsOrderLevel = currentLocalDefinitionTypeOrderLevel
				}

			}
		} else {
			params.hasOtherDefinitions = true
		}
	}

	private def String eClassesToString(List<EClass> order) {
		var String res = " "
		for (c : order) {
			res += c.name + " "
		}
		res
	}

	private def List<EClass> localDefOrderClasses() {
		val defs = activeProfile.localDefinitionTypes.toList
		val res = newArrayList
		for (d : defs) {
			if (d == "VarInstance") {
				res.add(TTCN3Package.eINSTANCE.varInstance)
			} else if (d == "ConstDef") {
				res.add(TTCN3Package.eINSTANCE.constDef)
			} else if (d == "TimerInstance") {
				res.add(TTCN3Package.eINSTANCE.timerInstance)
			} else if (d == "PortInstance") {
				res.add(TTCN3Package.eINSTANCE.portInstance)
			}
		}
		return res
	}

	@Check
	def checkImportsComeFirst(TTCN3Module module) {
		if (!activeProfile.checkImportsComeFirst)
			return;

		if (module.defs == null)
			return;

		var hasOtherDefs = false
		for (d : module.defs.definitions) {
			if (d.def instanceof ImportDef) {
				if (hasOtherDefs) {
					val message = "Import statement is not at the beginning!"
					val INode node = NodeModelUtils.getNode(d)
					warning(
						message,
						null, //TODO: EStructuralFeature
						MessageClass.STYLE.toString,
						node.startLine.toString,
						node.endLine.toString,
						"6.9, " + MiscTools.getMethodName()
					);
				}
			} else {
				hasOtherDefs = true
			}
		}
	}

	@Check
	def checkNoDuplicatedModuleDefinitionIdentifiers(ModuleDefinition definition) {
		if (!activeProfile.checkNoDuplicatedModuleDefinitionIdentifiers)
			return;

		val parentModule = definition.findDesiredParent(TTCN3Module)
		var ArrayList<String> identifiers = newArrayList
		var idExists = false
		var TTCN3Reference detailDef = null

		if (moduleLevelIdentifiersMap.containsKey(parentModule.name)) {
			identifiers = moduleLevelIdentifiersMap.get(parentModule.name)
		} else {
			moduleLevelIdentifiersMap.put(parentModule.name, identifiers)
		}

		if (definition.def instanceof ConstDef) {
			val constDefList = (definition.def as ConstDef).defs as ConstList
			for (SingleConstDef d : constDefList.list) {
				idExists = d.name.checkIdentifier(identifiers)
				detailDef = d
			}
		} else if (definition.def instanceof ModuleParDef) {
			if ((definition.def as ModuleParDef).param != null) {
				for (ModuleParameter p : (definition.def as ModuleParDef).param.list.params) {
					idExists = p.name.checkIdentifier(identifiers)
					detailDef = p
				}
			} else if ((definition.def as ModuleParDef).multitypeParam != null) {
				for (ModulePar p : (definition.def as ModuleParDef).multitypeParam.params) {
					for (ModuleParameter pa : p.list.params) {
						idExists = pa.name.checkIdentifier(identifiers)
						detailDef = pa
					}
				}
			}
		} else if (definition.def instanceof FunctionDef) {
			idExists = (definition.def as FunctionDef).name.checkIdentifier(identifiers)
			detailDef = definition.def as FunctionDef
		} else if (definition.def instanceof TemplateDef) {
			idExists = (definition.def as TemplateDef).base.name.checkIdentifier(identifiers)
			detailDef = (definition.def as TemplateDef).base
		} else if (definition.def instanceof SignatureDef) {
			idExists = (definition.def as SignatureDef).name.checkIdentifier(identifiers)
			detailDef = definition.def as SignatureDef
		} else if (definition.def instanceof TestcaseDef) {
			idExists = (definition.def as TestcaseDef).name.checkIdentifier(identifiers)
			detailDef = definition.def as TestcaseDef
		} else if (definition.def instanceof AltstepDef) {
			idExists = (definition.def as AltstepDef).name.checkIdentifier(identifiers)
			detailDef = definition.def as AltstepDef
		} else if (definition.def instanceof GroupDef) {
			idExists = (definition.def as GroupDef).name.checkIdentifier(identifiers)
			detailDef = definition.def as GroupDef
		}

		if (idExists) {
			val message = "Identifier \"" + detailDef.name + "\" on the module level has already been used in " +
				parentModule.name + "!"
			val INode node = NodeModelUtils.getNode(detailDef)
			warning(
				message,
				null, //TODO: EStructuralFeature
				MessageClass.STYLE.toString,
				node.startLine.toString,
				node.endLine.toString,
				"6.10, " + MiscTools.getMethodName()
			);
		}
	}

	private def boolean checkIdentifier(String name, ArrayList<String> ids) {
		var res = false
		if (ids.contains(name)) {
			res = true
		} else {
			ids.add(name)
		}
		res
	}

	// TODO: create own check method for every type???
	@Check
	def checkZeroReferencedModuleDefinitions(ModuleDefinition definition) {
		if (!activeProfile.checkZeroReferencedModuleDefinitions)
			return;

		// do not consider declarations groups?
		//val parentGroup = definition.findDesiredParent(GroupDef)		
		//if (parentGroup != null)
		//	return;
		val parentModule = definition.findDesiredParent(TTCN3Module)
		val Pattern zeroReferencedModuleDefinitionsExcludedPattern = Pattern.compile(
			activeProfile.getZeroReferencedModuleDefinitionsExcludedRegExp())
		val Matcher zeroReferencedModuleDefinitionsExcludedMatcher = zeroReferencedModuleDefinitionsExcludedPattern.
			matcher(parentModule.name)

		if (zeroReferencedModuleDefinitionsExcludedMatcher.matches())
			return;

		var TTCN3Reference detailDef = null
		var notReferenced = false

		//TODO: maybe use another type of cross referencer
		// TODO: find global cross references
		if (definition.def instanceof ConstDef) {
			val constDefList = (definition.def as ConstDef).defs as ConstList
			for (SingleConstDef d : constDefList.list) {
				notReferenced = d.isUnreferenced(parentModule)
				detailDef = d
			}
		} else if (definition.def instanceof ModuleParDef) {
			if ((definition.def as ModuleParDef).param != null) {
				for (ModuleParameter p : (definition.def as ModuleParDef).param.list.params) {
					notReferenced = p.isUnreferenced(parentModule)
					detailDef = p
				}
			} else if ((definition.def as ModuleParDef).multitypeParam != null) {
				for (ModulePar p : (definition.def as ModuleParDef).multitypeParam.params) {
					for (ModuleParameter pa : p.list.params) {
						notReferenced = pa.isUnreferenced(parentModule)
						detailDef = pa
					}
				}
			}
		} else if (definition.def instanceof FunctionDef) {
			notReferenced = definition.def.isUnreferenced(parentModule)
			detailDef = definition.def as FunctionDef
		} else if (definition.def instanceof TemplateDef) {
			notReferenced = (definition.def as TemplateDef).base.isUnreferenced(parentModule)
			detailDef = (definition.def as TemplateDef).base
		} else if (definition.def instanceof SignatureDef) {
			notReferenced = definition.def.isUnreferenced(parentModule)
			detailDef = definition.def as SignatureDef
		} else if (definition.def instanceof TestcaseDef) {
			notReferenced = definition.def.isUnreferenced(parentModule)
			detailDef = definition.def as TestcaseDef
		} else if (definition.def instanceof AltstepDef) {
			notReferenced = definition.def.isUnreferenced(parentModule)
			detailDef = definition.def as AltstepDef
		} else if (definition.def instanceof TypeDef) {
			val body = (definition.def as TypeDef).body

			if (body.structured != null) {
				if (body.structured.recordOf != null && body.structured.recordOf instanceof RecordOfDefNamed) {
					notReferenced = body.structured.recordOf.isUnreferenced(parentModule)
					detailDef = body.structured.recordOf as RecordOfDefNamed
				}
				if (body.structured.setOf != null && body.structured.setOf instanceof SetOfDefNamed) {
					notReferenced = body.structured.setOf.isUnreferenced(parentModule)
					detailDef = body.structured.setOf as SetOfDefNamed
				}
				if (body.structured.record != null && body.structured.record instanceof RecordDefNamed) {
					notReferenced = body.structured.record.isUnreferenced(parentModule)
					detailDef = body.structured.record as RecordDefNamed
				}
				if (body.structured.union != null && body.structured.union instanceof UnionDefNamed) {
					notReferenced = body.structured.union.isUnreferenced(parentModule)
					detailDef = body.structured.union as UnionDefNamed
				}
				if (body.structured.set != null && body.structured.set instanceof SetDefNamed) {
					notReferenced = body.structured.set.isUnreferenced(parentModule)
					detailDef = body.structured.set as SetDefNamed
				}
				if (body.structured.port != null && body.structured.port instanceof PortDef) {
					notReferenced = body.structured.port.isUnreferenced(parentModule)
					detailDef = body.structured.port as PortDef
				}
				if (body.structured.component != null && body.structured.component instanceof ComponentDef) {
					notReferenced = body.structured.component.isUnreferenced(parentModule)
					detailDef = body.structured.component as ComponentDef
				}
			} else if (body.sub != null) {
				if (body.sub instanceof SubTypeDefNamed) {
					notReferenced = body.sub.isUnreferenced(parentModule)
					detailDef = body.sub as SubTypeDefNamed
				}
			}
		}

		if (notReferenced) {
			val message = "Definition for \"" + detailDef.name + "\" is never referenced!"
			val INode node = NodeModelUtils.getNode(detailDef)
			warning(
				message,
				null, //TODO: EStructuralFeature
				MessageClass.STYLE.toString,
				node.startLine.toString,
				node.endLine.toString,
				"6.17, " + MiscTools.getMethodName()
			);
		}
	}

	private def boolean isUnreferenced(EObject type, EObject parent) {
		val result = UsageCrossReferencer.find(type, parent)
		result.size == 0
	}

	@Check
	def checkNoInlineTemplates(InLineTemplate template) {
		if (!activeProfile.checkNoInlineTemplates)
			return;

		val message = "Inline Template is used!"
		val INode node = NodeModelUtils.getNode(template)
		warning(
			message,
			null, //TODO: EStructuralFeature
			MessageClass.STYLE.toString,
			node.startLine.toString,
			node.endLine.toString,
			"6.13, " + MiscTools.getMethodName()
		);
	}

/**
	  * END: Code Style ------------------------------------------------------------------------------
	  */
//TODO: update error parameters
/*
	  
	@Check
	def checkUniqueNameNestedVariable(RefValue variable) {
		variable.isNameClashInHierarchy
@@ -1214,4 +1636,5 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		}
		return false;
	}
	 */
}