/******************************************************************************* * Copyright (c) 2010-2012, Zoltan Ujhelyi, Istvan Rath and Daniel Varro * 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: * Zoltan Ujhelyi - initial API and implementation *******************************************************************************/ package org.eclipse.incquery.patternlanguage.emf.scoping; import static org.eclipse.emf.ecore.util.EcoreUtil.getRootContainer; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EEnum; import org.eclipse.emf.ecore.EEnumLiteral; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.incquery.patternlanguage.emf.EMFPatternLanguageScopeHelper; import org.eclipse.incquery.patternlanguage.emf.ResolutionException; import org.eclipse.incquery.patternlanguage.emf.eMFPatternLanguage.ClassType; import org.eclipse.incquery.patternlanguage.emf.eMFPatternLanguage.EnumValue; import org.eclipse.incquery.patternlanguage.emf.eMFPatternLanguage.PackageImport; import org.eclipse.incquery.patternlanguage.emf.eMFPatternLanguage.PatternModel; import org.eclipse.incquery.patternlanguage.emf.eMFPatternLanguage.ReferenceType; import org.eclipse.incquery.patternlanguage.emf.helper.EMFPatternLanguageHelper; import org.eclipse.incquery.patternlanguage.patternLanguage.PathExpressionHead; import org.eclipse.incquery.patternlanguage.patternLanguage.PathExpressionTail; import org.eclipse.incquery.patternlanguage.patternLanguage.PatternBody; import org.eclipse.incquery.patternlanguage.patternLanguage.Type; import org.eclipse.incquery.patternlanguage.patternLanguage.Variable; import org.eclipse.incquery.patternlanguage.patternLanguage.util.PatternLanguageSwitch; import org.eclipse.incquery.patternlanguage.scoping.PatternLanguageDeclarativeScopeProvider; import org.eclipse.xtext.naming.IQualifiedNameConverter; import org.eclipse.xtext.naming.QualifiedName; import org.eclipse.xtext.scoping.IScope; import org.eclipse.xtext.scoping.Scopes; import org.eclipse.xtext.util.PolymorphicDispatcher; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.inject.Inject; /** * <p> * An extended abstract declarative scope provider to facilitate the reusing of abstract declarative scope providers * together with XBase scope provider. * </p> * <p> * See <a * href="http://www.eclipse.org/forums/index.php/mv/msg/219841/699521/#msg_699521">http://www.eclipse.org/forums/index * .php/mv/msg/219841/699521/#msg_699521</a> for details. * </p> * * @author Zoltan Ujhelyi * */ public class EMFPatternLanguageDeclarativeScopeProvider extends PatternLanguageDeclarativeScopeProvider { @Inject private IQualifiedNameConverter qualifiedNameConverter; @Inject private IMetamodelProvider metamodelProvider; /** * {@inheritDoc} Overridden for debugging purposes. */ @Override protected Predicate<Method> getPredicate(EObject context, EClass type) { String methodName = "scope_" + type.getName(); // System.out.println(methodName + " ctx " + context.eClass().getName()); return PolymorphicDispatcher.Predicates.forName(methodName, 2); } /** * {@inheritDoc} Overridden for debugging purposes. */ @Override protected Predicate<Method> getPredicate(EObject context, EReference reference) { String methodName = "scope_" + reference.getEContainingClass().getName() + "_" + reference.getName(); // System.out.println(methodName + " ctx " + context.eClass().getName()); return PolymorphicDispatcher.Predicates.forName(methodName, 2); } public IScope scope_EPackage(PackageImport ctx, EReference ref) { return metamodelProvider.getAllMetamodelObjects(ctx); } public IScope scope_EClassifier(PatternBody ctx, EReference ref) { // This is needed for content assist - in that case the ClassType does not exists EObject root = getRootContainer(ctx); if (root instanceof PatternModel) { return createReferencedPackagesScope((PatternModel) root); } else { return IScope.NULLSCOPE; } } public IScope scope_EClassifier(ClassType ctx, EReference ref) { EObject root = getRootContainer(ctx); if (root instanceof PatternModel) { return createReferencedPackagesScope((PatternModel) root); } else { return IScope.NULLSCOPE; } } public IScope scope_EClassifier(Variable ctx, EReference ref) { EObject root = getRootContainer(ctx); if (root instanceof PatternModel) { return createReferencedPackagesScope((PatternModel) root); } else { return IScope.NULLSCOPE; } } protected IScope createClassifierScope(Iterable<EClassifier> classifiers) { return Scopes.scopeFor(classifiers); } protected IScope createReferencedPackagesScope(PatternModel model) { final Collection<EClassifier> allClassifiers = new ArrayList<EClassifier>(); for (PackageImport decl : EMFPatternLanguageHelper.getPackageImportsIterable(model)) { if (decl.getEPackage() != null) { allClassifiers.addAll(decl.getEPackage().getEClassifiers()); } } return createClassifierScope(allClassifiers); } public IScope scope_EStructuralFeature(PathExpressionHead ctx, EReference ref) { // This is needed for content assist - in that case the ExpressionTail does not exists return expressionParentScopeProvider.doSwitch(ctx); } public IScope scope_EStructuralFeature(PathExpressionTail ctx, EReference ref) { return expressionParentScopeProvider.doSwitch(ctx.eContainer()); } public IScope scope_EEnum(EnumValue ctx, EReference ref) { PatternModel model = (PatternModel) getRootContainer(ctx); final Collection<EEnum> enums = Lists.newArrayList(); for (PackageImport decl : EMFPatternLanguageHelper.getPackageImportsIterable(model)) { if (decl.getEPackage() != null) { Iterables.addAll(enums, Iterables.filter(decl.getEPackage().getEClassifiers(), EEnum.class)); } } return Scopes.scopeFor(enums); } public IScope scope_EEnumLiteral(EnumValue ctx, EReference ref) { EEnum type; try { type = ctx.getEnumeration(); type = (type != null) ? type : EMFPatternLanguageScopeHelper .calculateEnumerationType((PathExpressionHead) ctx.eContainer()); } catch (ResolutionException e) { return IScope.NULLSCOPE; } return calculateEnumLiteralScope(type); } private IScope calculateEnumLiteralScope(EEnum enumeration) { EList<EEnumLiteral> literals = enumeration.getELiterals(); return Scopes.scopeFor(literals, new Function<EEnumLiteral, QualifiedName>() { @Override public QualifiedName apply(EEnumLiteral literal) { QualifiedName qualifiedName = qualifiedNameConverter.toQualifiedName(literal.getLiteral()); return qualifiedName; } }, IScope.NULLSCOPE); } private final ParentScopeProvider expressionParentScopeProvider = new ParentScopeProvider(); static class ParentScopeProvider extends PatternLanguageSwitch<IScope> { @Override public IScope casePathExpressionHead(PathExpressionHead object) { return calculateReferences(object.getType()); } @Override public IScope casePathExpressionTail(PathExpressionTail object) { return calculateReferences(object.getType()); } private IScope calculateReferences(Type type) { List<EStructuralFeature> targetReferences = Collections.emptyList(); if (type instanceof ReferenceType) { EClassifier referredType = ((ReferenceType) type).getRefname().getEType(); if (referredType instanceof EClass) { targetReferences = ((EClass) referredType).getEAllStructuralFeatures(); } } else if (type instanceof ClassType) { EClassifier classifier = ((ClassType) type).getClassname(); if (classifier instanceof EClass) { targetReferences = (((EClass) classifier).getEAllStructuralFeatures()); } } if (targetReferences.isEmpty()) { return IScope.NULLSCOPE; } return Scopes.scopeFor(targetReferences); } } }