From 8e0c98140a314ea8ca641fe63b5e7427067f6a35 Mon Sep 17 00:00:00 2001 From: Hannes Wellmann Date: Thu, 4 Apr 2024 19:08:48 +0200 Subject: [PATCH] Deprecate and replace Guava-using APIs in Scopes and QualifiedName Part of https://github.com/eclipse/xtext/issues/2975 --- .../xtext/naming/QualifiedNameTest.java | 12 +- .../eclipse/xtext/naming/QualifiedName.java | 29 ++-- .../src/org/eclipse/xtext/scoping/Scopes.java | 124 +++++++++++------- 3 files changed, 99 insertions(+), 66 deletions(-) diff --git a/org.eclipse.xtext.tests/src/org/eclipse/xtext/naming/QualifiedNameTest.java b/org.eclipse.xtext.tests/src/org/eclipse/xtext/naming/QualifiedNameTest.java index fea101bfea3..3259c0676bb 100644 --- a/org.eclipse.xtext.tests/src/org/eclipse/xtext/naming/QualifiedNameTest.java +++ b/org.eclipse.xtext.tests/src/org/eclipse/xtext/naming/QualifiedNameTest.java @@ -12,6 +12,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Collections; +import java.util.function.Function; import org.eclipse.emf.ecore.resource.impl.BinaryResourceImpl; import org.eclipse.emf.ecore.resource.impl.BinaryResourceImpl.EObjectInputStream; @@ -21,8 +22,6 @@ import org.junit.Assert; import org.junit.Test; -import com.google.common.base.Function; - /** * @author Jan Koehnlein - Initial contribution and API */ @@ -93,7 +92,7 @@ public void testAppendNull() { assertTrue(qn.startsWithIgnoreCase(qn2)); assertFalse(qn2.startsWithIgnoreCase(qn)); - assertThrows(IllegalArgumentException.class, ()->qn1.startsWith(null)); + assertThrows(NullPointerException.class, () -> qn1.startsWith(null)); } @Test public void testSkip() throws Exception { @@ -213,12 +212,7 @@ public void testAppendNull() { } @Test public void testWrapper() throws Exception { - Function identity = new Function() { - @Override - public String apply(String from) { - return from; - } - }; + Function identity = from -> from; Function wrapper = QualifiedName.wrapper(identity); assertEquals(QualifiedName.create(""), wrapper.apply("")); assertEquals(null, wrapper.apply(null)); diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/naming/QualifiedName.java b/org.eclipse.xtext/src/org/eclipse/xtext/naming/QualifiedName.java index de8ae22fd4e..356f70db1f2 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/naming/QualifiedName.java +++ b/org.eclipse.xtext/src/org/eclipse/xtext/naming/QualifiedName.java @@ -12,15 +12,14 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Objects; +import java.util.function.Function; import org.eclipse.emf.common.util.CommonUtil; import org.eclipse.emf.ecore.resource.impl.BinaryResourceImpl.EObjectInputStream; import org.eclipse.emf.ecore.resource.impl.BinaryResourceImpl.EObjectOutputStream; import org.eclipse.xtext.util.Strings; -import com.google.common.base.Function; -import com.google.common.base.Preconditions; - /** * A datatype for dealing with qualified names. * Instances are usually provided by a {@link IQualifiedNameProvider}. @@ -239,18 +238,26 @@ public static QualifiedName create(String singleSegment) { return new QualifiedName(intern(singleSegment)); } + /** + * Wraps a name function to return a qualified name. Returns null if the name function returns null. + * @deprecated Instead use {@link #wrapper(Function)} + */ + @Deprecated(since = "2.35.0", forRemoval = true) + public static com.google.common.base.Function wrapper( + com.google.common.base.Function nameFunction) { + return wrapper((Function) nameFunction)::apply; + } + /** * Wraps a name function to return a qualified name. Returns null if the name function returns null. */ public static Function wrapper(final Function nameFunction) { - return new Function() { - @Override - public QualifiedName apply(F from) { - String name = nameFunction.apply(from); - if (name == null) - return null; - return QualifiedName.create(name); + return from -> { + String name = nameFunction.apply(from); + if (name == null) { + return null; } + return QualifiedName.create(name); }; } @@ -486,7 +493,7 @@ public boolean startsWithIgnoreCase(QualifiedName prefix) { } protected boolean startsWith(QualifiedName prefix, boolean ignoreCase) { - Preconditions.checkArgument(prefix != null, "prefix must not be null"); + Objects.requireNonNull(prefix, "prefix must not be null"); if (prefix.getSegmentCount() > getSegmentCount()) { return false; diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/scoping/Scopes.java b/org.eclipse.xtext/src/org/eclipse/xtext/scoping/Scopes.java index 66a4d4864f6..40af36b88b0 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/scoping/Scopes.java +++ b/org.eclipse.xtext/src/org/eclipse/xtext/scoping/Scopes.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 itemis AG (http://www.itemis.eu) and others. + * Copyright (c) 2009, 2024 itemis AG (http://www.itemis.eu) and others. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at * http://www.eclipse.org/legal/epl-2.0. @@ -10,7 +10,13 @@ package org.eclipse.xtext.scoping; import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; @@ -22,30 +28,18 @@ import org.eclipse.xtext.scoping.impl.SimpleScope; import org.eclipse.xtext.util.SimpleAttributeResolver; -import com.google.common.base.Function; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; import com.google.common.collect.Iterables; -import com.google.common.collect.LinkedHashMultimap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; /** * This class contains static utility functions to create and work on {@link IScope} and {@link IEObjectDescription} - * + * * @author Sven Efftinge - Initial contribution and API * @author Jan Koehnlein - introduced QualifiedName */ public class Scopes { public static Iterable selectCompatible(Iterable exportedObjects, final EClass clazz) { - return Iterables.filter(exportedObjects, new Predicate() { - @Override - public boolean apply(IEObjectDescription input) { - return EcoreUtil2.isAssignableFrom(clazz,input.getEClass()); - } - }); + return Iterables.filter(exportedObjects, input -> EcoreUtil2.isAssignableFrom(clazz, input.getEClass())); } /** @@ -60,15 +54,25 @@ public static IScope scopeFor(Iterable elements) { * creates a scope using {@link SimpleAttributeResolver#NAME_RESOLVER} to compute the names */ public static IScope scopeFor(Iterable elements, IScope outer) { - return scopeFor(elements, QualifiedName.wrapper(SimpleAttributeResolver.NAME_RESOLVER), outer); + return scopeFor(elements, QualifiedName.wrapper((Function) SimpleAttributeResolver.NAME_RESOLVER), outer); + } + + /** + * creates a scope using the passed function to compute the names and sets the passed scope as the parent scope + * @deprecated Instead use {@link #scopeFor(Iterable, Function, IScope)} + */ + @Deprecated(since = "2.35.0", forRemoval = true) + public static IScope scopeFor(Iterable elements, + com.google.common.base.Function nameComputation, IScope outer) { + return scopeFor(elements, (java.util.function.Function) nameComputation, outer); } /** * creates a scope using the passed function to compute the names and sets the passed scope as the parent scope */ public static IScope scopeFor(Iterable elements, - final Function nameComputation, IScope outer) { - return new SimpleScope(outer,scopedElementsFor(elements, nameComputation)); + Function nameComputation, IScope outer) { + return new SimpleScope(outer, scopedElementsFor(elements, nameComputation)); } /** @@ -77,55 +81,83 @@ public static IScope scopeFor(Iterable elements * filtered out. */ public static Iterable scopedElementsFor(Iterable elements) { - return scopedElementsFor(elements, QualifiedName.wrapper(SimpleAttributeResolver.NAME_RESOLVER)); + return scopedElementsFor(elements, QualifiedName.wrapper((Function) SimpleAttributeResolver.NAME_RESOLVER)); } /** * transforms an {@link Iterable} of {@link EObject}s into an {@link Iterable} of {@link IEObjectDescription}s computing * the name of the elements using the passed {@link Function} If the passed function returns null the object is * filtered out. + * @deprecated Instead use {@link #scopedElementsFor(Iterable, Function)} */ + @Deprecated(since = "2.35.0", forRemoval = true) public static Iterable scopedElementsFor(Iterable elements, - final Function nameComputation) { - Iterable transformed = Iterables.transform(elements, - new Function() { - @Override - public IEObjectDescription apply(T from) { - final QualifiedName qualifiedName = nameComputation.apply(from); - if (qualifiedName != null) - return new EObjectDescription(qualifiedName, from, null); - return null; - } - }); - return Iterables.filter(transformed, Predicates.notNull()); + com.google.common.base.Function nameComputation) { + return scopedElementsFor(elements, (java.util.function.Function) nameComputation); } - + + /** + * transforms an {@link Iterable} of {@link EObject}s into an {@link Iterable} of {@link IEObjectDescription}s computing + * the name of the elements using the passed {@link Function} If the passed function returns null the object is + * filtered out. + */ + public static Iterable scopedElementsFor(Iterable elements, + Function nameComputation) { + Iterable transformed = Iterables.transform(elements, from -> { + final QualifiedName qualifiedName = nameComputation.apply(from); + if (qualifiedName != null) + return new EObjectDescription(qualifiedName, from, null); + return null; + }); + return Iterables.filter(transformed, Objects::nonNull); + } + + /** + * indexes the IEObject description using the given + * @deprecated Instead use {@link #index(Iterable, Function)} + */ + @Deprecated(since = "2.35.0", forRemoval = true) + public static com.google.common.collect.Multimap index( + Iterable descriptions, + com.google.common.base.Function indexer) { + Map> index = index(descriptions, (Function) indexer); + com.google.common.collect.Multimap multimap = com.google.common.collect.LinkedHashMultimap.create(); + index.forEach(multimap::putAll); + return multimap; + } + /** * indexes the IEObject description using the given */ - public static Multimap index(Iterable descriptions, Function indexer) { - ArrayList list = Lists.newArrayList(descriptions); - LinkedHashMultimap multimap = LinkedHashMultimap.create(list.size(),1); + public static Map> index(Iterable descriptions, + Function indexer) { + List list = new ArrayList<>(); + descriptions.forEach(list::add); + Map> multimap = new LinkedHashMap<>(list.size() * 4 / 3 + 1); for (IEObjectDescription desc : list) { - multimap.put(indexer.apply(desc), desc); + multimap.computeIfAbsent(indexer.apply(desc), n -> new LinkedHashSet<>(1)).add(desc); } return multimap; } - + /** * indexes the IEObject description using the given + * @deprecated Instead use {@link #indexByName(Iterable)} */ - public static Multimap index(Iterable descriptions) { - return index(descriptions, new Function() { - @Override - public QualifiedName apply(IEObjectDescription from) { - return from.getName().toLowerCase(); - } - }); + @Deprecated(since = "2.35.0", forRemoval = true) + public static com.google.common.collect.Multimap index(Iterable descriptions) { + return index(descriptions, from -> from.getName().toLowerCase()); + } + + /** + * indexes the IEObject description using the given + */ + public static Map> indexByName(Iterable descriptions) { + return index(descriptions, (Function) from -> from.getName().toLowerCase()); } public static Iterable filterDuplicates(Iterable filtered) { - Map result = Maps.newLinkedHashMap(); + Map result = new LinkedHashMap<>(); for (IEObjectDescription e : filtered) { QualifiedName qualifiedName = e.getName(); if (result.containsKey(qualifiedName)) { @@ -134,7 +166,7 @@ public static Iterable filterDuplicates(Iterable