From bc5be21125441f538f69308093f0b8cbe150cc77 Mon Sep 17 00:00:00 2001 From: Igor Rossinski Date: Tue, 30 Aug 2022 00:44:43 +0300 Subject: [PATCH 1/3] 'throw' statement translation and test; add 'panic' in grammar. Signed-off-by: Igor Rossinski --- .../ohos/migrator/java/JavaTransformer.java | 18 ++++++++--- .../migrator/staticTS/parser/StaticTSLexer.g4 | 3 ++ .../staticTS/parser/StaticTSParser.g4 | 8 ++++- .../staticTS/writer/StaticTSWriter.java | 10 ++++++ migrator/test/java/method_invocation.java.sts | 12 +++---- migrator/test/java/throw_statement.java | 32 +++++++++++++++++++ migrator/test/java/throw_statement.java.sts | 24 ++++++++++++++ 7 files changed, 93 insertions(+), 14 deletions(-) create mode 100644 migrator/test/java/throw_statement.java create mode 100644 migrator/test/java/throw_statement.java.sts diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index fe5c73d17..a005417fc 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -2189,7 +2189,6 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return false; } - private void translateBlockStatements(Block javaBlock) { List javaBlockStmts = javaBlock.statements(); for(Statement javaStmt : javaBlockStmts) { @@ -4554,11 +4553,20 @@ public class JavaTransformer extends ASTVisitor implements Transformer { @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, stsCurrent)).setParent(stsCurrent); + boolean isPanic = false; + Expression exceptionExpr = javaThrowStatement.getExpression(); + if( isPanicType(exceptionExpr) ) { + pushStatement(new PanicStatementContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Panic)); + } else { + pushStatement(new ThrowStatementContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Throw)); + } + exceptionExpr.accept(this); + + popStatement(); + ++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 839c8c4e3..ac583e2d8 100644 --- a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSLexer.g4 +++ b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSLexer.g4 @@ -122,6 +122,7 @@ Default: 'default'; Assert: 'assert'; If: 'if'; Throw: 'throw'; +Panic: 'panic'; Of: 'of'; Try: 'try'; Defer: 'defer'; @@ -155,6 +156,8 @@ Override: 'override'; Open: 'open'; Const: 'const'; Native: 'native'; +Throws: 'throws'; +Rethrows: 'rethrows' // Predefined types Byte: 'byte'; diff --git a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 index 5d07e2e2d..c98cfb1d2 100644 --- a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 +++ b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 @@ -172,7 +172,7 @@ classInitializer ; signature - : typeParameters? OpenParen parameterList? CloseParen typeAnnotation + : typeParameters? OpenParen parameterList? CloseParen typeAnnotation (Throws | Rethrows)? ; // Interfaces @@ -327,9 +327,11 @@ statement | returnStatement | labelledStatement | switchStatement + | panicStatement | throwStatement | deferStatement | trapStatement + | panicStatement | expressionStatement ; @@ -396,6 +398,10 @@ throwStatement : Throw {this.notLineTerminator()}? singleExpression SemiColon ; +panicStatement + : Panic {this.notLineTerminator()}? singleExpression SemiColon + ; + trapStatement : Trap block catchOrRecoverClause+ ; diff --git a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java index 3fba2b340..b096a4e01 100644 --- a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java +++ b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java @@ -1210,6 +1210,16 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { return null; } + @Override + public Void visitPanicStatement(PanicStatementContext stsPanicStatement) { + doNeededIndent(); + sb.append(stsPanicStatement.Panic().getText()).append(' '); + stsPanicStatement.singleExpression().accept(this); + sb.append(";\n"); + + return null; + } + // trapStatement: Trap block catchOrRecoverClause+; @Override public Void visitTrapStatement(TrapStatementContext stsTrapStatement) { diff --git a/migrator/test/java/method_invocation.java.sts b/migrator/test/java/method_invocation.java.sts index 2b2b6899f..2c0f2de93 100644 --- a/migrator/test/java/method_invocation.java.sts +++ b/migrator/test/java/method_invocation.java.sts @@ -12,7 +12,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.ohos.migrator.tests.java; open class SuperClass { @@ -23,8 +22,7 @@ open class SuperClass { open class SubClass1 extends SuperClass { override foo(): void { - __untranslated_statement(/* throw new UnsupportedOperationException(); - */); + throw new UnsupportedOperationException(); } tweak : Runnable = new Runnable() { public override run(): void { @@ -41,8 +39,7 @@ interface SuperInterface { open class SubClass2 implements SuperInterface { public override foo(): void { - __untranslated_statement(/* throw new UnsupportedOperationException(); - */); + throw new UnsupportedOperationException(); } open tweak(): void { SuperInterface.super.foo(); @@ -51,8 +48,7 @@ open class SubClass2 implements SuperInterface { open class SubClass3 implements SuperInterface { public override foo(): void { - __untranslated_statement(/* throw new UnsupportedOperationException(); - */); + throw new UnsupportedOperationException(); } tweak : Runnable = new Runnable() { public override run(): void { @@ -115,4 +111,4 @@ open class Test3 { let cp : ColoredPoint2 = new ColoredPoint2(); } } - \ No newline at end of file + diff --git a/migrator/test/java/throw_statement.java b/migrator/test/java/throw_statement.java new file mode 100644 index 000000000..22dd87643 --- /dev/null +++ b/migrator/test/java/throw_statement.java @@ -0,0 +1,32 @@ +/* + * 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 throw_statement { + private final int i = 0x7fff; + + public class Panic extends RuntimeException {} + + public int divide_test(int j) throws Exception { + if( j == 0 ) throw new Exception()[2]; + return i / j ; + } + + public int divide_test(long l) throws Panic { + if( l > i ) throw new Panic()[3]; + return (int) (i / l) ; + } +} diff --git a/migrator/test/java/throw_statement.java.sts b/migrator/test/java/throw_statement.java.sts new file mode 100644 index 000000000..7277b0cc2 --- /dev/null +++ b/migrator/test/java/throw_statement.java.sts @@ -0,0 +1,24 @@ +/* + * 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; + +export open class throw_statement { + private const i : int = 0x7fff; + public open divide_test(j : int): int { + if (j == 0) throw new Exception(); + return i / j; + } +} + -- Gitee From 8c18174a9713475d83040b2dd92d251796fc09dc Mon Sep 17 00:00:00 2001 From: Igor Rossinski Date: Wed, 21 Sep 2022 13:28:03 +0300 Subject: [PATCH 2/3] 'throw' statement part II, part III; 'throws' keyword; tests resilvering. Signed-off-by: Igor Rossinski --- .../ohos/migrator/java/JavaTransformer.java | 154 ++++++++++++++-- .../migrator/staticTS/parser/StaticTSLexer.g4 | 1 - .../staticTS/parser/StaticTSParser.g4 | 13 +- .../staticTS/writer/StaticTSWriter.java | 10 +- .../test/java/generic_interface_2.java.sts | 4 +- migrator/test/java/method_invocation.java.sts | 6 +- migrator/test/java/method_references.java.sts | 10 +- migrator/test/java/throw_statement.java | 5 +- migrator/test/java/throw_statement.java.sts | 9 +- migrator/test/java/throws_test.java | 169 +++++++++++++++++ migrator/test/java/throws_test.java.sts | 172 ++++++++++++++++++ migrator/test/java/try_catch_finally.java.sts | 24 +-- 12 files changed, 528 insertions(+), 49 deletions(-) create mode 100644 migrator/test/java/throws_test.java create mode 100644 migrator/test/java/throws_test.java.sts diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index a005417fc..75cdc925f 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -44,6 +44,13 @@ public class JavaTransformer extends ASTVisitor implements Transformer { private final Stack stsSaved = new Stack<>(); private final Stack stsCurrentTrapStatement = new Stack<>(); + // 'nested' methods may be declared through the local classes, + // so the list of collected exceptions for the 'outer' method might get mixed + // with exceptions of the method of 'nested' class so use stack + private final Stack> javaThrownExceptions = new Stack<>(); + + private final String INIT_THROWN_EXEPTIONS = "INIT_THROWN_EXCEPTIONS"; + 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"; @@ -130,6 +137,46 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent = stsSaved.pop(); } + // Entering each method create set of exceptions this method may throw + // If exception is caught inside method remove it from set + private void pushExceptionSet() { + Set excpSet = new HashSet<>(); + javaThrownExceptions.push( excpSet ); + } + + private void popExceptionSet() { + javaThrownExceptions.pop(); + } + + private boolean checkThrownExceptionSet(ASTNode javaNode) { + if( javaThrownExceptions.isEmpty()) { + reportError("Not initialized exception set", javaNode); + return false; + } + return true; + } + private Set currentExceptionsSet(ASTNode javaNode) { + if( checkThrownExceptionSet(javaNode)) + return javaThrownExceptions.peek(); + else + return new HashSet(); + } + private void addThrownException(ITypeBinding e) { + // java runtime exceptions transform into STS panics not exceptions + // so exclude them + if( (e != null) && !isRuntimeExceptionType(e) ) + javaThrownExceptions.peek().add(e); + } + + private void addMultipleThrownExceptions( ITypeBinding[] e) { + for( ITypeBinding excp : e) + addThrownException(excp); + } + + private void removeThrownException(ITypeBinding e) { + javaThrownExceptions.peek().remove(e); + } + private void pushStatement(ParserRuleContext stsStatement) { if (NodeBuilder.needStatementOrLocalDeclaration(stsCurrent)) pushCurrent(new StatementOrLocalDeclarationContext(stsCurrent, 0)); @@ -712,6 +759,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // Put statements from instance initializers into constructors which don't call // another constructor (i.e. don't have 'this()' call). List stsInitStmts = (List)javaTypeDeclaration.getProperty(INSTANCE_INITIALIZER); + Set stsInitThrownExceptions = (Set)javaTypeDeclaration.getProperty(INIT_THROWN_EXEPTIONS); if (stsCurrent instanceof ClassBodyContext && stsInitStmts != null && !stsInitStmts.isEmpty()) { ClassBodyContext stsClassBody = (ClassBodyContext) stsCurrent; @@ -721,6 +769,11 @@ public class JavaTransformer extends ASTVisitor implements Transformer { if (stsCtorDecl != null) { addInstanceInitializersToCtor(stsCtorDecl, stsInitStmts); needDefaultCtor = false; + + // if constructor already has 'throws' clause - do nothing + // else check thrown exceptions set for init blocks + if( (stsCtorDecl.Throws() == null) && !stsInitThrownExceptions.isEmpty() ) + stsCtorDecl.addChild(NodeBuilder.terminalNode(StaticTSParser.Throws)); } } @@ -735,6 +788,9 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Constructor)); stsCurrent.addChild(new ConstructorBodyContext(stsCurrent, 0)).setParent(stsCurrent); + if( !stsInitThrownExceptions.isEmpty() ) + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Throws)); + popCurrent(); // stsDefaultCtor popCurrent(); // ClassMemberContext @@ -1565,6 +1621,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // signature: typeParameters? OpenParen parameterList? CloseParen typeAnnotation @Override public boolean visit(MethodDeclaration javaMethodDeclaration) { + SignatureContext stsSignature = null; + ConstructorDeclarationContext stsConstructor = null; boolean isInClassContext = stsCurrent instanceof ClassBodyContext; assert(isInClassContext || (stsCurrent instanceof InterfaceBodyContext)); @@ -1583,6 +1641,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { javaMethodDeclaration.toString() + "\n*/\n")); return false; } + // create thrown exception set for current method + pushExceptionSet(); // Get current enclosing context - we'll need it later if // current method is synchronized (see below). Also store @@ -1595,7 +1655,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { pushCurrent(createDeclarationOrMemberContextWithAccessModifier(javaMods)); if (javaMethodDeclaration.isConstructor()) { - pushCurrent(new ConstructorDeclarationContext(stsCurrent, 0)); + stsConstructor = new ConstructorDeclarationContext(stsCurrent, 0); + pushCurrent(stsConstructor); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Constructor)).setParent(stsCurrent); // STS: typeParameters: LessThan typeParameterList? MoreThan @@ -1603,6 +1664,14 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // STS: OpenParen parameterList? CloseParen createStsParameterList(javaMethodDeclaration.parameters()); + + // thrown exceptions + List javaExceptions = javaMethodDeclaration.thrownExceptionTypes(); + if(checkThrownExceptionSet(javaMethodDeclaration)) { + for (Type javaExcp : javaExceptions) { + addThrownException(javaExcp.resolveBinding()); + } + } } else { // A regular method (not a constructor). // ClassMethodDeclarationContext object is needed for constructors of AbstractClassMethodContext and ClassMethodWithBodyContext. @@ -1615,7 +1684,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { pushCurrent(new ClassMethodWithBodyContext(stsClassMethodDeclaration)); } - translateMethodHeader(javaMethodDeclaration, isInClassContext); + stsSignature = translateMethodHeader(javaMethodDeclaration, isInClassContext); } if (javaBlock == null) { // Abstract method. @@ -1675,6 +1744,14 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // ConstructorBodyContext or BlockContext } + if( !currentExceptionsSet(javaMethodDeclaration).isEmpty()) { + if( javaMethodDeclaration.isConstructor() ) { + stsConstructor.addChild(NodeBuilder.terminalNode(StaticTSParser.Throws)); + } else if (stsSignature != null) + stsSignature.addChild(NodeBuilder.terminalNode(StaticTSParser.Throws)); + } + popExceptionSet(); // remove thrown exception set for current method + if (javaMethodDeclaration.isConstructor()) { popCurrent(); // ConstructorDeclarationContext } else { @@ -1688,13 +1765,14 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return false; } - private void translateMethodHeader(MethodDeclaration javaMethodDeclaration, boolean isInClassContext) { + private SignatureContext translateMethodHeader(MethodDeclaration javaMethodDeclaration, boolean isInClassContext) { // Non-access modifiers. translateNonAccessModifiers(javaMethodDeclaration, isInClassContext); // STS: signature: typeParameters? OpenParen parameterList? CloseParen typeAnnotation stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaMethodDeclaration.getName())); - pushCurrent(new SignatureContext(stsCurrent, 0)); + SignatureContext stsSignature = new SignatureContext(stsCurrent, 0); + pushCurrent(stsSignature); // STS: typeParameters: LessThan typeParameterList? MoreThan createStsTypeParameters(javaMethodDeclaration.typeParameters()); @@ -1703,14 +1781,30 @@ public class JavaTransformer extends ASTVisitor implements Transformer { createStsParameterList(javaMethodDeclaration.parameters()); // typeAnnotation - pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); - javaMethodDeclaration.getReturnType2().accept(this); + if(javaMethodDeclaration.getReturnType2() != null) { + pushCurrent(new TypeAnnotationContext(stsCurrent, 0)); + javaMethodDeclaration.getReturnType2().accept(this); + } + else { + // Warn and emit __UnknownType__ as variable type + reportError("Failed to resolve method returned type", javaMethodDeclaration); + stsCurrent.addChild(NodeBuilder.unknownTypeAnnotation()).setParent(stsCurrent); + } int javaExtraDims = javaMethodDeclaration.getExtraDimensions(); if (javaExtraDims > 0) NodeBuilder.addExtraDimensions(stsCurrent, javaExtraDims); + // thrown exceptions + List javaExceptions = javaMethodDeclaration.thrownExceptionTypes(); + if(checkThrownExceptionSet(javaMethodDeclaration)) { + for (Type javaExcp : javaExceptions) { + addThrownException(javaExcp.resolveBinding()); + } + } + popCurrent(); // TypeAnnotationContext popCurrent(); // SignatureContext + return stsSignature; } // Java tree: @@ -2431,17 +2525,24 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // static block @Override public boolean visit(Initializer javaInitializer) { - boolean isStatic = Modifier.isStatic(javaInitializer.getModifiers()); - // Sanity check: Initializers are allowed only in class body context. if (stsCurrent.getRuleIndex() != StaticTSParser.RULE_classBody) { // Warn and emit a comment with original source code of initializer reportError("Invalid context for initializer", javaInitializer); stsCurrent.addChild(NodeBuilder.multiLineComment("/* Untranslated initializer:\n" + - javaInitializer.toString() + "\n*/\n")); + javaInitializer.toString() + "\n*/\n")); return false; } + ASTNode javaInitParent = javaInitializer.getParent(); + Set javaInitThrownExceptions = (Set) javaInitParent.getProperty(INIT_THROWN_EXEPTIONS); + if( javaInitThrownExceptions == null ) { + javaInitThrownExceptions = new HashSet(); + javaInitParent.setProperty(INIT_THROWN_EXEPTIONS, javaInitThrownExceptions); + } + + boolean isStatic = Modifier.isStatic(javaInitializer.getModifiers()); + if (isStatic) { // StaticTS permits only one static initializer per class declaration. // Thus, we gather statements from all Java's static initializers @@ -2482,7 +2583,6 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // StaticTS doesn't have syntax for separate instance initializer blocks. // We gather all statements from such blocks in class declaration and place // at the beginning of all constructor's bodies that don't call another constructor. - ASTNode javaInitParent = javaInitializer.getParent(); List stsInitStmts = (List) javaInitParent.getProperty(INSTANCE_INITIALIZER); if (stsInitStmts == null) { @@ -2495,11 +2595,16 @@ public class JavaTransformer extends ASTVisitor implements Transformer { BlockContext stsBlock = new BlockContext(null, 0); pushCurrent(stsBlock, false); + pushExceptionSet(); + List javaStmts = javaInitializer.getBody().statements(); for(Statement javaStmt : javaStmts) { javaStmt.accept(this); } + javaInitThrownExceptions.addAll(currentExceptionsSet(javaInitializer)); + popExceptionSet(); + popCurrent(); // BlockContext stsInitStmts.addAll(stsBlock.statementOrLocalDeclaration()); @@ -2636,6 +2741,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { boolean isThrowingCall = false; if (javaCtorBinding != null) { isThrowingCall = javaCtorBinding.getExceptionTypes().length > 0; + if(isThrowingCall && checkThrownExceptionSet(javaCtorInvocation)) + addMultipleThrownExceptions(javaCtorBinding.getExceptionTypes()); } else { reportError("Failed to resolve constructor call", javaCtorInvocation); @@ -2669,6 +2776,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { boolean isThrowingCall = false; if (javaCtorBinding != null) { isThrowingCall = javaCtorBinding.getExceptionTypes().length > 0; + if(isThrowingCall && checkThrownExceptionSet(javaSuperCtorInvocation)) + addMultipleThrownExceptions(javaCtorBinding.getExceptionTypes()); } else { reportError("Failed to report constructor call", javaSuperCtorInvocation); @@ -2691,8 +2800,9 @@ public class JavaTransformer extends ASTVisitor implements Transformer { pushCurrent(new ConstructorCallContext(stsCurrent, 0)); // Add 'try' keyword if this is a throwing call. - if (isThrowingCall) stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); - + if (isThrowingCall) { + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); + } if (javaCtorExpr != null) { javaCtorExpr.accept(this); } @@ -2895,6 +3005,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // Add TryExpressionContext if ctor invoked can throw if (ctorCanThrow) { + if(checkThrownExceptionSet(javaClassInstanceCreation)) + addMultipleThrownExceptions(javaCtorBinding.getExceptionTypes()); pushCurrent(new TryExpressionContext(pushSingleExpression())); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); } @@ -3207,6 +3319,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // Add TryExpressionContext if this is a throwing call. if (isThrowingCall) { + if(checkThrownExceptionSet(javaMethodInvocation)) + addMultipleThrownExceptions(javaMethodBinding.getExceptionTypes()); pushCurrent(new TryExpressionContext(pushSingleExpression())); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Try)); } @@ -3639,6 +3753,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { pushCurrent(new LambdaExpressionContext(pushSingleExpression())); createStsParameterList(javaLambdaExpr.parameters()); + pushExceptionSet(); // resolveMethodBinding() can throw exceptions, // so let's catch them to make sure we proceed. @@ -3652,6 +3767,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { if (lambdaMethod != null) { translateType(lambdaMethod.getReturnType(), javaLambdaExpr); + if(checkThrownExceptionSet(javaLambdaExpr)) + addMultipleThrownExceptions(lambdaMethod.getExceptionTypes()); } else { // Warn and emit __UnknownType__ as return type @@ -3674,6 +3791,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // BlockContext } + popExceptionSet(); + popCurrent(); // LambdaBodyContext popSingleExpression(); // LambdaExpressionContext @@ -4275,6 +4394,9 @@ public class JavaTransformer extends ASTVisitor implements Transformer { reportError("Failed to resolve exception type", javaExceptionType); stsCurrent.addChild(NodeBuilder.unknownTypeAnnotation(javaExceptionType)).setParent(stsCurrent); } + // Do check to save some machine cycles on method call + if( !isRuntimeExceptionType(javaExcTypeBinding) && checkThrownExceptionSet(javaClauseBody)) + removeThrownException(javaExcTypeBinding); popCurrent(); // ExceptionParameterContext // NOTE: Can't call javaClauseBody.accept as that will @@ -4553,20 +4675,22 @@ public class JavaTransformer extends ASTVisitor implements Transformer { @Override public boolean visit(ThrowStatement javaThrowStatement) { - boolean isPanic = false; Expression exceptionExpr = javaThrowStatement.getExpression(); - if( isPanicType(exceptionExpr) ) { + if( isRuntimeExceptionType(exceptionExpr.resolveTypeBinding()) ) { pushStatement(new PanicStatementContext(stsCurrent, 0)); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Panic)); } else { pushStatement(new ThrowStatementContext(stsCurrent, 0)); stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Throw)); + if(checkThrownExceptionSet(javaThrowStatement)) + addThrownException(exceptionExpr.resolveTypeBinding()); } exceptionExpr.accept(this); popStatement(); - ++countExprTransformed; + stmtTransformed.add(javaThrowStatement); + 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 ac583e2d8..75be039e9 100644 --- a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSLexer.g4 +++ b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSLexer.g4 @@ -157,7 +157,6 @@ Open: 'open'; Const: 'const'; Native: 'native'; Throws: 'throws'; -Rethrows: 'rethrows' // Predefined types Byte: 'byte'; diff --git a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 index c98cfb1d2..7b455b61b 100644 --- a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 +++ b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 @@ -113,7 +113,7 @@ classMember ; constructorDeclaration - : Constructor typeParameters? OpenParen parameterList? CloseParen constructorBody + : Constructor typeParameters? OpenParen parameterList? CloseParen Throws? constructorBody ; parameterList @@ -172,7 +172,7 @@ classInitializer ; signature - : typeParameters? OpenParen parameterList? CloseParen typeAnnotation (Throws | Rethrows)? + : typeParameters? OpenParen parameterList? CloseParen typeAnnotation Throws? ; // Interfaces @@ -331,7 +331,6 @@ statement | throwStatement | deferStatement | trapStatement - | panicStatement | expressionStatement ; @@ -394,14 +393,14 @@ defaultClause : Default ':' statement* ; -throwStatement - : Throw {this.notLineTerminator()}? singleExpression SemiColon - ; - panicStatement : Panic {this.notLineTerminator()}? singleExpression SemiColon ; +throwStatement + : Throw {this.notLineTerminator()}? singleExpression SemiColon + ; + trapStatement : Trap block catchOrRecoverClause+ ; diff --git a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java index b096a4e01..4a3cadf5c 100644 --- a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java +++ b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java @@ -402,6 +402,9 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { visitTypeAnnotation(stsSignature.typeAnnotation()); + if( stsSignature.Throws() != null) + sb.append(' ').append(stsSignature.Throws().getText()).append(' '); + return null; } @@ -433,7 +436,12 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { visitParameterList(stsParameterList); } - sb.append(") {\n"); + sb.append(')'); + + if( stsConstructorDeclaration.Throws() != null) + sb.append(' ').append(stsConstructorDeclaration.Throws().getText()); + + sb.append(" {\n"); indentIncrement(); visitConstructorBody(stsConstructorDeclaration.constructorBody()); diff --git a/migrator/test/java/generic_interface_2.java.sts b/migrator/test/java/generic_interface_2.java.sts index 9bd613d2f..7c24c7520 100644 --- a/migrator/test/java/generic_interface_2.java.sts +++ b/migrator/test/java/generic_interface_2.java.sts @@ -15,11 +15,11 @@ package com.ohos.migrator.test.java; interface G1 { - m(): Object ; + m(): Object throws ; } interface G2 { - m(): String ; + m(): String throws ; } interface G extends G1, G2 { diff --git a/migrator/test/java/method_invocation.java.sts b/migrator/test/java/method_invocation.java.sts index 2c0f2de93..2dabc2f98 100644 --- a/migrator/test/java/method_invocation.java.sts +++ b/migrator/test/java/method_invocation.java.sts @@ -22,7 +22,7 @@ open class SuperClass { open class SubClass1 extends SuperClass { override foo(): void { - throw new UnsupportedOperationException(); + panic new UnsupportedOperationException(); } tweak : Runnable = new Runnable() { public override run(): void { @@ -39,7 +39,7 @@ interface SuperInterface { open class SubClass2 implements SuperInterface { public override foo(): void { - throw new UnsupportedOperationException(); + panic new UnsupportedOperationException(); } open tweak(): void { SuperInterface.super.foo(); @@ -48,7 +48,7 @@ open class SubClass2 implements SuperInterface { open class SubClass3 implements SuperInterface { public override foo(): void { - throw new UnsupportedOperationException(); + panic new UnsupportedOperationException(); } tweak : Runnable = new Runnable() { public override run(): void { diff --git a/migrator/test/java/method_references.java.sts b/migrator/test/java/method_references.java.sts index 6659df013..8bba70d10 100644 --- a/migrator/test/java/method_references.java.sts +++ b/migrator/test/java/method_references.java.sts @@ -210,21 +210,21 @@ open class MethodReferencesExamples { } interface TryFunction0 { - apply(): T ; + apply(): T throws ; } interface TryFunction1 { - apply(t : T): R ; + apply(t : T): R throws ; } open class MyException extends Exception { } static open class Exceptions { - public constructor() { + public constructor() throws { } - public open getName(): String { + public open getName(): String throws { return "George"; } } @@ -241,4 +241,4 @@ open class MethodReferencesExamples { } } - \ No newline at end of file + diff --git a/migrator/test/java/throw_statement.java b/migrator/test/java/throw_statement.java index 22dd87643..1a8abaa1b 100644 --- a/migrator/test/java/throw_statement.java +++ b/migrator/test/java/throw_statement.java @@ -21,12 +21,13 @@ public class throw_statement { public class Panic extends RuntimeException {} public int divide_test(int j) throws Exception { - if( j == 0 ) throw new Exception()[2]; + if( j == 0 ) throw new Exception(); return i / j ; } public int divide_test(long l) throws Panic { - if( l > i ) throw new Panic()[3]; + if( l > i ) throw new Panic(); return (int) (i / l) ; } + } diff --git a/migrator/test/java/throw_statement.java.sts b/migrator/test/java/throw_statement.java.sts index 7277b0cc2..12020ddb5 100644 --- a/migrator/test/java/throw_statement.java.sts +++ b/migrator/test/java/throw_statement.java.sts @@ -16,9 +16,16 @@ package com.ohos.migrator.test.java; export open class throw_statement { private const i : int = 0x7fff; - public open divide_test(j : int): int { + public open class Panic extends RuntimeException { + } + + public open divide_test(j : int): int throws { if (j == 0) throw new Exception(); return i / j; } + public open divide_test(l : long): int { + if (l > i) panic new Panic(); + return (i / l) as int; + } } diff --git a/migrator/test/java/throws_test.java b/migrator/test/java/throws_test.java new file mode 100644 index 000000000..2529cc4d8 --- /dev/null +++ b/migrator/test/java/throws_test.java @@ -0,0 +1,169 @@ +/* + * 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.tests.java; + +class MyException extends Exception { + MyException() { } + MyException(String s) { super(s); } +} + +class AnotherException extends Exception { +} + +class SuperClass { + private String s; + public SuperClass(String s) throws MyException { + if(s == null) throw new MyException(); + this.s = s; + } + void foo() { System.out.println(s); } +} + +class SubClass1 extends SuperClass { + + public SubClass1(String s) throws AnotherException, MyException { + super(s); + if(s == null ) throw new AnotherException(); + } + + void foo() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + public void run() throws UnsupportedOperationException { + foo(); + } + + public void toto() throws MyException { throw new MyException(); } +} + + +class SubClass2 extends SubClass1 { + + public SubClass2(String s) throws AnotherException, MyException, UnsupportedOperationException { + super(s); + if( s == "!" ) throw new UnsupportedOperationException(); + } + + public void foo() throws UnsupportedOperationException { super.foo(); } + public void bar() throws UnsupportedOperationException, AnotherException { super.foo(); throw new AnotherException(); } + public void toto() throws MyException { super.toto(); } +} + + +class Test { + + // throws + public static void test1(String s) throws MyException, AnotherException { + SubClass1 sc1 = new SubClass1(s); + sc1.foo(); + } + + // throws + public static void test2(String s) throws AnotherException { + try { + SubClass1 sc1 = new SubClass1(s); + } + catch( MyException e ) {} + } + + // no throws - all excepyions are catched + public static void test3(String s) { + try { + SubClass1 sc1 = new SubClass1(s); + } + catch( MyException | AnotherException e) {} + } + + // no throws - only panic + public static void test4(String s) { + try { + SubClass2 sc2 = new SubClass2(s); + } + catch( MyException | AnotherException e) {} + } + + // no throws - only panic + public static void test5(String s) { + try { + SubClass2 sc2 = new SubClass2(s); + sc2.foo(); + } + catch( MyException | AnotherException e) {} + } + + // throws + public static void test6(String s) throws AnotherException { + try { + SubClass2 sc2 = new SubClass2(s); + sc2.bar(); + } + catch( MyException e) {} + + } + + + // test for constructor with static initializer + static class E1 extends Exception {} + static class E2 extends Exception {} + static class E3 extends Exception {} + + static abstract class Ta { + public abstract void m() throws E1, E2; + } + + interface Tb { + void m() throws E2, E3; + } + + + // intersect throws clauses + static abstract class Tc extends Ta implements Tb { + { + try { + m(); + } + catch ( E2 e2 ) { + } + } + } + + + // STS constructor must have throws clause + static abstract class Td extends Ta { + { + try { + m(); + } + catch ( E2 e2 ) { + } + } + + public Td() throws E1 { + } + + } + + + // snippet untranslateble by Java, uncomment to check there is no NPE! + /*** + interface FunctionalInterface { void foo(); } + abstract class AbstractException extends Error implements FunctionalInterface {} + + final AbstractException notInitialized = (AbstractException)( (FunctionalInterface)( () -> { throw notInitialized; } ) ); + ***/ +} + diff --git a/migrator/test/java/throws_test.java.sts b/migrator/test/java/throws_test.java.sts new file mode 100644 index 000000000..5bce61a9b --- /dev/null +++ b/migrator/test/java/throws_test.java.sts @@ -0,0 +1,172 @@ +/* + * 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.tests.java; + +open class MyException extends Exception { + constructor() { + } + + constructor(s : String) { + super(s); + } + +} + +open class AnotherException extends Exception { +} + +open class SuperClass { + private s : String ; + public constructor(s : String) throws { + if (s == null) throw new MyException(); + this.s = s; + } + + open foo(): void { + System.out.println(s); + } +} + +open class SubClass1 extends SuperClass { + public constructor(s : String) throws { + try super(s); + if (s == null) throw new AnotherException(); + } + + override foo(): void { + panic new UnsupportedOperationException(); + } + public open run(): void { + try foo(); + } + public open toto(): void throws { + throw new MyException(); + } +} + +open class SubClass2 extends SubClass1 { + public constructor(s : String) throws { + try super(s); + if (s == "!") panic new UnsupportedOperationException(); + } + + public override foo(): void { + super.foo(); + } + public open bar(): void throws { + super.foo(); + throw new AnotherException(); + } + public override toto(): void throws { + super.toto(); + } +} + +open class Test { + public static test1(s : String): void throws { + let sc1 : SubClass1 = try new SubClass1(s); + try sc1.foo(); + } + public static test2(s : String): void throws { + trap { + let sc1 : SubClass1 = try new SubClass1(s); + } + catch (e : MyException) { + } + + } + public static test3(s : String): void { + trap { + let sc1 : SubClass1 = try new SubClass1(s); + } + catch (e : MyException) { + } + catch (e : AnotherException) { + } + + } + public static test4(s : String): void { + trap { + let sc2 : SubClass2 = try new SubClass2(s); + } + catch (e : MyException) { + } + catch (e : AnotherException) { + } + + } + public static test5(s : String): void { + trap { + let sc2 : SubClass2 = try new SubClass2(s); + try sc2.foo(); + } + catch (e : MyException) { + } + catch (e : AnotherException) { + } + + } + public static test6(s : String): void throws { + trap { + let sc2 : SubClass2 = try new SubClass2(s); + try sc2.bar(); + } + catch (e : MyException) { + } + + } + static open class E1 extends Exception { + } + + static open class E2 extends Exception { + } + + static open class E3 extends Exception { + } + + abstract static class Ta { + public abstract m(): void throws ; + } + + interface Tb { + m(): void throws ; + } + + abstract static class Tc extends Ta implements Tb { + public constructor() { + trap { + try m(); + } + catch (e2 : E2) { + } + + } + + } + + abstract static class Td extends Ta { + public constructor() throws { + trap { + try m(); + } + catch (e2 : E2) { + } + + } + + } + +} + diff --git a/migrator/test/java/try_catch_finally.java.sts b/migrator/test/java/try_catch_finally.java.sts index c48f24f97..61ee0a7a4 100644 --- a/migrator/test/java/try_catch_finally.java.sts +++ b/migrator/test/java/try_catch_finally.java.sts @@ -12,38 +12,36 @@ * 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() { } - constructor(s : String) { - super(s); + + constructor(s : String) { + super(s); } + } export open class try_catch_finally { - public constructor() { + public constructor() throws { } - public constructor(i : int) { - try this(); + public constructor(i : int) throws { + try this(); } - static blowUp(): void { + static blowUp(): void throws { } - - private static foo(): void { + private static foo(): void throws { { defer { System.out.println("In finally"); } - try blowUp(); } } - public static main(args : String[]): void { trap { defer { @@ -67,5 +65,7 @@ export open class try_catch_finally { catch (e : Exception) { System.out.println("Caught Exception"); } + } } + -- Gitee From 9e2e38a25aa781dedfd50eb3dd1c8f97a8971654 Mon Sep 17 00:00:00 2001 From: Igor Rossinski Date: Wed, 28 Sep 2022 22:50:45 +0300 Subject: [PATCH 3/3] improve throws check algorithm Signed-off-by: Igor Rossinski --- .../ohos/migrator/java/JavaTransformer.java | 47 ++++++++++++------- .../test/java/try_with_resources.java.sts | 13 +++-- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index 75cdc925f..bf5b8d622 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -174,7 +174,16 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } private void removeThrownException(ITypeBinding e) { - javaThrownExceptions.peek().remove(e); + Set javaExceptionSet = javaThrownExceptions.peek(); + // use Iterator due to bad design of Java collections! + Iterator iterator = javaThrownExceptions.peek().iterator(); + while( iterator.hasNext()) { + // check if catch superclass for exception + ITypeBinding exception = (ITypeBinding) iterator.next(); + if( exception.isSubTypeCompatible(e)) + iterator.remove(); + } + javaThrownExceptions.peek().remove(e); } private void pushStatement(ParserRuleContext stsStatement) { @@ -1625,6 +1634,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { ConstructorDeclarationContext stsConstructor = null; boolean isInClassContext = stsCurrent instanceof ClassBodyContext; assert(isInClassContext || (stsCurrent instanceof InterfaceBodyContext)); + boolean methodHasThrowsClause = false; + Set javaMethodExceptionSet = new HashSet<>(); // Sanity check: Constructors cannot be body-less and methods cannot be without return type Block javaBlock = javaMethodDeclaration.getBody(); @@ -1664,14 +1675,6 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // STS: OpenParen parameterList? CloseParen createStsParameterList(javaMethodDeclaration.parameters()); - - // thrown exceptions - List javaExceptions = javaMethodDeclaration.thrownExceptionTypes(); - if(checkThrownExceptionSet(javaMethodDeclaration)) { - for (Type javaExcp : javaExceptions) { - addThrownException(javaExcp.resolveBinding()); - } - } } else { // A regular method (not a constructor). // ClassMethodDeclarationContext object is needed for constructors of AbstractClassMethodContext and ClassMethodWithBodyContext. @@ -1687,6 +1690,15 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsSignature = translateMethodHeader(javaMethodDeclaration, isInClassContext); } + // process method thrown exceptions + List javaExceptions = javaMethodDeclaration.thrownExceptionTypes(); + methodHasThrowsClause = ! javaExceptions.isEmpty(); + for (Type javaExcp : javaExceptions) { + ITypeBinding javaExcpType = javaExcp.resolveBinding(); + if( !isRuntimeExceptionType(javaExcpType) ) + javaMethodExceptionSet.add(javaExcpType); + } + if (javaBlock == null) { // Abstract method. stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.SemiColon)); } else { @@ -1744,7 +1756,14 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // ConstructorBodyContext or BlockContext } - if( !currentExceptionsSet(javaMethodDeclaration).isEmpty()) { + // If method has 'throws' clause with exceptions which are not panics - add 'throws' in STS + // else emit message that only panics present + // If there is no 'throws' - get results from analize + if( methodHasThrowsClause && javaMethodExceptionSet.isEmpty()) { + String message = String.format("Java method '%s' throws only panics", javaMethodDeclaration.getName()); + reportError(message, javaMethodDeclaration); + } + if( !javaMethodExceptionSet.isEmpty() || !currentExceptionsSet(javaMethodDeclaration).isEmpty()) { if( javaMethodDeclaration.isConstructor() ) { stsConstructor.addChild(NodeBuilder.terminalNode(StaticTSParser.Throws)); } else if (stsSignature != null) @@ -1794,14 +1813,6 @@ public class JavaTransformer extends ASTVisitor implements Transformer { int javaExtraDims = javaMethodDeclaration.getExtraDimensions(); if (javaExtraDims > 0) NodeBuilder.addExtraDimensions(stsCurrent, javaExtraDims); - // thrown exceptions - List javaExceptions = javaMethodDeclaration.thrownExceptionTypes(); - if(checkThrownExceptionSet(javaMethodDeclaration)) { - for (Type javaExcp : javaExceptions) { - addThrownException(javaExcp.resolveBinding()); - } - } - popCurrent(); // TypeAnnotationContext popCurrent(); // SignatureContext return stsSignature; diff --git a/migrator/test/java/try_with_resources.java.sts b/migrator/test/java/try_with_resources.java.sts index 6d0f35cd6..157fc7a51 100644 --- a/migrator/test/java/try_with_resources.java.sts +++ b/migrator/test/java/try_with_resources.java.sts @@ -26,7 +26,7 @@ import java.sql.Statement; import java.sql.SQLException; import java.util.Scanner; open class TryWithResources { - open readFile(): void { + open readFile(): void throws { let line : String = ""; let path : String = ""; { @@ -93,7 +93,7 @@ open class TryWithResources { } } - open viewTable(con : Connection): void { + open viewTable(con : Connection): void throws { let query : String = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES"; trap { const stmt : Statement = try con.createStatement(); @@ -139,7 +139,7 @@ open class TryWithResources { } } - open readFile2(): void { + open readFile2(): void throws { let line : String = ""; let path : String = ""; { @@ -438,14 +438,13 @@ open class TryWithResources { open class Y implements AutoCloseable { public val : int = 10; - public override close(): void { + public override close(): void throws { if (val < 0) { - __untranslated_statement(/* throw new IOException("Invalid value: " + val); - */); + throw new IOException("Invalid value: " + val); } System.out.println("Closed"); } } } - \ No newline at end of file + -- Gitee