| /** |
| * Copyright (c) 2011, 2015 - Lunifera GmbH (Gross Enzersdorf, Austria), Loetz GmbH&Co.KG (69115 Heidelberg, Germany) |
| * 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: |
| * Florian Pirchner - Initial implementation |
| */ |
| package org.eclipse.osbp.dsl.xtext.lazyresolver.scoping; |
| |
| import static java.util.Collections.singletonList; |
| |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.xtext.EcoreUtil2; |
| import org.eclipse.xtext.common.types.TypesPackage; |
| import org.eclipse.xtext.naming.QualifiedName; |
| import org.eclipse.xtext.resource.IEObjectDescription; |
| import org.eclipse.xtext.resource.ISelectable; |
| import org.eclipse.xtext.scoping.IScope; |
| import org.eclipse.xtext.scoping.Scopes; |
| import org.eclipse.xtext.scoping.impl.ImportNormalizer; |
| import org.eclipse.xtext.scoping.impl.ImportedNamespaceAwareLocalScopeProvider; |
| import org.eclipse.xtext.scoping.impl.MultimapBasedSelectable; |
| import org.eclipse.xtext.scoping.impl.SelectableBasedScope; |
| import org.eclipse.xtext.util.IResourceScopeCache; |
| import org.eclipse.osbp.dsl.xtext.lazyresolver.SemanticLoadingResource; |
| import org.eclipse.osbp.dsl.xtext.lazyresolver.api.ISemanticLoadingResource; |
| |
| import com.google.inject.Inject; |
| import com.google.inject.Provider; |
| |
| public class FastImportedNamespaceAwareLocalScopeProvider extends |
| ImportedNamespaceAwareLocalScopeProvider { |
| |
| private boolean collectingParents; |
| |
| @Inject |
| private IResourceScopeCache cache = IResourceScopeCache.NullImpl.INSTANCE; |
| |
| protected IScope getResourceScope(Resource res, EReference reference) { |
| EObject context = null; |
| if (res instanceof ISemanticLoadingResource) { |
| context = ((ISemanticLoadingResource) res).getSemanticElement(); |
| } else { |
| context = res.getContents().get(0); |
| } |
| IScope globalScope = getGlobalScope(res, reference); |
| List<ImportNormalizer> normalizers = getImplicitImports(isIgnoreCase(reference)); |
| if (!normalizers.isEmpty()) { |
| globalScope = createImportScope(globalScope, normalizers, null, |
| reference.getEReferenceType(), isIgnoreCase(reference)); |
| } |
| return getResourceScope(globalScope, context, reference); |
| } |
| |
| protected IScope getResourceScope(final IScope parent, |
| final EObject context, final EReference reference) { |
| if (context.eResource() == null) |
| return parent; |
| |
| ISelectable allDescriptions = null; |
| if (context.eResource() instanceof SemanticLoadingResource |
| && !EcoreUtil2.isAssignableFrom( |
| TypesPackage.Literals.JVM_TYPE_REFERENCE, |
| reference.eClass())) { |
| // avoid derived state creation |
| allDescriptions = getSemanticDescription((SemanticLoadingResource) context |
| .eResource()); |
| } else { |
| allDescriptions = getAllDescriptions(context.eResource()); |
| } |
| return SelectableBasedScope.createScope(parent, allDescriptions, |
| reference.getEReferenceType(), isIgnoreCase(reference)); |
| } |
| |
| protected ISelectable getSemanticDescription( |
| final SemanticLoadingResource resource) { |
| return cache.get("internalGetSemanticDescription", resource, |
| new Provider<ISelectable>() { |
| public ISelectable get() { |
| return internalGetSemanticDescription(resource); |
| } |
| }); |
| } |
| |
| protected ISelectable internalGetSemanticDescription( |
| final SemanticLoadingResource resource) { |
| Iterable<EObject> allContents = new Iterable<EObject>() { |
| public Iterator<EObject> iterator() { |
| return EcoreUtil.getAllContents(resource.getSemanticElement(), |
| false); |
| } |
| }; |
| |
| Iterable<IEObjectDescription> allDescriptions = Scopes |
| .scopedElementsFor(allContents, getQualifiedNameProvider()); |
| return new MultimapBasedSelectable(allDescriptions); |
| } |
| |
| protected IScope getLocalElementsScope(IScope parent, |
| final EObject context, final EReference reference) { |
| IScope result = parent; |
| ISelectable allDescriptions = null; |
| if (context.eResource() instanceof SemanticLoadingResource |
| && !EcoreUtil2.isAssignableFrom( |
| TypesPackage.Literals.JVM_TYPE_REFERENCE, |
| reference.eClass())) { |
| // avoid derived state creation |
| allDescriptions = getSemanticDescription((SemanticLoadingResource) context |
| .eResource()); |
| } else { |
| allDescriptions = getAllDescriptions(context.eResource()); |
| } |
| |
| QualifiedName name = getQualifiedNameOfLocalElement(context); |
| boolean ignoreCase = isIgnoreCase(reference); |
| final List<ImportNormalizer> namespaceResolvers = getImportedNamespaceResolvers( |
| context, ignoreCase); |
| if (!namespaceResolvers.isEmpty()) { |
| if (isRelativeImport() && name != null) { |
| ImportNormalizer localNormalizer = doCreateImportNormalizer( |
| name, true, ignoreCase); |
| result = createImportScope(result, |
| singletonList(localNormalizer), allDescriptions, |
| reference.getEReferenceType(), isIgnoreCase(reference)); |
| } |
| result = createImportScope(result, namespaceResolvers, null, |
| reference.getEReferenceType(), isIgnoreCase(reference)); |
| } |
| if (name != null) { |
| ImportNormalizer localNormalizer = doCreateImportNormalizer(name, |
| true, ignoreCase); |
| result = createImportScope(result, singletonList(localNormalizer), |
| allDescriptions, reference.getEReferenceType(), |
| isIgnoreCase(reference)); |
| } |
| return result; |
| } |
| |
| @Override |
| public IScope getScope(final EObject context, final EReference reference) { |
| if (!collectingParents) { |
| try { |
| collectingParents = true; |
| return getCachingScope(context, reference); |
| } finally { |
| collectingParents = false; |
| } |
| } else { |
| return super.getScope(context, reference); |
| } |
| } |
| |
| public IScope getCachingScope(final EObject context, |
| final EReference reference) { |
| final String cacheId = getCacheID(reference); |
| return cache.get(cacheId, context.eResource(), new Provider<IScope>() { |
| public IScope get() { |
| try { |
| collectingParents = true; |
| final IScope parent = getScope(context, reference); |
| return new CachingTypeScope(cacheId, parent); |
| } finally { |
| collectingParents = false; |
| } |
| } |
| }); |
| } |
| |
| private String getCacheID(final EReference reference) { |
| EClass eClass = reference.getEReferenceType(); |
| EPackage ePkg = eClass.getEPackage(); |
| |
| return ePkg.getNsURI() + "-" + eClass.getName(); |
| } |
| |
| @Override |
| protected boolean isRelativeImport() { |
| // do not so to improve performance |
| return false; |
| } |
| |
| } |