org.eclipse.xtext.serializer.sequencer.AssignmentFinder.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.xtext.serializer.sequencer.AssignmentFinder.java

Source

/*******************************************************************************
 * Copyright (c) 2011 itemis AG (http://www.itemis.eu) 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
 *******************************************************************************/
package org.eclipse.xtext.serializer.sequencer;

import java.util.Collection;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;

import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.xtext.AbstractElement;
import org.eclipse.xtext.CrossReference;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.EnumRule;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.Keyword;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.serializer.ISerializationContext;
import org.eclipse.xtext.serializer.analysis.SerializationContext;
import org.eclipse.xtext.serializer.impl.FeatureFinderUtil;
import org.eclipse.xtext.serializer.tokens.ICrossReferenceSerializer;
import org.eclipse.xtext.serializer.tokens.IEnumLiteralSerializer;
import org.eclipse.xtext.serializer.tokens.IKeywordSerializer;
import org.eclipse.xtext.serializer.tokens.IValueSerializer;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.inject.Inject;

/**
 * @author Moritz Eysholdt - Initial contribution and API
 */
public class AssignmentFinder implements IAssignmentFinder {

    @Inject
    protected IContextFinder contextFinder;

    @Inject
    protected ICrossReferenceSerializer crossRefSerializer;

    @Inject
    protected IEnumLiteralSerializer enumLiteralSerializer;

    @Inject
    protected IKeywordSerializer keywordSerializer;

    @Inject
    protected IValueSerializer valueSerializer;

    @Override
    public Set<AbstractElement> findAssignmentsByValue(EObject semanticObj,
            Multimap<AbstractElement, ISerializationContext> assignments, Object value, INode node) {
        List<AbstractElement> assignedElements = Lists.newArrayList(assignments.keySet());
        EStructuralFeature feature = FeatureFinderUtil.getFeature(assignedElements.iterator().next(),
                semanticObj.eClass());
        if (feature instanceof EAttribute) {
            Class<?> clazz = feature.getEType().getInstanceClass();
            if (clazz == Boolean.class || clazz == boolean.class)
                return findValidBooleanAssignments(semanticObj, assignedElements, value);
            else
                return findValidValueAssignments(semanticObj, assignedElements, value);
        } else if (feature instanceof EReference) {
            EReference ref = (EReference) feature;
            if (ref.isContainment())
                return findValidAssignmentsForContainmentRef(semanticObj, assignments, (EObject) value);
            else
                return findValidAssignmentsForCrossRef(semanticObj, assignedElements, (EObject) value, node);
        }
        throw new RuntimeException("unknown feature type");
    }

    protected Set<AbstractElement> findValidAssignmentsForContainmentRef(EObject semanticObj,
            Multimap<AbstractElement, ISerializationContext> assignments, EObject value) {
        Multimap<ISerializationContext, AbstractElement> children = ArrayListMultimap.create();
        for (Entry<AbstractElement, Collection<ISerializationContext>> e : assignments.asMap().entrySet()) {
            AbstractElement ele = e.getKey();
            if (ele instanceof RuleCall) {
                EClassifier classifier = ((RuleCall) ele).getRule().getType().getClassifier();
                if (!classifier.isInstance(value))
                    continue;
            }
            for (ISerializationContext container : e.getValue()) {
                ISerializationContext child = SerializationContext.forChild(container, ele, value);
                children.put(child, ele);
            }
        }
        if (children.size() < 2)
            return Sets.newHashSet(children.values());
        Set<ISerializationContext> found = contextFinder.findByContents(value, children.keySet());
        Set<AbstractElement> result = Sets.newLinkedHashSet();
        for (ISerializationContext ctx : children.keySet())
            if (found.contains(ctx))
                result.addAll(children.get(ctx));
        return result;
    }

    protected Set<AbstractElement> findValidAssignmentsForCrossRef(EObject semanticObj,
            Iterable<AbstractElement> assignedElements, EObject value, INode node) {
        Set<AbstractElement> result = Sets.newLinkedHashSet();
        for (AbstractElement ass : assignedElements) {
            CrossReference crossref = GrammarUtil.containingCrossReference(ass);
            EReference eref = GrammarUtil.getReference(crossref, semanticObj.eClass());
            if (EcoreUtil2.isAssignableFrom(eref.getEReferenceType(), value.eClass())
                    && crossRefSerializer.isValid(semanticObj, crossref, value, node, null))
                result.add(ass);
        }
        return result;
    }

    protected Set<AbstractElement> findValidBooleanAssignments(EObject semanticObj,
            Iterable<AbstractElement> assignedElements, Object value) {
        Set<AbstractElement> result = Sets.newLinkedHashSet();
        for (AbstractElement ele : assignedElements)
            if (GrammarUtil.isBooleanAssignment(GrammarUtil.containingAssignment(ele))) {
                if (Boolean.TRUE.equals(value))
                    result.add(ele);
            } else {
                if (ele instanceof RuleCall && valueSerializer.isValid(semanticObj, (RuleCall) ele, value, null))
                    result.add(ele);
            }
        return result;
    }

    protected Set<AbstractElement> findValidValueAssignments(EObject semanticObj,
            Iterable<AbstractElement> assignedElements, Object value) {
        Set<AbstractElement> result = Sets.newLinkedHashSet();
        for (AbstractElement ass : assignedElements) {
            if (ass instanceof Keyword && keywordSerializer.isValid(semanticObj, (Keyword) ass, value, null))
                result.add(ass);
            else if (ass instanceof RuleCall) {
                RuleCall rc = (RuleCall) ass;
                if (rc.getRule() instanceof EnumRule) {
                    if (enumLiteralSerializer.isValid(semanticObj, rc, value, null))
                        result.add(ass);
                } else if (valueSerializer.isValid(semanticObj, rc, value, null))
                    result.add(ass);
            }
        }
        return result;
    }

}