Repository: groovy Updated Branches: refs/heads/master d5fc12260 -> 5ac20ba56
GROOVY-7840: Verifier#makeDescriptorWithoutReturnType uses ClassNode#toString with generics (closes #533) Project: http://git-wip-us.apache.org/repos/asf/groovy/repo Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/5ac20ba5 Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/5ac20ba5 Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/5ac20ba5 Branch: refs/heads/master Commit: 5ac20ba56fbb7f71d23218934cb9b39f15ce8858 Parents: d5fc122 Author: paulk <[email protected]> Authored: Wed May 3 19:12:31 2017 +1000 Committer: paulk <[email protected]> Committed: Wed May 17 11:31:58 2017 +1000 ---------------------------------------------------------------------- .../apache/groovy/ast/tools/ClassNodeUtils.java | 53 +++++++++++++++ .../groovy/ast/tools/MethodNodeUtils.java | 70 ++++++++++++++++++++ .../org/codehaus/groovy/ast/MethodNode.java | 42 ++---------- .../codehaus/groovy/ast/tools/GeneralUtils.java | 4 ++ .../org/codehaus/groovy/classgen/Verifier.java | 6 +- .../transform/AbstractASTTransformation.java | 13 ++-- .../AutoImplementASTTransformation.java | 8 +-- 7 files changed, 145 insertions(+), 51 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/groovy/blob/5ac20ba5/src/main/org/apache/groovy/ast/tools/ClassNodeUtils.java ---------------------------------------------------------------------- diff --git a/src/main/org/apache/groovy/ast/tools/ClassNodeUtils.java b/src/main/org/apache/groovy/ast/tools/ClassNodeUtils.java new file mode 100644 index 0000000..b8fd27a --- /dev/null +++ b/src/main/org/apache/groovy/ast/tools/ClassNodeUtils.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.groovy.ast.tools; + +import org.codehaus.groovy.ast.ClassNode; + +/** + * Utility class for working with ClassNodes + */ +public class ClassNodeUtils { + /** + * Formats a type name into a human readable version. For arrays, appends "[]" to the formatted + * type name of the component. For unit class nodes, uses the class node name. + * + * @param cNode the type to format + * @return a human readable version of the type name (java.lang.String[] for example) + */ + public static String formatTypeName(ClassNode cNode) { + if (cNode.isArray()) { + ClassNode it = cNode; + int dim = 0; + while (it.isArray()) { + dim++; + it = it.getComponentType(); + } + StringBuilder sb = new StringBuilder(it.getName().length() + 2 * dim); + sb.append(it.getName()); + for (int i = 0; i < dim; i++) { + sb.append("[]"); + } + return sb.toString(); + } + return cNode.getName(); + } + + private ClassNodeUtils() { } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/5ac20ba5/src/main/org/apache/groovy/ast/tools/MethodNodeUtils.java ---------------------------------------------------------------------- diff --git a/src/main/org/apache/groovy/ast/tools/MethodNodeUtils.java b/src/main/org/apache/groovy/ast/tools/MethodNodeUtils.java new file mode 100644 index 0000000..b43fc31 --- /dev/null +++ b/src/main/org/apache/groovy/ast/tools/MethodNodeUtils.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.groovy.ast.tools; + +import org.codehaus.groovy.ast.MethodNode; +import org.codehaus.groovy.ast.Parameter; + +/** + * Utility class for working with MethodNodes + */ +public class MethodNodeUtils { + /** + * Return the method node's descriptor including its + * name and parameter types without generics. + * + * @param mNode the method node + * @return the method node's abbreviated descriptor excluding the return type + */ + public static String methodDescriptorWithoutReturnType(MethodNode mNode) { + StringBuilder sb = new StringBuilder(); + mNode.getTypeDescriptor(); + sb.append(mNode.getName()).append(':'); + for (Parameter p : mNode.getParameters()) { + sb.append(ClassNodeUtils.formatTypeName(p.getType())).append(','); + } + return sb.toString(); + } + + /** + * Return the method node's descriptor which includes its return type, + * name and parameter types without generics. + * + * @param mNode the method node + * @return the method node's descriptor + */ + public static String methodDescriptor(MethodNode mNode) { + StringBuilder sb = new StringBuilder(mNode.getName().length() + mNode.getParameters().length * 10); + sb.append(mNode.getReturnType().getName()); + sb.append(' '); + sb.append(mNode.getName()); + sb.append('('); + for (int i = 0; i < mNode.getParameters().length; i++) { + if (i > 0) { + sb.append(", "); + } + Parameter p = mNode.getParameters()[i]; + sb.append(ClassNodeUtils.formatTypeName(p.getType())); + } + sb.append(')'); + return sb.toString(); + } + + private MethodNodeUtils() { } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/5ac20ba5/src/main/org/codehaus/groovy/ast/MethodNode.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/ast/MethodNode.java b/src/main/org/codehaus/groovy/ast/MethodNode.java index 1c867c3..7239a86 100644 --- a/src/main/org/codehaus/groovy/ast/MethodNode.java +++ b/src/main/org/codehaus/groovy/ast/MethodNode.java @@ -18,6 +18,7 @@ */ package org.codehaus.groovy.ast; +import org.apache.groovy.ast.tools.MethodNodeUtils; import org.codehaus.groovy.ast.stmt.BlockStatement; import org.codehaus.groovy.ast.stmt.Statement; import org.objectweb.asm.Opcodes; @@ -67,53 +68,18 @@ public class MethodNode extends AnnotatedNode implements Opcodes { /** * The type descriptor for a method node is a string containing the name of the method, its return type, - * and its parameter types in a canonical form. For simplicity, I'm using the format of a Java declaration - * without parameter names. + * and its parameter types in a canonical form. For simplicity, we use the format of a Java declaration + * without parameter names or generics. * * @return the type descriptor */ public String getTypeDescriptor() { if (typeDescriptor == null) { - StringBuilder buf = new StringBuilder(name.length() + parameters.length * 10); - buf.append(returnType.getName()); - buf.append(' '); - buf.append(name); - buf.append('('); - for (int i = 0; i < parameters.length; i++) { - if (i > 0) { - buf.append(", "); - } - Parameter param = parameters[i]; - buf.append(formatTypeName(param.getType())); - } - buf.append(')'); - typeDescriptor = buf.toString(); + typeDescriptor = MethodNodeUtils.methodDescriptor(this); } return typeDescriptor; } - /** - * Formats a type name in a readable version. For arrays, appends "[]" to the formatted - * type name of the component. For unit class nodes, uses the class node name. - * @param type the type to format - * @return a human readable version of the type name (java.lang.String[] for example) - */ - private static String formatTypeName(ClassNode type) { - if (type.isArray()) { - ClassNode it = type; - int dim = 0; - while (it.isArray()) { - dim++; - it = it.getComponentType(); - } - StringBuilder sb = new StringBuilder(it.getName().length()+2*dim); - sb.append(it.getName()); - for (int i=0;i<dim;i++) { sb.append("[]"); } - return sb.toString(); - } - return type.getName(); - } - private void invalidateCachedData() { typeDescriptor = null; } http://git-wip-us.apache.org/repos/asf/groovy/blob/5ac20ba5/src/main/org/codehaus/groovy/ast/tools/GeneralUtils.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/ast/tools/GeneralUtils.java b/src/main/org/codehaus/groovy/ast/tools/GeneralUtils.java index 413292a..c00a62d 100644 --- a/src/main/org/codehaus/groovy/ast/tools/GeneralUtils.java +++ b/src/main/org/codehaus/groovy/ast/tools/GeneralUtils.java @@ -559,6 +559,10 @@ public class GeneralUtils { return new BinaryExpression(lhv, LT, rhv); } + /** + * @deprecated use MethodNodeUtils#methodDescriptorWithoutReturnType(MethodNode) instead + */ + @Deprecated public static String makeDescriptorWithoutReturnType(MethodNode mn) { StringBuilder sb = new StringBuilder(); sb.append(mn.getName()).append(':'); http://git-wip-us.apache.org/repos/asf/groovy/blob/5ac20ba5/src/main/org/codehaus/groovy/classgen/Verifier.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/classgen/Verifier.java b/src/main/org/codehaus/groovy/classgen/Verifier.java index 9f90dd0..b98e784 100644 --- a/src/main/org/codehaus/groovy/classgen/Verifier.java +++ b/src/main/org/codehaus/groovy/classgen/Verifier.java @@ -73,7 +73,7 @@ import static java.lang.reflect.Modifier.isFinal; import static java.lang.reflect.Modifier.isPrivate; import static java.lang.reflect.Modifier.isPublic; import static java.lang.reflect.Modifier.isStatic; -import static org.codehaus.groovy.ast.tools.GeneralUtils.makeDescriptorWithoutReturnType; +import static org.apache.groovy.ast.tools.MethodNodeUtils.methodDescriptorWithoutReturnType; import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpec; import static org.codehaus.groovy.ast.tools.GenericsUtils.createGenericsSpec; @@ -266,7 +266,7 @@ public class Verifier implements GroovyClassVisitor, Opcodes { Set<String> descriptors = new HashSet<String>(); for (MethodNode mn : cn.getMethods()) { if (mn.isSynthetic()) continue; - String mySig = makeDescriptorWithoutReturnType(mn); + String mySig = methodDescriptorWithoutReturnType(mn); if (descriptors.contains(mySig)) { if (mn.isScriptBody() || mySig.equals(scriptBodySignatureWithoutReturnType(cn))) { throw new RuntimeParserException("The method " + mn.getText() + @@ -282,7 +282,7 @@ public class Verifier implements GroovyClassVisitor, Opcodes { private static String scriptBodySignatureWithoutReturnType(ClassNode cn) { for (MethodNode mn : cn.getMethods()) { - if (mn.isScriptBody()) return makeDescriptorWithoutReturnType(mn); + if (mn.isScriptBody()) return methodDescriptorWithoutReturnType(mn); } return null; } http://git-wip-us.apache.org/repos/asf/groovy/blob/5ac20ba5/src/main/org/codehaus/groovy/transform/AbstractASTTransformation.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/transform/AbstractASTTransformation.java b/src/main/org/codehaus/groovy/transform/AbstractASTTransformation.java index 7a289ea..24313f6 100644 --- a/src/main/org/codehaus/groovy/transform/AbstractASTTransformation.java +++ b/src/main/org/codehaus/groovy/transform/AbstractASTTransformation.java @@ -18,6 +18,7 @@ */ package org.codehaus.groovy.transform; +import org.apache.groovy.ast.tools.MethodNodeUtils; import org.codehaus.groovy.GroovyBugError; import org.codehaus.groovy.ast.ASTNode; import org.codehaus.groovy.ast.AnnotatedNode; @@ -285,7 +286,7 @@ public abstract class AbstractASTTransformation implements Opcodes, ASTTransform @Deprecated public static boolean shouldSkipOnDescriptor(boolean checkReturn, Map genericsSpec, MethodNode mNode, List<ClassNode> excludeTypes, List<ClassNode> includeTypes) { String descriptor = mNode.getTypeDescriptor(); - String descriptorNoReturn = GeneralUtils.makeDescriptorWithoutReturnType(mNode); + String descriptorNoReturn = MethodNodeUtils.methodDescriptorWithoutReturnType(mNode); for (ClassNode cn : excludeTypes) { List<ClassNode> remaining = new LinkedList<ClassNode>(); remaining.add(cn); @@ -300,7 +301,7 @@ public abstract class AbstractASTTransformation implements Opcodes, ASTTransform String md = correctedMethodNode.getTypeDescriptor(); if (md.equals(descriptor)) return true; } else { - String md = GeneralUtils.makeDescriptorWithoutReturnType(correctedMethodNode); + String md = MethodNodeUtils.methodDescriptorWithoutReturnType(correctedMethodNode); if (md.equals(descriptorNoReturn)) return true; } } @@ -323,7 +324,7 @@ public abstract class AbstractASTTransformation implements Opcodes, ASTTransform String md = correctedMethodNode.getTypeDescriptor(); if (md.equals(descriptor)) return false; } else { - String md = GeneralUtils.makeDescriptorWithoutReturnType(correctedMethodNode); + String md = MethodNodeUtils.methodDescriptorWithoutReturnType(correctedMethodNode); if (md.equals(descriptorNoReturn)) return false; } } @@ -336,7 +337,7 @@ public abstract class AbstractASTTransformation implements Opcodes, ASTTransform public static boolean shouldSkipOnDescriptorUndefinedAware(boolean checkReturn, Map genericsSpec, MethodNode mNode, List<ClassNode> excludeTypes, List<ClassNode> includeTypes) { String descriptor = mNode.getTypeDescriptor(); - String descriptorNoReturn = GeneralUtils.makeDescriptorWithoutReturnType(mNode); + String descriptorNoReturn = MethodNodeUtils.methodDescriptorWithoutReturnType(mNode); if (excludeTypes != null) { for (ClassNode cn : excludeTypes) { List<ClassNode> remaining = new LinkedList<ClassNode>(); @@ -352,7 +353,7 @@ public abstract class AbstractASTTransformation implements Opcodes, ASTTransform String md = correctedMethodNode.getTypeDescriptor(); if (md.equals(descriptor)) return true; } else { - String md = GeneralUtils.makeDescriptorWithoutReturnType(correctedMethodNode); + String md = MethodNodeUtils.methodDescriptorWithoutReturnType(correctedMethodNode); if (md.equals(descriptorNoReturn)) return true; } } @@ -376,7 +377,7 @@ public abstract class AbstractASTTransformation implements Opcodes, ASTTransform String md = correctedMethodNode.getTypeDescriptor(); if (md.equals(descriptor)) return false; } else { - String md = GeneralUtils.makeDescriptorWithoutReturnType(correctedMethodNode); + String md = MethodNodeUtils.methodDescriptorWithoutReturnType(correctedMethodNode); if (md.equals(descriptorNoReturn)) return false; } } http://git-wip-us.apache.org/repos/asf/groovy/blob/5ac20ba5/src/main/org/codehaus/groovy/transform/AutoImplementASTTransformation.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/transform/AutoImplementASTTransformation.java b/src/main/org/codehaus/groovy/transform/AutoImplementASTTransformation.java index 5ec874f..74124fd 100644 --- a/src/main/org/codehaus/groovy/transform/AutoImplementASTTransformation.java +++ b/src/main/org/codehaus/groovy/transform/AutoImplementASTTransformation.java @@ -48,7 +48,7 @@ import static org.codehaus.groovy.ast.ClassHelper.make; import static org.codehaus.groovy.ast.expr.ArgumentListExpression.EMPTY_ARGUMENTS; import static org.codehaus.groovy.ast.tools.GeneralUtils.constX; import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorX; -import static org.codehaus.groovy.ast.tools.GeneralUtils.makeDescriptorWithoutReturnType; +import static org.apache.groovy.ast.tools.MethodNodeUtils.methodDescriptorWithoutReturnType; import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS; import static org.codehaus.groovy.ast.tools.GeneralUtils.throwS; import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpec; @@ -107,7 +107,7 @@ public class AutoImplementASTTransformation extends AbstractASTTransformation { private static Map<String, MethodNode> getAllCorrectedMethodsMap(ClassNode cNode) { Map<String, MethodNode> result = new HashMap<String, MethodNode>(); for (MethodNode mn : cNode.getMethods()) { - result.put(makeDescriptorWithoutReturnType(mn), mn); + result.put(methodDescriptorWithoutReturnType(mn), mn); } ClassNode next = cNode; while (true) { @@ -118,7 +118,7 @@ public class AutoImplementASTTransformation extends AbstractASTTransformation { ClassNode correctedClass = correctToGenericsSpecRecurse(genericsSpec, next); MethodNode found = getDeclaredMethodCorrected(genericsSpec, correctedMethod, correctedClass); if (found != null) { - String td = makeDescriptorWithoutReturnType(found); + String td = methodDescriptorWithoutReturnType(found); if (result.containsKey(td) && !result.get(td).isAbstract()) { continue; } @@ -137,7 +137,7 @@ public class AutoImplementASTTransformation extends AbstractASTTransformation { MethodNode correctedMethod = correctToGenericsSpec(genericsSpec, nextMethod); MethodNode found = getDeclaredMethodCorrected(updatedGenericsSpec, correctedMethod, correctedInterface); if (found != null) { - String td = makeDescriptorWithoutReturnType(found); + String td = methodDescriptorWithoutReturnType(found); if (result.containsKey(td) && !result.get(td).isAbstract()) { continue; }
