blob: af07e3435f37a99ab1c19165815fe617b4c87da4 [file] [log] [blame]
/**
*
* 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
}
}