From 5eb30476029ce4547b9939481cc3ec43dae992a8 Mon Sep 17 00:00:00 2001 From: Igor Rossinski Date: Fri, 2 Sep 2022 11:13:26 +0300 Subject: [PATCH 1/6] Translation of Java 'Try' statement - part I. Signed-off-by: Igor Rossinski --- .../ohos/migrator/java/JavaTransformer.java | 59 +++++++++++++++---- .../migrator/staticTS/parser/StaticTSLexer.g4 | 6 +- .../staticTS/parser/StaticTSParser.g4 | 10 ++-- .../staticTS/writer/StaticTSWriter.java | 32 ++++++---- migrator/test/java/try_catch.java | 34 +++++++++++ 5 files changed, 108 insertions(+), 33 deletions(-) create mode 100644 migrator/test/java/try_catch.java diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index 057415c05..ae078ed5c 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -26,6 +26,7 @@ import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; import org.eclipse.jdt.core.dom.*; +import org.intellij.lang.annotations.Identifier; import org.jetbrains.annotations.NotNull; import java.io.File; @@ -1992,8 +1993,18 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return false; } + + private void translateBlock(Block javaBlock) { + pushCurrent( new BlockContext(null, 0)); + List javaBlockStmts = javaBlock.statements(); + for(Statement javaStmt : javaBlockStmts) { + javaStmt.accept(this); + } + popCurrent(); + } @Override public boolean visit(Block javaBlock) { + /* BlockContext stsBlock = new BlockContext(null, 0); pushStatement(stsBlock); @@ -2003,6 +2014,10 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } popStatement(); // BlockContext +*/ + pushCurrent(new StatementContext(null, 0)); + translateBlock(javaBlock); + popCurrent(); ++countStmtTransformed; return false; @@ -3364,15 +3379,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // Better this than calling javaBody.accept(this) here // as visit(Block) will call pushStatement() which will // add StatementContext node which isn't needed here. - pushCurrent(new BlockContext(stsCurrent, 0)); - - Block javaBlock = (Block) javaBody; - List javaBlockStmts = javaBlock.statements(); - for (Statement javaStmt : javaBlockStmts) { - javaStmt.accept(this); - } - - popCurrent(); // BlockContext + translateBlock((Block) javaBody); } popCurrent(); // LambdaBodyContext @@ -3436,11 +3443,37 @@ public class JavaTransformer extends ASTVisitor implements Transformer { @Override public boolean visit(TryStatement javaTryStatement) { - // 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(javaTryStatement)).setParent(stsCurrent); + pushStatement(new TrapStatementContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Trap)); + + Block javaTryBlock = javaTryStatement.getBody(); + translateBlock( javaTryBlock); + + // TODO: 'finally' should be transformed to 'defer' at the beginning of try block + Block javaFinally = javaTryStatement.getFinally(); + + List javaCatchClauses = javaTryStatement.catchClauses(); + for( CatchClause javaCatchClause: javaCatchClauses) { + SingleVariableDeclaration javaException = javaCatchClause.getException(); + //TODO: analyze Exception type and generate 'recovery' or 'catch' + + pushCurrent( new CatchClauseContext(null,0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Catch)); + + stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaException.getName())); + pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Colon)); + javaException.getType().accept(this); + popCurrent(); // TypeAnnotationContext + + Block clauseBody = javaCatchClause.getBody(); + translateBlock(clauseBody); + popCurrent(); + } + + popStatement(); // DoStatementContext + ++countExprTransformed; return false; } diff --git a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSLexer.g4 b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSLexer.g4 index d915ba7ca..29fc91563 100644 --- a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSLexer.g4 +++ b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSLexer.g4 @@ -111,8 +111,7 @@ Instanceof: 'instanceof'; Case: 'case'; Else: 'else'; New: 'new'; -Catch: 'catch'; -Finally: 'finally'; +///Finally: 'finally'; - No 'finally' according STS specification Return: 'return'; Continue: 'continue'; For: 'for'; @@ -127,6 +126,9 @@ Throw: 'throw'; Of: 'of'; Try: 'try'; Defer: 'defer'; +Trap: 'trap'; +Catch: 'catch'; +Recover: 'recover'; From: 'from'; As: 'as'; diff --git a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 index ca2f06803..1ddb85758 100644 --- a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 +++ b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 @@ -325,8 +325,8 @@ statement | labelledStatement | switchStatement | throwStatement - | tryStatement | deferStatement + | trapStatement | expressionStatement ; @@ -393,16 +393,16 @@ throwStatement : Throw {this.notLineTerminator()}? singleExpression SemiColon ; -tryStatement - : Try block (catchClause+ finallyClause? | finallyClause) +trapStatement + : Trap block (catchClause | recoveryClause)+ ; catchClause : Catch OpenParen Identifier typeAnnotation CloseParen block ; -finallyClause - : Finally block +recoveryClause + : Recovery OpenParen Identifier typeAnnotation CloseParen block ; deferStatement diff --git a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java index 4e652d54f..bc151c025 100644 --- a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java +++ b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java @@ -681,7 +681,7 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { // | labelledStatement // | switchStatement // | throwStatement - // | tryStatement + // | trapStatement // | debuggerStatement // | functionDeclaration // | generatorFunctionDeclaration @@ -1193,25 +1193,26 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { return null; } - // tryStatement: Try block (catchProduction finallyProduction? | finallyProduction); + // trapStatement: Trap block (catchProduction | recoveryProduction); @Override - public Void visitTryStatement(TryStatementContext stsTryStatement) { + public Void visitTrapStatement(TrapStatementContext stsTrapStatement) { doNeededIndent(); - sb.append(stsTryStatement.Try().getText()).append(' '); + sb.append(stsTrapStatement.Trap().getText()).append(' '); - visitBlock(stsTryStatement.block()); + visitBlock(stsTrapStatement.block()); - List stsCatches = stsTryStatement.catchClause(); - FinallyClauseContext stsFinally = stsTryStatement.finallyClause(); + List stsCatches = stsTrapStatement.catchClause(); + List stsRecoveries = stsTrapStatement.recoveryClause(); if (stsCatches != null) { for (CatchClauseContext stsCatch : stsCatches) { visitCatchClause(stsCatch); } } - else assert(stsFinally != null); - if (stsFinally != null) { - visitFinallyClause(stsFinally); + if (stsRecoveries != null) { + for (RecoveryClauseContext stsRecovery : stsRecoveries) { + visitRecoveryClause(stsRecovery); + } } sb.append('\n'); @@ -1233,10 +1234,15 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { } // finallyClause: Finally block - public Void visitFinallyClause(FinallyClauseContext stsFinally) { + public Void visitRecoveryClause(RecoveryClauseContext stsRecoveryClause) { doNeededIndent(); - sb.append(stsFinally.Finally().getText()).append(' '); - visitBlock(stsFinally.block()); + sb.append(stsRecoveryClause.Recovery().getText()).append(" ("); + + sb.append(stsRecoveryClause.Identifier().getText()); + visitTypeAnnotation(stsRecoveryClause.typeAnnotation()); + sb.append(") "); + + visitBlock(stsRecoveryClause.block()); return null; } diff --git a/migrator/test/java/try_catch.java b/migrator/test/java/try_catch.java new file mode 100644 index 000000000..0e6429e3b --- /dev/null +++ b/migrator/test/java/try_catch.java @@ -0,0 +1,34 @@ +/* + * 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; + +public class try_catch { + public static int i = 0x7fff; + + public static int divide(int k) { + int r = 0; + try { + r = i / k; + } + catch (Exception e) { + r = -1; + } + finally { + if ( r < 0 ) r = 0; + } + return r; + } +} -- Gitee From dbc71dd1ca9dd9705a4147b0446c97a0bbee7d71 Mon Sep 17 00:00:00 2001 From: Mikhail Velikanov Date: Fri, 2 Sep 2022 17:14:26 +0300 Subject: [PATCH 2/6] Translation of try statement, part 2. Signed-off-by: Mikhail Velikanov --- .../ohos/migrator/java/JavaTransformer.java | 156 +++++++++++++----- .../staticTS/parser/StaticTSParser.g4 | 22 ++- .../staticTS/writer/StaticTSWriter.java | 81 +++++---- ...{try_catch.java => try_catch_finally.java} | 45 +++-- migrator/test/java/try_catch_finally.java.sts | 58 +++++++ 5 files changed, 263 insertions(+), 99 deletions(-) rename migrator/test/java/{try_catch.java => try_catch_finally.java} (42%) create mode 100644 migrator/test/java/try_catch_finally.java.sts diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index ae078ed5c..2dc5ff09c 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -26,7 +26,6 @@ import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; import org.eclipse.jdt.core.dom.*; -import org.intellij.lang.annotations.Identifier; import org.jetbrains.annotations.NotNull; import java.io.File; @@ -54,6 +53,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { private final String ENUM_CONST_ORDINAL = "ENUM_CONST_ORDINAL"; + private final ITypeBinding RUNTIME_EXCEPTION_TYPE; + private static int countStmtTotal = 0; private static int countExprTotal = 0; private static int countDeclTotal = 0; @@ -157,6 +158,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { public JavaTransformer(CompilationUnit javaCU, File srcFile) { this.javaCU = javaCU; this.srcFile = srcFile; + RUNTIME_EXCEPTION_TYPE = this.javaCU.getAST().resolveWellKnownType("java.lang.RuntimeException"); } public CompilationUnitContext transform() { @@ -1994,30 +1996,18 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } - private void translateBlock(Block javaBlock) { - pushCurrent( new BlockContext(null, 0)); + private void translateBlockStatements(Block javaBlock) { List javaBlockStmts = javaBlock.statements(); for(Statement javaStmt : javaBlockStmts) { javaStmt.accept(this); } - popCurrent(); } + @Override public boolean visit(Block javaBlock) { - /* - BlockContext stsBlock = new BlockContext(null, 0); - pushStatement(stsBlock); - - List javaBlockStmts = javaBlock.statements(); - for(Statement javaStmt : javaBlockStmts) { - javaStmt.accept(this); - } - + pushStatement(new BlockContext(stsCurrent, 0)); + translateBlockStatements(javaBlock); popStatement(); // BlockContext -*/ - pushCurrent(new StatementContext(null, 0)); - translateBlock(javaBlock); - popCurrent(); ++countStmtTransformed; return false; @@ -2422,11 +2412,20 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // this ( [ Expression { , Expression } ] ) ; // STS tree: // constructorCall: - // this typeArguments? arguments SemiColon + // Try? + // ( + // This typeArguments? arguments + // | (singleExpression Dot)? Super typeArguments? arguments + // ) @Override public boolean visit(ConstructorInvocation javaCtorInvocation) { - TerminalNode stsThis = NodeBuilder.terminalNode(StaticTSParser.This); - translateCtorInvocation(stsThis, javaCtorInvocation.typeArguments(), javaCtorInvocation.arguments(), null); + IMethodBinding javaCtorBinding = javaCtorInvocation.resolveConstructorBinding(); + boolean isThrowingCall = javaCtorBinding != null && javaCtorBinding.getExceptionTypes().length > 0; + + translateCtorInvocation(NodeBuilder.terminalNode(StaticTSParser.This), + javaCtorInvocation.typeArguments(), + javaCtorInvocation.arguments(), + null, isThrowingCall); ++countStmtTransformed; return false; @@ -2442,16 +2441,28 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // | (singleExpression . )? super typeArguments? arguments SemiColon @Override public boolean visit(SuperConstructorInvocation javaSuperCtorInvocation) { - TerminalNode stsSuper = NodeBuilder.terminalNode(StaticTSParser.Super); - translateCtorInvocation(stsSuper, javaSuperCtorInvocation.typeArguments(), javaSuperCtorInvocation.arguments(), javaSuperCtorInvocation.getExpression()); + IMethodBinding javaCtorBinding = javaSuperCtorInvocation.resolveConstructorBinding(); + boolean isThrowingCall = javaCtorBinding != null && javaCtorBinding.getExceptionTypes().length > 0; + + translateCtorInvocation(NodeBuilder.terminalNode(StaticTSParser.Super), + javaSuperCtorInvocation.typeArguments(), + javaSuperCtorInvocation.arguments(), + javaSuperCtorInvocation.getExpression(), + isThrowingCall); ++countStmtTransformed; return false; } - private void translateCtorInvocation(TerminalNode stsThisOrSuper, List javaTypeArgs, List javaArgs, Expression javaCtorExpr) { + // NOTE: If ctor called can throw exceptions, prepend 'try' keyword to result. + private void translateCtorInvocation(TerminalNode stsThisOrSuper, List javaTypeArgs, + List javaArgs, Expression javaCtorExpr, + boolean isThrowingCall) { pushCurrent(new ConstructorCallContext(stsCurrent, 0)); + // Add 'try' keyword if this is a throwing call. + if (isThrowingCall) stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); + if (javaCtorExpr != null) { javaCtorExpr.accept(this); } @@ -2646,8 +2657,20 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // | New typeReference arguments? classBody? # NewClassExpression // arguments: OpenParen expressionSequence? CloseParen // classBody: OpenBrace classMember* clinit=classInitializer? classMember* CloseBrace + // NOTE: If ctor called by class instance creation expression can throw exceptions, + // wrap result in try expression. + // | Try singleExpression #TryExpression @Override public boolean visit(ClassInstanceCreation javaClassInstanceCreation) { + IMethodBinding javaCtorBinding = javaClassInstanceCreation.resolveConstructorBinding(); + boolean ctorCanThrow = javaCtorBinding != null && javaCtorBinding.getExceptionTypes().length > 0; + + // Add TryExpressionContext if ctor invoked can throw + if (ctorCanThrow) { + pushCurrent(new TryExpressionContext(pushSingleExpression())); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); + } + pushCurrent(new NewClassExpressionContext(pushSingleExpression())); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.New)).setParent(stsCurrent); @@ -2663,6 +2686,10 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); + if (ctorCanThrow) { + popSingleExpression(); // TryExpressionContext + } + ++countExprTransformed; return false; } @@ -2924,8 +2951,19 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // typeArgument: typeReference | arrayType // arguments: OpenParen expressionSequence? CloseParen // expressionSequence: singleExpression (Comma singleExpression)* + // NOTE: If method called can throw exceptions, wrap result in try expression. + // | Try singleExpression #TryExpression @Override public boolean visit(MethodInvocation javaMethodInvocation) { + IMethodBinding javaMethodBinding = javaMethodInvocation.resolveMethodBinding(); + boolean isThrowingCall = javaMethodBinding != null && javaMethodBinding.getExceptionTypes().length > 0; + + // Add TryExpressionContext if this is a throwing call. + if (isThrowingCall) { + pushCurrent(new TryExpressionContext(pushSingleExpression())); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); + } + pushCurrent(new CallExpressionContext(pushSingleExpression())); Expression javaObjectExpression = javaMethodInvocation.getExpression(); @@ -2946,6 +2984,10 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); // CallExpressionContext + if (isThrowingCall) { + popSingleExpression(); // TryExpressionContext + } + ++countExprTransformed; return false; } @@ -3376,10 +3418,11 @@ public class JavaTransformer extends ASTVisitor implements Transformer { if (javaBody instanceof Expression) { javaBody.accept(this); } else { - // Better this than calling javaBody.accept(this) here - // as visit(Block) will call pushStatement() which will - // add StatementContext node which isn't needed here. - translateBlock((Block) javaBody); + // NOTE: Can't call javaBody.accept as that will emit + // StatementContext which we don't need here + pushCurrent(new BlockContext(stsCurrent, 0)); + translateBlockStatements((Block)javaBody); + popCurrent(); // BlockContext } popCurrent(); // LambdaBodyContext @@ -3446,37 +3489,66 @@ public class JavaTransformer extends ASTVisitor implements Transformer { pushStatement(new TrapStatementContext(stsCurrent, 0)); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Trap)); - Block javaTryBlock = javaTryStatement.getBody(); - translateBlock( javaTryBlock); + pushCurrent(new BlockContext(stsCurrent, 0)); - // TODO: 'finally' should be transformed to 'defer' at the beginning of try block + // If there is a finally clause, create a defer statement + // and add it to the beginning of trap block Block javaFinally = javaTryStatement.getFinally(); + if (javaFinally != null) { + pushStatement(new DeferStatementContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Defer)); + javaFinally.accept(this); + popStatement(); // DeferStatementContext + } + + // NOTE: Can't call javaTryBlock.accept as that will + // emit StatementContext which we don't need here + Block javaTryBlock = javaTryStatement.getBody(); + translateBlockStatements(javaTryBlock); + + popCurrent(); // BlockContext List javaCatchClauses = javaTryStatement.catchClauses(); - for( CatchClause javaCatchClause: javaCatchClauses) { + for (CatchClause javaCatchClause: javaCatchClauses) { + pushCurrent(new CatchOrRecoverClauseContext(stsCurrent,0)); SingleVariableDeclaration javaException = javaCatchClause.getException(); - //TODO: analyze Exception type and generate 'recovery' or 'catch' + Type javaExceptionType = javaException.getType(); - pushCurrent( new CatchClauseContext(null,0)); - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Catch)); + // Emit 'recover' keyword instead of 'catch' if exception type + // is a subtype of RuntimeException. + ITypeBinding javaExcTypeBinding = javaExceptionType.resolveBinding(); + int termCode = isRuntimeExceptionType(javaExcTypeBinding) ? + StaticTSParser.Recover : StaticTSParser.Catch; + stsCurrent.addChild(NodeBuilder.terminalNode(termCode)); + pushCurrent(new ExceptionParameterContext(stsCurrent, 0)); stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaException.getName())); - pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Colon)); - javaException.getType().accept(this); + javaExceptionType.accept(this); popCurrent(); // TypeAnnotationContext + popCurrent(); // ExceptionParameterContext + + // NOTE: Can't call javaClauseBody.accept as that will + // emit StatementContext which we don't need here + Block javaClauseBody = javaCatchClause.getBody(); + pushCurrent(new BlockContext(stsCurrent, 0)); + translateBlockStatements(javaClauseBody); + popCurrent(); // BlockContext - Block clauseBody = javaCatchClause.getBody(); - translateBlock(clauseBody); - popCurrent(); + popCurrent(); // CatchOrRecoverClauseContext } - popStatement(); // DoStatementContext - ++countExprTransformed; + popStatement(); // TrapStatementContext + + ++countStmtTransformed; return false; } + private boolean isRuntimeExceptionType(ITypeBinding javaExcType) { + return javaExcType != null && + (javaExcType.isEqualTo(RUNTIME_EXCEPTION_TYPE) || + javaExcType.isSubTypeCompatible(RUNTIME_EXCEPTION_TYPE)); + } @Override public boolean visit(ThrowStatement javaThrowStatement) { // TODO: To be implemented diff --git a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 index 1ddb85758..75f21b6b6 100644 --- a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 +++ b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 @@ -138,8 +138,11 @@ constructorBody ; constructorCall - : This typeArguments? arguments - | (singleExpression Dot)? Super typeArguments? arguments + : Try? + ( + This typeArguments? arguments + | (singleExpression Dot)? Super typeArguments? arguments + ) ; statementOrLocalDeclaration @@ -327,6 +330,7 @@ statement | throwStatement | deferStatement | trapStatement + | deferStatement | expressionStatement ; @@ -394,15 +398,18 @@ throwStatement ; trapStatement - : Trap block (catchClause | recoveryClause)+ + : Trap block catchOrRecoverClause+ ; -catchClause - : Catch OpenParen Identifier typeAnnotation CloseParen block +catchOrRecoverClause + : (Catch | Recover) exceptionParameter? block ; -recoveryClause - : Recovery OpenParen Identifier typeAnnotation CloseParen block +exceptionParameter + : OpenParen Identifier typeAnnotation CloseParen + ; +deferStatement + : Defer statement ; deferStatement @@ -451,6 +458,7 @@ singleExpression | primaryType Dot Class # ClassLiteralExpression | OpenParen singleExpression CloseParen # ParenthesizedExpression | singleExpression As (intersectionType | primaryType) # CastExpression + | Try singleExpression # TryExpression ; shiftOperator diff --git a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java index bc151c025..4d5c35eca 100644 --- a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java +++ b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java @@ -22,7 +22,6 @@ import com.ohos.migrator.staticTS.parser.StaticTSParserBaseVisitor; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; -import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; import java.io.FileWriter; @@ -353,7 +352,8 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { PrimaryTypeContext stsType = stsTypeAnnotation.primaryType(); stsType.accept(this); - if (!(stsTypeAnnotation.parent instanceof ParameterContext)) + if (stsTypeAnnotation.parent.getRuleIndex() != StaticTSParser.RULE_parameter && + stsTypeAnnotation.parent.getRuleIndex() != StaticTSParser.RULE_exceptionParameter) sb.append(' '); return null; @@ -428,13 +428,16 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { public Void visitConstructorCall(ConstructorCallContext stsConstructorCall) { doNeededIndent(); + TerminalNode term = stsConstructorCall.Try(); + if (term != null) sb.append(term.getText()).append(' '); + SingleExpressionContext stsSuperExpr = stsConstructorCall.singleExpression(); if (stsSuperExpr != null) { stsSuperExpr.accept(this); sb.append('.'); } - TerminalNode term = stsConstructorCall.This(); + term = stsConstructorCall.This(); if (term == null) term = stsConstructorCall.Super(); assert(term != null); @@ -881,7 +884,7 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { @Override public Void visitDoStatement(DoStatementContext stsDoStatement) { doNeededIndent(); - sb.append(stsDoStatement.Do().getText() + "\n"); + sb.append(stsDoStatement.Do().getText()).append("\n"); StatementContext stsStmt = stsDoStatement.statement(); assert(stsStmt != null); @@ -1193,7 +1196,7 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { return null; } - // trapStatement: Trap block (catchProduction | recoveryProduction); + // trapStatement: Trap block catchOrRecoverClause+; @Override public Void visitTrapStatement(TrapStatementContext stsTrapStatement) { doNeededIndent(); @@ -1201,49 +1204,45 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { visitBlock(stsTrapStatement.block()); - List stsCatches = stsTrapStatement.catchClause(); - List stsRecoveries = stsTrapStatement.recoveryClause(); - if (stsCatches != null) { - for (CatchClauseContext stsCatch : stsCatches) { - visitCatchClause(stsCatch); - } - } - - if (stsRecoveries != null) { - for (RecoveryClauseContext stsRecovery : stsRecoveries) { - visitRecoveryClause(stsRecovery); - } + List stsCatchesOrRecovers = stsTrapStatement.catchOrRecoverClause(); + assert(stsCatchesOrRecovers != null && !stsCatchesOrRecovers.isEmpty()); + for (CatchOrRecoverClauseContext stsCatchOrRecover : stsCatchesOrRecovers) { + visitCatchOrRecoverClause(stsCatchOrRecover); } sb.append('\n'); return null; } - // catchClause: Catch '(' Identifier typeAnnotation ')' block - public Void visitCatchClause(CatchClauseContext stsCatchClause) { + // catchOrRecoverClause: (Catch|Recover) exceptionParameter? block + + @Override + public Void visitCatchOrRecoverClause(CatchOrRecoverClauseContext stsCatchOrRecoverClause) { doNeededIndent(); - sb.append(stsCatchClause.Catch().getText()).append(" ("); - sb.append(stsCatchClause.Identifier().getText()); - visitTypeAnnotation(stsCatchClause.typeAnnotation()); - sb.append(") "); + TerminalNode stsTerm = stsCatchOrRecoverClause.Catch(); + if (stsTerm == null) stsTerm = stsCatchOrRecoverClause.Recover(); + assert(stsTerm != null); + sb.append(stsTerm.getText()).append(' '); - visitBlock(stsCatchClause.block()); + ExceptionParameterContext stsExceptionParam = stsCatchOrRecoverClause.exceptionParameter(); + if (stsExceptionParam != null) { + visitExceptionParameter(stsExceptionParam); + } + + BlockContext stsBlock = stsCatchOrRecoverClause.block(); + assert(stsBlock != null); + visitBlock(stsBlock); return null; } - // finallyClause: Finally block - public Void visitRecoveryClause(RecoveryClauseContext stsRecoveryClause) { - doNeededIndent(); - sb.append(stsRecoveryClause.Recovery().getText()).append(" ("); - - sb.append(stsRecoveryClause.Identifier().getText()); - visitTypeAnnotation(stsRecoveryClause.typeAnnotation()); + @Override + public Void visitExceptionParameter(ExceptionParameterContext stsExceptionParam) { + sb.append('(').append(stsExceptionParam.Identifier().getText()).append(' '); + visitTypeAnnotation(stsExceptionParam.typeAnnotation()); sb.append(") "); - visitBlock(stsRecoveryClause.block()); - return null; } @@ -1863,12 +1862,22 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { return null; } + // deferStatement: Defer statement; @Override - public Void visitDeferStatement(DeferStatementContext stsDeferStmt) { + public Void visitDeferStatement(DeferStatementContext stsDeferStatement) { doNeededIndent(); - sb.append(stsDeferStmt.Defer().getText()).append(' '); - stsDeferStmt.statement().accept(this); + sb.append(stsDeferStatement.Defer().getText()).append(' '); + stsDeferStatement.statement().accept(this); + + return null; + } + + // Try singleExpression # TryExpression + @Override + public Void visitTryExpression(TryExpressionContext stsTryExpression) { + sb.append(stsTryExpression.Try()).append(' '); + stsTryExpression.singleExpression().accept(this); return null; } diff --git a/migrator/test/java/try_catch.java b/migrator/test/java/try_catch_finally.java similarity index 42% rename from migrator/test/java/try_catch.java rename to migrator/test/java/try_catch_finally.java index 0e6429e3b..23cb3b5f3 100644 --- a/migrator/test/java/try_catch.java +++ b/migrator/test/java/try_catch_finally.java @@ -15,20 +15,37 @@ package com.ohos.migrator.test.java; -public class try_catch { - public static int i = 0x7fff; +class BlewIt extends Exception { + BlewIt() { } + BlewIt(String s) { super(s); } +} + +public class try_catch_finally { + public try_catch_finally() throws Exception { } + + public try_catch_finally(int i) throws Exception { this(); } + + static void blowUp() throws BlewIt { } - public static int divide(int k) { - int r = 0; - try { - r = i / k; - } - catch (Exception e) { - r = -1; - } - finally { - if ( r < 0 ) r = 0; - } - return r; + public static void main(String[] args) { + try { + blowUp(); + try_catch_finally t = new try_catch_finally(); + } + catch (NullPointerException n) { + System.out.println("Caught NullPointerException"); + } + catch (BlewIt b) { + System.out.println("Caught BlewIt"); + } + catch (RuntimeException r) { + System.out.println("Caught RuntimeException"); + } + catch (Exception e) { + System.out.println("Caught Exception"); + } + finally { + System.out.println("In finally"); + } } } diff --git a/migrator/test/java/try_catch_finally.java.sts b/migrator/test/java/try_catch_finally.java.sts new file mode 100644 index 000000000..00f1e166d --- /dev/null +++ b/migrator/test/java/try_catch_finally.java.sts @@ -0,0 +1,58 @@ +/* + * 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; + +open class BlewIt extends Exception { + constructor() { + } + constructor(s : String) { + super(s); + } +} + +export open class try_catch_finally { + public constructor() { + } + + public constructor(i : int) { + try this(); + } + + static blowUp(): void { + } + + public static main(args : String[]): void { + trap { + defer { + System.out.println("In finally"); + } + try blowUp(); + let t : try_catch_finally = try new try_catch_finally(); + } + recover (n : NullPointerException) { + System.out.println("Caught NullPointerException"); + } + catch (b : BlewIt) { + System.out.println("Caught BlewIt"); + } + recover (r : RuntimeException) { + System.out.println("Caught RuntimeException"); + } + catch (e : Exception) { + System.out.println("Caught Exception"); + } + } +} -- Gitee From 1ff8af54a1cd8a2db265534429bce35daeffe130 Mon Sep 17 00:00:00 2001 From: Mikhail Velikanov Date: Fri, 2 Sep 2022 18:08:05 +0300 Subject: [PATCH 3/6] Implemented translation of try statement with no catch clauses. Signed-off-by: Mikhail Velikanov --- .../ohos/migrator/java/JavaTransformer.java | 48 +++++++++++++++---- migrator/test/java/try_catch_finally.java | 9 ++++ migrator/test/java/try_catch_finally.java.sts | 10 ++++ 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index 2dc5ff09c..dc8b23d56 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -3484,12 +3484,38 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return false; } + // Java AST: + // TryStatement: + // try Block Catches + // try Block [Catches] Finally + // + // STS AST: + // trapStatement + // : Trap block catchOrRecoverClause+ + // ; + // + // catchOrRecoverClause + // : (Catch | Recover) exceptionParameter? block + // ; + // + // exceptionParameter + // : OpenParen Identifier typeAnnotation CloseParen + // ; @Override public boolean visit(TryStatement javaTryStatement) { - pushStatement(new TrapStatementContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Trap)); + List javaCatchClauses = javaTryStatement.catchClauses(); - pushCurrent(new BlockContext(stsCurrent, 0)); + // If there are no catch clauses (implying there must be a finally clause), + // don't emit trap statement. Emit a plain block instead with defer statement + // representing finally clause. + if (!javaCatchClauses.isEmpty()) { + pushStatement(new TrapStatementContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Trap)); + pushCurrent(new BlockContext(stsCurrent, 0)); + } + else { + pushStatement(new BlockContext(stsCurrent, 0)); + } // If there is a finally clause, create a defer statement // and add it to the beginning of trap block @@ -3506,16 +3532,20 @@ public class JavaTransformer extends ASTVisitor implements Transformer { Block javaTryBlock = javaTryStatement.getBody(); translateBlockStatements(javaTryBlock); - popCurrent(); // BlockContext + if (!javaCatchClauses.isEmpty()) { + popCurrent(); // BlockContext + } + else { + popStatement(); // BlockContext + } - List javaCatchClauses = javaTryStatement.catchClauses(); for (CatchClause javaCatchClause: javaCatchClauses) { pushCurrent(new CatchOrRecoverClauseContext(stsCurrent,0)); SingleVariableDeclaration javaException = javaCatchClause.getException(); Type javaExceptionType = javaException.getType(); - // Emit 'recover' keyword instead of 'catch' if exception type - // is a subtype of RuntimeException. + // Emit 'recover' keyword instead of 'catch' if + // exception type is a subtype of RuntimeException. ITypeBinding javaExcTypeBinding = javaExceptionType.resolveBinding(); int termCode = isRuntimeExceptionType(javaExcTypeBinding) ? StaticTSParser.Recover : StaticTSParser.Catch; @@ -3538,7 +3568,9 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // CatchOrRecoverClauseContext } - popStatement(); // TrapStatementContext + if (!javaCatchClauses.isEmpty()) { + popStatement(); // TrapStatementContext + } ++countStmtTransformed; return false; diff --git a/migrator/test/java/try_catch_finally.java b/migrator/test/java/try_catch_finally.java index 23cb3b5f3..eac22c07f 100644 --- a/migrator/test/java/try_catch_finally.java +++ b/migrator/test/java/try_catch_finally.java @@ -27,6 +27,15 @@ public class try_catch_finally { static void blowUp() throws BlewIt { } + private static void foo() throws BlewIt { + try { + blowUp(); + } + finally { + System.out.println("In finally"); + } + } + public static void main(String[] args) { try { blowUp(); diff --git a/migrator/test/java/try_catch_finally.java.sts b/migrator/test/java/try_catch_finally.java.sts index 00f1e166d..1b188f840 100644 --- a/migrator/test/java/try_catch_finally.java.sts +++ b/migrator/test/java/try_catch_finally.java.sts @@ -34,6 +34,16 @@ export open class try_catch_finally { static blowUp(): void { } + private static foo(): void { + { + defer { + System.out.println("In finally"); + } + + try blowUp(); + } + } + public static main(args : String[]): void { trap { defer { -- Gitee From c4b58a15728d18cf30ac429e4387e566e32930ac Mon Sep 17 00:00:00 2001 From: Mikhail Velikanov Date: Mon, 5 Sep 2022 12:58:41 +0300 Subject: [PATCH 4/6] Handle invalid and unresolved exception types in Java try statements. Signed-off-by: Mikhail Velikanov --- .../ohos/migrator/java/JavaTransformer.java | 18 ++++++++++++++---- .../ohos/migrator/staticTS/NodeBuilder.java | 5 +++++ .../staticTS/writer/StaticTSWriter.java | 9 +++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index dc8b23d56..1854b9c77 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -3553,9 +3553,15 @@ public class JavaTransformer extends ASTVisitor implements Transformer { pushCurrent(new ExceptionParameterContext(stsCurrent, 0)); stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaException.getName())); - pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); - javaExceptionType.accept(this); - popCurrent(); // TypeAnnotationContext + if (isValidExceptionType(javaExcTypeBinding)) { + pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); + javaExceptionType.accept(this); + popCurrent(); // TypeAnnotationContext + } + else { + // For invalid exception types, emit __UnknownType__ and continue + stsCurrent.addChild(NodeBuilder.unknownTypeAnnotation(javaExceptionType)).setParent(stsCurrent); + } popCurrent(); // ExceptionParameterContext // NOTE: Can't call javaClauseBody.accept as that will @@ -3577,10 +3583,14 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } private boolean isRuntimeExceptionType(ITypeBinding javaExcType) { - return javaExcType != null && + return isValidExceptionType(javaExcType) && (javaExcType.isEqualTo(RUNTIME_EXCEPTION_TYPE) || javaExcType.isSubTypeCompatible(RUNTIME_EXCEPTION_TYPE)); } + + private boolean isValidExceptionType(ITypeBinding javaExcType) { + return javaExcType != null && !javaExcType.isRecovered() && javaExcType.isClass(); + } @Override public boolean visit(ThrowStatement javaThrowStatement) { // TODO: To be implemented diff --git a/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java b/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java index cdea22909..fdc6681ba 100644 --- a/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java +++ b/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java @@ -411,6 +411,11 @@ public class NodeBuilder { return stsExpression; } + public static TypeAnnotationContext unknownTypeAnnotation(Type javaType) { + TypeAnnotationContext stsTypeAnnotation = typeAnnotation("__UnknownType__"); + stsTypeAnnotation.addChild(multiLineComment("/* " + javaType.toString() + " */")); + return stsTypeAnnotation; + } public static StatementContext untranslatedStatement(ASTNode node) { StatementContext stsStatement = new StatementContext(null, 0); ExpressionStatementContext stsExprStatement = new ExpressionStatementContext(stsStatement, 0); diff --git a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java index 4d5c35eca..bb1cb0226 100644 --- a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java +++ b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java @@ -22,6 +22,8 @@ import com.ohos.migrator.staticTS.parser.StaticTSParserBaseVisitor; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; import java.io.FileWriter; @@ -356,6 +358,13 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { stsTypeAnnotation.parent.getRuleIndex() != StaticTSParser.RULE_exceptionParameter) sb.append(' '); + if (stsTypeAnnotation.getChildCount() > 1) { + ParseTree lastChild = stsTypeAnnotation.getChild(stsTypeAnnotation.getChildCount()-1); + if (lastChild instanceof TerminalNode) { + stsTypeAnnotation.getChild(1).accept(this); + } + } + return null; } -- Gitee From 356b0d224a541e09de0bc4aa2837196eb8eeec08 Mon Sep 17 00:00:00 2001 From: Mikhail Velikanov Date: Mon, 5 Sep 2022 13:34:13 +0300 Subject: [PATCH 5/6] Handle union-typed exceptions in Java try statement. Signed-off-by: Mikhail Velikanov --- .../ohos/migrator/java/JavaTransformer.java | 138 +++++++++++------- .../ohos/migrator/staticTS/NodeBuilder.java | 7 +- .../migrator/staticTS/parser/StaticTSLexer.g4 | 1 - .../staticTS/parser/StaticTSParser.g4 | 4 - .../staticTS/writer/StaticTSWriter.java | 27 ++-- migrator/test/java/try_catch_finally.java | 4 +- migrator/test/java/try_catch_finally.java.sts | 5 +- 7 files changed, 111 insertions(+), 75 deletions(-) diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index 1854b9c77..829fa35af 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -54,6 +54,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { private final String ENUM_CONST_ORDINAL = "ENUM_CONST_ORDINAL"; private final ITypeBinding RUNTIME_EXCEPTION_TYPE; + private final ITypeBinding THROWABLE_TYPE; private static int countStmtTotal = 0; private static int countExprTotal = 0; @@ -158,7 +159,9 @@ public class JavaTransformer extends ASTVisitor implements Transformer { public JavaTransformer(CompilationUnit javaCU, File srcFile) { this.javaCU = javaCU; this.srcFile = srcFile; - RUNTIME_EXCEPTION_TYPE = this.javaCU.getAST().resolveWellKnownType("java.lang.RuntimeException"); + AST javaAST = this.javaCU.getAST(); + RUNTIME_EXCEPTION_TYPE = javaAST.resolveWellKnownType("java.lang.RuntimeException"); + THROWABLE_TYPE = javaAST.resolveWellKnownType("java.lang.Throwable"); } public CompilationUnitContext transform() { @@ -1572,24 +1575,19 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaVariableDeclarationFragment.getName())); - pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); IVariableBinding variableBinding = javaVariableDeclarationFragment.resolveBinding(); if (variableBinding != null) { + pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); translateType(variableBinding.getType()); + popCurrent(); // TypeAnnotationContext } else { // Warn and emit __UnknownType__ as variable type - String loc = srcFile.getPath() + ":" + javaCU.getLineNumber(javaVariableDeclarationFragment.getStartPosition()); - Main.addError(ResultCode.TranspileError, "Failed to resolve lambda parameter at " + loc); - - pushCurrent(new PrimaryTypeContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.typeReference("__UnknownType__")).setParent(stsCurrent); - popCurrent(); // PrimaryTypeContext + reportError("Failed to resolve lambda parameter", javaVariableDeclarationFragment); + stsCurrent.addChild(NodeBuilder.unknownTypeAnnotation(null)).setParent(stsCurrent); } - popCurrent(); // TypeAnnotationContext - // Note: no need to process the "{ Dimension }" part, as the extra dimensions // of the declaration are covered by "translateType(ITypeBinding)" call. @@ -2420,7 +2418,13 @@ public class JavaTransformer extends ASTVisitor implements Transformer { @Override public boolean visit(ConstructorInvocation javaCtorInvocation) { IMethodBinding javaCtorBinding = javaCtorInvocation.resolveConstructorBinding(); - boolean isThrowingCall = javaCtorBinding != null && javaCtorBinding.getExceptionTypes().length > 0; + boolean isThrowingCall = false; + if (javaCtorBinding != null) { + isThrowingCall = javaCtorBinding.getExceptionTypes().length > 0; + } + else { + reportError("Failed to resolve constructor call", javaCtorInvocation); + } translateCtorInvocation(NodeBuilder.terminalNode(StaticTSParser.This), javaCtorInvocation.typeArguments(), @@ -2431,6 +2435,11 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return false; } + private void reportError(String message, ASTNode node) { + String loc = srcFile.getPath() + ":" + javaCU.getLineNumber(node.getStartPosition()); + Main.addError(ResultCode.TranspileError, message + " at " + loc); + } + // Java tree: // SuperConstructorInvocation: // [ Expression . ] @@ -2442,7 +2451,13 @@ public class JavaTransformer extends ASTVisitor implements Transformer { @Override public boolean visit(SuperConstructorInvocation javaSuperCtorInvocation) { IMethodBinding javaCtorBinding = javaSuperCtorInvocation.resolveConstructorBinding(); - boolean isThrowingCall = javaCtorBinding != null && javaCtorBinding.getExceptionTypes().length > 0; + boolean isThrowingCall = false; + if (javaCtorBinding != null) { + isThrowingCall = javaCtorBinding.getExceptionTypes().length > 0; + } + else { + reportError("Failed to report constructor call", javaSuperCtorInvocation); + } translateCtorInvocation(NodeBuilder.terminalNode(StaticTSParser.Super), javaSuperCtorInvocation.typeArguments(), @@ -2663,7 +2678,13 @@ public class JavaTransformer extends ASTVisitor implements Transformer { @Override public boolean visit(ClassInstanceCreation javaClassInstanceCreation) { IMethodBinding javaCtorBinding = javaClassInstanceCreation.resolveConstructorBinding(); - boolean ctorCanThrow = javaCtorBinding != null && javaCtorBinding.getExceptionTypes().length > 0; + boolean ctorCanThrow = false; + if (javaCtorBinding != null) { + ctorCanThrow = javaCtorBinding.getExceptionTypes().length > 0; + } + else { + reportError("Failed to resolve instance creation expression", javaClassInstanceCreation); + } // Add TryExpressionContext if ctor invoked can throw if (ctorCanThrow) { @@ -2956,7 +2977,13 @@ public class JavaTransformer extends ASTVisitor implements Transformer { @Override public boolean visit(MethodInvocation javaMethodInvocation) { IMethodBinding javaMethodBinding = javaMethodInvocation.resolveMethodBinding(); - boolean isThrowingCall = javaMethodBinding != null && javaMethodBinding.getExceptionTypes().length > 0; + boolean isThrowingCall = false; + if (javaMethodBinding != null) { + isThrowingCall = javaMethodBinding.getExceptionTypes().length > 0; + } + else { + reportError("Failed to resolve method call", javaMethodInvocation); + } // Add TryExpressionContext if this is a throwing call. if (isThrowingCall) { @@ -3393,23 +3420,18 @@ public class JavaTransformer extends ASTVisitor implements Transformer { createStsParameterList(javaLambdaExpr.parameters()); IMethodBinding lambdaMethod = javaLambdaExpr.resolveMethodBinding(); - pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); if (lambdaMethod != null) { + pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); translateType(lambdaMethod.getReturnType()); + popCurrent(); // TypeAnnotationContext } else { // Warn and emit __UnknownType__ as return type - String loc = srcFile.getPath() + ":" + javaCU.getLineNumber(javaLambdaExpr.getStartPosition()); - Main.addError(ResultCode.TranspileError, "Failed to resolve lambda expression at " + loc); - - pushCurrent(new PrimaryTypeContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.typeReference("__UnknownType__")).setParent(stsCurrent); - popCurrent(); // PrimaryTypeContext + reportError("Failed to resolve lambda expression", javaLambdaExpr); + stsCurrent.addChild(NodeBuilder.unknownTypeAnnotation(null)).setParent(stsCurrent); } - popCurrent(); // TypeAnnotationContext - stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Arrow)); pushCurrent(new LambdaBodyContext(stsCurrent, 0)); @@ -3540,38 +3562,21 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } for (CatchClause javaCatchClause: javaCatchClauses) { - pushCurrent(new CatchOrRecoverClauseContext(stsCurrent,0)); SingleVariableDeclaration javaException = javaCatchClause.getException(); Type javaExceptionType = javaException.getType(); + Block javaCatchBody = javaCatchClause.getBody(); + SimpleName javaExceptionName = javaException.getName(); - // Emit 'recover' keyword instead of 'catch' if - // exception type is a subtype of RuntimeException. - ITypeBinding javaExcTypeBinding = javaExceptionType.resolveBinding(); - int termCode = isRuntimeExceptionType(javaExcTypeBinding) ? - StaticTSParser.Recover : StaticTSParser.Catch; - stsCurrent.addChild(NodeBuilder.terminalNode(termCode)); - - pushCurrent(new ExceptionParameterContext(stsCurrent, 0)); - stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaException.getName())); - if (isValidExceptionType(javaExcTypeBinding)) { - pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); - javaExceptionType.accept(this); - popCurrent(); // TypeAnnotationContext + if (javaExceptionType.isUnionType()) { + List javaExcTypes = ((UnionType)javaExceptionType).types(); + for (Type javaExcType : javaExcTypes) { + createCatchOrRecoverClause(javaExcType, javaExceptionName, javaCatchBody); + } } else { - // For invalid exception types, emit __UnknownType__ and continue - stsCurrent.addChild(NodeBuilder.unknownTypeAnnotation(javaExceptionType)).setParent(stsCurrent); + createCatchOrRecoverClause(javaExceptionType, javaExceptionName, javaCatchBody); } - popCurrent(); // ExceptionParameterContext - // NOTE: Can't call javaClauseBody.accept as that will - // emit StatementContext which we don't need here - Block javaClauseBody = javaCatchClause.getBody(); - pushCurrent(new BlockContext(stsCurrent, 0)); - translateBlockStatements(javaClauseBody); - popCurrent(); // BlockContext - - popCurrent(); // CatchOrRecoverClauseContext } if (!javaCatchClauses.isEmpty()) { @@ -3582,6 +3587,40 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return false; } + private void createCatchOrRecoverClause(Type javaExceptionType, + SimpleName javaExceptionName, + Block javaClauseBody) { + pushCurrent(new CatchOrRecoverClauseContext(stsCurrent,0)); + + // Emit 'recover' keyword instead of 'catch' if + // exception type is a subtype of RuntimeException. + ITypeBinding javaExcTypeBinding = javaExceptionType.resolveBinding(); + int termCode = isRuntimeExceptionType(javaExcTypeBinding) ? + StaticTSParser.Recover : StaticTSParser.Catch; + stsCurrent.addChild(NodeBuilder.terminalNode(termCode)); + + pushCurrent(new ExceptionParameterContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaExceptionName)); + if (isValidExceptionType(javaExcTypeBinding)) { + pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); + javaExceptionType.accept(this); + popCurrent(); // TypeAnnotationContext + } + else { + // Warn and emit __UnknownType__ for invalid exception types + reportError("Failed to resolve exception type", javaExceptionType); + stsCurrent.addChild(NodeBuilder.unknownTypeAnnotation(javaExceptionType)).setParent(stsCurrent); + } + popCurrent(); // ExceptionParameterContext + + // NOTE: Can't call javaClauseBody.accept as that will + // emit StatementContext which we don't need here + pushCurrent(new BlockContext(stsCurrent, 0)); + translateBlockStatements(javaClauseBody); + popCurrent(); // BlockContext + + popCurrent(); // CatchOrRecoverClauseContext + } private boolean isRuntimeExceptionType(ITypeBinding javaExcType) { return isValidExceptionType(javaExcType) && (javaExcType.isEqualTo(RUNTIME_EXCEPTION_TYPE) || @@ -3589,7 +3628,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } private boolean isValidExceptionType(ITypeBinding javaExcType) { - return javaExcType != null && !javaExcType.isRecovered() && javaExcType.isClass(); + return javaExcType != null && !javaExcType.isRecovered() && javaExcType.isClass() && + (javaExcType.isEqualTo(THROWABLE_TYPE) || javaExcType.isSubTypeCompatible(THROWABLE_TYPE)); } @Override public boolean visit(ThrowStatement javaThrowStatement) { diff --git a/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java b/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java index fdc6681ba..4c755679a 100644 --- a/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java +++ b/migrator/src/com/ohos/migrator/staticTS/NodeBuilder.java @@ -413,9 +413,14 @@ public class NodeBuilder { public static TypeAnnotationContext unknownTypeAnnotation(Type javaType) { TypeAnnotationContext stsTypeAnnotation = typeAnnotation("__UnknownType__"); - stsTypeAnnotation.addChild(multiLineComment("/* " + javaType.toString() + " */")); + + if (javaType != null) { + stsTypeAnnotation.addChild(multiLineComment("/* " + javaType.toString() + " */")); + } + return stsTypeAnnotation; } + public static StatementContext untranslatedStatement(ASTNode node) { StatementContext stsStatement = new StatementContext(null, 0); ExpressionStatementContext stsExprStatement = new ExpressionStatementContext(stsStatement, 0); diff --git a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSLexer.g4 b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSLexer.g4 index 29fc91563..691dbf922 100644 --- a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSLexer.g4 +++ b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSLexer.g4 @@ -111,7 +111,6 @@ Instanceof: 'instanceof'; Case: 'case'; Else: 'else'; New: 'new'; -///Finally: 'finally'; - No 'finally' according STS specification Return: 'return'; Continue: 'continue'; For: 'for'; diff --git a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 index 75f21b6b6..f4539df96 100644 --- a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 +++ b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 @@ -330,7 +330,6 @@ statement | throwStatement | deferStatement | trapStatement - | deferStatement | expressionStatement ; @@ -408,9 +407,6 @@ catchOrRecoverClause exceptionParameter : OpenParen Identifier typeAnnotation CloseParen ; -deferStatement - : Defer statement - ; deferStatement : Defer statement diff --git a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java index bb1cb0226..c7a674c66 100644 --- a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java +++ b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java @@ -359,6 +359,11 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { sb.append(' '); if (stsTypeAnnotation.getChildCount() > 1) { + // In case of unresolved or invalid type, we add a comment to TypeAnnotationContext + // node indicating the original type name where we can (the type itself is emitted as + // __UnknownType__, see, e.g., JavaTransformer.createCatchOrRecoverClause method). + // Here we check if that additional child of TypeAnnotationContext node exists, + // and if so, emit it in STS source code. ParseTree lastChild = stsTypeAnnotation.getChild(stsTypeAnnotation.getChildCount()-1); if (lastChild instanceof TerminalNode) { stsTypeAnnotation.getChild(1).accept(this); @@ -675,32 +680,20 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { return null; } - // statement - // : importStatement - // | exportStatement - // | emptyStatement_ - // | abstractDeclaration //ADDED - // | decoratorList - // | classDeclaration - // | interfaceDeclaration //ADDED - // | namespaceDeclaration //ADDED + // statement + // : block + // | assertStatement // | ifStatement // | iterationStatement // | continueStatement // | breakStatement // | returnStatement - // | yieldStatement // | labelledStatement // | switchStatement // | throwStatement + // | deferStatement // | trapStatement - // | debuggerStatement - // | functionDeclaration - // | generatorFunctionDeclaration - // | variableStatement - // | enumDeclaration //ADDED // | expressionStatement - // | Export statement @Override public Void visitStatement(StatementContext stsStatement) { doNeededIndent(); @@ -710,7 +703,7 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { return null; } - // block: '{' statementList? '}' + // block: '{' statementOrLocalDeclaration* '}' @Override public Void visitBlock(BlockContext stsBlock) { doNeededIndent(); diff --git a/migrator/test/java/try_catch_finally.java b/migrator/test/java/try_catch_finally.java index eac22c07f..5a3817356 100644 --- a/migrator/test/java/try_catch_finally.java +++ b/migrator/test/java/try_catch_finally.java @@ -44,8 +44,8 @@ public class try_catch_finally { catch (NullPointerException n) { System.out.println("Caught NullPointerException"); } - catch (BlewIt b) { - System.out.println("Caught BlewIt"); + catch (BlewIt | IllegalArgumentException b) { + System.out.println("Caught BlewIt or IllegalArgumentException"); } catch (RuntimeException r) { System.out.println("Caught RuntimeException"); diff --git a/migrator/test/java/try_catch_finally.java.sts b/migrator/test/java/try_catch_finally.java.sts index 1b188f840..c48f24f97 100644 --- a/migrator/test/java/try_catch_finally.java.sts +++ b/migrator/test/java/try_catch_finally.java.sts @@ -56,7 +56,10 @@ export open class try_catch_finally { System.out.println("Caught NullPointerException"); } catch (b : BlewIt) { - System.out.println("Caught BlewIt"); + System.out.println("Caught BlewIt or IllegalArgumentException"); + } + recover (b : IllegalArgumentException) { + System.out.println("Caught BlewIt or IllegalArgumentException"); } recover (r : RuntimeException) { System.out.println("Caught RuntimeException"); -- Gitee From 15c2d4329800d29ccd2fd2c3fe4137e7ca501cf8 Mon Sep 17 00:00:00 2001 From: Mikhail Velikanov Date: Mon, 5 Sep 2022 17:37:25 +0300 Subject: [PATCH 6/6] Minor change: Renamed importStatement to importDeclaration to match STS specification document. Signed-off-by: Mikhail Velikanov --- .../ohos/migrator/java/JavaTransformer.java | 8 +++---- .../staticTS/parser/StaticTSParser.g4 | 6 ++--- .../staticTS/writer/StaticTSWriter.java | 22 +++++++++---------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index 829fa35af..97e651b0f 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -670,11 +670,11 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // import [ static ] Name [ . * ] ; // // STS tree: - // importStatement - // : Import qualifiedName (Dot Multiply)? SemiColon + // importDeclaration + // : Import qualifiedName (Dot Multiply)? SemiColon? @Override public boolean visit(ImportDeclaration javaImportDeclaration) { - pushCurrent(new ImportStatementContext(stsCurrent, 0)); + pushCurrent(new ImportDeclarationContext(stsCurrent, 0)); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Import)); stsCurrent.addChild(NodeBuilder.qualifiedName(javaImportDeclaration.getName())); @@ -686,7 +686,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.SemiColon)); - popCurrent(); // ImportStatementContext + popCurrent(); // ImportDeclarationContext ++countDeclTransformed; return false; diff --git a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 index f4539df96..af215832c 100644 --- a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 +++ b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 @@ -50,15 +50,15 @@ options { } compilationUnit - : packageDeclaration? importStatement* topDeclaration* EOF + : packageDeclaration? importDeclaration* topDeclaration* EOF ; packageDeclaration : Package qualifiedName SemiColon? // notLineTerminator ; -importStatement - : Import qualifiedName ((As Identifier) | (Dot Multiply))? SemiColon // notLineTerminator +importDeclaration + : Import qualifiedName ((As Identifier) | (Dot Multiply))? SemiColon? // notLineTerminator ; qualifiedName diff --git a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java index c7a674c66..6cff9ad2d 100644 --- a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java +++ b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java @@ -22,7 +22,6 @@ import com.ohos.migrator.staticTS.parser.StaticTSParserBaseVisitor; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; -import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; @@ -646,8 +645,8 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { PackageDeclarationContext stsPackageDecl = stsCompilationUnit.packageDeclaration(); if (stsPackageDecl != null) visitPackageDeclaration(stsPackageDecl); - for (ImportStatementContext stsImportStatement : stsCompilationUnit.importStatement()) { - visitImportStatement(stsImportStatement); + for (ImportDeclarationContext stsImportDeclaration : stsCompilationUnit.importDeclaration()) { + visitImportDeclaration(stsImportDeclaration); } for (TopDeclarationContext stsTopDeclaration : stsCompilationUnit.topDeclaration()) { @@ -721,25 +720,24 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { return null; } - // importStatement: Import qualifiedName (Dot Multiply)? SemiColon - @Override - public Void visitImportStatement(ImportStatementContext stsImportStatement) { + // importDeclaration: Import qualifiedName (Dot Multiply)? SemiColon? + public Void visitImportDeclaration(ImportDeclarationContext stsImportDeclatation) { doNeededIndent(); - sb.append(stsImportStatement.Import().getText()).append(' '); + sb.append(stsImportDeclatation.Import().getText()).append(' '); - visitQualifiedName(stsImportStatement.qualifiedName()); + visitQualifiedName(stsImportDeclatation.qualifiedName()); - TerminalNode termDot = stsImportStatement.Dot(); - TerminalNode termAs = stsImportStatement.As(); + TerminalNode termDot = stsImportDeclatation.Dot(); + TerminalNode termAs = stsImportDeclatation.As(); if (termDot != null) { sb.append(termDot.getText()); - TerminalNode termMult = stsImportStatement.Multiply(); + TerminalNode termMult = stsImportDeclatation.Multiply(); assert(termMult != null); sb.append(termMult.getText()); } else if (termAs != null) { sb.append(termAs.getText()).append(' '); - TerminalNode termId = stsImportStatement.Identifier(); + TerminalNode termId = stsImportDeclatation.Identifier(); assert(termId != null); sb.append(termId.getText()); } -- Gitee