Github user jwagenleitner commented on a diff in the pull request:
https://github.com/apache/groovy/pull/381#discussion_r74691103
--- Diff: src/main/org/codehaus/groovy/ast/tools/ClassNodeUtils.java ---
@@ -65,4 +73,122 @@ public static void
addDeclaredMethodMapsFromSuperInterfaces(ClassNode cn, Map<St
sn = sn.getSuperClass();
}
}
+
+ /**
+ * Returns true if the given method has a possibly matching static
method with the given name and arguments.
+ *
+ * @param cNode the ClassNode of interest
+ * @param name the name of the method of interest
+ * @param arguments the arguments to match against
+ * @param trySpread whether to try to account for SpreadExpressions
within the arguments
+ * @return true if a matching method was found
+ */
+ public static boolean hasPossibleStaticMethod(ClassNode cNode, String
name, Expression arguments, boolean trySpread) {
+ int count = 0;
+ boolean foundSpread = false;
+
+ if (arguments instanceof TupleExpression) {
+ TupleExpression tuple = (TupleExpression) arguments;
+ for (Expression arg : tuple.getExpressions()) {
+ if (arg instanceof SpreadExpression) {
+ foundSpread = true;
+ } else {
+ count++;
+ }
+ }
+ } else if (arguments instanceof MapExpression) {
+ count = 1;
+ }
+
+ for (MethodNode method : cNode.getMethods(name)) {
+ if (method.isStatic()) {
+ Parameter[] parameters = method.getParameters();
+ // do fuzzy match for spread case: count will be number of
non-spread args
+ if (trySpread && foundSpread && parameters.length >=
count) return true;
+
+ if (parameters.length == count) return true;
+
+ // handle varargs case
+ if (parameters.length > 0 && parameters[parameters.length
- 1].getType().isArray()) {
+ if (count >= parameters.length - 1) return true;
+ // fuzzy match any spread to a varargs
+ if (trySpread && foundSpread) return true;
+ }
+
+ // handle parameters with default values
+ int nonDefaultParameters = 0;
+ for (Parameter parameter : parameters) {
+ if (!parameter.hasInitialExpression()) {
+ nonDefaultParameters++;
+ }
+ }
+
+ if (count < parameters.length && nonDefaultParameters <=
count) {
+ return true;
+ }
+ // TODO handle spread with nonDefaultParams?
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return true if we have a static accessor
+ */
+ public static boolean hasPossibleStaticProperty(ClassNode candidate,
String methodName) {
+ // assume explicit static method call checked first so we can
assume a simple check here
+ if (!methodName.startsWith("get") && !methodName.startsWith("is"))
{
+ return false;
+ }
+ String propName = getPropNameForAccessor(methodName);
+ PropertyNode pNode = getStaticProperty(candidate, propName);
+ return pNode != null && (methodName.startsWith("get") ||
boolean_TYPE.equals(pNode.getType()));
+ }
+
+ /**
+ * Returns the property name, e.g. age, given an accessor name, e.g.
getAge.
+ * Returns the original if a valid prefix cannot be removed.
+ *
+ * @param accessorName the accessor name of interest, e.g. getAge
+ * @return the property name, e.g. age, or original if not a valid
property accessor name
+ */
+ public static String getPropNameForAccessor(String accessorName) {
+ int prefixLength = accessorName.startsWith("is") ? 2 : 3;
+ if (accessorName.length() < prefixLength + 1) return accessorName;
+ if (!isValidAccessorName(accessorName)) return accessorName;
--- End diff --
Would it make sense to move the length check to the `isValidAccessorName`
method below? That would ensure `isValidAccessorName` would not return true
for methods named `get()`/`is()`/`set()`.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at [email protected] or file a JIRA ticket
with INFRA.
---