| /** |
| * |
| * 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 |
| * |
| * This copyright notice shows up in the generated Java code |
| * |
| */ |
| |
| package org.eclipse.osbp.xtext.oxtype.scoping.jvmtype |
| |
| import com.google.common.collect.Lists |
| import com.google.inject.Inject |
| import com.google.inject.Provider |
| import java.util.List |
| import java.util.Set |
| import org.eclipse.emf.ecore.EClass |
| import org.eclipse.emf.ecore.EObject |
| import org.eclipse.emf.ecore.EReference |
| import org.eclipse.emf.ecore.resource.Resource |
| import org.eclipse.osbp.xtext.oxtype.oxtype.OXImportDeclaration |
| import org.eclipse.osbp.xtext.oxtype.scoping.IScopingInfoProvider |
| import org.eclipse.xtext.common.types.JvmDeclaredType |
| import org.eclipse.xtext.common.types.JvmType |
| import org.eclipse.xtext.common.types.access.IJvmTypeProvider |
| import org.eclipse.xtext.common.types.xtext.AbstractTypeScope |
| import org.eclipse.xtext.common.types.xtext.AbstractTypeScopeProvider |
| import org.eclipse.xtext.linking.impl.ImportedNamesAdapter |
| import org.eclipse.xtext.naming.IQualifiedNameConverter |
| import org.eclipse.xtext.naming.QualifiedName |
| import org.eclipse.xtext.resource.CompilerPhases |
| import org.eclipse.xtext.resource.IResourceDescription |
| import org.eclipse.xtext.resource.IResourceDescriptions |
| import org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider |
| import org.eclipse.xtext.scoping.IScope |
| import org.eclipse.xtext.scoping.impl.ImportNormalizer |
| import org.eclipse.xtext.scoping.impl.SelectableBasedScope |
| import org.eclipse.xtext.util.IResourceScopeCache |
| import org.eclipse.xtext.util.Strings |
| import org.eclipse.xtext.xbase.scoping.AbstractNestedTypeAwareImportNormalizer |
| import org.eclipse.xtext.xbase.scoping.XImportSectionNamespaceScopeProvider |
| import org.eclipse.xtext.xtype.XImportDeclaration |
| import org.eclipse.xtext.xtype.XImportSection |
| import org.eclipse.xtext.xbase.imports.IImportsConfiguration |
| import org.eclipse.xtext.resource.XtextResource |
| |
| @SuppressWarnings("restriction") |
| class OXJvmTypesImportSectionNamespaceScopeProvider extends XImportSectionNamespaceScopeProvider { |
| |
| public static final QualifiedName XBASE_LIB = XImportSectionNamespaceScopeProvider.XBASE_LIB; |
| public static final QualifiedName JAVA_LANG = XImportSectionNamespaceScopeProvider.JAVA_LANG; |
| public static final QualifiedName JAVA_UTIL = QualifiedName.create("java","util"); |
| |
| @Inject |
| private AbstractTypeScopeProvider typeScopeProvider; |
| |
| @Inject |
| private IQualifiedNameConverter qualifiedNameConverter; |
| |
| @Inject |
| private IResourceScopeCache cache; |
| |
| @Inject |
| private CompilerPhases compilerPhases; |
| |
| @Inject |
| private ResourceDescriptionsProvider resourceDescriptionsProvider; |
| |
| @Inject |
| private IScopingInfoProvider infoProvider; |
| |
| @Inject |
| private IImportsConfiguration importsConfig; |
| |
| override IScope getScope(EObject context, EReference reference) { |
| val EClass referenceType = reference.getEReferenceType(); |
| if (context instanceof XImportDeclaration) { |
| val Resource resource = context.eResource(); |
| val IJvmTypeProvider typeProvider = typeScopeProvider.getTypeProvider(resource.getResourceSet()); |
| var AbstractTypeScope typeScope = typeScopeProvider.createTypeScope(typeProvider, null); |
| val IResourceDescriptions descriptions = resourceDescriptionsProvider. |
| getResourceDescriptions(context.eResource().getResourceSet()); |
| val IResourceDescription resourceDescription = descriptions.getResourceDescription(resource.getURI()); |
| if (resourceDescription !== null) { |
| typeScope = new LocalResourceFilteringTypeScope(typeScope, resourceDescription); |
| } |
| val RecordingTypeScope recordingTypeScope = new RecordingTypeScope(typeScope, |
| getImportedNamesSet(resource)); |
| |
| //TODO this scope doesn't support binary syntax for inner types. It should be a KnownTypes scope which doesn't allow simple names |
| // Unfortunately I cannot use a RecordingTypeScope as a parent as it is not compatible... |
| val IScope scope = SelectableBasedScope.createScope(recordingTypeScope, getAllDescriptions(resource), |
| reference.getEReferenceType(), false); |
| return scope; |
| } |
| |
| val Resource resource = context.eResource(); |
| val AbstractOXTypeTypeScope result = cache.get( |
| "type.scope", |
| resource, |
| new Provider<AbstractOXTypeTypeScope>() { |
| override AbstractOXTypeTypeScope get() { |
| val IJvmTypeProvider typeProvider = typeScopeProvider.getTypeProvider(resource.getResourceSet()); |
| var AbstractTypeScope typeScope = typeScopeProvider.createTypeScope(typeProvider, null); |
| val IResourceDescriptions descriptions = resourceDescriptionsProvider. |
| getResourceDescriptions(context.eResource().getResourceSet()); |
| val IResourceDescription resourceDescription = descriptions. |
| getResourceDescription(resource.getURI()); |
| if (resourceDescription !== null) { |
| typeScope = new LocalResourceFilteringTypeScope(typeScope, resourceDescription); |
| } |
| val RecordingTypeScope recordingTypeScope = new RecordingTypeScope(typeScope, |
| getImportedNamesSet(resource)); |
| val AbstractOXTypeTypeScope rootTypeScope = getRootTypeScope( |
| infoProvider.getPackageName(context), recordingTypeScope); |
| val AbstractOXTypeTypeScope importScope = getImportScope(importsConfig.getImportSection(context.eResource as XtextResource), |
| rootTypeScope, recordingTypeScope); |
| val AbstractOXTypeTypeScope localTypes = getResourceTypeScope(resource, |
| infoProvider.getPackageName(context), importScope); |
| val AbstractOXTypeTypeScope primitiveAware = new PrimitiveAwareScope(localTypes, typeScope); |
| val AbstractOXTypeTypeScope caching = new CachingTypeScope(primitiveAware); |
| return caching; |
| } |
| } |
| ); |
| return result; |
| } |
| |
| def protected AbstractOXTypeTypeScope getImportScope(XImportSection importSection, AbstractOXTypeTypeScope parent, |
| RecordingTypeScope typeScope) { |
| if (importSection === null) |
| return parent; |
| val List<XImportDeclaration> importDeclarations = importSection.getImportDeclarations(); |
| if (importDeclarations.isEmpty()) { |
| return parent; |
| } |
| var List<ImportNormalizer> wildcardImports = null; |
| var List<JvmType> concreteImports = null; |
| var List<QualifiedName> importedNames = null; |
| var List<ImportNormalizer> fqnImports = null; |
| var boolean hasLegacyImport = false; |
| for (XImportDeclaration importDeclaration : importDeclarations) { |
| val OXImportDeclaration oxImportDecl = importDeclaration as OXImportDeclaration; |
| if (!importDeclaration.isStatic()) { |
| if (importDeclaration.isWildcard()) { |
| if (wildcardImports === null) { |
| wildcardImports = Lists.newArrayListWithCapacity(4); |
| } |
| var String importedNamespace = importDeclaration.getImportedNamespace(); |
| importedNamespace = importedNamespace.substring(0, importedNamespace.length() - 2); |
| var QualifiedName qualifiedImportedNamespace = qualifiedNameConverter.toQualifiedName( |
| importedNamespace); |
| wildcardImports.add( |
| AbstractNestedTypeAwareImportNormalizer. |
| createNestedTypeAwareImportNormalizer(qualifiedImportedNamespace, true, false)); |
| } else if (oxImportDecl.isFqnImport) { |
| if (fqnImports === null) { |
| fqnImports = Lists.newArrayListWithCapacity(4); |
| } |
| var String importedFqn = oxImportDecl.importedFullyQualifiedName; |
| var QualifiedName qualifiedImportedNamespace = qualifiedNameConverter.toQualifiedName( |
| importedFqn); |
| fqnImports.add( |
| AbstractNestedTypeAwareImportNormalizer. |
| createNestedTypeAwareImportNormalizer(qualifiedImportedNamespace, false, false)); |
| } else { |
| var JvmDeclaredType importedType = importDeclaration.getImportedType(); |
| if (importedType !== null && !importedType.eIsProxy()) { |
| if (concreteImports === null) { |
| concreteImports = Lists.newArrayListWithCapacity(10); |
| } |
| if (importedNames === null) { |
| importedNames = Lists.newArrayListWithCapacity(10); |
| } |
| concreteImports.add(importedType); |
| if (importedType.eContainer() instanceof JvmDeclaredType) { |
| var String importSyntax = getImportsConfiguration().getLegacyImportSyntax(importDeclaration); |
| if (importSyntax !== null) { |
| hasLegacyImport = true; |
| importedNames.add(getQualifiedNameConverter().toQualifiedName(importSyntax)); |
| } else |
| importedNames.add(null); |
| } else { |
| importedNames.add(null); |
| } |
| } |
| } |
| } |
| } |
| return getImportScope(wildcardImports, concreteImports, importedNames, fqnImports, parent, typeScope); |
| } |
| |
| def AbstractOXTypeTypeScope getImportScope(List<ImportNormalizer> wildcardImports, List<JvmType> concreteImports, |
| List<QualifiedName> importedNames, List<ImportNormalizer> fqnImports, AbstractOXTypeTypeScope parent, |
| RecordingTypeScope typeScope) { |
| var AbstractOXTypeTypeScope result = parent; |
| if (wildcardImports !== null) |
| result = new TypeScopeWithWildcardImports(wildcardImports, typeScope, result); |
| if (importedNames !== null) |
| result = new LegacyKnownTypesScope(concreteImports, importedNames, result); |
| if (fqnImports !== null) |
| result = new TypeScopeWithFqnImports(fqnImports, typeScope, result) |
| if (concreteImports !== null) |
| result = new KnownTypesScope(concreteImports, result); |
| return result; |
| } |
| |
| def protected AbstractOXTypeTypeScope getRootTypeScope(String packageName, RecordingTypeScope typeScope) { |
| var ImportNormalizer[][] implicitImports = null; |
| if (packageName !== null && packageName.length() > 0) { |
| implicitImports = #[ |
| #[ |
| AbstractNestedTypeAwareImportNormalizer. |
| createNestedTypeAwareImportNormalizer(JAVA_LANG, true, false), |
| AbstractNestedTypeAwareImportNormalizer. |
| createNestedTypeAwareImportNormalizer(JAVA_UTIL, true, false), |
| AbstractNestedTypeAwareImportNormalizer. |
| createNestedTypeAwareImportNormalizer(XBASE_LIB, true, false) |
| ] |
| ] |
| } else { |
| implicitImports = #[ |
| #[ |
| AbstractNestedTypeAwareImportNormalizer. |
| createNestedTypeAwareImportNormalizer(JAVA_LANG, true, false), |
| AbstractNestedTypeAwareImportNormalizer. |
| createNestedTypeAwareImportNormalizer(JAVA_UTIL, true, false), |
| AbstractNestedTypeAwareImportNormalizer. |
| createNestedTypeAwareImportNormalizer(XBASE_LIB, true, false) |
| ] |
| ] |
| } |
| return new TypeScopeWithWildcardImports(implicitImports, typeScope); |
| } |
| |
| def AbstractOXTypeTypeScope getResourceTypeScope(Resource resource, String packageName, |
| AbstractOXTypeTypeScope parent) { |
| val List<EObject> contents = resource.getContents(); |
| val List<JvmType> knownTypes = Lists.newArrayListWithExpectedSize(contents.size() - 1); |
| for (EObject content : contents) { |
| if (content instanceof JvmType) { |
| if (content instanceof JvmDeclaredType) { |
| if (Strings.equal(packageName, (content as JvmDeclaredType).getPackageName())) { |
| knownTypes.add(content as JvmType); |
| } |
| } else { |
| knownTypes.add(content as JvmType); |
| } |
| } |
| } |
| if (knownTypes.isEmpty()) |
| return parent; |
| return new KnownTypesScope(knownTypes, parent); |
| } |
| |
| def protected Set<QualifiedName> getImportedNamesSet(Resource resource) { |
| val ImportedNamesAdapter adapter = getImportedNamesAdapter(resource); |
| return adapter.getImportedNames(); |
| } |
| |
| def protected ImportedNamesAdapter getImportedNamesAdapter(Resource resource) { |
| return ImportedNamesAdapter.findOrInstall(resource); |
| } |
| |
| override List<ImportNormalizer> getImportedNamespaceResolvers(XImportSection importSection, boolean ignoreCase) { |
| val List<XImportDeclaration> importDeclarations = importSection.getImportDeclarations() |
| val List<ImportNormalizer> result = Lists.newArrayListWithExpectedSize(importDeclarations.size()); |
| for (XImportDeclaration imp : importDeclarations) { |
| if (!imp.isStatic()) { |
| val OXImportDeclaration decl = imp as OXImportDeclaration; |
| var String value = decl.getImportedFullyQualifiedName(); |
| if (value === null) |
| value = imp.getImportedNamespace(); |
| if (value === null) |
| value = imp.getImportedTypeName(); |
| val ImportNormalizer resolver = createImportedNamespaceResolver(value, ignoreCase); |
| if (resolver !== null) |
| result.add(resolver); |
| } |
| } |
| return result; |
| } |
| |
| def List<ImportNormalizer> getImportedFQNResolvers(XImportSection importSection, boolean ignoreCase) { |
| val List<XImportDeclaration> importDeclarations = importSection.getImportDeclarations() |
| val List<ImportNormalizer> result = Lists.newArrayListWithExpectedSize(importDeclarations.size()); |
| for (XImportDeclaration imp : importDeclarations) { |
| val OXImportDeclaration decl = imp as OXImportDeclaration; |
| if (decl.isFqnImport()) { |
| var String value = decl.getImportedFullyQualifiedName(); |
| val ImportNormalizer resolver = createImportedNamespaceResolver(value, ignoreCase); |
| if (resolver !== null) |
| result.add(resolver); |
| } |
| } |
| return result; |
| } |
| |
| override List<ImportNormalizer> getImplicitImports(boolean ignoreCase) { |
| val result = super.getImplicitImports(ignoreCase); |
| result.addAll(infoProvider.getImplicitImports(ignoreCase)) |
| return result |
| } |
| } |