Browse Source

Issue pro 1293 (#1857)

* Create new duplicate name validator helper

* Fix: Add Rootnode to flattened list to improve error message

* Remove Tree data structure
Rene Beckmann 7 years ago
parent
commit
b618ce2aaf

+ 3 - 0
plugins/org.yakindu.sct.model.stext/src/org/yakindu/sct/model/stext/STextRuntimeModule.java

@@ -18,6 +18,7 @@ import org.eclipse.xtext.parser.antlr.IReferableElementsUnloader;
 import org.eclipse.xtext.parsetree.reconstr.ITransientValueService;
 import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy;
 import org.eclipse.xtext.validation.CompositeEValidator;
+import org.eclipse.xtext.validation.INamesAreUniqueValidationHelper;
 import org.yakindu.base.types.inferrer.ITypeSystemInferrer;
 import org.yakindu.base.types.typesystem.GenericTypeSystem;
 import org.yakindu.base.types.typesystem.ITypeSystem;
@@ -29,6 +30,7 @@ import org.yakindu.sct.model.stext.resource.StextResource;
 import org.yakindu.sct.model.stext.scoping.STextGlobalScopeProvider;
 import org.yakindu.sct.model.stext.serialization.STextTransientValueService;
 import org.yakindu.sct.model.stext.terminals.STextValueConverterService;
+import org.yakindu.sct.model.stext.validation.STextNamesAreUniqueValidationHelper;
 
 import com.google.inject.Binder;
 import com.google.inject.name.Names;
@@ -48,6 +50,7 @@ public class STextRuntimeModule extends org.yakindu.sct.model.stext.AbstractSTex
 		binder.bind(IDefaultResourceDescriptionStrategy.class).to(SCTResourceDescriptionStrategy.class);
 		// https://github.com/Yakindu/statecharts/issues/1199
 		binder.bind(IReferableElementsUnloader.class).to(IReferableElementsUnloader.NullUnloader.class);
+		binder.bind(INamesAreUniqueValidationHelper.class).to(STextNamesAreUniqueValidationHelper.class);
 	}
 
 	public Class<? extends org.eclipse.xtext.scoping.IGlobalScopeProvider> bindIGlobalScopeProvider() {

+ 119 - 0
plugins/org.yakindu.sct.model.stext/src/org/yakindu/sct/model/stext/validation/STextNamesAreUniqueValidationHelper.java

@@ -0,0 +1,119 @@
+/**
+ * Copyright (c) 2018 committers of YAKINDU and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * Contributors:
+ * 	rbeckmann - initial API and implementation
+ * 
+ */
+package org.yakindu.sct.model.stext.validation;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.xtext.naming.QualifiedName;
+import org.eclipse.xtext.resource.IEObjectDescription;
+import org.eclipse.xtext.service.OperationCanceledManager;
+import org.eclipse.xtext.util.CancelIndicator;
+import org.eclipse.xtext.validation.INamesAreUniqueValidationHelper;
+import org.eclipse.xtext.validation.NamesAreUniqueValidationHelper;
+import org.eclipse.xtext.validation.ValidationMessageAcceptor;
+
+/**
+ * @author rbeckmann
+ *
+ */
+public class STextNamesAreUniqueValidationHelper extends NamesAreUniqueValidationHelper implements INamesAreUniqueValidationHelper {
+	protected OperationCanceledManager operationCanceledManager = new OperationCanceledManager();
+
+	protected Map<QualifiedName, IEObjectDescription> nameMap;
+	
+	@Override
+	public void checkUniqueNames(Iterable<IEObjectDescription> descriptions, ValidationMessageAcceptor acceptor) {
+		checkUniqueNames(descriptions, null, acceptor);
+	}
+
+	/**
+	 * <p>
+	 * {@inheritDoc}
+	 * </p>
+	 * The cancel indicator will be queried everytime a description has been
+	 * processed. It should provide a fast answer about its canceled state.
+	 */
+	@Override
+	public void checkUniqueNames(Iterable<IEObjectDescription> descriptions, CancelIndicator cancelIndicator,
+			ValidationMessageAcceptor acceptor) {
+		Iterator<IEObjectDescription> iter = descriptions.iterator();
+		this.nameMap = new HashMap<>();
+		if (!iter.hasNext())
+			return;
+		while (iter.hasNext()) {
+			IEObjectDescription description = iter.next();
+			checkDescriptionForDuplicatedName(description, acceptor);
+			operationCanceledManager.checkCanceled(cancelIndicator);
+		}
+	}
+
+	protected void checkDescriptionForDuplicatedName(IEObjectDescription description,
+			ValidationMessageAcceptor acceptor) {
+		QualifiedName qName = description.getName();
+		IEObjectDescription put = nameMap.put(qName, description);
+		if(put != null) {
+			EClass common = checkForCommonSuperClass(put, description, acceptor);
+			if(common != null) {
+				createDuplicateNameError(description, common, acceptor);
+				createDuplicateNameError(put, common, acceptor);
+			}
+		}
+	}
+
+	protected EClass checkForCommonSuperClass(IEObjectDescription one, IEObjectDescription two,
+			ValidationMessageAcceptor acceptor) {
+		
+		
+		List<EClass> flatOne = buildSuperClassList(one.getEClass());
+		List<EClass> flatTwo = buildSuperClassList(two.getEClass());
+		
+		for(EClass eC : flatOne) {
+			if(flatTwo.contains(eC))
+				return eC;
+		}
+		
+		return null;
+	}
+	
+	protected List<EClass> buildSuperClassList(EClass eClass) {
+		List<List<EClass>> superClasses = new ArrayList<>();
+		
+		buildSuperClassList(superClasses, eClass, 0);
+		
+		List<EClass> result = new ArrayList<>();
+		for(List<EClass> list : superClasses) {
+			result.addAll(list);
+		}
+		
+		return result;
+	}
+	
+	protected void buildSuperClassList(List<List<EClass>> superClasses, EClass eClass, int depth) {
+		if(superClasses.size() <= depth) {
+			superClasses.add(depth, new ArrayList<>());
+		}
+		
+		List<EClass> superTypes = eClass.getESuperTypes();
+
+		superClasses.get(depth).add(eClass);
+		
+		for(EClass superType : superTypes) {
+			buildSuperClassList(superClasses, superType, depth + 1);
+		}
+	}
+}