Created
August 8, 2024 08:53
-
-
Save tfonda-fbk/5661e27f58ae5180507ff71a25b90a54 to your computer and use it in GitHub Desktop.
Extension of ImportedNamespaceAwareLocalScopeProvider to implement transitive imports of namespaces
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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