diff --git a/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/serializer/ChangeSerializerTest.xtend b/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/serializer/ChangeSerializerTest.xtend index bb34098a4..3fcc049ee 100644 --- a/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/serializer/ChangeSerializerTest.xtend +++ b/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/serializer/ChangeSerializerTest.xtend @@ -235,6 +235,72 @@ class ChangeSerializerTest { ''' } + @Test + def void testRenameFqn1() { + val fs = new InMemoryURIHandler() + fs += "inmemory:/file1.pstl" -> ''' + #1 r { + X refs a1.a2 X.a1.a2 r.X.a1.a2 { a1 { a2 refs a2 { a3 { ref a3 } } } } + Y refs b1.b2 Y.b1.b2 r.Y.b1.b2 { b1 { b2 { ref b2 } } } + } + ''' + + val rs = fs.createResourceSet + val model = rs.contents("inmemory:/file1.pstl", Node) + + val serializer = newChangeSerializer() + serializer.addModification(model.eResource) [ + model.children.head.children.head.children.head.name = "b" + ] + Assert.assertEquals(1, model.eResource.resourceSet.resources.size) + serializer.endRecordChangesToTextDocuments === ''' + ----------------- inmemory:/file1.pstl (syntax: ) ----------------- + #1 r { + X refs <15:5|a1.b> <21:7|a1.b> <29:9|a1.b> { a1 { <46:2|b> refs <54:2|b> { a3 { ref a3 } } } } + Y refs b1.b2 Y.b1.b2 r.Y.b1.b2 { b1 { b2 { ref b2 } } } + } + -------------------------------------------------------------------------------- + 15 5 "a1.a2" -> "a1.b" + 21 7 "X.a1.a2" -> "a1.b" + 29 9 "r.X.a1.a2" -> "a1.b" + 46 2 "a2" -> "b" + 54 2 "a2" -> "b" + ''' + } + + @Test + def void testRenameFqn1ValueConversion() { + val fs = new InMemoryURIHandler() + fs += "inmemory:/file1.pstl" -> ''' + #1 r { + X refs ^a1.^a2 ^X.^a1.^a2 ^r.^X.^a1.^a2 { a1 { a2 refs ^a2 { a3 { ref ^a3 } } } } + Y refs ^b1.^b2 ^Y.^b1.^b2 ^r.^Y.^b1.^b2 { b1 { b2 { ref b2 } } } + } + ''' + + val rs = fs.createResourceSet + val model = rs.contents("inmemory:/file1.pstl", Node) + + val serializer = newChangeSerializer() + serializer.addModification(model.eResource) [ + model.children.head.children.head.children.head.name = "b" + ] + Assert.assertEquals(1, model.eResource.resourceSet.resources.size) + serializer.endRecordChangesToTextDocuments === ''' + ----------------- inmemory:/file1.pstl (syntax: ) ----------------- + #1 r { + X refs <15:7|a1.b> <23:10|a1.b> <34:13|a1.b> { a1 { <55:2|b> refs <63:3|b> { a3 { ref ^a3 } } } } + Y refs ^b1.^b2 ^Y.^b1.^b2 ^r.^Y.^b1.^b2 { b1 { b2 { ref b2 } } } + } + -------------------------------------------------------------------------------- + 15 7 "^a1.^a2" -> "a1.b" + 23 10 "^X.^a1.^a2" -> "a1.b" + 34 13 "^r.^X.^a1.^a2" -> "a1.b" + 55 2 "a2" -> "b" + 63 3 "^a2" -> "b" + ''' + } + @Test def void testResourceURIChange() { val fs = new InMemoryURIHandler() diff --git a/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/RenameTest2.xtend b/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/RenameTest2.xtend index 1a5ca58ef..131bf34a8 100644 --- a/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/RenameTest2.xtend +++ b/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/RenameTest2.xtend @@ -12,7 +12,6 @@ import org.eclipse.lsp4j.RenameParams import org.eclipse.lsp4j.TextDocumentIdentifier import org.eclipse.xtext.testing.AbstractLanguageServerTest import org.junit.Test -import org.junit.Ignore /** * @author koehnlein - Initial contribution and API @@ -45,7 +44,7 @@ class RenameTest2 extends AbstractLanguageServerTest { '''.toString, toExpectation(workspaceEdit)) } - @Test@Ignore + @Test def void testRenameContainer() { val model = ''' package foo @@ -66,8 +65,8 @@ class RenameTest2 extends AbstractLanguageServerTest { assertEquals(''' changes : Foo.fileawaretestlanguage : Baz [[2, 8] .. [2, 11]] - Baz [[3, 9] .. [3, 12]] - Baz [[3, 6] .. [3, 9]] + Bar [[5, 5] .. [5, 16]] + Bar [[6, 5] .. [6, 12]] documentChanges : '''.toString, toExpectation(workspaceEdit)) } diff --git a/org.eclipse.xtext.ide.tests/testlang-src/org/eclipse/xtext/ide/tests/testlanguage/PartialSerializationTestLanguageRuntimeModule.xtend b/org.eclipse.xtext.ide.tests/testlang-src/org/eclipse/xtext/ide/tests/testlanguage/PartialSerializationTestLanguageRuntimeModule.xtend index 25971d17d..90ab7e165 100644 --- a/org.eclipse.xtext.ide.tests/testlang-src/org/eclipse/xtext/ide/tests/testlanguage/PartialSerializationTestLanguageRuntimeModule.xtend +++ b/org.eclipse.xtext.ide.tests/testlang-src/org/eclipse/xtext/ide/tests/testlanguage/PartialSerializationTestLanguageRuntimeModule.xtend @@ -9,11 +9,12 @@ package org.eclipse.xtext.ide.tests.testlanguage import com.google.inject.Binder import com.google.inject.name.Names +import org.eclipse.xtext.ide.serializer.hooks.IReferenceUpdater +import org.eclipse.xtext.ide.tests.testlanguage.ide.serializer.PartialSerializationTestLanguageReferenceUpdater import org.eclipse.xtext.resource.IResourceDescriptions import org.eclipse.xtext.resource.impl.LiveShadowedResourceDescriptions import org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider -import org.eclipse.xtext.ide.serializer.hooks.IReferenceUpdater -import org.eclipse.xtext.ide.tests.testlanguage.ide.serializer.PartialSerializationTestLanguageReferenceUpdater +import org.eclipse.xtext.ide.tests.testlanguage.scoping.PartialSerializationTestLanguageValueConverter /** * Use this class to register components to be used at runtime / without the Equinox extension registry. @@ -28,4 +29,9 @@ class PartialSerializationTestLanguageRuntimeModule extends AbstractPartialSeria def Class bindCleanupStrategy() { return PartialSerializationTestLanguageReferenceUpdater } + + override bindIValueConverterService() { + PartialSerializationTestLanguageValueConverter + } + } diff --git a/org.eclipse.xtext.ide.tests/testlang-src/org/eclipse/xtext/ide/tests/testlanguage/scoping/PartialSerializationTestLanguageValueConverter.xtend b/org.eclipse.xtext.ide.tests/testlang-src/org/eclipse/xtext/ide/tests/testlanguage/scoping/PartialSerializationTestLanguageValueConverter.xtend new file mode 100644 index 000000000..51a12a7a3 --- /dev/null +++ b/org.eclipse.xtext.ide.tests/testlang-src/org/eclipse/xtext/ide/tests/testlanguage/scoping/PartialSerializationTestLanguageValueConverter.xtend @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * 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 + *******************************************************************************/ +package org.eclipse.xtext.ide.tests.testlanguage.scoping + +import com.google.inject.Inject +import org.eclipse.xtext.common.services.DefaultTerminalConverters +import org.eclipse.xtext.conversion.IValueConverter +import org.eclipse.xtext.conversion.ValueConverter +import org.eclipse.xtext.conversion.impl.QualifiedNameValueConverter + +/** + * @author Moritz Eysholdt - Initial contribution and API + */ +class PartialSerializationTestLanguageValueConverter extends DefaultTerminalConverters { + + @Inject QualifiedNameValueConverter fqnc + + @ValueConverter(rule="QualifiedName") + def IValueConverter QualifiedName() { + return fqnc + } + +} diff --git a/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/serializer/ChangeSerializerTest.java b/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/serializer/ChangeSerializerTest.java index fc6768cda..320e3a83c 100644 --- a/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/serializer/ChangeSerializerTest.java +++ b/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/serializer/ChangeSerializerTest.java @@ -26,6 +26,7 @@ import org.eclipse.xtext.testing.InjectWith; import org.eclipse.xtext.testing.XtextRunner; import org.eclipse.xtext.testing.util.InMemoryURIHandler; import org.eclipse.xtext.xbase.lib.Extension; +import org.eclipse.xtext.xbase.lib.IterableExtensions; import org.eclipse.xtext.xbase.lib.ObjectExtensions; import org.eclipse.xtext.xbase.lib.Pair; import org.eclipse.xtext.xbase.lib.Procedures.Procedure1; @@ -355,6 +356,114 @@ public class ChangeSerializerTest { this._changeSerializerTestHelper.operator_tripleEquals(_endRecordChangesToTextDocuments, _builder_2); } + @Test + public void testRenameFqn1() { + final InMemoryURIHandler fs = new InMemoryURIHandler(); + StringConcatenation _builder = new StringConcatenation(); + _builder.append("#1 r {"); + _builder.newLine(); + _builder.append("\t"); + _builder.append("X refs a1.a2 X.a1.a2 r.X.a1.a2 { a1 { a2 refs a2 { a3 { ref a3 } } } }"); + _builder.newLine(); + _builder.append("\t"); + _builder.append("Y refs b1.b2 Y.b1.b2 r.Y.b1.b2 { b1 { b2 { ref b2 } } }"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + Pair _mappedTo = Pair.of("inmemory:/file1.pstl", _builder.toString()); + this._changeSerializerTestHelper.operator_add(fs, _mappedTo); + final ResourceSet rs = this._changeSerializerTestHelper.createResourceSet(fs); + final Node model = this._changeSerializerTestHelper.contents(rs, "inmemory:/file1.pstl", Node.class); + final IChangeSerializer serializer = this._changeSerializerTestHelper.newChangeSerializer(); + final IChangeSerializer.IModification _function = (Resource it) -> { + Node _head = IterableExtensions.head(IterableExtensions.head(IterableExtensions.head(model.getChildren()).getChildren()).getChildren()); + _head.setName("b"); + }; + serializer.addModification(model.eResource(), _function); + Assert.assertEquals(1, model.eResource().getResourceSet().getResources().size()); + Collection _endRecordChangesToTextDocuments = this._changeSerializerTestHelper.endRecordChangesToTextDocuments(serializer); + StringConcatenation _builder_1 = new StringConcatenation(); + _builder_1.append("----------------- inmemory:/file1.pstl (syntax: ) -----------------"); + _builder_1.newLine(); + _builder_1.append("#1 r {"); + _builder_1.newLine(); + _builder_1.append("\t"); + _builder_1.append("X refs <15:5|a1.b> <21:7|a1.b> <29:9|a1.b> { a1 { <46:2|b> refs <54:2|b> { a3 { ref a3 } } } }"); + _builder_1.newLine(); + _builder_1.append("\t"); + _builder_1.append("Y refs b1.b2 Y.b1.b2 r.Y.b1.b2 { b1 { b2 { ref b2 } } }"); + _builder_1.newLine(); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append("--------------------------------------------------------------------------------"); + _builder_1.newLine(); + _builder_1.append("15 5 \"a1.a2\" -> \"a1.b\""); + _builder_1.newLine(); + _builder_1.append("21 7 \"X.a1.a2\" -> \"a1.b\""); + _builder_1.newLine(); + _builder_1.append("29 9 \"r.X.a1.a2\" -> \"a1.b\""); + _builder_1.newLine(); + _builder_1.append("46 2 \"a2\" -> \"b\""); + _builder_1.newLine(); + _builder_1.append("54 2 \"a2\" -> \"b\""); + _builder_1.newLine(); + this._changeSerializerTestHelper.operator_tripleEquals(_endRecordChangesToTextDocuments, _builder_1); + } + + @Test + public void testRenameFqn1ValueConversion() { + final InMemoryURIHandler fs = new InMemoryURIHandler(); + StringConcatenation _builder = new StringConcatenation(); + _builder.append("#1 r {"); + _builder.newLine(); + _builder.append("\t"); + _builder.append("X refs ^a1.^a2 ^X.^a1.^a2 ^r.^X.^a1.^a2 { a1 { a2 refs ^a2 { a3 { ref ^a3 } } } }"); + _builder.newLine(); + _builder.append("\t"); + _builder.append("Y refs ^b1.^b2 ^Y.^b1.^b2 ^r.^Y.^b1.^b2 { b1 { b2 { ref b2 } } }"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + Pair _mappedTo = Pair.of("inmemory:/file1.pstl", _builder.toString()); + this._changeSerializerTestHelper.operator_add(fs, _mappedTo); + final ResourceSet rs = this._changeSerializerTestHelper.createResourceSet(fs); + final Node model = this._changeSerializerTestHelper.contents(rs, "inmemory:/file1.pstl", Node.class); + final IChangeSerializer serializer = this._changeSerializerTestHelper.newChangeSerializer(); + final IChangeSerializer.IModification _function = (Resource it) -> { + Node _head = IterableExtensions.head(IterableExtensions.head(IterableExtensions.head(model.getChildren()).getChildren()).getChildren()); + _head.setName("b"); + }; + serializer.addModification(model.eResource(), _function); + Assert.assertEquals(1, model.eResource().getResourceSet().getResources().size()); + Collection _endRecordChangesToTextDocuments = this._changeSerializerTestHelper.endRecordChangesToTextDocuments(serializer); + StringConcatenation _builder_1 = new StringConcatenation(); + _builder_1.append("----------------- inmemory:/file1.pstl (syntax: ) -----------------"); + _builder_1.newLine(); + _builder_1.append("#1 r {"); + _builder_1.newLine(); + _builder_1.append("\t"); + _builder_1.append("X refs <15:7|a1.b> <23:10|a1.b> <34:13|a1.b> { a1 { <55:2|b> refs <63:3|b> { a3 { ref ^a3 } } } }"); + _builder_1.newLine(); + _builder_1.append("\t"); + _builder_1.append("Y refs ^b1.^b2 ^Y.^b1.^b2 ^r.^Y.^b1.^b2 { b1 { b2 { ref b2 } } }"); + _builder_1.newLine(); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append("--------------------------------------------------------------------------------"); + _builder_1.newLine(); + _builder_1.append("15 7 \"^a1.^a2\" -> \"a1.b\""); + _builder_1.newLine(); + _builder_1.append("23 10 \"^X.^a1.^a2\" -> \"a1.b\""); + _builder_1.newLine(); + _builder_1.append("34 13 \"^r.^X.^a1.^a2\" -> \"a1.b\""); + _builder_1.newLine(); + _builder_1.append("55 2 \"a2\" -> \"b\""); + _builder_1.newLine(); + _builder_1.append("63 3 \"^a2\" -> \"b\""); + _builder_1.newLine(); + this._changeSerializerTestHelper.operator_tripleEquals(_endRecordChangesToTextDocuments, _builder_1); + } + @Test public void testResourceURIChange() { final InMemoryURIHandler fs = new InMemoryURIHandler(); diff --git a/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/RenameTest2.java b/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/RenameTest2.java index 8c6865daa..d2906a260 100644 --- a/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/RenameTest2.java +++ b/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/RenameTest2.java @@ -14,7 +14,6 @@ import org.eclipse.lsp4j.WorkspaceEdit; import org.eclipse.xtend2.lib.StringConcatenation; import org.eclipse.xtext.testing.AbstractLanguageServerTest; import org.eclipse.xtext.xbase.lib.Exceptions; -import org.junit.Ignore; import org.junit.Test; /** @@ -65,7 +64,6 @@ public class RenameTest2 extends AbstractLanguageServerTest { } @Test - @Ignore public void testRenameContainer() { try { StringConcatenation _builder = new StringConcatenation(); @@ -105,10 +103,10 @@ public class RenameTest2 extends AbstractLanguageServerTest { _builder_1.append("Foo.fileawaretestlanguage : Baz [[2, 8] .. [2, 11]]"); _builder_1.newLine(); _builder_1.append(" "); - _builder_1.append("Baz [[3, 9] .. [3, 12]]"); + _builder_1.append("Bar [[5, 5] .. [5, 16]]"); _builder_1.newLine(); _builder_1.append(" "); - _builder_1.append("Baz [[3, 6] .. [3, 9]]"); + _builder_1.append("Bar [[6, 5] .. [6, 12]]"); _builder_1.newLine(); _builder_1.append("documentChanges : "); _builder_1.newLine(); diff --git a/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/testlanguage/PartialSerializationTestLanguageRuntimeModule.java b/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/testlanguage/PartialSerializationTestLanguageRuntimeModule.java index 8cdc784cc..a5a08c71d 100644 --- a/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/testlanguage/PartialSerializationTestLanguageRuntimeModule.java +++ b/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/testlanguage/PartialSerializationTestLanguageRuntimeModule.java @@ -9,9 +9,11 @@ package org.eclipse.xtext.ide.tests.testlanguage; import com.google.inject.Binder; import com.google.inject.name.Names; +import org.eclipse.xtext.conversion.IValueConverterService; import org.eclipse.xtext.ide.serializer.hooks.IReferenceUpdater; import org.eclipse.xtext.ide.tests.testlanguage.AbstractPartialSerializationTestLanguageRuntimeModule; import org.eclipse.xtext.ide.tests.testlanguage.ide.serializer.PartialSerializationTestLanguageReferenceUpdater; +import org.eclipse.xtext.ide.tests.testlanguage.scoping.PartialSerializationTestLanguageValueConverter; import org.eclipse.xtext.resource.IResourceDescriptions; import org.eclipse.xtext.resource.impl.LiveShadowedResourceDescriptions; import org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider; @@ -30,4 +32,9 @@ public class PartialSerializationTestLanguageRuntimeModule extends AbstractParti public Class bindCleanupStrategy() { return PartialSerializationTestLanguageReferenceUpdater.class; } + + @Override + public Class bindIValueConverterService() { + return PartialSerializationTestLanguageValueConverter.class; + } } diff --git a/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/serializer/PartialSerializationTestLanguageReferenceUpdater.java b/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/serializer/PartialSerializationTestLanguageReferenceUpdater.java index 2a24ea205..159537638 100644 --- a/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/serializer/PartialSerializationTestLanguageReferenceUpdater.java +++ b/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/serializer/PartialSerializationTestLanguageReferenceUpdater.java @@ -58,7 +58,7 @@ public class PartialSerializationTestLanguageReferenceUpdater extends ReferenceU List _updatableReferences = context.getUpdatableReferences(); for (final IUpdatableReference target : _updatableReferences) { { - final EObjectDescriptionDeltaProvider.Delta delta = context.getEObjectDescriptionDeltas().findContainingDelta(target.getTargetEObject()); + final EObjectDescriptionDeltaProvider.Delta delta = this.findContainingDelta(context.getEObjectDescriptionDeltas(), target.getTargetEObject()); if ((delta != null)) { final QualifiedName original = IterableExtensions.head(delta.getSnapshot().getDescriptions()).getQualifiedName(); final QualifiedName modified = IterableExtensions.head(delta.getDescriptions()).getQualifiedName(); diff --git a/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/testlanguage/scoping/PartialSerializationTestLanguageValueConverter.java b/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/testlanguage/scoping/PartialSerializationTestLanguageValueConverter.java new file mode 100644 index 000000000..03444e330 --- /dev/null +++ b/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/testlanguage/scoping/PartialSerializationTestLanguageValueConverter.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * 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 + */ +package org.eclipse.xtext.ide.tests.testlanguage.scoping; + +import com.google.inject.Inject; +import org.eclipse.xtext.common.services.DefaultTerminalConverters; +import org.eclipse.xtext.conversion.IValueConverter; +import org.eclipse.xtext.conversion.ValueConverter; +import org.eclipse.xtext.conversion.impl.QualifiedNameValueConverter; + +/** + * @author Moritz Eysholdt - Initial contribution and API + */ +@SuppressWarnings("all") +public class PartialSerializationTestLanguageValueConverter extends DefaultTerminalConverters { + @Inject + private QualifiedNameValueConverter fqnc; + + @ValueConverter(rule = "QualifiedName") + public IValueConverter QualifiedName() { + return this.fqnc; + } +} diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/hooks/IReferenceUpdaterContext.java b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/hooks/IReferenceUpdaterContext.java index 4ddbcc726..568ca871d 100644 --- a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/hooks/IReferenceUpdaterContext.java +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/hooks/IReferenceUpdaterContext.java @@ -9,8 +9,6 @@ package org.eclipse.xtext.ide.serializer.hooks; import java.util.List; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EReference; import org.eclipse.xtext.formatting2.regionaccess.ITextRegionDiffBuilder; import org.eclipse.xtext.ide.serializer.impl.EObjectDescriptionDeltaProvider.Deltas; import org.eclipse.xtext.resource.XtextResource; @@ -33,7 +31,5 @@ public interface IReferenceUpdaterContext { void modifyModel(Runnable runnable); - void updateReference(EObject owner, EReference reference); - - void updateReference(EObject owner, EReference reference, int index); + void updateReference(IUpdatableReference updatableReference); } \ No newline at end of file diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/impl/EObjectDescriptionDeltaProvider.java b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/impl/EObjectDescriptionDeltaProvider.java index 6e0ac5388..7294daa4f 100644 --- a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/impl/EObjectDescriptionDeltaProvider.java +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/impl/EObjectDescriptionDeltaProvider.java @@ -12,6 +12,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.BiFunction; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.util.EcoreUtil; @@ -34,45 +35,118 @@ public class EObjectDescriptionDeltaProvider { public static class Delta { private List descriptions = Lists.newArrayList(); private final EObject object; + private boolean qualifiedNameChanged; + private boolean simpleNameAndUserDataChanged; private IEObjectSnapshot snapshot; - public Delta(EObject object) { + public Delta(EObject object, IEObjectSnapshot snapshot, List descriptions) { super(); this.object = object; + this.snapshot = snapshot; + this.descriptions = descriptions; + this.simpleNameAndUserDataChanged = !forAll(this::isSimpleNameAndUserdataEqual); + this.qualifiedNameChanged = !forAll(this::isQualifiedNameEqual); + } + + protected boolean forAll(BiFunction comparator) { + if (snapshot == null) { + return false; + } + List snap = snapshot.getDescriptions(); + if (snap == null && descriptions == null) { + return true; + } + if (snap == null || descriptions == null) { + return false; + } + int size = descriptions.size(); + if (size == 0 && snap.isEmpty()) { + return true; + } + if (size != snap.size()) { + return false; + } + if (size == 1) { + return comparator.apply(snap.get(0), descriptions.get(0)); + } + Set candidates = Sets.newHashSet(snap); + FOR: for (IEObjectDescription d : descriptions) { + Iterator it = candidates.iterator(); + while (it.hasNext()) { + IEObjectDescription s = it.next(); + if (comparator.apply(d, s)) { + it.remove(); + continue FOR; + } + } + return false; + } + return true; } public List getDescriptions() { return descriptions; } + public EObject getObject() { + return object; + } + public IEObjectSnapshot getSnapshot() { return snapshot; } - public EObject getObject() { - return object; + public boolean hasQualifiedNameChanged() { + return qualifiedNameChanged; + } + + public boolean hasSimpleNameOrUserdataChanged() { + return simpleNameAndUserDataChanged; + } + + protected boolean isQualifiedNameEqual(IEObjectDescription desc1, IEObjectDescription desc2) { + return desc1.getQualifiedName().equals(desc2.getQualifiedName()); + } + + protected boolean isSimpleNameAndUserdataEqual(IEObjectDescription oldDesc, IEObjectDescription newDesc) { + if (!oldDesc.getName().equals(newDesc.getName())) { + return false; + } + if (!isUserDataEqual(oldDesc, newDesc)) { + return false; + } + return true; + } + + protected boolean isUserDataEqual(IEObjectDescription oldObj, IEObjectDescription newObj) { + String[] oldKeys = oldObj.getUserDataKeys(); + String[] newKeys = newObj.getUserDataKeys(); + if (oldKeys.length != newKeys.length) + return false; + for (String key : oldKeys) { + if (!Arrays.contains(newKeys, key)) + return false; + String oldValue = oldObj.getUserData(key); + String newValue = newObj.getUserData(key); + if (!Objects.equal(oldValue, newValue)) + return false; + } + return true; } } public static class Deltas { - private Collection snapshots; private final Map deltas = Maps.newLinkedHashMap(); + private Collection snapshots; + + public Delta getDelta(EObject obj) { + return deltas.get(obj); + } public Collection getSnapshots() { return snapshots; } - public Delta findContainingDelta(EObject obj) { - EObject current = obj; - while (current != null) { - Delta delta = deltas.get(current); - if (delta != null) { - return delta; - } - current = current.eContainer(); - } - return null; - } } public static class Group { @@ -87,37 +161,7 @@ public class EObjectDescriptionDeltaProvider { } protected Delta createDelta(EObject object, IEObjectSnapshot snapshot, List descriptions) { - Delta delta = new Delta(object); - delta.descriptions = descriptions; - delta.snapshot = snapshot; - if (snapshot == null || snapshot.getDescriptions() == null || delta.descriptions == null) { - return delta; - } - if (delta.descriptions.size() != snapshot.getDescriptions().size()) { - return delta; - } - if (delta.snapshot.getDescriptions().size() == 1 && delta.descriptions.size() == 1) { - if (!simpleNameAndUserDataEquals(delta.snapshot.getDescriptions().get(0), delta.descriptions.get(0))) { - return delta; - } - return null; - } - Set remaining = Sets.newHashSet(snapshot.getDescriptions()); - FOR: for (IEObjectDescription desc : descriptions) { - Iterator it = remaining.iterator(); - while (it.hasNext()) { - IEObjectDescription next = it.next(); - if (simpleNameAndUserDataEquals(desc, next)) { - it.remove(); - continue FOR; - } - } - return null; - } - if (remaining.isEmpty()) { - return delta; - } - return null; + return new Delta(object, snapshot, descriptions); } public Deltas getDelta(ChangeSerializer serializer, Collection snapshots) { @@ -144,37 +188,11 @@ public class EObjectDescriptionDeltaProvider { result.snapshots = snapshots; for (Group g : groups.values()) { Delta delta = createDelta(g.object, g.snapshot, g.descriptions); - if (delta != null) { + if (delta.hasQualifiedNameChanged() || delta.hasSimpleNameOrUserdataChanged()) { result.deltas.put(delta.object, delta); } } return result; } - protected boolean simpleNameAndUserDataEquals(IEObjectDescription oldDesc, IEObjectDescription newDesc) { - if (!oldDesc.getName().equals(newDesc.getName())) { - return false; - } - if (!userDataEuqals(oldDesc, newDesc)) { - return false; - } - return true; - } - - protected boolean userDataEuqals(IEObjectDescription oldObj, IEObjectDescription newObj) { - String[] oldKeys = oldObj.getUserDataKeys(); - String[] newKeys = newObj.getUserDataKeys(); - if (oldKeys.length != newKeys.length) - return false; - for (String key : oldKeys) { - if (!Arrays.contains(newKeys, key)) - return false; - String oldValue = oldObj.getUserData(key); - String newValue = newObj.getUserData(key); - if (!Objects.equal(oldValue, newValue)) - return false; - } - return true; - } - } diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/impl/ReferenceUpdater.java b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/impl/ReferenceUpdater.java index 80633942e..98641a90d 100644 --- a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/impl/ReferenceUpdater.java +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/impl/ReferenceUpdater.java @@ -9,12 +9,14 @@ package org.eclipse.xtext.ide.serializer.impl; import java.util.List; -import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; -import org.eclipse.xtext.EcoreUtil2; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.xtext.CrossReference; +import org.eclipse.xtext.GrammarUtil; import org.eclipse.xtext.conversion.IValueConverterService; import org.eclipse.xtext.conversion.ValueConverterException; +import org.eclipse.xtext.formatting2.regionaccess.IEObjectRegion; import org.eclipse.xtext.formatting2.regionaccess.ISemanticRegion; import org.eclipse.xtext.formatting2.regionaccess.ITextRegionDiffBuilder; import org.eclipse.xtext.ide.serializer.hooks.IReferenceSnapshot; @@ -39,6 +41,9 @@ import com.google.inject.Inject; */ public class ReferenceUpdater implements IReferenceUpdater { + @Inject + private IQualifiedNameConverter converter; + @Inject private LinkingHelper linkingHelper; @@ -51,6 +56,52 @@ public class ReferenceUpdater implements IReferenceUpdater { @Inject private IValueConverterService valueConverter; + protected boolean containsReferenceText(Delta delta, QualifiedName exp) { + DESC: for (IEObjectDescription desc : delta.getDescriptions()) { + QualifiedName cand = desc.getQualifiedName(); + if (cand.getSegmentCount() >= exp.getSegmentCount()) { + for (int i = 1; i <= exp.getSegmentCount(); i++) { + String expSeg = exp.getSegment(exp.getSegmentCount() - i); + String candSeg = cand.getSegment(cand.getSegmentCount() - i); + if (!expSeg.equals(candSeg)) { + continue DESC; + } + } + } + return true; + } + return false; + } + + protected IUpdatableReference createUpdatableReference(ISemanticRegion current) { + EReference ref = (EReference) current.getContainingFeature(); + CrossReference crossRef = GrammarUtil.containingCrossReference(current.getGrammarElement()); + EObject owner = current.getContainingRegion().getSemanticElement(); + Object value = owner.eGet(ref); + if (value instanceof List) { + List targets = (List) value; + int i = current.getIndexInContainingFeature(); + EObject t = (EObject) targets.get(i); + return new UpdatableReference(owner, ref, i, t, crossRef, current); + } else if (value instanceof EObject) { + return new UpdatableReference(owner, ref, -1, (EObject) value, crossRef, current); + } else { + throw new IllegalStateException(); + } + } + + public Delta findContainingDelta(Deltas deltas, EObject obj) { + EObject current = obj; + while (current != null) { + Delta delta = deltas.getDelta(current); + if (delta != null && delta.hasSimpleNameOrUserdataChanged()) { + return delta; + } + current = current.eContainer(); + } + return null; + } + protected String findValidName(IUpdatableReference updatable, IScope scope) { Iterable elements = scope.getElements(updatable.getTargetEObject()); String ruleName = linkingHelper.getRuleNameFrom(updatable.getCrossReference()); @@ -66,10 +117,24 @@ public class ReferenceUpdater implements IReferenceUpdater { return null; } + protected QualifiedName getQualifiedName(IUpdatableReference updatable) { + String text = updatable.getReferenceRegion().getText(); + String ruleName = linkingHelper.getRuleNameFrom(updatable.getCrossReference()); + try { + Object converted = valueConverter.toValue(text, ruleName, null); + if (converted != null) { + return converter.toQualifiedName(converted.toString()); + } + } catch (ValueConverterException e) { + // do nothing + } + return null; + } + @Override public boolean isAffected(Deltas deltas, RelatedResource resource) { for (IReferenceSnapshot ref : resource.outgoingReferences) { - Delta delta = deltas.findContainingDelta(ref.getTarget().getObject()); + Delta delta = deltas.getDelta(ref.getTarget().getObject()); if (delta != null) { return true; } @@ -77,41 +142,38 @@ public class ReferenceUpdater implements IReferenceUpdater { return false; } - protected boolean needsUpdating(Deltas deltas, EObject source, EObject target) { - Delta targetDelta = deltas.findContainingDelta(target); - if (targetDelta != null && targetDelta.getObject() == target) + protected boolean needsUpdating(IReferenceUpdaterContext context, IUpdatableReference ref) { + QualifiedName fqn = getQualifiedName(ref); + if (fqn == null) { + return false; + } + EObject target = ref.getTargetEObject(); + Deltas deltas = context.getEObjectDescriptionDeltas(); + Delta delta = deltas.getDelta(target); + if (delta != null && !containsReferenceText(delta, fqn)) { return true; - Delta sourceDelta = deltas.findContainingDelta(source); + } + Delta targetDelta = findContainingDelta(deltas, target); + if (targetDelta != null && targetDelta.getObject() == target) { + return true; + } + Delta sourceDelta = findContainingDelta(deltas, ref.getSourceEObject()); return !Objects.equal(sourceDelta, targetDelta); } @Override public void update(IReferenceUpdaterContext context) { - EObject root = context.getResource().getContents().get(0); - Deltas deltas = context.getEObjectDescriptionDeltas(); - - TreeIterator iterator = EcoreUtil2.eAll(root); - while (iterator.hasNext()) { - EObject next = iterator.next(); - for (EReference ref : next.eClass().getEAllReferences()) { - if (ref.isContainment()) { - continue; - } - Object value = next.eGet(ref); - if (value instanceof List) { - List targets = (List) value; - for (int i = 0; i < targets.size(); i++) { - EObject t = (EObject) targets.get(i); - if (needsUpdating(deltas, next, t)) { - context.updateReference(next, ref, i); - } - } - } else if (value instanceof EObject) { - if (needsUpdating(deltas, next, (EObject) value)) { - context.updateReference(next, ref); - } + IEObjectRegion root = context.getModifyableDocument().getOriginalTextRegionAccess().regionForRootEObject(); + ISemanticRegion current = root.getPreviousHiddenRegion().getNextSemanticRegion(); + while (current != null) { + EStructuralFeature feature = current.getContainingFeature(); + if (feature instanceof EReference && !((EReference) feature).isContainment()) { + IUpdatableReference updatable = createUpdatableReference(current); + if (needsUpdating(context, updatable)) { + context.updateReference(updatable); } } + current = current.getNextSemanticRegion(); } } diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/impl/ReferenceUpdaterContext.java b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/impl/ReferenceUpdaterContext.java index e46c80580..37e3d014d 100644 --- a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/impl/ReferenceUpdaterContext.java +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/impl/ReferenceUpdaterContext.java @@ -9,19 +9,12 @@ package org.eclipse.xtext.ide.serializer.impl; import java.util.List; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EReference; -import org.eclipse.xtext.CrossReference; -import org.eclipse.xtext.GrammarUtil; -import org.eclipse.xtext.formatting2.regionaccess.IEObjectRegion; -import org.eclipse.xtext.formatting2.regionaccess.ISemanticRegion; import org.eclipse.xtext.formatting2.regionaccess.ITextRegionDiffBuilder; import org.eclipse.xtext.ide.serializer.hooks.IReferenceUpdaterContext; import org.eclipse.xtext.ide.serializer.hooks.IUpdatableReference; import org.eclipse.xtext.ide.serializer.impl.EObjectDescriptionDeltaProvider.Deltas; import org.eclipse.xtext.resource.XtextResource; -import com.google.common.base.Preconditions; import com.google.common.collect.Lists; /** @@ -70,33 +63,8 @@ public class ReferenceUpdaterContext implements IReferenceUpdaterContext { } @Override - public void updateReference(EObject owner, EReference reference) { - IEObjectRegion objectRegion = diffBuilder.getOriginalTextRegionAccess().regionForEObject(owner); - ISemanticRegion region = objectRegion.getRegionFor().feature(reference); - EObject target = (EObject) owner.eGet(reference); - CrossReference crossref = GrammarUtil.containingCrossReference(region.getGrammarElement()); - updateReference(owner, reference, -1, region, target, crossref); - } - - @Override - public void updateReference(EObject owner, EReference reference, int index) { - IEObjectRegion objectRegion = diffBuilder.getOriginalTextRegionAccess().regionForEObject(owner); - List regions = objectRegion.getRegionFor().features(reference); - ISemanticRegion region = regions.get(index); - EObject target = (EObject) ((List) owner.eGet(reference)).get(index); - CrossReference crossref = GrammarUtil.containingCrossReference(region.getGrammarElement()); - updateReference(owner, reference, index, region, target, crossref); - } - - private void updateReference(EObject owner, EReference reference, int index, ISemanticRegion region, EObject target, - CrossReference crossref) { - Preconditions.checkNotNull(owner); - Preconditions.checkNotNull(reference); - Preconditions.checkArgument(!reference.isContainment()); - if (region == null || target == null || target.eIsProxy() || crossref == null) { - return; - } - references.add(new UpdatableReference(owner, reference, index, target, crossref, region)); + public void updateReference(IUpdatableReference updatableReference) { + references.add(updatableReference); } } diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/impl/UpdatableReference.java b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/impl/UpdatableReference.java index 88b7113d2..89bb99838 100644 --- a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/impl/UpdatableReference.java +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/serializer/impl/UpdatableReference.java @@ -13,6 +13,8 @@ import org.eclipse.xtext.CrossReference; import org.eclipse.xtext.formatting2.regionaccess.ISemanticRegion; import org.eclipse.xtext.ide.serializer.hooks.IUpdatableReference; +import com.google.common.base.Preconditions; + /** * @author Moritz Eysholdt - Initial contribution and API */ @@ -27,6 +29,12 @@ public class UpdatableReference implements IUpdatableReference { public UpdatableReference(EObject owner, EReference reference, int index, EObject target, CrossReference crossref, ISemanticRegion region) { super(); + Preconditions.checkNotNull(owner); + Preconditions.checkNotNull(reference); + Preconditions.checkArgument(!reference.isContainment()); + Preconditions.checkNotNull(target); + Preconditions.checkNotNull(crossref); + Preconditions.checkNotNull(region); this.owner = owner; this.reference = reference; this.index = index; diff --git a/org.eclipse.xtext.testlanguages.ide/src/org/eclipse/xtext/testlanguages/fileAware/ide/refactoring/FileAwareTestLanguageReferenceUpdater.xtend b/org.eclipse.xtext.testlanguages.ide/src/org/eclipse/xtext/testlanguages/fileAware/ide/refactoring/FileAwareTestLanguageReferenceUpdater.xtend index 2b3289243..aec48e60c 100644 --- a/org.eclipse.xtext.testlanguages.ide/src/org/eclipse/xtext/testlanguages/fileAware/ide/refactoring/FileAwareTestLanguageReferenceUpdater.xtend +++ b/org.eclipse.xtext.testlanguages.ide/src/org/eclipse/xtext/testlanguages/fileAware/ide/refactoring/FileAwareTestLanguageReferenceUpdater.xtend @@ -20,7 +20,7 @@ class FileAwareTestLanguageReferenceUpdater extends ReferenceUpdater { val pkgName = names.getFullyQualifiedName(pkg) val actual = pkg.imports.toMap[element] val targets = context.updatableReferences.map[targetEObject].filter(Element) - val expected = targets.filter[names.getFullyQualifiedName(it).skipLast(1) != pkgName].toSet + val expected = targets.filter[!names.getFullyQualifiedName(it).startsWith(pkgName)].toSet val toAdd = expected.filter[!actual.containsKey(it)].toSet val toDelete = actual.filter[!expected.contains($0)] if (!toAdd.isEmpty || !toDelete.isEmpty) { diff --git a/org.eclipse.xtext.testlanguages.ide/xtend-gen/org/eclipse/xtext/testlanguages/fileAware/ide/refactoring/FileAwareTestLanguageReferenceUpdater.java b/org.eclipse.xtext.testlanguages.ide/xtend-gen/org/eclipse/xtext/testlanguages/fileAware/ide/refactoring/FileAwareTestLanguageReferenceUpdater.java index 497842d8a..769ccfa2c 100644 --- a/org.eclipse.xtext.testlanguages.ide/xtend-gen/org/eclipse/xtext/testlanguages/fileAware/ide/refactoring/FileAwareTestLanguageReferenceUpdater.java +++ b/org.eclipse.xtext.testlanguages.ide/xtend-gen/org/eclipse/xtext/testlanguages/fileAware/ide/refactoring/FileAwareTestLanguageReferenceUpdater.java @@ -1,6 +1,5 @@ package org.eclipse.xtext.testlanguages.fileAware.ide.refactoring; -import com.google.common.base.Objects; import com.google.common.collect.Iterables; import java.util.Map; import java.util.Set; @@ -50,8 +49,8 @@ public class FileAwareTestLanguageReferenceUpdater extends ReferenceUpdater { }; final Iterable targets = Iterables.filter(ListExtensions.map(context.getUpdatableReferences(), _function_1), Element.class); final Function1 _function_2 = (Element it) -> { - QualifiedName _skipLast = this.names.getFullyQualifiedName(it).skipLast(1); - return Boolean.valueOf((!Objects.equal(_skipLast, pkgName))); + boolean _startsWith = this.names.getFullyQualifiedName(it).startsWith(pkgName); + return Boolean.valueOf((!_startsWith)); }; final Set expected = IterableExtensions.toSet(IterableExtensions.filter(targets, _function_2)); final Function1 _function_3 = (Element it) -> {