use of soot.Type in project robovm by robovm.
the class ObjCMemberPlugin method findStrongRefGetter.
private SootMethod findStrongRefGetter(SootClass sootClass, final SootMethod method, boolean extensions) {
AnnotationTag annotation = getAnnotation(method, PROPERTY);
if (annotation == null) {
annotation = getAnnotation(method, IBOUTLET);
}
if (annotation == null) {
annotation = getAnnotation(method, IBOUTLETCOLLECTION);
}
String setterPropName = readStringElem(annotation, "name", "").trim();
if (setterPropName.length() == 0) {
String methodName = method.getName();
if (!methodName.startsWith("set") || methodName.length() == 3) {
throw new CompilerException("Failed to determine the property " + "name from the @Property method " + method + ". Either specify the name explicitly in the @Property " + "annotation or rename the method according to the Java " + "beans property setter method naming convention.");
}
setterPropName = methodName.substring(3);
setterPropName = setterPropName.substring(0, 1).toLowerCase() + setterPropName.substring(1);
}
int paramCount = extensions ? 1 : 0;
Type propType = method.getParameterType(extensions ? 1 : 0);
for (SootMethod m : sootClass.getMethods()) {
if (m != method && method.isStatic() == m.isStatic() && m.getParameterCount() == paramCount && m.getReturnType().equals(propType)) {
AnnotationTag propertyAnno = getAnnotation(m, PROPERTY);
if (propertyAnno != null) {
String getterPropName = readStringElem(propertyAnno, "name", "").trim();
if (getterPropName.length() == 0) {
String methodName = m.getName();
if (!methodName.startsWith("get") || methodName.length() == 3) {
// style getter
continue;
}
getterPropName = methodName.substring(3);
getterPropName = getterPropName.substring(0, 1).toLowerCase() + getterPropName.substring(1);
}
if (setterPropName.equals(getterPropName)) {
return m;
}
}
}
}
throw new CompilerException("Failed to determine the getter method " + "corresponding to the strong ref @Property setter method " + method + ". The getter must either specify the name explicitly in the @Property " + "annotation or be named according to the Java " + "beans property getter method naming convention.");
}
use of soot.Type in project robovm by robovm.
the class ObjCMemberPlugin method transformMethod.
private void transformMethod(Config config, Clazz clazz, SootClass sootClass, SootMethod method, Set<String> selectors, Set<String> overridables, boolean extensions) {
AnnotationTag annotation = getAnnotation(method, METHOD);
if (annotation != null) {
if (extensions && !(method.isStatic() && method.isNative())) {
throw new CompilerException("Objective-C @Method method " + method + " in extension class must be static and native.");
}
transformObjCMethod(annotation, sootClass, method, selectors, overridables, extensions);
return;
}
annotation = getAnnotation(method, IBACTION);
if (annotation != null) {
if (method.isStatic() || method.isNative()) {
throw new CompilerException("Objective-C @IBAction method " + method + " must not be static or native.");
}
int paramCount = method.getParameterCount();
Type param1 = paramCount > 0 ? method.getParameterType(0) : null;
Type param2 = paramCount > 1 ? method.getParameterType(1) : null;
if (method.getReturnType() != VoidType.v() || paramCount > 2 || (param1 != null && (!isNSObject(param1) && !isNSObject(param1))) || (param2 != null && (!isUIEvent(param2) || isNSObject(param1)))) {
throw new CompilerException("Objective-C @IBAction method " + method + " does not have a supported signature. @IBAction methods" + " must return void and either take no arguments, 1 argument of type NSObject" + ", or 2 arguments of types NSObject and UIEvent.");
}
transformObjCMethod(annotation, sootClass, method, selectors, overridables, extensions);
return;
}
annotation = getAnnotation(method, PROPERTY);
if (annotation != null) {
if (extensions && !(method.isStatic() && method.isNative())) {
throw new CompilerException("Objective-C @Property method " + method + " in extension class must be static and native.");
}
transformObjCProperty(annotation, "@Property", sootClass, method, selectors, overridables, extensions);
return;
}
annotation = getAnnotation(method, IBOUTLET);
if (annotation != null) {
if (method.isStatic()) {
throw new CompilerException("Objective-C @IBOutlet method " + method + " must not be static.");
}
transformObjCProperty(annotation, "@IBOutlet", sootClass, method, selectors, overridables, extensions);
return;
}
annotation = getAnnotation(method, IBOUTLETCOLLECTION);
if (annotation != null) {
if (method.isStatic()) {
throw new CompilerException("Objective-C @IBOutletCollection method " + method + " must not be static.");
}
if (method.getReturnType() != VoidType.v() && !isNSArray(method.getReturnType()) || method.getReturnType() == VoidType.v() && method.getParameterCount() == 1 && !isNSArray(method.getParameterType(0))) {
throw new CompilerException("Objective-C @IBOutletCollection method " + method + " does not have a supported signature. " + "@IBOutletCollection getter methods must return NSArray. " + "@IBOutletCollection setter methods must have 1 parameter of type NSArray.");
}
transformObjCProperty(annotation, "@IBOutletCollection", sootClass, method, selectors, overridables, extensions);
return;
}
if (!method.isStatic() && !method.isNative() && !method.isAbstract() && !method.isPrivate() && isCustomClass(sootClass) && !hasAnnotation(method, NOT_IMPLEMENTED)) {
/*
* Create a @Callback for this method if it overrides a
* @Method/@Property method in a superclass/interface.
*/
List<SootMethod> superMethods = findOverriddenMethods(sootClass, method);
for (SootMethod superMethod : superMethods) {
if (createCustomClassCallbackIfNeeded(sootClass, method, superMethod)) {
break;
}
}
}
}
use of soot.Type in project robovm by robovm.
the class ObjCMemberPlugin method createBridge.
private void createBridge(SootClass sootClass, SootMethod method, String selectorName, boolean strongRefSetter, boolean extensions) {
Jimple j = Jimple.v();
boolean usingGenericInstanceMethod = false;
SootMethod msgSendMethod = getMsgSendMethod(selectorName, method, extensions);
/*
* Add the method even if we might remove it later to make marshaler
* lookup on the method work as expected.
*/
sootClass.addMethod(msgSendMethod);
addBridgeAnnotation(msgSendMethod);
SootMethodRef msgSendMethodRef = getGenericMsgSendReplacementMethod(msgSendMethod);
if (!msgSendMethodRef.declaringClass().getType().equals(msgSendMethod.getDeclaringClass().getType())) {
/*
* There's a generic objc_msgSend method we can use. Remove
* msgSendMethod from the class.
*/
sootClass.removeMethod(msgSendMethod);
/*
* Can we use a generic <name>_instance method from $M? If we can we
* won't have to make a call to objc_msgSendSuper.
*/
if (!method.isStatic()) {
// Yes!
msgSendMethodRef = Scene.v().makeMethodRef(msgSendMethodRef.declaringClass(), msgSendMethodRef.name() + "_instance", msgSendMethodRef.parameterTypes(), msgSendMethodRef.returnType(), true);
usingGenericInstanceMethod = true;
}
}
SootMethodRef msgSendSuperMethodRef = null;
if (!usingGenericInstanceMethod && !extensions && !method.isStatic()) {
SootMethod msgSendSuperMethod = getMsgSendSuperMethod(selectorName, method);
/*
* Add the method even if we might remove it later to make marshaler
* lookup on the method work as expected.
*/
sootClass.addMethod(msgSendSuperMethod);
addBridgeAnnotation(msgSendSuperMethod);
msgSendSuperMethodRef = getGenericMsgSendSuperReplacementMethod(msgSendSuperMethod);
if (!msgSendSuperMethodRef.declaringClass().getType().equals(msgSendSuperMethod.getDeclaringClass().getType())) {
/*
* There's a generic objc_msgSendSuper method we can use. Remove
* msgSendSuperMethod from the class.
*/
sootClass.removeMethod(msgSendSuperMethod);
}
}
method.setModifiers(method.getModifiers() & ~NATIVE);
Body body = j.newBody(method);
method.setActiveBody(body);
PatchingChain<Unit> units = body.getUnits();
Local thiz = null;
if (extensions) {
thiz = j.newLocal("$this", method.getParameterType(0));
body.getLocals().add(thiz);
units.add(j.newIdentityStmt(thiz, j.newParameterRef(method.getParameterType(0), 0)));
} else if (!method.isStatic()) {
thiz = j.newLocal("$this", sootClass.getType());
body.getLocals().add(thiz);
units.add(j.newIdentityStmt(thiz, j.newThisRef(sootClass.getType())));
}
LinkedList<Value> args = new LinkedList<>();
for (int i = extensions ? 1 : 0; i < method.getParameterCount(); i++) {
Type t = method.getParameterType(i);
Local p = j.newLocal("$p" + i, t);
body.getLocals().add(p);
units.add(j.newIdentityStmt(p, j.newParameterRef(t, i)));
args.add(p);
}
Local objCClass = null;
if (!extensions && method.isStatic()) {
objCClass = j.newLocal("$objCClass", org_robovm_objc_ObjCClass.getType());
body.getLocals().add(objCClass);
units.add(j.newAssignStmt(objCClass, j.newStaticFieldRef(Scene.v().makeFieldRef(sootClass, "$objCClass", org_robovm_objc_ObjCClass.getType(), true))));
}
if (strongRefSetter) {
Type propType = method.getParameterType(extensions ? 1 : 0);
if (propType instanceof RefLikeType) {
SootMethodRef getter = findStrongRefGetter(sootClass, method, extensions).makeRef();
Local before = j.newLocal("$before", propType);
body.getLocals().add(before);
units.add(j.newAssignStmt(before, extensions ? j.newStaticInvokeExpr(getter, thiz) : (objCClass != null ? j.newStaticInvokeExpr(getter) : j.newVirtualInvokeExpr(thiz, getter))));
Value after = args.get(0);
if (extensions) {
units.add(j.newInvokeStmt(j.newStaticInvokeExpr(org_robovm_objc_ObjCExtensions_updateStrongRef, Arrays.asList(thiz, before, after))));
} else {
units.add(j.newInvokeStmt(j.newVirtualInvokeExpr(objCClass != null ? objCClass : thiz, org_robovm_objc_ObjCObject_updateStrongRef, before, after)));
}
}
}
Local sel = j.newLocal("$sel", org_robovm_objc_Selector.getType());
body.getLocals().add(sel);
// $sel = <selector>
units.add(j.newAssignStmt(sel, j.newStaticFieldRef(Scene.v().makeFieldRef(sootClass, getSelectorFieldName(selectorName), org_robovm_objc_Selector.getType(), true))));
args.addFirst(sel);
Local customClass = null;
if (!usingGenericInstanceMethod && !extensions && !Modifier.isFinal(sootClass.getModifiers()) && !method.isStatic()) {
customClass = j.newLocal("$customClass", BooleanType.v());
body.getLocals().add(customClass);
units.add(j.newAssignStmt(customClass, j.newInstanceFieldRef(thiz, org_robovm_objc_ObjCObject_customClass)));
}
Local ret = null;
if (method.getReturnType() != VoidType.v()) {
ret = j.newLocal("$ret", msgSendMethodRef.returnType());
body.getLocals().add(ret);
}
Local castRet = null;
if (!msgSendMethodRef.returnType().equals(method.getReturnType())) {
/*
* We're calling a generic method in $M which returns an NSObject.
* We need to cast that to the return type declared by the method
* being generated.
*/
castRet = j.newLocal("$castRet", method.getReturnType());
body.getLocals().add(castRet);
}
StaticInvokeExpr invokeMsgSendExpr = j.newStaticInvokeExpr(msgSendMethodRef, l(thiz != null ? thiz : objCClass, args));
Stmt invokeMsgSendStmt = ret == null ? j.newInvokeStmt(invokeMsgSendExpr) : j.newAssignStmt(ret, invokeMsgSendExpr);
if (customClass != null) {
// if $customClass == 0 goto <invokeMsgSendStmt>
units.add(j.newIfStmt(j.newEqExpr(customClass, IntConstant.v(0)), invokeMsgSendStmt));
// $super = this.getSuper()
Local zuper = j.newLocal("$super", org_robovm_objc_ObjCSuper.getType());
body.getLocals().add(zuper);
units.add(j.newAssignStmt(zuper, j.newVirtualInvokeExpr(body.getThisLocal(), org_robovm_objc_ObjCObject_getSuper)));
StaticInvokeExpr invokeMsgSendSuperExpr = j.newStaticInvokeExpr(msgSendSuperMethodRef, l(zuper, args));
units.add(ret == null ? j.newInvokeStmt(invokeMsgSendSuperExpr) : j.newAssignStmt(ret, invokeMsgSendSuperExpr));
if (ret != null) {
if (castRet != null) {
units.add(j.newAssignStmt(castRet, j.newCastExpr(ret, castRet.getType())));
units.add(j.newReturnStmt(castRet));
} else {
units.add(j.newReturnStmt(ret));
}
} else {
units.add(j.newReturnVoidStmt());
}
}
units.add(invokeMsgSendStmt);
if (ret != null) {
if (castRet != null) {
units.add(j.newAssignStmt(castRet, j.newCastExpr(ret, castRet.getType())));
units.add(j.newReturnStmt(castRet));
} else {
units.add(j.newReturnStmt(ret));
}
} else {
units.add(j.newReturnVoidStmt());
}
}
use of soot.Type in project robovm by robovm.
the class TypeEncoder method getStructMembers.
private List<Member> getStructMembers(SootClass clazz, boolean is64bit) {
List<Member> members = new ArrayList<>();
if (clazz.hasSuperclass()) {
SootClass superclass = clazz.getSuperclass();
if (!superclass.getName().equals("org.robovm.rt.bro.Struct")) {
members.addAll(getStructMembers(clazz, is64bit));
}
}
for (SootMethod method : clazz.getMethods()) {
int offset = getStructMemberOffset(method);
if (offset != -1) {
if (!method.isNative() && !method.isStatic()) {
// thrown by the ClassCompiler later on.
continue;
}
Type type;
int idx;
if (method.getParameterCount() == 0) {
type = method.getReturnType();
idx = -1;
} else if (method.getParameterCount() == 1) {
type = method.getParameterType(0);
idx = 0;
} else {
// throw by the ClassCompiler later on.
continue;
}
Member member = new Member();
member.offset = offset;
member.type = encodeOne(method, type, idx, is64bit);
members.add(member);
}
}
return members;
}
Aggregations