private void validateSignature(MethodReader method) { if (!method.hasModifier(ElementModifier.STATIC)) { if (!typeHelper.isJavaScriptClass(method.getOwnerName())) { diagnostics.error(location, "Can't call method {{m0}} of non-JS class", method.getReference()); } } for (int i = 0; i < method.parameterCount(); ++i) { if (!typeHelper.isSupportedType(method.parameterType(i))) { diagnostics.error(location, "Invalid type {{t0}} of parameter " + (i + 1) + " of method {{m1}}", method.parameterType(i), method.getReference()); } } if (method.getResultType() != ValueType.VOID && !typeHelper.isSupportedType(method.getResultType())) { diagnostics.error(location, "Invalid type {{t0}} of return value of method {{m1}}", method.getResultType(), method.getReference()); } }
public static MethodHolder copyMethod(MethodReader method, boolean withProgram) { MethodHolder copy = new MethodHolder(method.getDescriptor()); copy.setLevel(method.getLevel()); copy.getModifiers().addAll(method.readModifiers()); if (method.getProgram() != null && withProgram) { copy.setProgram(ProgramUtils.copy(method.getProgram())); } copyAnnotations(method.getAnnotations(), copy.getAnnotations()); if (method.getAnnotationDefault() != null) { copy.setAnnotationDefault(copyAnnotationValue(method.getAnnotationDefault())); } for (int i = 0; i < method.parameterCount(); ++i) { copyAnnotations(method.parameterAnnotation(i), copy.parameterAnnotation(i)); } return copy; }
private boolean isProperSetter(MethodReader method) { if (method.parameterCount() != 1 || !typeHelper.isSupportedType(method.parameterType(0)) || method.getResultType() != ValueType.VOID) { return false; } return extractSuggestedPropertyName(method) != null || isProperPrefix(method.getName(), "set"); }
private boolean matchSignature(ClassHierarchy hierarchy, MethodReader functionMethod, MethodReader candidateMethod) { if (functionMethod.parameterCount() > candidateMethod.parameterCount()) { return false; } for (int i = 0; i < functionMethod.parameterCount(); ++i) { if (!hierarchy.isSuperType(functionMethod.parameterType(i), candidateMethod.parameterType(i), false)) { return false; } } return true; }
private static boolean needsClinitCall(MethodReader method) { if (method.getName().equals("<clinit>")) { return false; } if (method.getName().equals("<init>")) { return true; } return method.hasModifier(ElementModifier.STATIC); } }
private boolean isWrappedNativeCall(MethodReader method) { if (!method.hasModifier(ElementModifier.NATIVE)) { return false; } for (ValueType type : method.getParameterTypes()) { if (type.isObject(String.class)) { return true; } } return false; }
private boolean processInvocation(MethodReader method, CallLocation callLocation, InvokeInstruction invoke, MethodHolder methodToProcess) { if (method.getAnnotations().get(JSBody.class.getName()) != null) { return processJSBodyInvocation(method, callLocation, invoke, methodToProcess); if (method.hasModifier(ElementModifier.STATIC)) { return false; if (method.getProgram() != null && method.getProgram().basicBlockCount() > 0) { MethodReader overridden = getOverriddenMethod(method); if (overridden != null) { diagnostics.error(callLocation, "JS final method {{m0}} overrides {{m1}}. " + "Overriding final method of overlay types is prohibited.", method.getReference(), overridden.getReference()); if (method.getProgram() != null && method.getProgram().basicBlockCount() > 0) { invoke.setMethod(new MethodReference(method.getOwnerName(), method.getName() + "$static", getStaticSignature(method.getReference()))); Variable[] newArguments = new Variable[invoke.getArguments().size() + 1]; newArguments[0] = invoke.getInstance(); if (method.getAnnotations().get(JSProperty.class.getName()) != null) { return processProperty(method, callLocation, invoke); } else if (method.getAnnotations().get(JSIndexer.class.getName()) != null) { return processIndexer(method, callLocation, invoke); } else {
added = true; for (MethodReader method : iface.getMethods()) { if (method.hasModifier(ElementModifier.STATIC) || (method.getProgram() != null && method.getProgram().basicBlockCount() > 0)) { continue; if (!exposedCls.inheritedMethods.containsKey(method.getDescriptor())) { String name = method.getName(); AnnotationReader methodAnnot = method.getAnnotations().get(JSMethod.class.getName()); if (methodAnnot != null) { AnnotationValue nameVal = methodAnnot.getValue("value"); exposedCls.methods.put(method.getDescriptor(), name);
MethodReader candidate = null; for (MethodReader method : classReader.getMethods()) { if (!method.getName().equals(name)) { continue; if (!Arrays.equals(method.getParameterTypes(), internalParameterTypes)) { continue; candidate = method; } else { boolean moreSpecial = context.getHierarchy().isSuperType(candidate.getResultType(), method.getResultType(), false); if (moreSpecial) { candidate = method; return candidate != null ? getDeclaredMethod(candidate.getDescriptor()) : null; });
private MethodReference createCallbackMethod(MethodReader method) { int paramCount = method.parameterCount(); if (!method.hasModifier(ElementModifier.STATIC)) { paramCount++; } ValueType[] signature = new ValueType[paramCount + 1]; for (int i = 0; i < paramCount; ++i) { signature[i] = ValueType.object(JSObject.class.getName()); } signature[paramCount] = method.getResultType() == ValueType.VOID ? ValueType.VOID : ValueType.object(JSObject.class.getName()); return new MethodReference(location.getMethod().getClassName(), method.getName() + "$jsocb$_" + idGenerator++, signature); }
private Program generateAfterProgram(MethodHolder method, ClassHierarchy hierarchy) { ProgramEmitter pe = ProgramEmitter.create(method, hierarchy); ValueEmitter testCaseVar = pe.getField(TestEntryPoint.class, "testCase", Object.class); List<ClassReader> classes = collectSuperClasses(pe.getClassSource(), testMethod.getClassName()); classes.stream() .flatMap(cls -> cls.getMethods().stream()) .filter(m -> m.getAnnotations().get(JUNIT4_AFTER) != null) .forEach(m -> testCaseVar.cast(ValueType.object(m.getOwnerName())).invokeVirtual(m.getReference())); if (hierarchy.isSuperType(JUNIT3_BASE_CLASS, testMethod.getClassName(), false)) { testCaseVar.cast(ValueType.object(JUNIT3_BASE_CLASS)).invokeVirtual(JUNIT3_AFTER); } pe.exit(); return pe.getProgram(); }
@Override public void methodReached(DependencyAgent agent, MethodDependency method) { AnnotationReader delegateAnnot = method.getMethod().getAnnotations().get(DelegateTo.class.getName()); if (delegateAnnot != null) { String delegateMethodName = delegateAnnot.getValue("value").getString(); ClassReader cls = agent.getClassSource().get(method.getReference().getClassName()); for (MethodReader delegate : cls.getMethods()) { if (delegate.getName().equals(delegateMethodName)) { if (delegate != method.getMethod()) { MethodDependency dep = agent.linkMethod(delegate.getReference()); dep.use(); method.addLocationListener(dep::addLocation); } } } } }
private boolean validateSignature(MethodReader method, CallLocation callLocation, boolean[] byRefParams) { if (method.getResultType() != ValueType.VOID && !typeHelper.isSupportedType(method.getResultType())) { diagnostics.error(callLocation, "Method {{m0}} is not a proper native JavaScript method " + "declaration, since it returns wrong type", method.getReference()); return false; } ValueType[] parameterTypes = method.getParameterTypes(); AnnotationContainerReader[] parameterAnnotations = method.getParameterAnnotations(); for (int i = 0; i < parameterTypes.length; i++) { ValueType paramType = parameterTypes[i]; if (!typeHelper.isSupportedType(paramType)) { diagnostics.error(callLocation, "Method {{m0}} is not a proper native JavaScript method " + "declaration: its " + (i + 1) + "th parameter has wrong type", method.getReference()); return false; } if (parameterAnnotations[i].get(JSByRef.class.getName()) != null) { if (!typeHelper.isSupportedByRefType(paramType)) { diagnostics.error(callLocation, "Method {{m0}} is not a proper native JavaScript method " + "declaration: its " + (i + 1) + "th parameter is declared as JSByRef, " + "which has incompatible type", method.getReference()); return false; } byRefParams[i] = true; } } return true; }
@Override public void methodReached(DependencyAgent agent, MethodDependency method) { if (!reachedMethods.add(method.getReference())) { return; } ValueType type = method.getMethod().getResultType(); while (type instanceof ValueType.Array) { type = ((ValueType.Array) type).getItemType(); } if (type instanceof ValueType.Object) { String className = ((ValueType.Object) type).getClassName(); ClassReader cls = agent.getClassSource().get(className); if (cls != null && cls.hasModifier(ElementModifier.ANNOTATION)) { agent.linkClass(className); } } if (method.getMethod().hasModifier(ElementModifier.STATIC) && method.getMethod().getName().equals("$$__readAnnotations__$$")) { ClassReader cls = agent.getClassSource().get(method.getReference().getClassName()); if (cls != null) { for (AnnotationReader annotation : cls.getAnnotations().all()) { agent.linkClass(annotation.getType()); } } } MethodReference methodRef = method.getMethod().getReference(); if (methodRef.getClassName().equals("java.lang.Class") && methodRef.getName().equals("getAnnotations")) { reachGetAnnotations(agent, method.getVariable(0)); } }
@Override public void methodReached(DependencyAgent agent, MethodDependency method) { MethodReader reader = method.getMethod(); if (reader.getOwnerName().equals(Platform.class.getName()) && reader.getName().equals("newInstanceImpl")) { allClassesNode.connect(method.getResult()); MethodReference methodRef = reader.getReference(); method.getResult().addConsumer(type -> attachConstructor(agent, type.getName(), new CallLocation(methodRef))); } }
private void requireJSBody(Diagnostics diagnostics, MethodReader methodToProcess) { if (!repository.processedMethods.add(methodToProcess.getReference())) { return; } processJSBody(diagnostics, methodToProcess); }
private void collectMethodsToCopyFromInterfacesImpl(ClassReader cls, List<MethodReference> targetList, Set<MethodDescriptor> visited, Set<String> visitedClasses) { if (!visitedClasses.add(cls.getName())) { return; } for (MethodReader method : cls.getMethods()) { if (!method.hasModifier(ElementModifier.STATIC) && !method.hasModifier(ElementModifier.ABSTRACT)) { if (visited.add(method.getDescriptor())) { targetList.add(method.getReference()); } } } for (String ifaceName : cls.getInterfaces()) { ClassReader iface = classSource.get(ifaceName); if (iface != null) { collectMethodsToCopyFromInterfacesImpl(iface, targetList, visited, visitedClasses); } } }
private boolean isProperGetter(MethodReader method) { if (method.parameterCount() > 0 || !typeHelper.isSupportedType(method.getResultType())) { return false; } if (extractSuggestedPropertyName(method) != null) { return true; } if (method.getResultType().equals(ValueType.BOOLEAN)) { if (isProperPrefix(method.getName(), "is")) { return true; } } return isProperPrefix(method.getName(), "get"); }
appendProperty(writer, "parameterTypes", false, () -> { writer.append('['); for (int i = 0; i < method.parameterCount(); ++i) { if (i > 0) { writer.append(',').ws(); writer.append(context.typeToClassString(method.parameterType(i))); writer.append(context.typeToClassString(method.getResultType())); }); if (accessibleMethods != null && accessibleMethods.contains(method.getDescriptor())) { renderCallable(writer, method); } else {
@Override public ReflectMethod[] getMethods() { resolve(); if (classReader == null) { return new ReflectMethod[0]; } if (methodsCache == null) { Set<String> visited = new HashSet<>(); methodsCache = context.getClassSource().getAncestors(classReader.getName()) .flatMap(cls -> cls.getMethods().stream()) .filter(method -> !method.getName().equals("<clinit>")) .filter(method -> visited.add(method.getDescriptor().toString())) .map(method -> context.getClass(ValueType.object(method.getOwnerName())) .getDeclaredMethod(method.getDescriptor())) .filter(Objects::nonNull) .toArray(ReflectMethod[]::new); } return methodsCache.clone(); }