diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index f505aabf153a25de8cd71f194005437a89eb6497..d3e79c671c67662d49142da47031f4835d58cdbb 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -42,14 +42,14 @@ public class JavaTransformer extends ASTVisitor implements Transformer { private ParserRuleContext stsCurrent; private final Stack stsSaved = new Stack<>(); + private final Stack stsCurrentTrapStatement = new Stack<>(); private final String INSTANCE_INITIALIZER = "INSTANCE_INITIALIZER"; - private final String USED_IN_ANOTHER_CASE_CLAUSE = "USED_IN_ANOTHER_CASE_CLAUSE"; - private final String ENUM_TYPE_NAME = "ENUM_TYPE_NAME"; - private final String ENUM_CONST_ORDINAL = "ENUM_CONST_ORDINAL"; + private final String RUNTIME_EXCEPTION_TYPE_NAME = "java.lang.RuntimeException"; + private final String THROWABLE_TYPE_NAME = "java.lang.Throwable"; private final String METHOD_REF_PARAM_PREFIX = "__migrator_lambda_param_"; @@ -100,6 +100,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return (normFactor > 0) ? result / (double)normFactor : 0.; } + private TrapStatementContext getCurrentTrap() { return stsCurrentTrapStatement.isEmpty() ? null : stsCurrentTrapStatement.peek(); } + /** * Push node onto stack and add it to the children of * the current top node. @@ -129,8 +131,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } private void pushStatement(ParserRuleContext stsStatement) { - if (stsCurrent.getRuleIndex() == StaticTSParser.RULE_block - || stsCurrent.getRuleIndex() == StaticTSParser.RULE_constructorBody) + if (NodeBuilder.needStatementOrLocalDeclaration(stsCurrent)) pushCurrent(new StatementOrLocalDeclarationContext(stsCurrent, 0)); pushCurrent(new StatementContext(stsCurrent, 0)); @@ -171,8 +172,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { this.javaCU = javaCU; this.srcFile = srcFile; AST javaAST = this.javaCU.getAST(); - RUNTIME_EXCEPTION_TYPE = javaAST.resolveWellKnownType("java.lang.RuntimeException"); - THROWABLE_TYPE = javaAST.resolveWellKnownType("java.lang.Throwable"); + RUNTIME_EXCEPTION_TYPE = javaAST.resolveWellKnownType(RUNTIME_EXCEPTION_TYPE_NAME); + THROWABLE_TYPE = javaAST.resolveWellKnownType(THROWABLE_TYPE_NAME); } public CompilationUnitContext transform() { @@ -310,6 +311,10 @@ public class JavaTransformer extends ASTVisitor implements Transformer { for (CatchClause catchClause : catches) catchClause.accept(this); + List resources = node.resources(); + for (Expression resource : resources) + resource.accept(this); + return false; } @@ -4021,8 +4026,14 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // Java AST: // TryStatement: - // try Block Catches - // try Block [Catches] Finally + // try [ ( Resource { ; Resource } ) ] + // Block + // [ { CatchClause } ] + // [ finally Block ] + // Resource: + // VariableDeclarationExpression | Name + // CatchClause: + // catch ( FormalParameter ) Block // // STS AST: // trapStatement @@ -4062,11 +4073,33 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popStatement(); // DeferStatementContext } + int resCount = processTryResources(javaTryStatement.resources()); + + // If try statement is parametrized with resources, then try block + // executes only after all resources are initialized successfully. + // To conform to this condition, translate try block in the context + // of trap statement generated for the last resource. + TrapStatementContext stsResourceTrapStmt = getCurrentTrap(); + if (resCount > 0) { + if(stsResourceTrapStmt == null) { + // No trap statements were generated for resources. Warn and + // translate the try-block in the context of this try statement. + reportError("Failed to process resources correctly", javaTryStatement); + } + else { + pushCurrent(stsResourceTrapStmt.block(), false); + } + } + // NOTE: Can't call javaTryBlock.accept as that will // emit StatementContext which we don't need here Block javaTryBlock = javaTryStatement.getBody(); translateBlockStatements(javaTryBlock); + if (resCount > 0 && stsResourceTrapStmt != null) { + popCurrent(); // stsResourceTrapStmt.block() + } + if (!javaCatchClauses.isEmpty()) { popCurrent(); // BlockContext } @@ -4096,6 +4129,12 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popStatement(); // TrapStatementContext } + // Remove generated trap statements from the stack. + while (resCount > 0) { + stsCurrentTrapStatement.pop(); + --resCount; + } + stmtTransformed.add(javaTryStatement); return false; } @@ -4144,12 +4183,268 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return javaExcType != null && !javaExcType.isRecovered() && javaExcType.isClass() && (javaExcType.isEqualTo(THROWABLE_TYPE) || javaExcType.isSubTypeCompatible(THROWABLE_TYPE)); } + + private int processTryResources(List javaResources) { + // Generate trap statement for each resource. Each trap statement + // will contain the trap statement for the next resource, or block + // of the original try statement. + int resCounter = 0; + + for (Expression javaResExpr : javaResources) { + if (javaResExpr.getNodeType() == ASTNode.VARIABLE_DECLARATION_EXPRESSION) { + VariableDeclarationExpression javaVarDeclExpr = (VariableDeclarationExpression) javaResExpr; + List javaResDeclList = javaVarDeclExpr.fragments(); + for (VariableDeclarationFragment javaResDecl : javaResDeclList) { + TrapStatementContext stsResourceTrapStmt = getCurrentTrap(); + if (resCounter > 0) { + if(stsResourceTrapStmt == null) { + // Emit untranslated_try_resource code, warn and bail out. + stsCurrent.addChild(NodeBuilder.untranslatedTryResource(javaResExpr, stsCurrent)).setParent(stsCurrent); + reportError("No enclosing trap statement for resource", javaResExpr); + continue; + } + else { + pushCurrent(stsResourceTrapStmt.block(), false); + } + } + + // Translate resource variable declaration. It should always be declared final. + int javaResVarMods = javaVarDeclExpr.getModifiers() | Modifier.FINAL; + ArrayList javaDeclFragmentList = new ArrayList<>(); + javaDeclFragmentList.add(javaResDecl); + pushStatement(new VariableOrConstantDeclarationContext(stsCurrent, 0)); + createAndFillVarOrConstDeclarationList(javaResVarMods, javaDeclFragmentList, javaVarDeclExpr.getType()); + popStatement(); // VariableOrConstantDeclarationContext + + emitTrapStmtForResourceAllocation(javaResDecl.getName()); + + if (resCounter > 0 && stsResourceTrapStmt != null) { + popCurrent(); // stsResourceTrapStmt.block() + } + + ++resCounter; + } + + exprTransformed.add(javaResExpr); + } + else { + // Resource expression is either variable access or field access. + + // NOTE: Currently, one case (try(this) { .. }) doesn't work properly due to + // bug in eclipse JDT: https://bugs.eclipse.org/bugs/show_bug.cgi?id=577128 + // This problem is present in the version of library that we are currently + // restricted to use in migrator. Once this restriction is removed, we will + // update the library to more recent version, that contains fix for that bug. + + TrapStatementContext stsResourceTrapStmt = getCurrentTrap(); + if (resCounter > 0) { + if(stsResourceTrapStmt == null) { + // Emit untranslated_try_resource code, warn and bail out. + stsCurrent.addChild(NodeBuilder.untranslatedTryResource(javaResExpr, stsCurrent)).setParent(stsCurrent); + reportError("No enclosing trap statement for resource", javaResExpr); + continue; + } + else { + pushCurrent(stsResourceTrapStmt.block(), false); + } + } + + emitTrapStmtForResourceAllocation(javaResExpr); + + if (resCounter > 0 && stsResourceTrapStmt != null) { + popCurrent(); // stsResourceTrapStmt.block() + } + + ++resCounter; + } + } + + return resCounter; + } + + private void emitTrapStmtForResourceAllocation(Expression javaResourceName) { + // The code for resource is emitted according to the Java specification: + // https://docs.oracle.com/javase/specs/jls/se9/html/jls-14.html#jls-14.20.3.1 + + // Throwable #primaryExc = null; + String primaryExceptionVarName = "primaryExc_res" + stsCurrentTrapStatement.size(); + pushStatement(new VariableOrConstantDeclarationContext(stsCurrent, 0)); + pushCurrent(createVarOrConstDeclarationList(0)); + pushCurrent(createVarOrConstDeclaration(0)); + stsCurrent.addChild(NodeBuilder.terminalIdentifier(primaryExceptionVarName)); + stsCurrent.addChild(NodeBuilder.typeAnnotation("Throwable")).setParent(stsCurrent); + pushCurrent(new InitializerContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.nullLiteral()).setParent(stsCurrent); + popCurrent(); // InitializerContext + popCurrent(); // VarOrConstDeclaration + popCurrent(); // VarOrConstDeclarationListContext + popStatement(); // VariableOrConstantDeclarationContext + + TrapStatementContext stsTrapStmt = new TrapStatementContext(stsCurrent, 0); + pushStatement(stsTrapStmt); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Trap)); + pushCurrent(new BlockContext(stsCurrent, 0)); + + // defer { [if-stmt for resource disposal] } + pushStatement(new DeferStatementContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Defer)); + + // if (Identifier != null) { .. } + IfStatementContext stsIfStmt = new IfStatementContext(stsCurrent, 0); + pushStatement(stsIfStmt); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.If)); + pushCurrent(new EqualityExpressionContext(pushSingleExpression())); + javaResourceName.accept(this); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.NotEquals)); + stsCurrent.addChild(NodeBuilder.nullLiteral()).setParent(stsCurrent); + popSingleExpression(); // EqualityExpressionContext + pushStatement(new BlockContext(stsCurrent, 0)); + + // if (#primaryExc != null) { .. } + IfStatementContext stsInnerIfStmt = new IfStatementContext(stsCurrent, 0); + pushStatement(stsInnerIfStmt); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.If)); + pushCurrent(new EqualityExpressionContext(pushSingleExpression())); + stsCurrent.addChild(NodeBuilder.identifierExpression(primaryExceptionVarName)).setParent(stsCurrent); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.NotEquals)); + stsCurrent.addChild(NodeBuilder.nullLiteral()).setParent(stsCurrent); + popSingleExpression(); // EqualityExpressionContext + + // Trap statement for resource disposal + pushStatement(new BlockContext(stsCurrent, 0)); + emitTrapStmtForResourceDisposal(javaResourceName, primaryExceptionVarName); + popStatement(); // BlockContext + + ParseTree lastChild = stsCurrent.getChild(stsCurrent.getChildCount() - 1); + assert(lastChild instanceof StatementContext); + stsInnerIfStmt.ifStmt = (StatementContext)lastChild; + + // else { Identifier.close(); } + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Else)); + pushStatement(new BlockContext(stsCurrent, 0)); + pushStatement(new ExpressionStatementContext(stsCurrent, 0)); + pushCurrent(new TryExpressionContext(pushSingleExpression())); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); + pushCurrent(new CallExpressionContext(pushSingleExpression())); + pushCurrent(new MemberAccessExpressionContext(pushSingleExpression())); + javaResourceName.accept(this); + stsCurrent.addChild(NodeBuilder.terminalIdentifier("close")); + popSingleExpression(); // MemberAccessExpressionContext + pushCurrent(new ArgumentsContext(stsCurrent, 0)); + popCurrent(); // ArgumentsContext + popSingleExpression(); // CallExpressionContext + popSingleExpression(); // TryExpressionContext + popStatement(); // ExpressionStatementContext + popStatement(); // BlockContext + + lastChild = stsCurrent.getChild(stsCurrent.getChildCount() - 1); + assert(lastChild instanceof StatementContext); + stsInnerIfStmt.elseStmt = (StatementContext)lastChild; + popStatement(); // IfStatementContext + popStatement(); // BlockContext + + lastChild = stsCurrent.getChild(stsCurrent.getChildCount() - 1); + assert(lastChild instanceof StatementContext); + stsIfStmt.ifStmt = (StatementContext)lastChild; + popStatement(); // IfStatementContext + + popStatement(); // DeferStatementContext + popCurrent(); // BlockContext + emitCatchOrRecoverClauseForResourceAllocation(primaryExceptionVarName, true); + emitCatchOrRecoverClauseForResourceAllocation(primaryExceptionVarName, false); + popStatement(); // TrapStatementContext + + stsCurrentTrapStatement.push(stsTrapStmt); + } + + private void emitCatchOrRecoverClauseForResourceAllocation(String primaryExceptionVarName, boolean isCatchClause) { + // catch (Throwable #t) { + // #primaryExc = #t; + // throw #t; + // } + pushCurrent(new CatchOrRecoverClauseContext(stsCurrent, 0)); + int termCode = isCatchClause ? StaticTSParser.Catch : StaticTSParser.Recover; + stsCurrent.addChild(NodeBuilder.terminalNode(termCode)); + pushCurrent(new ExceptionParameterContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalIdentifier("t")); + stsCurrent.addChild(NodeBuilder.typeAnnotation("Throwable")).setParent(stsCurrent); + popCurrent(); // ExceptionParameterContext + pushCurrent(new BlockContext(stsCurrent, 0)); + + pushStatement(new ExpressionStatementContext(stsCurrent, 0)); + pushCurrent(new AssignmentExpressionContext(pushSingleExpression())); + stsCurrent.addChild(NodeBuilder.identifierExpression(primaryExceptionVarName)).setParent(stsCurrent); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Assign)); + stsCurrent.addChild(NodeBuilder.identifierExpression("t")).setParent(stsCurrent); + popSingleExpression(); // AssignmentExpressionContext + popStatement(); // ExpressionStatementContext + + pushStatement(new ThrowStatementContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Throw)); + stsCurrent.addChild(NodeBuilder.identifierExpression("t")).setParent(stsCurrent); + popStatement(); // ThrowStatementContext + + popCurrent(); // BlockContext + popCurrent(); // CatchOrRecoverClauseContext + } + private void emitTrapStmtForResourceDisposal(Expression javaResourceName, String primaryExceptionVarName) { + // try { #resource.close(); } catch {..} + pushStatement(new TrapStatementContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Trap)); + pushCurrent(new BlockContext(stsCurrent, 0)); + pushStatement(new ExpressionStatementContext(stsCurrent, 0)); + pushCurrent(new TryExpressionContext(pushSingleExpression())); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); + pushCurrent(new CallExpressionContext(pushSingleExpression())); + pushCurrent(new MemberAccessExpressionContext(pushSingleExpression())); + javaResourceName.accept(this); + stsCurrent.addChild(NodeBuilder.terminalIdentifier("close")); + popSingleExpression(); // MemberAccessExpressionContext + pushCurrent(new ArgumentsContext(stsCurrent, 0)); + popCurrent(); // ArgumentsContext + popSingleExpression(); // CallExpressionContext + popSingleExpression(); // TryExpressionContext + popStatement(); // ExpressionStatementContext + popCurrent(); // BlockContext + emitCatchOrRecoverClauseForResourceDisposal(primaryExceptionVarName, true); + emitCatchOrRecoverClauseForResourceDisposal(primaryExceptionVarName, false); + popStatement(); // TrapStatementContext + } + + private void emitCatchOrRecoverClauseForResourceDisposal(String primaryExceptionVarName, boolean isCatchClause) { + // catch (Throwable #suppressedExc) { #primaryExc.addSuppressed(#suppressedExc); } + pushCurrent(new CatchOrRecoverClauseContext(stsCurrent, 0)); + int termCode = isCatchClause ? StaticTSParser.Catch : StaticTSParser.Recover; + stsCurrent.addChild(NodeBuilder.terminalNode(termCode)); + pushCurrent(new ExceptionParameterContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalIdentifier("suppressedExc")); + stsCurrent.addChild(NodeBuilder.typeAnnotation("Throwable")).setParent(stsCurrent); + popCurrent(); // ExceptionParameterContext + + pushCurrent(new BlockContext(stsCurrent, 0)); + pushStatement(new ExpressionStatementContext(null, 0)); + pushCurrent(new CallExpressionContext(pushSingleExpression())); + pushCurrent(new MemberAccessExpressionContext(pushSingleExpression())); + stsCurrent.addChild(NodeBuilder.identifierExpression(primaryExceptionVarName)).setParent(stsCurrent); + stsCurrent.addChild(NodeBuilder.terminalIdentifier("addSuppressed")); + popSingleExpression(); // MemberAccessExpressionContext + pushCurrent(new ArgumentsContext(stsCurrent, 0)); + pushCurrent(new ExpressionSequenceContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.identifierExpression("suppressedExc")).setParent(stsCurrent); + popCurrent(); // ExpressionSequenceContext + popCurrent(); // ArgumentsContext + popSingleExpression(); // CallExpressionContext + popStatement(); // ExpressionStatementContext + popCurrent(); // BlockContext + popCurrent(); // CatchOrRecoverClauseContext + } + @Override public boolean visit(ThrowStatement javaThrowStatement) { // TODO: To be implemented // Emit __untranslated_statement call with commented-out original syntax as argument for now. // This is done to avoid building invalid STS AST which causes exceptions in StaticTSWriter. - stsCurrent.addChild(NodeBuilder.untranslatedStatement(javaThrowStatement)).setParent(stsCurrent); + stsCurrent.addChild(NodeBuilder.untranslatedStatement(javaThrowStatement, stsCurrent)).setParent(stsCurrent); return false; } @@ -4236,7 +4531,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { @Override public boolean visit(YieldStatement javaYieldStatement) { // Emit __untranslatedStatement call, warn and continue. - stsCurrent.addChild(NodeBuilder.untranslatedStatement(javaYieldStatement)).setParent(stsCurrent); + stsCurrent.addChild(NodeBuilder.untranslatedStatement(javaYieldStatement, stsCurrent)).setParent(stsCurrent); reportError("Unsupported Java syntax (yield statement)", javaYieldStatement); return false; } diff --git a/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java b/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java index 70d6744d499eb70f0f85f37a78eed23b16498ed0..f5d173cb9a9f6ee313f3cb794873cd474d6ad145 100644 --- a/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java +++ b/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java @@ -395,22 +395,6 @@ public class NodeBuilder { return stsSuperCtorCall; } - public static SingleExpressionContext untranslatedExpression(ASTNode node) { - SingleExpressionContext stsExpression = new SingleExpressionContext(null, 0); - CallExpressionContext stsCallExpression = new CallExpressionContext(stsExpression); - stsExpression.addChild(stsCallExpression).setParent(stsExpression); - - SingleExpressionContext stsIdentifier = identifierExpression("__untranslated_expression"); - stsCallExpression.addChild(stsIdentifier).setParent(stsCallExpression); - - ArgumentsContext stsArguments = new ArgumentsContext(stsCallExpression, 0); - stsCallExpression.addChild(stsArguments).setParent(stsCallExpression); - - stsArguments.addChild(multiLineComment("/*" + node.toString() + "*/")); - - return stsExpression; - } - public static TypeAnnotationContext unknownTypeAnnotation() { return typeAnnotation("__UnknownType__"); } @@ -435,12 +419,57 @@ public class NodeBuilder { return stsTypeAnnotation; } - public static StatementContext untranslatedStatement(ASTNode node) { + private static SingleExpressionContext dummyCall(String callName, String comment) { + SingleExpressionContext stsExpression = new SingleExpressionContext(null, 0); + CallExpressionContext stsCallExpression = new CallExpressionContext(stsExpression); + stsExpression.addChild(stsCallExpression).setParent(stsExpression); + + SingleExpressionContext stsIdentifier = identifierExpression(callName); + stsCallExpression.addChild(stsIdentifier).setParent(stsCallExpression); + + ArgumentsContext stsArguments = new ArgumentsContext(stsCallExpression, 0); + stsCallExpression.addChild(stsArguments).setParent(stsCallExpression); + + stsArguments.addChild(multiLineComment("/* " + comment + " */")); + + return stsExpression; + } + + public static SingleExpressionContext untranslatedExpression(ASTNode node) { + return dummyCall("__untranslated_expression", node.toString()); + } + + public static boolean needStatementOrLocalDeclaration(ParserRuleContext stsContext) { + return stsContext.getRuleIndex() == StaticTSParser.RULE_block + || stsContext.getRuleIndex() == StaticTSParser.RULE_constructorBody; + } + + public static ParserRuleContext untranslatedStatement(ASTNode node, ParserRuleContext stsContext) { + StatementContext stsStatement = new StatementContext(null, 0); + ExpressionStatementContext stsExprStatement = new ExpressionStatementContext(stsStatement, 0); + stsStatement.addChild(stsExprStatement); + stsExprStatement.addChild(dummyCall("__untranslated_statement", node.toString())).setParent(stsExprStatement); + + if (needStatementOrLocalDeclaration(stsContext)) { + StatementOrLocalDeclarationContext stsStmtOrLocalDecl = new StatementOrLocalDeclarationContext(null, 0); + stsStmtOrLocalDecl.addChild(stsStatement).setParent(stsStmtOrLocalDecl); + return stsStmtOrLocalDecl; + } + + return stsStatement; + } + + public static ParserRuleContext untranslatedTryResource(ASTNode node, ParserRuleContext stsContext) { StatementContext stsStatement = new StatementContext(null, 0); ExpressionStatementContext stsExprStatement = new ExpressionStatementContext(stsStatement, 0); - stsStatement.addChild(stsExprStatement).setParent(stsStatement); + stsStatement.addChild(stsExprStatement); + stsExprStatement.addChild(dummyCall("__untranslated_try_resource", node.toString())).setParent(stsExprStatement); - stsExprStatement.addChild(untranslatedExpression(node)).setParent(stsExprStatement); + if (needStatementOrLocalDeclaration(stsContext)) { + StatementOrLocalDeclarationContext stsStmtOrLocalDecl = new StatementOrLocalDeclarationContext(null, 0); + stsStmtOrLocalDecl.addChild(stsStatement).setParent(stsStmtOrLocalDecl); + return stsStmtOrLocalDecl; + } return stsStatement; } diff --git a/migrator/test/java/method_invocation.java.sts b/migrator/test/java/method_invocation.java.sts index b7b1808fb2cef72361fb6a925390702eb0c3fea5..2b2b6899f58d7e423e30226f323e547b96a81858 100644 --- a/migrator/test/java/method_invocation.java.sts +++ b/migrator/test/java/method_invocation.java.sts @@ -23,6 +23,8 @@ open class SuperClass { open class SubClass1 extends SuperClass { override foo(): void { + __untranslated_statement(/* throw new UnsupportedOperationException(); + */); } tweak : Runnable = new Runnable() { public override run(): void { @@ -39,6 +41,8 @@ interface SuperInterface { open class SubClass2 implements SuperInterface { public override foo(): void { + __untranslated_statement(/* throw new UnsupportedOperationException(); + */); } open tweak(): void { SuperInterface.super.foo(); @@ -47,6 +51,8 @@ open class SubClass2 implements SuperInterface { open class SubClass3 implements SuperInterface { public override foo(): void { + __untranslated_statement(/* throw new UnsupportedOperationException(); + */); } tweak : Runnable = new Runnable() { public override run(): void { @@ -109,3 +115,4 @@ open class Test3 { let cp : ColoredPoint2 = new ColoredPoint2(); } } + \ No newline at end of file diff --git a/migrator/test/java/try_with_resources.java b/migrator/test/java/try_with_resources.java new file mode 100644 index 0000000000000000000000000000000000000000..f2f336d5d5dc5aabb3c81761b3dcc0ca8e4854ee --- /dev/null +++ b/migrator/test/java/try_with_resources.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.migrator.test.java; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; +import java.sql.SQLException; +import java.util.Scanner; + +class TryWithResources { + + // Basic try-with-resources (no catch/finally blocks) + void readFile() throws IOException { + String line = ""; + String path = ""; + try (FileReader fr = new FileReader(path); + BufferedReader br = new BufferedReader(fr)) { + line = br.readLine(); + } + } + + // with catch block + void viewTable(Connection con) throws SQLException { + String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES"; + + try (Statement stmt = con.createStatement()) { + ResultSet rs = stmt.executeQuery(query); + + while (rs.next()) { + System.out.println(rs.getString("COF_NAME") + ", " + rs.getInt("SUP_ID") + ", " + + rs.getFloat("PRICE") + ", " + rs.getInt("SALES") + ", " + rs.getInt("TOTAL")); + } + } catch (SQLException e) { + System.err.println("SQLState: " + e.getSQLState()); + System.err.println("Error Code: " + e.getErrorCode()); + System.err.println("Message: " + e.getMessage()); + } + } + + // with finally block + void readFile2() throws IOException { + String line = ""; + String path = ""; + try (FileReader fr = new FileReader(path); + BufferedReader br = new BufferedReader(fr)) { + line = br.readLine(); + } finally { + System.out.println("Successful!"); + } + } + + // with catch and finally block + void scanFile() { + try (Scanner scanner = new java.util.Scanner(new File("test.txt"))) { + while (scanner.hasNext()) { + System.out.println(scanner.nextLine()); + } + } catch (FileNotFoundException fnfe) { + fnfe.printStackTrace(); + } finally { + System.out.println("Successful!"); + } + } + + // Resource is variable access + void writeFile() { + try { + final Scanner scanner = new Scanner(new File("testRead.txt")); + PrintWriter writer = new PrintWriter(new File("testWrite.txt")); + + try (scanner; writer) { + while (scanner.hasNext()) { + String line = scanner.nextLine(); + writer.println(line); + } + } + } catch (Exception ex) { + System.err.println(ex.getMessage()); + } + } + + // Resource is field access + class Z { + public final Y yz = new Y(); + } + public class X extends Z { + final Y y2 = new Y(); + + public void foo() { + Z z = new Z(); + + try (this.y2; super.yz) { + try (z.yz) { + System.out.println(this.y2.val + super.yz.val + z.yz.val); + } + } catch (IOException e) { + System.err.println(e.getMessage()); + } + } + } + class Y implements AutoCloseable { + public int val = 10; + + @Override + public void close() throws IOException { + if (val < 0) { + throw new IOException("Invalid value: " + val); + } + + System.out.println("Closed"); + } + +// Currently, "try(this)" case doesn't work properly due to bug +// in Eclipse JDT library: +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=577128 +// The bug is present in the version of library that the migrator +// is currently restricted to use. +// Uncomment this case, when the library is updated to newer version. +// +// private void bar() { +// try (this) { +// System.out.println("In Try"); +// } catch (IOException e) { +// System.err.println(e.getMessage()); +// } +// } + } +} \ No newline at end of file diff --git a/migrator/test/java/try_with_resources.java.sts b/migrator/test/java/try_with_resources.java.sts new file mode 100644 index 0000000000000000000000000000000000000000..6d0f35cd6b6ddb69e4496f3bab7ca6e5b848d620 --- /dev/null +++ b/migrator/test/java/try_with_resources.java.sts @@ -0,0 +1,451 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ohos.migrator.test.java; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; +import java.sql.SQLException; +import java.util.Scanner; +open class TryWithResources { + open readFile(): void { + let line : String = ""; + let path : String = ""; + { + const fr : FileReader = try new FileReader(path); + let primaryExc_res0 : Throwable = null; + trap { + defer if (fr != null) { + if (primaryExc_res0 != null) { + trap { + try fr.close(); + } + catch (suppressedExc : Throwable) { + primaryExc_res0.addSuppressed(suppressedExc); + } + recover (suppressedExc : Throwable) { + primaryExc_res0.addSuppressed(suppressedExc); + } + + } + else { + try fr.close(); + } + } + const br : BufferedReader = new BufferedReader(fr); + let primaryExc_res1 : Throwable = null; + trap { + defer if (br != null) { + if (primaryExc_res1 != null) { + trap { + try br.close(); + } + catch (suppressedExc : Throwable) { + primaryExc_res1.addSuppressed(suppressedExc); + } + recover (suppressedExc : Throwable) { + primaryExc_res1.addSuppressed(suppressedExc); + } + + } + else { + try br.close(); + } + } + line = try br.readLine(); + } + catch (t : Throwable) { + primaryExc_res1 = t; + throw t; + } + recover (t : Throwable) { + primaryExc_res1 = t; + throw t; + } + + } + catch (t : Throwable) { + primaryExc_res0 = t; + throw t; + } + recover (t : Throwable) { + primaryExc_res0 = t; + throw t; + } + + } + } + open viewTable(con : Connection): void { + let query : String = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES"; + trap { + const stmt : Statement = try con.createStatement(); + let primaryExc_res0 : Throwable = null; + trap { + defer if (stmt != null) { + if (primaryExc_res0 != null) { + trap { + try stmt.close(); + } + catch (suppressedExc : Throwable) { + primaryExc_res0.addSuppressed(suppressedExc); + } + recover (suppressedExc : Throwable) { + primaryExc_res0.addSuppressed(suppressedExc); + } + + } + else { + try stmt.close(); + } + } + let rs : ResultSet = try stmt.executeQuery(query); + while(try rs.next()) + { + System.out.println(try rs.getString("COF_NAME") + ", " + try rs.getInt("SUP_ID") + ", " + try rs.getFloat("PRICE") + ", " + try rs.getInt("SALES") + ", " + try rs.getInt("TOTAL")); + } + } + catch (t : Throwable) { + primaryExc_res0 = t; + throw t; + } + recover (t : Throwable) { + primaryExc_res0 = t; + throw t; + } + + } + catch (e : SQLException) { + System.err.println("SQLState: " + e.getSQLState()); + System.err.println("Error Code: " + e.getErrorCode()); + System.err.println("Message: " + e.getMessage()); + } + + } + open readFile2(): void { + let line : String = ""; + let path : String = ""; + { + defer { + System.out.println("Successful!"); + } + const fr : FileReader = try new FileReader(path); + let primaryExc_res0 : Throwable = null; + trap { + defer if (fr != null) { + if (primaryExc_res0 != null) { + trap { + try fr.close(); + } + catch (suppressedExc : Throwable) { + primaryExc_res0.addSuppressed(suppressedExc); + } + recover (suppressedExc : Throwable) { + primaryExc_res0.addSuppressed(suppressedExc); + } + + } + else { + try fr.close(); + } + } + const br : BufferedReader = new BufferedReader(fr); + let primaryExc_res1 : Throwable = null; + trap { + defer if (br != null) { + if (primaryExc_res1 != null) { + trap { + try br.close(); + } + catch (suppressedExc : Throwable) { + primaryExc_res1.addSuppressed(suppressedExc); + } + recover (suppressedExc : Throwable) { + primaryExc_res1.addSuppressed(suppressedExc); + } + + } + else { + try br.close(); + } + } + line = try br.readLine(); + } + catch (t : Throwable) { + primaryExc_res1 = t; + throw t; + } + recover (t : Throwable) { + primaryExc_res1 = t; + throw t; + } + + } + catch (t : Throwable) { + primaryExc_res0 = t; + throw t; + } + recover (t : Throwable) { + primaryExc_res0 = t; + throw t; + } + + } + } + open scanFile(): void { + trap { + defer { + System.out.println("Successful!"); + } + const scanner : Scanner = try new java.util.Scanner(new File("test.txt")); + let primaryExc_res0 : Throwable = null; + trap { + defer if (scanner != null) { + if (primaryExc_res0 != null) { + trap { + try scanner.close(); + } + catch (suppressedExc : Throwable) { + primaryExc_res0.addSuppressed(suppressedExc); + } + recover (suppressedExc : Throwable) { + primaryExc_res0.addSuppressed(suppressedExc); + } + + } + else { + try scanner.close(); + } + } + while(scanner.hasNext()) + { + System.out.println(scanner.nextLine()); + } + } + catch (t : Throwable) { + primaryExc_res0 = t; + throw t; + } + recover (t : Throwable) { + primaryExc_res0 = t; + throw t; + } + + } + catch (fnfe : FileNotFoundException) { + fnfe.printStackTrace(); + } + + } + open writeFile(): void { + trap { + const scanner : Scanner = try new Scanner(new File("testRead.txt")); + let writer : PrintWriter = try new PrintWriter(new File("testWrite.txt")); + { + let primaryExc_res0 : Throwable = null; + trap { + defer if (scanner != null) { + if (primaryExc_res0 != null) { + trap { + try scanner.close(); + } + catch (suppressedExc : Throwable) { + primaryExc_res0.addSuppressed(suppressedExc); + } + recover (suppressedExc : Throwable) { + primaryExc_res0.addSuppressed(suppressedExc); + } + + } + else { + try scanner.close(); + } + } + let primaryExc_res1 : Throwable = null; + trap { + defer if (writer != null) { + if (primaryExc_res1 != null) { + trap { + try writer.close(); + } + catch (suppressedExc : Throwable) { + primaryExc_res1.addSuppressed(suppressedExc); + } + recover (suppressedExc : Throwable) { + primaryExc_res1.addSuppressed(suppressedExc); + } + + } + else { + try writer.close(); + } + } + while(scanner.hasNext()) + { + let line : String = scanner.nextLine(); + writer.println(line); + } + } + catch (t : Throwable) { + primaryExc_res1 = t; + throw t; + } + recover (t : Throwable) { + primaryExc_res1 = t; + throw t; + } + + } + catch (t : Throwable) { + primaryExc_res0 = t; + throw t; + } + recover (t : Throwable) { + primaryExc_res0 = t; + throw t; + } + + } + } + catch (ex : Exception) { + System.err.println(ex.getMessage()); + } + + } + open class Z { + public const yz : Y = new Y(); + } + + public open class X extends Z { + const y2 : Y = new Y(); + public open foo(): void { + let z : Z = new Z(); + trap { + let primaryExc_res0 : Throwable = null; + trap { + defer if (this.y2 != null) { + if (primaryExc_res0 != null) { + trap { + try this.y2.close(); + } + catch (suppressedExc : Throwable) { + primaryExc_res0.addSuppressed(suppressedExc); + } + recover (suppressedExc : Throwable) { + primaryExc_res0.addSuppressed(suppressedExc); + } + + } + else { + try this.y2.close(); + } + } + let primaryExc_res1 : Throwable = null; + trap { + defer if (super.yz != null) { + if (primaryExc_res1 != null) { + trap { + try super.yz.close(); + } + catch (suppressedExc : Throwable) { + primaryExc_res1.addSuppressed(suppressedExc); + } + recover (suppressedExc : Throwable) { + primaryExc_res1.addSuppressed(suppressedExc); + } + + } + else { + try super.yz.close(); + } + } + { + let primaryExc_res2 : Throwable = null; + trap { + defer if (z.yz != null) { + if (primaryExc_res2 != null) { + trap { + try z.yz.close(); + } + catch (suppressedExc : Throwable) { + primaryExc_res2.addSuppressed(suppressedExc); + } + recover (suppressedExc : Throwable) { + primaryExc_res2.addSuppressed(suppressedExc); + } + + } + else { + try z.yz.close(); + } + } + System.out.println(this.y2.val + super.yz.val + z.yz.val); + } + catch (t : Throwable) { + primaryExc_res2 = t; + throw t; + } + recover (t : Throwable) { + primaryExc_res2 = t; + throw t; + } + + } + } + catch (t : Throwable) { + primaryExc_res1 = t; + throw t; + } + recover (t : Throwable) { + primaryExc_res1 = t; + throw t; + } + + } + catch (t : Throwable) { + primaryExc_res0 = t; + throw t; + } + recover (t : Throwable) { + primaryExc_res0 = t; + throw t; + } + + } + catch (e : IOException) { + System.err.println(e.getMessage()); + } + + } + } + + open class Y implements AutoCloseable { + public val : int = 10; + public override close(): void { + if (val < 0) { + __untranslated_statement(/* throw new IOException("Invalid value: " + val); + */); + } + System.out.println("Closed"); + } + } + +} + \ No newline at end of file