// We generate the runtime debug method -memDebugStrongReferences. // This method will return an array of information about a strong reference, // including pointer to object and name. private void printStrongReferencesMethod(List<VariableDeclarationFragment> properties) { if (Options.memoryDebug()) { if (!Options.useReferenceCounting()) { println("- (NSArray *)memDebugStrongReferences {"); println(" return nil;"); println("}"); return; } println("- (NSArray *)memDebugStrongReferences {"); println(" NSMutableArray *result ="); println(" [[[super memDebugStrongReferences] mutableCopy] autorelease];"); for (VariableDeclarationFragment property : properties) { String propName = NameTable.getName(property.getName()); String objCFieldName = NameTable.javaFieldToObjC(propName); if (isStrongReferenceProperty(property)) { println( String.format( " [result addObject:[JreMemDebugStrongReference " + "strongReferenceWithObject:%s name:@\"%s\"]];", objCFieldName, propName)); } } println(" return result;"); println("}\n"); } }
public void testCombinedJarHeaderMapping() throws IOException { File outputHeaderMappingFile = new File(tempDir, "mappings.j2objc"); Options.setOutputHeaderMappingFile(outputHeaderMappingFile); Options.setOutputStyle(Options.OutputStyleOption.SOURCE); addSourceFile("package unit; public class Test { }", "unit/Test.java"); addSourceFile( "package unit; public class AnotherTest extends Test { }", "unit/AnotherTest.java"); addSourceFile( "package unit2;" + "import unit.Test;" + "public class AnotherTest extends Test { }", "unit2/AnotherTest.java"); addSourceFile( "package unit2;" + "import unit.AnotherTest;" + "public class YetAnotherTest extends AnotherTest { }", "unit2/YetAnotherTest.java"); translateCombinedFiles("unit/Foo", ".h", "unit/Test.java", "unit/AnotherTest.java"); String header2 = translateCombinedFiles( "unit2/Foo", ".h", "unit2/AnotherTest.java", "unit2/YetAnotherTest.java"); HeaderMap headerMap = Options.getHeaderMap(); assertEquals("unit/Foo.h", headerMap.get("unit.Test")); assertEquals("unit/Foo.h", headerMap.get("unit.AnotherTest")); assertTranslation(header2, "#include \"unit/Foo.h\""); assertEquals("unit2/Foo.h", headerMap.get("unit2.AnotherTest")); assertEquals("unit2/Foo.h", headerMap.get("unit2.YetAnotherTest")); }
private void printStaticInterface( AbstractTypeDeclaration node, String typeName, List<FieldDeclaration> fields, List<MethodDeclaration> methods) { List<IVariableBinding> staticFields = getStaticFieldsNeedingAccessors(fields, /* isInterface */ true); if (staticFields.isEmpty()) { if (!Options.stripReflection()) { printf("\n@interface %s : NSObject\n@end\n", typeName); } else { return; } } printf("\n@implementation %s\n\n", typeName); printStaticVars(fields, /* isInterface */ true); printStaticFieldAccessors(staticFields, methods); for (MethodDeclaration method : methods) { if (method.getBody() != null) { printNormalMethod(method); } } if (!Options.stripReflection()) { printMetadata(node); } println("@end"); }
public void testOutputHeaderFileMapping() throws IOException { Options.setHeaderMappingFiles(Lists.newArrayList("testMappings.j2objc")); Options.setOutputStyle(Options.OutputStyleOption.SOURCE); addSourceFile("package unit.test; public class Dummy {}", "unit/test/Dummy.java"); addSourceFile( "package unit.test;" + "public class AnotherDummy extends Dummy { " + " public AnotherDummy() {}" + "}", "unit/test/AnotherDummy.java"); preprocessFiles("unit/test/Dummy.java", "unit/test/AnotherDummy.java"); loadHeaderMappings(); String translation = translateSourceFile( getTranslatedFile("unit/test/AnotherDummy.java"), "AnotherDummy", "AnotherDummy.h"); assertTranslation(translation, "#include \"unit/test/Dummy.h\""); HeaderMap headerMap = Options.getHeaderMap(); assertEquals(headerMap.get("unit.test.Dummy"), "unit/test/Dummy.h"); assertEquals(headerMap.get("unit.test.AnotherDummy"), "unit/test/AnotherDummy.h"); assertEquals(headerMap.get("unit.mapping.custom.Test"), "my/mapping/custom/Test.h"); assertEquals(headerMap.get("unit.mapping.custom.AnotherTest"), "my/mapping/custom/Test.h"); }
public FileProcessor(JdtParser parser) { this.parser = Preconditions.checkNotNull(parser); if (Options.buildClosure()) { // Should be an error if the user specifies this with --build-closure assert !Options.shouldMapHeaders(); closureQueue = new BuildClosureQueue(); } else { closureQueue = null; } }
private String generateMethodBody(MethodDeclaration m) { String methodBody; if (Modifier.isNative(m.getModifiers())) { if (hasNativeCode(m, true)) { methodBody = extractNativeMethodBody(m); } else if (Options.generateNativeStubs()) { return generateNativeStub(m); } else { return null; } } else if (Modifier.isAbstract(m.getModifiers())) { // Generate a body which throws a NSInvalidArgumentException. String body = "{\n // can't call an abstract method\n " + "[self doesNotRecognizeSelector:_cmd];\n "; if (!Types.isVoidType(m.getReturnType2())) { body += "return 0;\n"; // Never executes, but avoids a gcc warning. } return body + "}"; } else { // generate a normal method body methodBody = generateStatement(m.getBody(), false); } boolean isStatic = (m.getModifiers() & Modifier.STATIC) != 0; boolean isSynchronized = (m.getModifiers() & Modifier.SYNCHRONIZED) != 0; if (isStatic && isSynchronized) { methodBody = "{\n@synchronized([self class]) {\n" + methodBody + "}\n}\n"; } else if (isSynchronized) { methodBody = "{\n@synchronized(self) {\n" + methodBody + "}\n}\n"; } return methodBody; }
public void testFullyQualifiedDeprecatedTypeNameTranslation() throws IOException { Options.enableDeprecatedDeclarations(); String translation = translateSourceFile( "public @java.lang.Deprecated class Example {}", "Example", "Example.h"); assertTranslation(translation, "__attribute__((deprecated))\n@interface Example "); }
@Override protected void generate(AnnotationTypeDeclaration node) { syncLineNumbers(node.getName()); // avoid doc-comment String typeName = NameTable.getFullName(node); printf("@implementation %s\n", typeName); if (BindingUtil.isRuntimeAnnotation(Types.getTypeBinding(node))) { List<AnnotationTypeMemberDeclaration> members = Lists.newArrayList(); for (BodyDeclaration decl : ASTUtil.getBodyDeclarations(node)) { if (decl instanceof AnnotationTypeMemberDeclaration) { members.add((AnnotationTypeMemberDeclaration) decl); } } printAnnotationProperties(members); if (!members.isEmpty()) { printAnnotationConstructor(Types.getTypeBinding(node)); } printAnnotationAccessors(members); } List<FieldDeclaration> fields = ASTUtil.getFieldDeclarations(node); List<IVariableBinding> fieldsNeedingAccessors = getStaticFieldsNeedingAccessors(fields, /* isInterface */ true); printStaticVars(fields, /* isInterface */ true); printStaticFieldAccessors(fieldsNeedingAccessors, Collections.<MethodDeclaration>emptyList()); println("- (IOSClass *)annotationType {"); printf(" return [IOSClass classWithProtocol:@protocol(%s)];\n", typeName); println("}\n"); if (!Options.stripReflection()) { printTypeAnnotationsMethod(node); printMetadata(node); } println("@end\n"); }
@Override public void generate(TypeDeclaration node) { syncLineNumbers(node.getName()); // avoid doc-comment String typeName = NameTable.getFullName(node); List<FieldDeclaration> fields = Lists.newArrayList(node.getFields()); List<MethodDeclaration> methods = Lists.newArrayList(node.getMethods()); fieldHiders = HiddenFieldDetector.getFieldNameConflicts(node); if (node.isInterface()) { printStaticInterface(node, typeName, fields, methods); } else { printf("@implementation %s\n\n", typeName); printStaticReferencesMethod(fields); printStaticVars(fields, /* isInterface */ false); printStaticFieldAccessors(fields, methods, /* isInterface */ false); printMethods(node); if (!Options.stripReflection()) { printTypeAnnotationsMethod(node); printMethodAnnotationMethods(Lists.newArrayList(node.getMethods())); printFieldAnnotationMethods(Lists.newArrayList(node.getFields())); printMetadata(node); } println("@end"); } }
public void testDeprecatedInterfaceTranslation() throws IOException { Options.enableDeprecatedDeclarations(); String translation = translateSourceFile( "package unit.test; public @Deprecated interface Example {}", "Example", "unit/test/Example.h"); assertTranslation(translation, "__attribute__((deprecated))\n@protocol UnitTestExample"); }
public void testInterfaceWithDeprecatedMethodTranslation() throws IOException { Options.enableDeprecatedDeclarations(); String translation = translateSourceFile( "package unit.test; public interface Example { @Deprecated Example getExample(); }", "Example", "unit/test/Example.h"); assertTranslation( translation, "- (id<UnitTestExample>)getExample __attribute__((deprecated));"); }
private void printAnnotations(List<Annotation> runtimeAnnotations) { boolean first = true; for (Annotation annotation : runtimeAnnotations) { if (first) { first = false; } else { print(", "); } if (Options.useReferenceCounting()) { print('['); } printf("[[%s alloc] init", NameTable.getFullName(Types.getTypeBinding(annotation))); printAnnotationParameters(annotation); print(']'); if (Options.useReferenceCounting()) { print(" autorelease]"); } } }
public void testAddIgnoreDeprecationWarningsPragmaIfDeprecatedDeclarationsIsEnabled() throws IOException { Options.enableDeprecatedDeclarations(); String sourceContent = "class Test {}"; String translation = translateSourceFile(sourceContent, "FooBar", "FooBar.h"); assertTranslation(translation, "#pragma clang diagnostic push"); assertTranslation(translation, "#pragma GCC diagnostic ignored \"-Wdeprecated-declarations\""); assertTranslation(translation, "#pragma clang diagnostic pop"); }
public void testNoHeaderMapping() throws IOException { // Should be able to turn off header mappings by passing empty collection Options.setHeaderMappingFiles(Collections.<String>emptyList()); addSourceFile("package unit.mapping; public class Test { }", "unit/mapping/Test.java"); loadHeaderMappings(); String translation = translateSourceFile( "import unit.mapping.Test; " + "public class MyTest extends Test { MyTest() {}}", "MyTest", "MyTest.h"); assertTranslation(translation, "#include \"unit/mapping/Test.h\""); }
public void testHeaderFileMapping() throws IOException { Options.setHeaderMappingFiles(Lists.newArrayList("testMappings.j2objc")); addSourceFile( "package unit.mapping.custom; public class Test { }", "unit/mapping/custom/Test.java"); loadHeaderMappings(); String translation = translateSourceFile( "import unit.mapping.custom.Test; " + "public class MyTest extends Test { MyTest() {}}", "MyTest", "MyTest.h"); assertTranslation(translation, "#include \"my/mapping/custom/Test.h\""); }
private Statement createReleaseStatement(IVariableBinding var) { if (Options.useARC()) { ITypeBinding voidType = typeEnv.resolveJavaType("void"); FunctionInvocation invocation = new FunctionInvocation("JreRelease", voidType, voidType, null); invocation.getArguments().add(new SimpleName(var)); return new ExpressionStatement(invocation); } else { return new ExpressionStatement( new MethodInvocation(typeEnv.getReleaseMethod(), new SimpleName(var))); } }
/** Verify fields are released in a dealloc for reference counted code. */ public void testFieldReleaseReferenceCounting() throws IOException { Options.setMemoryManagementOption(Options.MemoryManagementOption.REFERENCE_COUNTING); String translation = translateSourceFile("class Test { Object o; Runnable r; }", "Test", "Test.m"); assertTranslatedLines( translation, "- (void)dealloc {", "RELEASE_(o_);", "RELEASE_(r_);", "[super dealloc];", "}"); }
@Override protected void printStaticFieldSetter(IVariableBinding var) { String fieldName = NameTable.getStaticVarQualifiedName(var); String paramName = NameTable.getName(var); String signature = staticFieldSetterSignature(var); if (Options.useReferenceCounting()) { printf( "%s {\n JreOperatorRetainedAssign(&%s, nil, %s);\n}\n\n", signature, fieldName, paramName); } else { printf("%s {\n %s = %s;\n}\n\n", signature, fieldName, paramName); } }
// We generate the runtime debug method +memDebugStaticReferences. // This method will return an array of NSNumber containing pointers (casted into unsigned long) // to the objects referenced by a class variable with a strong reference. // It will be useful for debug purpose. // // Arrays returned by -memDebugStaticReferences and -memDebugStaticReferencesNames (see below) // must be the same size. // // In case of a Java enum, valuesVarNameis the name of the array of enum values. private void printStaticReferencesMethod(List<FieldDeclaration> fields, String valuesVarName) { if (Options.memoryDebug()) { if (!Options.useReferenceCounting()) { println("+ (NSArray *)memDebugStaticReferences {"); println(" return nil;"); println("}"); return; } println("+ (NSArray *)memDebugStaticReferences {"); println(" NSMutableArray *result = [NSMutableArray array];"); for (FieldDeclaration f : fields) { if (Modifier.isStatic(f.getModifiers())) { for (VariableDeclarationFragment var : ASTUtil.getFragments(f)) { IVariableBinding binding = Types.getVariableBinding(var); // All non-primitive static variables are strong references. if (!binding.getType().isPrimitive()) { String name = NameTable.getStaticVarQualifiedName(binding); println( String.format( " [result addObject:[JreMemDebugStrongReference " + "strongReferenceWithObject:%s name:@\"%s\"]];", name, name)); } } } } if (valuesVarName != null) { println( String.format( " [result addObject:[JreMemDebugStrongReference " + "strongReferenceWithObject:%s name:@\"enumValues\"]];", valuesVarName)); } println(" return result;"); println("}\n"); } }
/** Verify fields are not released for ARC code when a finalize() method is defined. */ public void testFieldReleaseFinalizeARC() throws IOException { Options.setMemoryManagementOption(Options.MemoryManagementOption.ARC); String translation = translateSourceFile( "class Test { Object o; Runnable r;" + "public void finalize() throws Throwable { System.out.println(this); }}", "Test", "Test.m"); assertTranslatedLines( translation, "- (void)dealloc {", "[((JavaIoPrintStream *) nil_chk(JreLoadStatic(JavaLangSystem, out_))) " + "printlnWithId:self];", "}"); }
@Override protected String constructorDeclaration(MethodDeclaration m) { String methodBody; IMethodBinding binding = Types.getMethodBinding(m); boolean memDebug = Options.memoryDebug(); List<Statement> statements = ASTUtil.getStatements(m.getBody()); if (binding.getDeclaringClass().isEnum()) { return enumConstructorDeclaration(m, statements, binding); } StringBuffer sb = new StringBuffer("{\n"); int constructorIdx = findConstructorInvocation(statements); int idx = 0; while (idx < constructorIdx) { sb.append(generateStatement(statements.get(idx++), false)); } String superCall = idx == constructorIdx ? generateStatement(statements.get(idx++), false) : "[super init]"; if (idx >= statements.size()) { sb.append("return "); if (memDebug) { sb.append("JreMemDebugAdd("); } sb.append(superCall).append(memDebug ? ");\n}" : ";\n}"); } else { sb.append("if (self = ").append(superCall).append(") {\n"); while (idx < statements.size()) { sb.append(generateStatement(statements.get(idx++), false)); } if (memDebug) { sb.append("JreMemDebugAdd(self);\n"); } sb.append("}\nreturn self;\n}"); } methodBody = sb.toString(); if (invokedConstructors.contains(methodKey(binding))) { return super.constructorDeclaration(m, true) + " " + reindent(methodBody) + "\n\n" + super.constructorDeclaration(m, false) + " {\n return " + generateStatement(createInnerConstructorInvocation(m), false) + ";\n}\n\n"; } else { return super.constructorDeclaration(m, false) + " " + reindent(methodBody) + "\n\n"; } }
private String enumConstructorDeclaration( MethodDeclaration m, List<Statement> statements, IMethodBinding binding) { assert !statements.isEmpty(); // The InitializationNormalizer should have fixed this constructor so the // first statement is a constructor or super invocation. Statement s = statements.get(0); assert s instanceof ConstructorInvocation || s instanceof SuperConstructorInvocation; String invocation = generateStatement(statements.get(0), false); StringBuffer sb = new StringBuffer(); boolean memDebug = Options.memoryDebug(); if (statements.size() == 1) { sb.append("{\nreturn "); if (memDebug) { sb.append("JreMemDebugAdd(" + invocation + ")"); } else { sb.append(invocation); } sb.append(";\n}"); } else { sb.append("{\nif ((self = "); sb.append(invocation); sb.append(")) {\n"); for (int i = 1; i < statements.size(); i++) { sb.append(generateStatement(statements.get(i), false)); } if (memDebug) { sb.append("JreMemDebugAdd(self);\n"); } sb.append("}\nreturn self;\n}"); } if (invokedConstructors.contains(methodKey(binding))) { return super.constructorDeclaration(m, true) + " " + reindent(sb.toString()) + "\n\n" + super.constructorDeclaration(m, false) + " {\n return " + generateStatement(createInnerConstructorInvocation(m), false) + ";\n}\n\n"; } else { return super.constructorDeclaration(m, false) + " " + reindent(sb.toString()) + "\n\n"; } }
@Override public void endVisit(CastExpression node) { ITypeBinding type = node.getType().getTypeBinding(); Expression expr = node.getExpression(); ITypeBinding exprType = expr.getTypeBinding(); // TODO(kirbs): Implement correct conversion of Java 8 intersection types to Objective-C. if (node.getType().isIntersectionType() && !Options.isJava8Translator()) { // Technically we can't currently get here, but as we add support and change flags in the // future this should alert us to implement intersection types. assert false : "not implemented yet"; } if (BindingUtil.isFloatingPoint(exprType)) { assert type.isPrimitive(); // Java wouldn't allow a cast from primitive to non-primitive. switch (type.getBinaryName().charAt(0)) { case 'J': node.replaceWith(rewriteFloatToIntegralCast(type, expr, "JreFpToLong", type)); return; case 'C': node.replaceWith(rewriteFloatToIntegralCast(type, expr, "JreFpToChar", type)); return; case 'B': case 'S': case 'I': node.replaceWith( rewriteFloatToIntegralCast(type, expr, "JreFpToInt", typeEnv.resolveJavaType("int"))); return; } // else fall-through. } // Lean on Java's type-checking. if (!type.isPrimitive() && exprType.isAssignmentCompatible(type.getErasure())) { node.replaceWith(TreeUtil.remove(expr)); return; } FunctionInvocation castCheck = createCastCheck(type, expr); if (castCheck != null) { node.setExpression(castCheck); } }
// Verify that inherited constructors are disallowed. Exception has four constructors, // so a subclass that only implements one should have the other three disallowed. public void testConstructorsDisallowed() throws IOException { Options.setDisallowInheritedConstructors(true); String translation = translateSourceFile( "class Test extends Exception { Test(String s) { super(s); } }", "Test", "Test.h"); assertTranslation(translation, "- (instancetype)initWithNSString:(NSString *)s;"); assertTranslation(translation, "- (instancetype)init NS_UNAVAILABLE;"); assertTranslation( translation, "- (instancetype)initWithJavaLangThrowable:(JavaLangThrowable *)arg0 NS_UNAVAILABLE;"); assertTranslatedLines( translation, "- (instancetype)initWithNSString:(NSString *)arg0", "withJavaLangThrowable:(JavaLangThrowable *)arg1 NS_UNAVAILABLE;"); assertTranslatedLines( translation, "- (instancetype)initWithNSString:(NSString *)arg0", "withJavaLangThrowable:(JavaLangThrowable *)arg1", "withBoolean:(jboolean)arg2", "withBoolean:(jboolean)arg3 NS_UNAVAILABLE;"); }
public void testAcceptJsniDelimiters() throws IOException { String source = "class Example { " + " native void test1() /*-[ ocni(); ]-*/; " + " native void test2() /*-{ jsni(); }-*/; " + "}"; // First test with defaults, JSNI should be accepted. String translation = translateSourceFile(source, "Example", "Example.m"); assertTranslation(translation, "ocni();"); assertTranslation(translation, "jsni();"); // Now rebuild with option set. Options.setAcceptJsniDelimiters(false); translation = translateSourceFile(source, "Example", "Example.h"); // Verify JSNI method is declared in a native methods category, // and not implemented. assertTranslation(translation, "@interface Example (NativeMethods)\n- (void)test2"); translation = getTranslatedFile("Example.m"); assertTranslation(translation, "ocni();"); assertFalse(translation.contains("jsni();")); }
/** * Class for processing GenerationUnits in minimum increments of one GenerationUnit. * * @author Tom Ball, Keith Stanger, Mike Thvedt */ abstract class FileProcessor { private static final Logger logger = Logger.getLogger(FileProcessor.class.getName()); private final JdtParser parser; protected final BuildClosureQueue closureQueue; private final NameTable.Factory nameTableFactory = NameTable.newFactory(); private final int batchSize = Options.batchTranslateMaximum(); private final Set<ProcessingContext> batchInputs = Sets.newLinkedHashSetWithExpectedSize(batchSize); private final boolean doBatching = batchSize > 0; public FileProcessor(JdtParser parser) { this.parser = Preconditions.checkNotNull(parser); if (Options.buildClosure()) { // Should be an error if the user specifies this with --build-closure assert !Options.shouldMapHeaders(); closureQueue = new BuildClosureQueue(); } else { closureQueue = null; } } public void processInputs(Iterable<ProcessingContext> inputs) { for (ProcessingContext input : inputs) { processInput(input); } processBatch(); } public void processBuildClosureDependencies() { if (closureQueue != null) { while (true) { InputFile file = closureQueue.getNextFile(); if (file == null) { processBatch(); file = closureQueue.getNextFile(); } if (file == null) { break; } processInput(ProcessingContext.fromFile(file)); } } } private void processInput(ProcessingContext input) { InputFile file = input.getFile(); if (isBatchable(file)) { batchInputs.add(input); if (batchInputs.size() == batchSize) { processBatch(); } return; } logger.finest("parsing " + file); String source = null; CompilationUnit compilationUnit = null; try { source = FileUtil.readFile(file); compilationUnit = parser.parseWithBindings(file.getUnitName(), source); } catch (IOException e) { ErrorUtil.error(e.getMessage()); } if (compilationUnit == null) { handleError(input); return; } processCompiledSource(input, source, compilationUnit); } protected boolean isBatchable(InputFile file) { return doBatching && file.getContainingPath().endsWith(".java"); } private void processBatch() { if (batchInputs.isEmpty()) { return; } List<String> paths = Lists.newArrayListWithCapacity(batchInputs.size()); final Map<String, ProcessingContext> inputMap = Maps.newHashMapWithExpectedSize(batchInputs.size()); for (ProcessingContext input : batchInputs) { String path = input.getFile().getPath(); paths.add(path); inputMap.put(path, input); } JdtParser.Handler handler = new JdtParser.Handler() { @Override public void handleParsedUnit(String path, CompilationUnit unit) { ProcessingContext input = inputMap.get(path); try { String source = FileUtil.readFile(input.getFile()); processCompiledSource(input, source, unit); batchInputs.remove(input); } catch (IOException e) { ErrorUtil.error(e.getMessage()); } } }; logger.finest("Processing batch of size " + batchInputs.size()); parser.parseFiles(paths, handler); // Any remaining files in batchFiles has some kind of error. for (ProcessingContext input : batchInputs) { handleError(input); } batchInputs.clear(); } private void processCompiledSource(ProcessingContext input, String source, CompilationUnit unit) { InputFile file = input.getFile(); if (closureQueue != null) { closureQueue.addProcessedName(FileUtil.getQualifiedMainTypeName(file, unit)); } com.google.devtools.j2objc.ast.CompilationUnit convertedUnit = TreeConverter.convertCompilationUnit( unit, input.getOriginalSourcePath(), FileUtil.getMainTypeName(file), source, nameTableFactory); processConvertedTree(input, convertedUnit); } protected abstract void processConvertedTree( ProcessingContext input, com.google.devtools.j2objc.ast.CompilationUnit unit); protected abstract void handleError(ProcessingContext input); }
/** Verify fields are not released for ARC code, and a dealloc method is not created. */ public void testFieldReleaseARC() throws IOException { Options.setMemoryManagementOption(Options.MemoryManagementOption.ARC); String translation = translateSourceFile("class Test { Object o; Runnable r; }", "Test", "Test.m"); assertNotInTranslation(translation, "dealloc"); }
// Verify that the default constructor is disallowed if the class has a non-default // constructor. public void testDefaultConstructorDisallowed() throws IOException { Options.setDisallowInheritedConstructors(true); String translation = translateSourceFile("class Test { Test(int i) {} }", "Test", "Test.h"); assertTranslation(translation, "- (instancetype)initWithInt:(jint)i;"); assertTranslation(translation, "- (instancetype)init NS_UNAVAILABLE;"); }
public void testDeprecatedEnumType() throws IOException { Options.enableDeprecatedDeclarations(); String translation = translateSourceFile("@Deprecated public enum Test { A, B }", "Test", "Test.h"); assertTranslation(translation, "__attribute__((deprecated))\n@interface TestEnum"); }
@Override protected void tearDown() throws Exception { Options.resetFinalMethodsAsFunctions(); super.tearDown(); }