@Override public void endVisit(JMethodCall x, Context ctx) { JMethod target = x.getTarget(); JDeclaredType type = target.getEnclosingType(); if (type instanceof JClassType) { JClassType cType = (JClassType) type; if (target == enumNameMethod || target == enumToStringMethod || target == enumValueOfMethod) { warn(x); } else if (cType.isEnumOrSubclass() != null) { if ("valueOf".equals(target.getName())) { /* * Check for calls to the auto-generated * EnumSubType.valueOf(String). Note, the check of the signature for * the single String arg version is to avoid flagging user-defined * overloaded versions of the method, which are presumably ok. */ List<JParameter> jParameters = target.getParams(); if (jParameters.size() == 1 && jParameters.get(0).getType() == stringType) { warn(x); } } } } }
private static JMethod createEmptyMethodFromExample( JDeclaredType inType, JMethod exampleMethod, boolean isAbstract) { JMethod emptyMethod = new JMethod( exampleMethod.getSourceInfo(), exampleMethod.getName(), inType, exampleMethod.getType(), isAbstract, false, false, exampleMethod.getAccess()); emptyMethod.addThrownExceptions(exampleMethod.getThrownExceptions()); emptyMethod.setSynthetic(); // Copy parameters. for (JParameter param : exampleMethod.getParams()) { emptyMethod.addParam( new JParameter( param.getSourceInfo(), param.getName(), param.getType(), param.isFinal(), param.isThis(), emptyMethod)); } JMethodBody body = new JMethodBody(exampleMethod.getSourceInfo()); emptyMethod.setBody(body); emptyMethod.freezeParamTypes(); inType.addMethod(emptyMethod); return emptyMethod; }
public EnumNameCallChecker(JProgram jprogram, TreeLogger logger) { this.logger = logger; this.enumNameMethod = jprogram.getIndexedMethod("Enum.name"); this.enumToStringMethod = jprogram.getIndexedMethod("Enum.toString"); this.classType = jprogram.getIndexedType("Class"); this.enumType = jprogram.getIndexedType("Enum"); this.stringType = jprogram.getIndexedType("String"); /* * Find the correct version of enumValueOfMethod. * * Note: it doesn't work to check against a ref returned by * jprogram.getIndexedMethod("Enum.valueOf"), since there are 2 different * versions of Enum.valueOf in our jre emulation library, and the indexed * ref won't reliably flag the public instance, which is the one we want * here (i.e. Enum.valueOf(Class<T>,String)). The other version is * protected, but is called by the generated constructors for sub-classes * of Enum, and we don't want to warn for those cases. */ JMethod foundMethod = null; List<JMethod> enumMethods = enumType.getMethods(); for (JMethod enumMethod : enumMethods) { if ("valueOf".equals(enumMethod.getName())) { List<JParameter> jParameters = enumMethod.getParams(); if (jParameters.size() == 2 && jParameters.get(0).getType() == classType && jParameters.get(1).getType() == stringType) { foundMethod = enumMethod; break; } } } this.enumValueOfMethod = foundMethod; }
/** Returns a description for a member suitable for reporting errors to the users. */ public static String getReadableDescription(JMember member) { if (member instanceof JField) { return String.format( "%s %s.%s", getReadableDescription(member.getType()), getReadableDescription(member.getEnclosingType()), member.getName()); } JMethod method = (JMethod) member; String printableDescription = ""; if (!method.isConstructor()) { printableDescription += getReadableDescription(method.getType()) + " "; } printableDescription += String.format( "%s.%s(%s)", getReadableDescription(method.getEnclosingType()), method.getName(), Joiner.on(", ") .join( Iterables.transform( method.getOriginalParamTypes(), new Function<JType, String>() { @Override public String apply(JType type) { return getReadableDescription(type); } }))); return printableDescription; }
public JExpression doRebind(String clsName, ReflectionGeneratorContext params) throws UnableToCompleteException { // generate params.getLogger().log(Type.INFO, "Binding magic class for " + clsName); // JType type = params.getClazz().getRefType(); JDeclaredType type = params.getAst().searchForTypeBySource(params.getClazz().getRefType().getName()); StandardGeneratorContext ctx = params.getGeneratorContext(); Class<? extends Generator> generator = MagicClassGenerator.class; String result = ctx.runGenerator(params.getLogger(), generator, SourceUtil.toSourceName(type.getName())); ctx.finish(params.getLogger()); params.getLogger().log(Type.INFO, "Generated Class Enhancer: " + result); JDeclaredType success = params.getAst().searchForTypeBySource(result); // Okay, we've generated the correct magic class subtype; // Now pull off its static accessor method to grab our generated class. for (JMethod method : success.getMethods()) { if (method.isStatic() && method.getName().equals("enhanceClass")) { JMethodCall call = new JMethodCall(method.getSourceInfo(), null, method); call.addArg(params.getClazz().makeStatement().getExpr()); return call; } } params.getLogger().log(Type.ERROR, "Unable to load " + result + ".enhanceClass()"); throw new UnableToCompleteException(); }
private static boolean isNewMethod(HasEnclosingType member) { if (member instanceof JMethod) { JMethod method = (JMethod) member; return method.getName().equals(JsniRef.NEW); } assert member instanceof JField; return false; }
/** * Return the JSNI signature for a member. Leave off the return type for a method signature, so as * to match what a user would type in as a JsniRef. */ private static String getJsniSignature(HasEnclosingType member, boolean wildcardParams) { if (member instanceof JField) { return ((JField) member).getName(); } JMethod method = (JMethod) member; if (wildcardParams) { return method.getName() + "(" + JsniRef.WILDCARD_PARAM_LIST + ")"; } else { return JProgram.getJsniSig(method, false); } }
private static void setJsPropertyProperties(JMethod method) { String methodName = method.getName(); if (startsWithCamelCase(methodName, "set")) { String jsName = Introspector.decapitalize(methodName.substring(3)); method.setJsPropertyInfo(jsName, JsPropertyAccessorType.SETTER); } else if (startsWithCamelCase(methodName, "get")) { String jsName = Introspector.decapitalize(methodName.substring(3)); method.setJsPropertyInfo(jsName, JsPropertyAccessorType.GETTER); } else if (startsWithCamelCase(methodName, "is")) { String jsName = Introspector.decapitalize(methodName.substring(2)); method.setJsPropertyInfo(jsName, JsPropertyAccessorType.GETTER); } else { method.setJsPropertyInfo(INVALID_JSNAME, JsPropertyAccessorType.UNDEFINED); } }
private static void setJsPropertyProperties(JMethod method) { String methodName = method.getName(); if (startsWithCamelCase(methodName, "set")) { method.setJsPropertyType(JsPropertyType.SET); method.setJsMemberName(Introspector.decapitalize(methodName.substring(3))); } else if (startsWithCamelCase(methodName, "get")) { method.setJsPropertyType(JsPropertyType.GET); method.setJsMemberName(Introspector.decapitalize(methodName.substring(3))); } else if (startsWithCamelCase(methodName, "is")) { method.setJsPropertyType(JsPropertyType.GET); method.setJsMemberName(Introspector.decapitalize(methodName.substring(2))); } else { method.setJsPropertyType(JsPropertyType.UNDEFINED); } }
/** * For each member with the given name, find the most derived members for each JSNI reference that * match it. For wildcard JSNI references, there will in general be more than one match. This * method does not ignore synthetic methods. */ private static void findMostDerivedMembers( LinkedHashMap<String, LinkedHashMap<String, HasEnclosingType>> matchesBySig, JDeclaredType targetType, String memberName, boolean addConstructors) { /* * Analyze superclasses and interfaces first. More derived members will thus * be seen later. */ if (targetType instanceof JClassType) { JClassType targetClass = (JClassType) targetType; if (targetClass.getSuperClass() != null) { findMostDerivedMembers(matchesBySig, targetClass.getSuperClass(), memberName, false); } } for (JDeclaredType intf : targetType.getImplements()) { findMostDerivedMembers(matchesBySig, intf, memberName, false); } // Get the methods on this class/interface. for (JMethod method : targetType.getMethods()) { if (method.getName().equals(memberName)) { if (addConstructors || !method.getName().equals(JsniRef.NEW)) { addMember(matchesBySig, method, getJsniSignature(method, false)); addMember(matchesBySig, method, getJsniSignature(method, true)); } } } // Get the fields on this class/interface. for (JField field : targetType.getFields()) { if (field.getName().equals(memberName)) { addMember(matchesBySig, field, field.getName()); } } }
/** * Java8 Method References such as String::equalsIgnoreCase should produce inner class names that * are a function of the samInterface (e.g. Runnable), the method being referred to, and the * qualifying disposition (this::foo vs Class::foo if foo is an instance method) */ public static String classNameForMethodReference( JType cuType, JInterfaceType functionalInterface, JMethod referredMethod, boolean hasReceiver) { String prefix = classNamePrefixForMethodReference( cuType.getPackageName(), cuType.getName(), functionalInterface.getName(), referredMethod.getEnclosingType().getName(), referredMethod.getName(), hasReceiver); return StringInterner.get().intern(constructManglingSignature(referredMethod, prefix)); }