
org.jruby.anno.AnnotationHelper Maven / Gradle / Ivy
package org.jruby.anno;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
/**
* Utility methods for generating bindings at build time. Used by AnnotationBinder.
*
* NOTE: This class must ONLY reference classes in the org.jruby.anno package, to avoid forcing
* a transitive dependency on any runtime JRuby classes!
*
* @see org.jruby.anno.AnnotationBinder
*/
public class AnnotationHelper {
private AnnotationHelper() { /* no instances */ }
public static void addMethodNamesToMap(Map map, JRubyMethod jrubyMethod, String simpleName) {
addMethodNamesToMap(map, jrubyMethod, simpleName, jrubyMethod.name(), jrubyMethod.alias());
}
public static void addMethodNamesToMap(final Map map, JRubyMethod anno, final String simpleName,
final String[] names, final String[] aliases) {
if ( names.length == 0 ) map.put(simpleName, anno);
else {
for ( String name : names ) map.put(name, anno);
}
if ( aliases.length > 0 ) {
for ( String alias : aliases ) map.put(alias, anno);
}
}
public static int getArityValue(JRubyMethod anno, int actualRequired) {
if (anno.optional() > 0 || anno.rest()) {
return -(actualRequired + 1);
}
return actualRequired;
}
/**
* Produce a CallConfiguration name that represents what *caller* methods must prepare for
* the method with this annotation.
*
* @see org.jruby.internal.runtime.methods.CallConfiguration#getCallerCallConfigByAnno(JRubyMethod)
*/
public static String getCallerCallConfigNameByAnno(JRubyMethod jrubyMethod) {
boolean frame = false;
boolean scope = false;
for (FrameField field : jrubyMethod.reads()) {
frame |= field.needsFrame();
scope |= field.needsScope();
}
for (FrameField field : jrubyMethod.writes()) {
frame |= field.needsFrame();
scope |= field.needsScope();
}
return getCallConfigName(frame, scope);
}
/**
* Given a frame and scope requirement, return the name of the appropriate CallConfiguration.
*
* @see org.jruby.internal.runtime.methods.CallConfiguration#getCallConfig(boolean, boolean)
*/
public static String getCallConfigName(boolean frame, boolean scope) {
if (frame) {
return scope ? "FrameFullScopeFull" : "FrameFullScopeNone";
}
return scope ? "FrameNoneScopeFull" : "FrameNoneScopeNone";
}
public static void groupFrameFields(Map, List> readGroups, Map, List> writeGroups, JRubyMethod anno, String simpleName) {
if (anno.reads().length > 0) {
Set reads = new HashSet<>(Arrays.asList(anno.reads()));
List nameList = readGroups.get(reads);
if (nameList == null) readGroups.put(reads, nameList = new ArrayList<>());
if (anno.name().length == 0) {
nameList.add(simpleName);
} else {
nameList.addAll(Arrays.asList(anno.name()));
}
}
if (anno.writes().length > 0) {
Set writes = new HashSet<>(Arrays.asList(anno.writes()));
List nameList = writeGroups.get(writes);
if (nameList == null) writeGroups.put(writes, nameList = new ArrayList<>());
if (anno.name().length == 0) {
nameList.add(simpleName);
} else {
nameList.addAll(Arrays.asList(anno.name()));
}
}
}
public static void populateMethodIndex(Map, List> accessGroups, BiConsumer action) {
if (!accessGroups.isEmpty()) {
for (Map.Entry, List> accessEntry : accessGroups.entrySet()) {
Set reads = accessEntry.getKey();
List names = accessEntry.getValue();
int bits = FrameField.pack(reads.stream().toArray(n -> new FrameField[n]));
String namesJoined = names.stream().distinct().collect(Collectors.joining(";"));
action.accept(bits, namesJoined);
}
}
}
public static void addSubclassNames(List classAndSubs, JRubyClass classAnno) {
for (int i = 0; i < classAnno.overrides().length; i++) {
classAndSubs.add(classAnno.overrides()[i].getCanonicalName());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy