Commit 289fb5cf authored by Philip Makedonski's avatar Philip Makedonski
Browse files

* thorough revision for checkNoUninitializedFieldsInTemplates (#8) to address...

* thorough revision for checkNoUninitializedFieldsInTemplates (#8) to address corner cases, further cleanup pending
parent 2f667ca6
Loading
Loading
Loading
Loading
+170 −62
Original line number Diff line number Diff line
@@ -107,12 +107,17 @@ import static extension de.ugoe.cs.swe.common.TTCN3ScopeHelper.*
import static extension org.eclipse.emf.ecore.util.EcoreUtil.*
import static extension org.eclipse.xtext.EcoreUtil2.*
import de.ugoe.cs.swe.tTCN3.NestedUnionDef
import de.ugoe.cs.swe.tTCN3.ReferencedType

class CheckDefinitionComeFirstParameter {
	public boolean hasOtherDefinitions
	public int previousLocalDefinitionsOrderLevel
}

class Guard {
	public boolean stop = false
}

class CodeStyleValidator extends AbstractDeclarativeValidator {
	val static Map<String, HashMap<String, List<TTCN3Reference>>> moduleLevelIdentifiersMap = new ConcurrentHashMap<String, HashMap<String, List<TTCN3Reference>>>();
	val ConfigTools configTools = ConfigTools.getInstance;
@@ -1209,13 +1214,19 @@ class CodeStyleValidator extends AbstractDeclarativeValidator {
		if (!activeProfile.checkNoZeroOrMultipleFieldsInUnionTemplates)
			return;
		if (template.base.type.ref !== null) {
			var expr = template.body.simple.expr
			if (expr instanceof FieldExpressionList) {
			var type = getReferencedOrNestedTypeWithTail(template.base.type.ref)
			if (type instanceof NestedUnionDef || type instanceof UnionDefNamed) {
				var expr = template.body.simple.expr
				var guard = new Guard()
//				if (expr instanceof OpCall) {
//					var ref = expr.function.ref
//					if (!(ref instanceof BaseTemplate)) {
//						guard.stop = true
//					}
//				}
				var referencedFields = new ArrayList<FieldReference>()
					referencedFields.addAll(expr.specs.map[it.fieldRef])
					template.collectInheritedFieldSpecifications(referencedFields)
				template.collectAssignedFieldSpecifications(referencedFields, true, guard)
				if (!guard.stop) {
					if (referencedFields.size==0) {
						statistics.incrementCountStyle
						val message = "At lest one field shall be specified in union template \""+template.base.name+"\"!"
@@ -1229,7 +1240,7 @@ class CodeStyleValidator extends AbstractDeclarativeValidator {
							//TODO: check number
							"6.19, " + MiscTools.getMethodName()
						);
					} else if (referencedFields.size>1) {
					} else if (referencedFields.toSet.size>1) {
						statistics.incrementCountStyle
						val message = "More than one field specified in union template \""+template.base.name+"\"!"
						val INode node = NodeModelUtils.getNode(expr)
@@ -1244,23 +1255,7 @@ class CodeStyleValidator extends AbstractDeclarativeValidator {
						);
					}
				}
			} else if (expr instanceof ArrayOrMixedExpression) {
				if (expr.list === null) {
						statistics.incrementCountStyle
						val message = "At lest one field shall be specified in union template \""+template.base.name+"\"!"
						val INode node = NodeModelUtils.getNode(expr)
						warning(
							message,
							null,
							MessageClass.STYLE.toString,
							node.startLine.toString,
							node.endLine.toString,
							//TODO: check number
							"6.19, " + MiscTools.getMethodName()
						);
				}
			}
			
		}		
	}
	
@@ -1270,57 +1265,170 @@ class CodeStyleValidator extends AbstractDeclarativeValidator {
		if (!activeProfile.checkNoUninitializedFieldsInTemplates)
			return;
		if (template.base.type.ref !== null) {
			//skip omit templates
			var expr = template.body.simple.expr
			if (expr instanceof FieldExpressionList) {
				//DONE: this seems to break things.. also for unions it has to be treated differently
				//DONE: get all fields in a unified way, also for nested -> factor out above
				//TODO: handle record of / set of?
			if (expr instanceof Value) {
				if (expr.predef !== null) {
					if (expr.predef.omit !== null) {
						return
					}
				}
			}
			
			var type = getReferencedOrNestedTypeWithTail(template.base.type.ref)
				var fields = type.getFields
				if (type instanceof NestedUnionDef || type instanceof UnionDefNamed) {
			var originalType = type
			if (type instanceof ReferencedType) {
				originalType = findOriginalType(type)
			}
			//DONE: get all fields in a unified way, also for nested -> factor out above
			//DONE: handle fields of assigned template -> below
			//DONE: handle unions -> skip altogether? or separate warning? (new feature)
			//DONE: handle record of / set of? -> skip for now -> document
			if (originalType instanceof NestedUnionDef || originalType instanceof UnionDefNamed ||
				type instanceof RecordOfDefNamed || type instanceof SetOfDefNamed
			) {
				
			} else {
				//TODO: should this be for non-optionals?
				var guard = new Guard()
				var fields = type.getFields
				//DONE: handle value list notation alternative
				var referencedFields = new ArrayList<FieldReference>()
					//DONE: handle unions -> skip altogether? or separate warning? (new feature)
					referencedFields.addAll(expr.specs.map[it.fieldRef])
					template.collectInheritedFieldSpecifications(referencedFields)
				template.collectAssignedFieldSpecifications(referencedFields, true, guard)
				if (!guard.stop) {
					checkNoUninitializedFieldsInTemplates(referencedFields, fields, template.base.name, expr)
				}
			} else if (expr instanceof ArrayOrMixedExpression) {
				//no fields specified
				if (expr.list === null) {
					var type = getReferencedOrNestedTypeWithTail(template.base.type.ref)
					var fields = type.getFields
					if (type instanceof NestedUnionDef || type instanceof UnionDefNamed) {
			}

					} else {
						var referencedFields = new ArrayList<FieldReference>()
						//DONE: handle unions -> skip altogether? or separate warning? (new feature)
						template.collectInheritedFieldSpecifications(referencedFields)
						checkNoUninitializedFieldsInTemplates(referencedFields, fields, template.base.name, expr)
//			var expr = template.body.simple.expr
//			if (expr instanceof FieldExpressionList) {
//				//DONE: this seems to break things.. also for unions it has to be treated differently
//				if (type instanceof NestedUnionDef || type instanceof UnionDefNamed) {
//					
//				} else {
//					//DONE: handle unions -> skip altogether? or separate warning? (new feature)
//					referencedFields.addAll(expr.specs.map[it.fieldRef])
//					//DONE: handle fields of assigned template -> below
//					//TODO: what if modified template is assigned?
//					if (template.derived !== null) {
//						template.collectInheritedFieldSpecifications(referencedFields)
//					}
//					checkNoUninitializedFieldsInTemplates(referencedFields, fields, template.base.name, expr)
//				}
//			} else if (expr instanceof OpCall) {
//				//assigned to another template
//				var type = getReferencedOrNestedTypeWithTail(template.base.type.ref)
//				var fields = type.getFields
//				var ref = expr.function.ref
//				if (ref instanceof BaseTemplate) {
//					var assigned = ref.eContainer
//					if (assigned instanceof TemplateDef) {
//						var referencedFields = new ArrayList<FieldReference>()
//						assigned.collectAssignedFieldSpecifications(referencedFields)
//						checkNoUninitializedFieldsInTemplates(referencedFields, fields, template.base.name, expr)
//					}
//				}
//			} else if (expr instanceof ArrayOrMixedExpression) {
//				//no fields specified
//				if (expr.list === null) {
//					var type = getReferencedOrNestedTypeWithTail(template.base.type.ref)
//					var fields = type.getFields
//					if (type instanceof NestedUnionDef || type instanceof UnionDefNamed) {
//						
//					} else {
//						var referencedFields = new ArrayList<FieldReference>()
//						//DONE: handle unions -> skip altogether? or separate warning? (new feature)
//						if (template.derived !== null) {
//							template.collectInheritedFieldSpecifications(referencedFields)
//						}
//						checkNoUninitializedFieldsInTemplates(referencedFields, fields, template.base.name, expr)
//					}
//				}
//			}
		}
	}

	protected def void collectAssignedFieldSpecifications(TemplateDef template, ArrayList<FieldReference> referencedFields, boolean recursive, Guard guard) {
		//DONE: factor out
		//TODO:handle record of / set of
		var expr = template.body.simple.expr
		if (expr instanceof FieldExpressionList) {
			referencedFields.addAll(expr.specs.map[it.fieldRef])
		} else if (expr instanceof Value) {
			//no parameters..
			//also conditioned on recursive?
			if (expr.ref !== null) {
				var value = expr.ref.referencedValue
				if (value instanceof BaseTemplate) {
					var assigned = value.eContainer
					if (assigned instanceof TemplateDef) {
						assigned.collectAssignedFieldSpecifications(referencedFields, activeProfile.checkNoUninitializedFieldsInTemplatesRecursion, guard)
					}
				}
			}
		} else if (expr instanceof OpCall) {
			//with parameters
			//also conditioned on recursive?
			//TODO: this is a whole other ordeal if parameter assignments are to be considered.. -> document/clarify
			//		-> if ref is a function, no way to determine what is initialised.. 
			var ref = expr.function.ref
			if (ref instanceof BaseTemplate) {
				var assigned = ref.eContainer
				if (assigned instanceof TemplateDef) {
					assigned.collectAssignedFieldSpecifications(referencedFields, activeProfile.checkNoUninitializedFieldsInTemplatesRecursion, guard)
				}
			} else {
				guard.stop = true	
			} 
		} else if (expr instanceof ArrayOrMixedExpression) {
			//TODO: handle?
			//empty
			if (expr.list === null) {
				
	protected def void collectInheritedFieldSpecifications(TemplateDef template, ArrayList<FieldReference> referencedFields) {
		if (template.derived !== null) {
			//TODO: check same type?
			//TODO: check type, further derivation?
			var baseTemplate = (template.derived.template.eContainer as TemplateDef)
			var derivedExpr = baseTemplate.body.simple.expr
			if (derivedExpr instanceof FieldExpressionList) {
				referencedFields.addAll(derivedExpr.specs.map[it.fieldRef])
			} else {
				if (template.base.type.ref !== null) {
					var type = getReferencedOrNestedTypeWithTail(template.base.type.ref)
					//TODO: find original?
					var fields = type.getFields
					if (expr.list.expr.size < fields.size) {
						var filteredFields = fields.toList.subList(0, expr.list.expr.size())
						referencedFields.addAll(filteredFields)
					} else {
						referencedFields.addAll(fields)
					}
				}
			}
			//TODO: make optional
		if (activeProfile.checkNoUninitializedFieldsInTemplatesRecursion)
			if (baseTemplate.derived !== null) {
				baseTemplate.collectInheritedFieldSpecifications(referencedFields)
		}
		//also from inherited
		if (template.derived !== null && recursive) {
			var derivedTemplate = (template.derived.template.eContainer as TemplateDef)
			derivedTemplate.collectAssignedFieldSpecifications(referencedFields, activeProfile.checkNoUninitializedFieldsInTemplatesRecursion, guard)
		}
	}
	
//	protected def void collectInheritedFieldSpecifications(TemplateDef template, ArrayList<FieldReference> referencedFields) {
//		//TODO: check same type?
//		//TODO: check type, further derivation?
//		var baseTemplate = (template.derived.template.eContainer as TemplateDef)
//		var derivedExpr = baseTemplate.body.simple.expr
//		if (derivedExpr instanceof FieldExpressionList) {
//			referencedFields.addAll(derivedExpr.specs.map[it.fieldRef])
//		} else if (derivedExpr instanceof OpCall) {
//			var ref = derivedExpr.function.ref
//			if (ref instanceof BaseTemplate) {
//				var assigned = ref.eContainer
//				if (assigned instanceof TemplateDef) {
//					assigned.collectAssignedFieldSpecifications(referencedFields)
//				}
//			}
//		}
//		if (activeProfile.checkNoUninitializedFieldsInTemplatesRecursion) {
//			if (baseTemplate.derived !== null) {
//				baseTemplate.collectInheritedFieldSpecifications(referencedFields)
//			}
//		}
//	}

	@Check
	def checkNoUninitializedFieldsInTemplates(VarInstance variable) {
		//TODO: also for variables and parameters? other expressions? operations? -> deactivated for now, pending clarification