[
https://issues.apache.org/jira/browse/GROOVY-10123?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17357441#comment-17357441
]
Eric Milles edited comment on GROOVY-10123 at 6/4/21, 4:26 PM:
---------------------------------------------------------------
This came up while investigating GROOVY-8638. I was looking for a way to get
all methods for a type and then group by overrides. This is not easy to sort
out given the current APIs.
This is what I came up with to find the non-synthetic methods of a given type:
{code:java}
protected Collection<MethodNode> getAllMethods(ClassNode type,
Set<ClassNode> exclude) {
Map<String, MethodNode> methods = new HashMap<>();
BiConsumer<MethodNode, Map<String, ClassNode>> mapper = (mn, spec) -> {
StringBuilder sb = new StringBuilder(mn.getName());
sb.append('(');
for (org.codehaus.groovy.ast.Parameter p : mn.getParameters()) {
ClassNode pt = p.getOriginType();
if (!pt.isGenericsPlaceHolder()) {
sb.append(pt.getName());
} else {
sb.append(spec.getOrDefault(pt.getUnresolvedName(),
pt).getName());
}
sb.append(';');
}
methods.merge(sb.toString(), mn, (m1, m2) ->
// keep override method unless it's synthetic
!Flags.isSynthetic(m1.getModifiers()) ? m1 : m2);
};
// some special handling for traits ommitted, which is the reason for
mapper being separated out
Set<ClassNode> types = new LinkedHashSet<>();
VariableScope.createTypeHierarchy(type, types, true); // GRECLIPSE API;
you would need to use a GROOVY API here
for (ClassNode cn : types) {
if ((exclude != null && exclude.contains(cn)) ||
Flags.isSynthetic(cn.getModifiers())) continue;
Map<String, ClassNode> spec = GenericsUtils.createGenericsSpec(cn);
for (MethodNode mn : cn.getMethods()) {
mapper.accept(mn, spec);
}
}
if (exclude != null) exclude.addAll(types); // exclude types next time
return methods.values();
}
{code}
I think {{ClassNode#getDeclaredMethodsMap}} could be overloaded to accept a key
function and merge strategy. Or something like that could be offered by
{{ClassNodeUtils}}. I just never got around to making something publicly
available out of this.
was (Author: emilles):
This came up while investigating GROOVY-8638. I was looking for a way to get
all methods for a type and then group by overrides. This is not easy to sort
out given the current APIs.
This is what I came up with to find the non-synthetic methods of a given type:
{code:java}
protected Collection<MethodNode> getAllMethods(ClassNode type,
Set<ClassNode> exclude) {
Map<String, MethodNode> methods = new HashMap<>();
BiConsumer<MethodNode, Map<String, ClassNode>> mapper = (mn, spec) -> {
StringBuilder sb = new StringBuilder(mn.getName());
sb.append('(');
for (org.codehaus.groovy.ast.Parameter p : mn.getParameters()) {
ClassNode pt = p.getOriginType();
if (!pt.isGenericsPlaceHolder()) {
sb.append(pt.getName());
} else {
sb.append(spec.getOrDefault(pt.getUnresolvedName(),
pt).getName());
}
sb.append(';');
}
methods.merge(sb.toString(), mn, (m1, m2) ->
// keep override method unless it's synthetic
!Flags.isSynthetic(m1.getModifiers()) ? m1 : m2);
};
Set<ClassNode> types = new LinkedHashSet<>();
VariableScope.createTypeHierarchy(type, types, true); // GRECLIPSE API;
you would need to use a GROOVY API here
for (ClassNode cn : types) {
if ((exclude != null && exclude.contains(cn)) ||
Flags.isSynthetic(cn.getModifiers())) continue;
Map<String, ClassNode> spec = GenericsUtils.createGenericsSpec(cn);
for (MethodNode mn : cn.getMethods()) {
mapper.accept(mn, spec);
}
}
if (exclude != null) exclude.addAll(types); // exclude types next time
return methods.values();
}
{code}
I think {{ClassNode#getDeclaredMethodsMap}} could be overloaded to accept a key
function and merge strategy. Or something like that could be offered by
{{ClassNodeUtils}}. I just never got around to making something publicly
available out of this.
> Consolidate methods for collecting interfaces
> ---------------------------------------------
>
> Key: GROOVY-10123
> URL: https://issues.apache.org/jira/browse/GROOVY-10123
> Project: Groovy
> Issue Type: Improvement
> Reporter: Eric Milles
> Assignee: Eric Milles
> Priority: Minor
> Labels: breaking
> Fix For: 4.0.0-beta-1
>
>
> There are a number of options presented for collecting interfaces or methods,
> each with some subtle difference.
> {code:java}
> // interface collection
> org.codehaus.groovy.ast.tools.GeneralUtils#getInterfacesAndSuperInterfaces(ClassNode)
> // if parameter is interface, returns singleton set (IMO it was not intended
> to work this way)
> org.codehaus.groovy.ast.ClassNode#getAllInterfaces() // includes this,
> excludes super types
> org.codehaus.groovy.transform.trait.Traits.collectAllInterfacesReverseOrder(ClassNode,
> LinkedHashSet<ClassNode>) // parameterizes results
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.collectAllInterfaces(ClassNode)
> // unused by current codebase; redundant with
> GeneralUtils#getInterfacesAndSuperInterfaces if "singleton set" bug is fixed
> // method collection
> org.codehaus.groovy.ast.ClassNode#getAllDeclaredMethods() // deduplicated by
> MethodNode#getTypeDescriptor() which keeps bridge/synthetics instead of
> overridden
> org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor.collectAllInterfaceMethodsByName(ClassNode,
> String, List<MethodNode>) // non-static and available only to subclasses
> org.apache.groovy.ast.tools.ClassNodeUtils.addDeclaredMethodsFromInterfaces(ClassNode,
> Map<String, MethodNode>) // non-synthetic already
> org.apache.groovy.ast.tools.ClassNodeUtils.addDeclaredMethodsFromAllInterfaces(ClassNode,
> Map<String, MethodNode>) // includes synthetics, not all interfaces
> {code}
--
This message was sent by Atlassian Jira
(v8.3.4#803005)