Use IChangeSerializer for refactoring that changes multiple Xtext files [message #1827408] |
Thu, 14 May 2020 08:21 |
Stefan Kapferer Messages: 19 Registered: March 2020 |
Junior Member |
|
|
Hi there
I have a question regarding the ChangeSerializer that I use to implement a refactoring for my Xtext language (Xtext LSP + VS code IDE).
My language uses imports, which means a user is able to reference objects in other files. Therefore, my refactoring potentially changes multiple files (Xtext resources).
In my language server I implement the refactoring as a command that creates a WorkspaceEdit.
I construct the WorkspaceEdit as follows:
private WorkspaceEdit createWorkspaceEdit(ILanguageServerAccess access, URI resourceURI, Document document, IChangeSerializer.IModification<Resource> mod) {
ResourceSet rs = access.newLiveScopeResourceSet(resourceURI);
Resource copy = rs.getResource(resourceURI, true);
IChangeSerializer serializer = serializerProvider.get();
EcoreUtil.resolveAll(copy); // resolve all imported resources (ensures that imported files are part of the ResourceSet)
serializer.addModification(copy, mod);
List<IEmfResourceChange> documentchanges = new ArrayList<>();
serializer.applyModifications(CollectionBasedAcceptor.of(documentchanges));
WorkspaceEdit workspaceEdit = new WorkspaceEdit();
for (ITextDocumentChange documentchange : Iterables.filter(documentchanges, ITextDocumentChange.class)) {
List<TextEdit> edits = ListExtensions.map(documentchange.getReplacements(), (ITextReplacement replacement) -> {
TextEdit textEdit = new TextEdit();
...
// I create the textEdit here
...
return textEdit;
});
workspaceEdit.getChanges().put(documentchange.getNewURI().toString(), edits);
}
return workspaceEdit;
}
My problem: everything works fine as long as my modification (IChangeSerializer.IModification) only changes objects in a single file. If the modification changes objects that are spread accross multiple files, I get the following exception when calling serializer.applyModifications:
org.eclipse.emf.common.util.BasicEList$BasicIndexOutOfBoundsException: index=1, size=1
at org.eclipse.emf.common.util.BasicEList.get(BasicEList.java:346)
at org.eclipse.xtext.ide.serializer.impl.ReferenceUpdater.createUpdatableReference(ReferenceUpdater.java:90)
at org.eclipse.xtext.ide.serializer.impl.ReferenceUpdater.updateAllReferences(ReferenceUpdater.java:215)
at org.eclipse.xtext.ide.serializer.impl.ReferenceUpdater.update(ReferenceUpdater.java:203)
at org.eclipse.xtext.ide.serializer.impl.RecordingXtextResourceUpdater.applyChange(RecordingXtextResourceUpdater.java:70)
at org.eclipse.xtext.ide.serializer.impl.ChangeSerializer.endRecordChanges(ChangeSerializer.java:191)
at org.eclipse.xtext.ide.serializer.impl.ChangeSerializer.applyModifications(ChangeSerializer.java:113)
Any ideas what I am doing wrong? Do I somehow have to register all affected resources manually?
|
|
|
|
|
|
|
|
Re: Use IChangeSerializer for refactoring that changes multiple Xtext files [message #1827435 is a reply to message #1827415] |
Thu, 14 May 2020 12:19 |
Stefan Kapferer Messages: 19 Registered: March 2020 |
Junior Member |
|
|
Seems to be a bug, from my perspective.
Problem update:
It has nothing to do with the fact that I use multiple files. I can now reproduce it with a single DSL file as well.
The problem occurs because my modification deletes EObjects from the model which are referenced in the original state.
Although I also delete the reference from the corresponding reference list, the exception occurs.
As I see it, there is a problem with this logic in the ReferenceUpdater (createUpdatableReference method):
List<?> targets = (List<?>) value;
int i = current.getIndexInContainingFeature();
EObject t = (EObject) targets.get(i);
if (t != null && !t.eIsProxy()) {
return new UpdatableReference(owner, ref, i, t, crossRef, current);
}
And the problem with this code is that the index i is calculated based on the original model state. The index is correct for the state before the modification.
But the targets list corresponds to the state after the modification and does no longer contain the deleted reference.
My modification removes an EObject by calling EcoreUtil2.delete(object), which already cleans the references and removes it from the list.
Is it possible that the ReferenceUpdater cannot handle modifications which delete model parts?
Or formulated in another way: Does the ReferenceUpdater respect the fact that some references may have been deleted during a modification? It seems to me that it does not handle this case.
|
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.03861 seconds