Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate and replace Guava-using APIs in Scopes and QualifiedName #2978

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
*/
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -213,12 +212,7 @@ public void testAppendNull() {
}

@Test public void testWrapper() throws Exception {
Function<String, String> identity = new Function<String, String>() {
@Override
public String apply(String from) {
return from;
}
};
Function<String, String> identity = from -> from;
Function<String, QualifiedName> wrapper = QualifiedName.wrapper(identity);
assertEquals(QualifiedName.create(""), wrapper.apply(""));
assertEquals(null, wrapper.apply(null));
Expand Down
29 changes: 18 additions & 11 deletions org.eclipse.xtext/src/org/eclipse/xtext/naming/QualifiedName.java
Original file line number Diff line number Diff line change
Expand Up @@ -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}.
Expand Down Expand Up @@ -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 <F> com.google.common.base.Function<F, QualifiedName> wrapper(
com.google.common.base.Function<F, String> nameFunction) {
return wrapper((Function<F, String>) nameFunction)::apply;
}

/**
* Wraps a name function to return a qualified name. Returns null if the name function returns null.
*/
public static <F> Function<F, QualifiedName> wrapper(final Function<F, String> nameFunction) {
return new Function<F, QualifiedName>() {
@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);
};
}

Expand Down Expand Up @@ -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");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This now throws a NullPointerException instead of an IllegalArgumentException. I assume that's the reason for the test-failure.
Is that an acceptable change or should it continue to throw a IllegalArgumentException if the argument is null?


if (prefix.getSegmentCount() > getSegmentCount()) {
return false;
Expand Down
124 changes: 78 additions & 46 deletions org.eclipse.xtext/src/org/eclipse/xtext/scoping/Scopes.java
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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;
Expand All @@ -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<IEObjectDescription> selectCompatible(Iterable<IEObjectDescription> exportedObjects, final EClass clazz) {
return Iterables.filter(exportedObjects, new Predicate<IEObjectDescription>() {
@Override
public boolean apply(IEObjectDescription input) {
return EcoreUtil2.isAssignableFrom(clazz,input.getEClass());
}
});
return Iterables.filter(exportedObjects, input -> EcoreUtil2.isAssignableFrom(clazz, input.getEClass()));
}

/**
Expand All @@ -60,15 +54,25 @@ public static IScope scopeFor(Iterable<? extends EObject> elements) {
* creates a scope using {@link SimpleAttributeResolver#NAME_RESOLVER} to compute the names
*/
public static IScope scopeFor(Iterable<? extends EObject> elements, IScope outer) {
return scopeFor(elements, QualifiedName.wrapper(SimpleAttributeResolver.NAME_RESOLVER), outer);
return scopeFor(elements, QualifiedName.wrapper((Function<EObject, String>) 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 <T extends EObject> IScope scopeFor(Iterable<? extends T> elements,
com.google.common.base.Function<T, QualifiedName> nameComputation, IScope outer) {
return scopeFor(elements, (java.util.function.Function<T, QualifiedName>) nameComputation, outer);
}

/**
* creates a scope using the passed function to compute the names and sets the passed scope as the parent scope
*/
public static <T extends EObject> IScope scopeFor(Iterable<? extends T> elements,
final Function<T, QualifiedName> nameComputation, IScope outer) {
return new SimpleScope(outer,scopedElementsFor(elements, nameComputation));
Function<T, QualifiedName> nameComputation, IScope outer) {
return new SimpleScope(outer, scopedElementsFor(elements, nameComputation));
}

/**
Expand All @@ -77,55 +81,83 @@ public static <T extends EObject> IScope scopeFor(Iterable<? extends T> elements
* filtered out.
*/
public static Iterable<IEObjectDescription> scopedElementsFor(Iterable<? extends EObject> elements) {
return scopedElementsFor(elements, QualifiedName.wrapper(SimpleAttributeResolver.NAME_RESOLVER));
return scopedElementsFor(elements, QualifiedName.wrapper((Function<EObject, String>) 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 <T extends EObject> Iterable<IEObjectDescription> scopedElementsFor(Iterable<? extends T> elements,
final Function<T, QualifiedName> nameComputation) {
Iterable<IEObjectDescription> transformed = Iterables.transform(elements,
new Function<T, IEObjectDescription>() {
@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<T, QualifiedName> nameComputation) {
return scopedElementsFor(elements, (java.util.function.Function<T, QualifiedName>) 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 <T extends EObject> Iterable<IEObjectDescription> scopedElementsFor(Iterable<? extends T> elements,
Function<T, QualifiedName> nameComputation) {
Iterable<IEObjectDescription> 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 <T> com.google.common.collect.Multimap<T, IEObjectDescription> index(
Iterable<IEObjectDescription> descriptions,
com.google.common.base.Function<IEObjectDescription, T> indexer) {
Map<T, Set<IEObjectDescription>> index = index(descriptions, (Function<IEObjectDescription, T>) indexer);
com.google.common.collect.Multimap<T, IEObjectDescription> multimap = com.google.common.collect.LinkedHashMultimap.create();
index.forEach(multimap::putAll);
return multimap;
}

/**
* indexes the IEObject description using the given
*/
public static <T> Multimap<T,IEObjectDescription> index(Iterable<IEObjectDescription> descriptions, Function<IEObjectDescription,T> indexer) {
ArrayList<IEObjectDescription> list = Lists.newArrayList(descriptions);
LinkedHashMultimap<T, IEObjectDescription> multimap = LinkedHashMultimap.create(list.size(),1);
public static <T> Map<T, Set<IEObjectDescription>> index(Iterable<IEObjectDescription> descriptions,
Function<IEObjectDescription, T> indexer) {
List<IEObjectDescription> list = new ArrayList<>();
descriptions.forEach(list::add);
Map<T, Set<IEObjectDescription>> 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<QualifiedName,IEObjectDescription> index(Iterable<IEObjectDescription> descriptions) {
return index(descriptions, new Function<IEObjectDescription, QualifiedName>() {
@Override
public QualifiedName apply(IEObjectDescription from) {
return from.getName().toLowerCase();
}
});
@Deprecated(since = "2.35.0", forRemoval = true)
public static com.google.common.collect.Multimap<QualifiedName,IEObjectDescription> index(Iterable<IEObjectDescription> descriptions) {
return index(descriptions, from -> from.getName().toLowerCase());
}

/**
* indexes the IEObject description using the given
*/
public static Map<QualifiedName, Set<IEObjectDescription>> indexByName(Iterable<IEObjectDescription> descriptions) {
return index(descriptions, (Function<IEObjectDescription, QualifiedName>) from -> from.getName().toLowerCase());
}

public static Iterable<IEObjectDescription> filterDuplicates(Iterable<IEObjectDescription> filtered) {
Map<QualifiedName, IEObjectDescription> result = Maps.newLinkedHashMap();
Map<QualifiedName, IEObjectDescription> result = new LinkedHashMap<>();
for (IEObjectDescription e : filtered) {
QualifiedName qualifiedName = e.getName();
if (result.containsKey(qualifiedName)) {
Expand All @@ -134,7 +166,7 @@ public static Iterable<IEObjectDescription> filterDuplicates(Iterable<IEObjectDe
result.put(qualifiedName, e);
}
}
return Iterables.filter(result.values(), Predicates.notNull());
return Iterables.filter(result.values(), Objects::nonNull);
}

}
Loading