Commit 960d60c7 authored by Daniel Honsel's avatar Daniel Honsel
Browse files

some work on name clashes

parent 767796ec
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -75,7 +75,7 @@ Workflow {
			// Xtend-based API for validation
			fragment = validation.ValidatorFragment auto-inject {
			//    composedCheck = "org.eclipse.xtext.validation.ImportUriValidator"
			    composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator"
			//    composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator"
			}

			// old scoping and exporting API
+6 −18
Original line number Diff line number Diff line
@@ -415,13 +415,13 @@ FunctionActualParList:
FunctionActualParAssignment:
	TemplateInstanceAssignment | ComponentRefAssignment | ArrayIdentifierRefAssignment;

	//TODO: check ref
// FormalValuePar according to antlr implementation
ComponentRefAssignment:
	name=IDENTIFIER ASSIGNMENTCHAR ref=ComponentRef;
	ref=[FormalValuePar|IDENTIFIER] ASSIGNMENTCHAR value=ComponentRef;

	//TODO: check ref
ArrayIdentifierRefAssignment:
	name=IDENTIFIER ASSIGNMENTCHAR ref=ArrayIdentifierRef;
	name=IDENTIFIER ASSIGNMENTCHAR value=ArrayIdentifierRef;

FunctionActualPar:
	ArrayIdentifierRef | InLineTemplate | ComponentRef | {FunctionActualPar} MINUS;
@@ -619,7 +619,7 @@ FunctionLocalDef:
	constDef=ConstDef | templateDef=TemplateDef;

FunctionLocalInst:
	VarInstance | TimerInstance;
	variable=VarInstance | timer=TimerInstance;

TimerInstance:
	TIMERKEYWORD VarList;
@@ -669,9 +669,6 @@ StructFieldDef:
	{StructFieldDef} (type=Type | nestedType=NestedTypeDef) name=IDENTIFIER array=ArrayDef? spec=SubTypeSpec?
	optional=OPTIONALKEYWORD?;

StructFieldReference:
	name=[StructFieldDef|IDENTIFIER];

SetOfDef:
	SETKEYWORD setLength=StringLength? OFKEYWORD (setType=Type | nested2=NestedTypeDef) ADDRESSKEYWORD
	setSpec=SubTypeSpec? | SetOfDefNamed;
@@ -1146,18 +1143,9 @@ ReadTimerOp:
PermutationMatch:
	PERMUTATIONKEYWORD ListOfTemplates;

	// TODO: check references!
// Identifier | TypeReference | ParRef
	// TODO: complete this rule parRef!
StructFieldRef:
	StructFieldReference | Type;

	// TODO: check if this rule is necessary
TypeReference returns ecore::EString:
	IDENTIFIER;

	// TODO: check if this rule is necessary
ParRef returns ecore::EString:
	IDENTIFIER;
	StructFieldDef| ReferencedType;

ExtendedFieldReference:
	DOT (field+=ReferencedValue | type+=PredefinedType) | array+=ArrayOrBitRef | {ExtendedFieldReference} SQUAREOPEN
+91 −18
Original line number Diff line number Diff line
@@ -2,45 +2,118 @@ package de.ugoe.cs.swe.validation

import de.ugoe.cs.swe.tTCN3.ConstDef
import de.ugoe.cs.swe.tTCN3.ConstList
import de.ugoe.cs.swe.tTCN3.FunctionDefList
import de.ugoe.cs.swe.tTCN3.ModuleDefinition
import de.ugoe.cs.swe.tTCN3.ModuleDefinitionsList
import de.ugoe.cs.swe.tTCN3.RefValue
import de.ugoe.cs.swe.tTCN3.SingleConstDef
import de.ugoe.cs.swe.tTCN3.StatementBlock
import de.ugoe.cs.swe.tTCN3.TTCN3Module
import de.ugoe.cs.swe.tTCN3.TTCN3Package
import org.eclipse.emf.ecore.EObject
import org.eclipse.xtext.validation.Check

import static extension de.ugoe.cs.swe.common.TTCN3ScopeHelper.*
import de.ugoe.cs.swe.tTCN3.ModuleDefinitionsList
import de.ugoe.cs.swe.tTCN3.SingleVarInstance
import de.ugoe.cs.swe.tTCN3.VarList
import de.ugoe.cs.swe.tTCN3.Initial

class TTCN3Validator extends AbstractTTCN3Validator {

	@Check
	def checkUniqueNameNestedVariable(SingleConstDef variable) {
		val container = variable.findDesiredParent(typeof(ModuleDefinitionsList)) as ModuleDefinitionsList
		variable.isNameClashInHierarchy
	}

		if (container == null) return;
	@Check
	def checkUniqueNameNestedVariable(SingleVarInstance variable) {
		variable.isNameClashInHierarchy
	}

		val defs = container.definitions.filter[it.def instanceof ConstDef]
	def private isNameClashInHierarchy(RefValue variable) {
		var parent = variable.eContainer
		while (parent != null) {

			if (parent instanceof ModuleDefinitionsList) {
				if (parent.checkNameClashModuleDefinitionsList(variable)) {
					// TODO: TTCN3Package$Literals::SINGLE_CONST_DEF__NAME
					error('Name clash with constant variable definition in this scope!', null, -1);
					return;
				}
			} else if (parent instanceof StatementBlock) {
				if (parent.checkNameClasStatementBlock(variable)) {
					error('Name clash with constant variable definition in this scope!', null, -1);
					return;
				}
			} else if (parent instanceof Initial) {
				if (parent.checkNameClashInitial(variable)) {
					error('Name clash with constant variable definition in this scope!', null, -1);
					return;
				}				
			}
			
			// TODO: function parameter
			// TODO: other references in scope
			parent = parent.eContainer
		}
	}

	def private boolean checkNameClashModuleDefinitionsList(ModuleDefinitionsList list, RefValue variable) {
		val defs = list.definitions.filter[it.def instanceof ConstDef]
		for (EObject v : defs) {
			val constDefList = ((v as ModuleDefinition).def as ConstDef).defs as ConstList

			for (SingleConstDef d : constDefList.list) {
				if (d != variable && d.name == variable.name) {
					// TODO: TTCN3Package$Literals::SINGLE_CONST_DEF__NAME
					error('Name clash with constant variable definition in this scope!', null, -1);
					return;
					return true;
				}
			}
		}
		return false;
	}

	def private boolean checkNameClasStatementBlock(StatementBlock block, RefValue variable) {
		for (FunctionDefList l : block.def.filter[it != null]) {

			if (l.locDef != null && l.locDef.constDef != null) {
				val constDefList = l.locDef.constDef.defs as ConstList
				for (SingleConstDef d : constDefList.list) {
					if (d != variable && d.name == variable.name) {
						return true;
					}
				}
			}

			if (l.locInst != null && l.locInst.variable != null) {
				val varList = l.locInst.variable.list as VarList
				for (SingleVarInstance d : varList.variables) {
					if (d != variable && d.name == variable.name) {
						return true;
					}
				}
			}

		}
		return false;
	}
	
	// TODO: fix this
	def private boolean checkNameClashInitial(Initial init, RefValue variable) {
		if (init.variable != null) {
			val varList = init.variable.list as VarList
			for (SingleVarInstance d : varList.variables) {
				if (d != variable && d.name == variable.name) {
					return true;
				}
			}
		}
		return false
	}

	@Check
	def checkModuleStartsWithM(TTCN3Module module) {
		val char pattern = 'M';

		if (module.name.charAt(0) != pattern) {

			//TODO: TTCN3Package$Literals::TTCN3_MODULE__NAME or get EStructuralFeature from somewhere else
			warning('Module names should start with M!', null, TTCN3Package.TTCN3_MODULE__NAME);
		}