Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save tfonda-fbk/5661e27f58ae5180507ff71a25b90a54 to your computer and use it in GitHub Desktop.
Save tfonda-fbk/5661e27f58ae5180507ff71a25b90a54 to your computer and use it in GitHub Desktop.
Extension of ImportedNamespaceAwareLocalScopeProvider to implement transitive imports of namespaces
package eu.fbk.sysmlv2.scoping;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static java.util.Collections.singletonList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.resource.ISelectable;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.impl.ImportNormalizer;
import org.eclipse.xtext.scoping.impl.ImportedNamespaceAwareLocalScopeProvider;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Streams;
import eu.fbk.sysmlv2.sysMLv2.Import;
public class SysMLv2ImportedNamespaceAwareLocalScopeProvider extends ImportedNamespaceAwareLocalScopeProvider {
private static final Set<ResourceSet> POPULATED_RESOURCE_SETS = new HashSet<>();
private static final IWorkspaceRoot ROOT = ResourcesPlugin.getWorkspace().getRoot();
private static final ImmutableList<URI> FILES = collectFilesWithExtension(ROOT, ".sysml", ImmutableList.builder());
private final Map<EObject, List<ImportNormalizer>> normalizersMap = new HashMap<>();
private String stripWildcardIfPresent(String importedNamespace) {
if (importedNamespace.endsWith(getWildCard())) {
return importedNamespace.substring(0, importedNamespace.length() - 3);
} else {
return importedNamespace;
}
}
private boolean isEObjectImported(EObject eObject, List<Import> imports) {
final QualifiedName qualifiedName = getQualifiedNameProvider().getFullyQualifiedName(eObject);
if (qualifiedName == null) {
return false;
}
final String SysMLv2QualifiedName = qualifiedName.toString("::");
return imports.stream().anyMatch(i -> i.getImportedNamespace() != null &&
SysMLv2QualifiedName.equals(stripWildcardIfPresent(i.getImportedNamespace())));
}
private List<ImportNormalizer> recursivelyGetImportedNamespaceResolvers(EObject context, boolean ignoreCase) {
final List<ImportNormalizer> forChilds = new LinkedList<>();
List<ImportNormalizer> contextTransitiveNormalizers = normalizersMap.get(context);
if (contextTransitiveNormalizers != null) {
return contextTransitiveNormalizers;
}
contextTransitiveNormalizers = getImportedNamespaceResolvers(context, ignoreCase);
if (contextTransitiveNormalizers.size() == 0) {
return contextTransitiveNormalizers;
}
final var importStatementsInContext = EcoreUtil2.getAllContentsOfType(context, Import.class);
final ResourceSet resourceSet = EcoreUtil2.getResourceSet(context);
Streams.stream(EcoreUtil2.getAllContents(resourceSet, false))
.filter(EObject.class::isInstance).map(EObject.class::cast)
.filter(eobj -> isEObjectImported(eobj, importStatementsInContext))
.forEach(e -> forChilds.addAll(recursivelyGetImportedNamespaceResolvers(e, ignoreCase)));
contextTransitiveNormalizers.addAll(forChilds);
normalizersMap.put(context, contextTransitiveNormalizers);
return contextTransitiveNormalizers;
}
private static ImmutableList<URI> collectFilesWithExtension(IResource resource, String fileExtension, ImmutableList.Builder<URI> builder) {
if (resource instanceof final IContainer container) {
try {
IResource[] members = container.members();
for (IResource member : members) {
if (member instanceof final IFolder folder && !folder.getName().equals("bin")) {
collectFilesWithExtension(folder, fileExtension, builder);
} else if (!(member instanceof IFolder)) {
collectFilesWithExtension(member, fileExtension, builder);
}
}
} catch (CoreException e) {
e.printStackTrace();
}
} else if (resource instanceof final IFile file && file.getName().endsWith(fileExtension)) {
builder.add(URI.createFileURI(file.getRawLocation().makeAbsolute().toOSString()));
}
if (resource.equals(ROOT)) {
return builder.build();
} else {
return null;
}
}
@Override
protected IScope getLocalElementsScope(IScope parent, final EObject context,
final EReference reference) {
IScope result = parent;
ISelectable allDescriptions = getAllDescriptions(context.eResource());
QualifiedName name = getQualifiedNameOfLocalElement(context);
boolean ignoreCase = isIgnoreCase(reference);
final ResourceSet resourceSet = context.eResource().getResourceSet();
if (POPULATED_RESOURCE_SETS.add(resourceSet)) {
FILES.forEach(f -> resourceSet.getResource(f, true));
}
final List<ImportNormalizer> namespaceResolvers = recursivelyGetImportedNamespaceResolvers(context, ignoreCase);
if (!namespaceResolvers.isEmpty()) {
if (isRelativeImport() && name!=null && !name.isEmpty()) {
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
protected ImportNormalizer doCreateImportNormalizer(QualifiedName importedNamespace, boolean wildcard, boolean ignoreCase) {
return new SysMLv2ImportNormalizer(importedNamespace, wildcard, ignoreCase);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment