diff --git a/migrator/TSLinter.README.md b/migrator/TSLinter.README.md new file mode 100644 index 0000000000000000000000000000000000000000..1d4a3a350c43b0dfbf10e4a5cd4bc7b2974198aa --- /dev/null +++ b/migrator/TSLinter.README.md @@ -0,0 +1,58 @@ +# TypeScript linter +Typescript linter ( further mentioned as 'linter' ) is a tool to check typescript sources and find language elements +and constructions which are deprecated to use in a purpose to migrate sources to STS. +The linter is currently under development. + +## Building +To build linter download from gitee (https://gitee.com/openharmony-sig/arkcompiler_ets_frontend/tree/master/migrator), + +### Requirements +This project is using the **Apache Ant** tool for building. You can download binaries from [here](https://ant.apache.org/bindownload.cgi) (it's recommended to use the latest available version) and use the [official guide](https://ant.apache.org/manual/install.html) to install and setup the tool. + +You also need to use **Java 11** (or newer) to build the project. + +The linter is written on TypeScript and requires NodeJS to build the project and run. For details, see the [typescript](typescript) page. + +### Steps to build + +The build supports two main targets: **clean** and **build**: +- Use **ant clean build** to perform build with preliminary cleaning of previous build artifacts. +- Use **ant build** to do incremental build (does not re-build sources that didn't change). + +The result file is web packet **out/typescript/javascript/src/linter/dist/tslinter.ts**. + +## Running +To use linter after the build, run the following command from the top-level folder of +the repository: + +node ./out/typescript/javascript/src/linter/dist/tslinter.ts [options] [input files] + +or use command files tslinter.sh or tslinter.cmd with same arguments as for direct launch. + +Possible options are: + +**--deveco-plugin-mode** this options defines special mode to launch from IDE and shouldn't be used in command line work + +**--strict** defines 'strict' mode in which all problem TypeScript language elements are counted; + if this option is not set, linter works in 'relax' mode in which counts only elements that cannot be transpiled + by TypeSctipt migrator. + +**--project-folder ** defines path to folder with TypeScript sources and subfolders which linter walks recurscevely. + This option may be repeated in command line with different paths. + +All other command line arguments are considered as paths to TypeScript files. + +To prevent command line buffer overflow response file may be used. Its name is set by adding '@' prefix to file name +( for example: 'tslinter.sh @responce.file.txt' ). +Response file should contain TypeScript source paths (one at each line). +In case of using responce file no other arguments except options take effect. + +Work results are printed to stdout and may be redirected to file. + + + +## Running tests +All tests are located under the test folder in linter subfolder. + + +To run all tests, run **ant test_linter** on the command line. diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index 62aedf7cd244c9a825962f94290c756c12443031..56a4ac6bf3fd83b743eaae84981f7ceadda87ccd 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -906,8 +906,8 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // if constructor already has 'throws' clause - do nothing // else check thrown exceptions set for init blocks - if ((stsCtorDecl.Identifier() == null) && !stsInitThrownExceptions.isEmpty()) - stsCtorDecl.addChild(NodeBuilder.terminalIdentifier(StaticTSParser.THROWS)); + if ((stsCtorDecl.throwsAnnotation() == null) && !stsInitThrownExceptions.isEmpty()) + stsCtorDecl.addChild(NodeBuilder.throwsAnnotation(true)); } } @@ -923,7 +923,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(new ConstructorBodyContext(stsCurrent, 0)).setParent(stsCurrent); if( !stsInitThrownExceptions.isEmpty() ) - stsCurrent.addChild(NodeBuilder.terminalIdentifier(StaticTSParser.THROWS)); + stsCurrent.addChild(NodeBuilder.throwsAnnotation(true)); popCurrent(); // stsDefaultCtor popCurrent(); // ClassMemberContext @@ -2067,9 +2067,9 @@ public class JavaTransformer extends ASTVisitor implements Transformer { } if( !javaMethodExceptionSet.isEmpty() || !currentExceptionsSet(javaMethodDeclaration).isEmpty()) { if( javaMethodDeclaration.isConstructor() ) - stsConstructor.addChild(NodeBuilder.terminalIdentifier(StaticTSParser.THROWS)); + stsConstructor.addChild(NodeBuilder.throwsAnnotation(true)).setParent(stsConstructor); else if (stsSignature != null) - stsSignature.addChild(NodeBuilder.terminalIdentifier(StaticTSParser.THROWS)); + stsSignature.addChild(NodeBuilder.throwsAnnotation(true)).setParent(stsSignature); } popExceptionSet(); // remove thrown exception set for current method @@ -4290,6 +4290,9 @@ public class JavaTransformer extends ASTVisitor implements Transformer { stsCurrent.addChild(NodeBuilder.unknownTypeAnnotation()).setParent(stsCurrent); } + if (!currentExceptionsSet(javaLambdaExpr).isEmpty()) + stsCurrent.addChild(NodeBuilder.throwsAnnotation(true)).setParent(stsCurrent); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Arrow)); pushCurrent(new LambdaBodyContext(stsCurrent, 0)); @@ -4349,6 +4352,9 @@ public class JavaTransformer extends ASTVisitor implements Transformer { : javaMethodBinding.getReturnType(); translateTypeBinding(returnType, javaMethodRef); + if (javaMethodBinding.getExceptionTypes().length > 0) + stsCurrent.addChild(NodeBuilder.throwsAnnotation(true)).setParent(stsCurrent); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Arrow)); // Create lambda body. It consists of the method reference call. @@ -4774,16 +4780,20 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // // STS AST: // tryStatement - // : Try block catchOrRecoverClause+ + // : Try block (catchClause+ | catchClause* defaultCatch) // ; // - // catchOrRecoverClause - // : (Catch | Recover) exceptionParameter? block + // catchClause + // : Catch exceptionParameter block // ; // // exceptionParameter // : OpenParen Identifier typeAnnotation CloseParen // ; + // + // defaultCatch + // : Catch (OpenParen Identifier CloseParen)? block + // @Override public boolean visit(TryStatement javaTryStatement) { List javaCatchClauses = javaTryStatement.catchClauses(); @@ -4853,11 +4863,11 @@ public class JavaTransformer extends ASTVisitor implements Transformer { if (javaExceptionType.isUnionType()) { List javaExcTypes = ((UnionType)javaExceptionType).types(); for (Type javaExcType : javaExcTypes) { - createCatchOrRecoverClause(javaExcType, javaExceptionName, javaCatchBody); + createCatchClause(javaExcType, javaExceptionName, javaCatchBody); } } else { - createCatchOrRecoverClause(javaExceptionType, javaExceptionName, javaCatchBody); + createCatchClause(javaExceptionType, javaExceptionName, javaCatchBody); } } @@ -4876,17 +4886,13 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return false; } - private void createCatchOrRecoverClause(Type javaExceptionType, - SimpleName javaExceptionName, - Block javaClauseBody) { - pushCurrent(new CatchOrRecoverClauseContext(stsCurrent,0)); + private void createCatchClause(Type javaExceptionType, + SimpleName javaExceptionName, + Block javaClauseBody) { + pushCurrent(new CatchClauseContext(stsCurrent,0)); - // Emit 'recover' keyword instead of 'catch' if - // exception type is a subtype of RuntimeException. ITypeBinding javaExcTypeBinding = NodeBuilder.getTypeBinding(javaExceptionType); - String stsKeyword = isRuntimeExceptionType(javaExcTypeBinding) ? - StaticTSParser.RECOVER : StaticTSParser.CATCH; - stsCurrent.addChild(NodeBuilder.terminalIdentifier(stsKeyword)); + stsCurrent.addChild(NodeBuilder.terminalIdentifier(StaticTSParser.CATCH)); pushCurrent(new ExceptionParameterContext(stsCurrent, 0)); stsCurrent.addChild(NodeBuilder.terminalIdentifier(javaExceptionName)); @@ -4911,7 +4917,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { translateBlockStatements(javaClauseBody); popCurrent(); // BlockContext - popCurrent(); // CatchOrRecoverClauseContext + popCurrent(); // CatchClauseContext } private boolean isRuntimeExceptionType(ITypeBinding javaExcType) { return isValidExceptionType(javaExcType) && @@ -5088,21 +5094,19 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popStatement(); // DeferStatementContext popCurrent(); // BlockContext - emitCatchOrRecoverClauseForResourceAllocation(primaryExceptionVarName, true); - emitCatchOrRecoverClauseForResourceAllocation(primaryExceptionVarName, false); + emitCatchClauseForResourceAllocation(primaryExceptionVarName); popStatement(); // TryStatementContext stsCurrentTryStatement.push(stsTryStmt); } - private void emitCatchOrRecoverClauseForResourceAllocation(String primaryExceptionVarName, boolean isCatchClause) { + private void emitCatchClauseForResourceAllocation(String primaryExceptionVarName) { // catch (Throwable #t) { // #primaryExc = #t; // throw #t; // } - pushCurrent(new CatchOrRecoverClauseContext(stsCurrent, 0)); - String stsKeyword = isCatchClause ? StaticTSParser.CATCH : StaticTSParser.RECOVER; - stsCurrent.addChild(NodeBuilder.terminalIdentifier(stsKeyword)); + pushCurrent(new CatchClauseContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalIdentifier(StaticTSParser.CATCH)); pushCurrent(new ExceptionParameterContext(stsCurrent, 0)); stsCurrent.addChild(NodeBuilder.terminalIdentifier("t")); stsCurrent.addChild(NodeBuilder.typeAnnotation("Throwable")).setParent(stsCurrent); @@ -5123,7 +5127,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popStatement(); // ThrowStatementContext popCurrent(); // BlockContext - popCurrent(); // CatchOrRecoverClauseContext + popCurrent(); // CatchClauseContext } private void emitTryStmtForResourceDisposal(Expression javaResourceName, String primaryExceptionVarName) { // try { #resource.close(); } catch {..} @@ -5142,16 +5146,14 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); // CallExpressionContext popStatement(); // ExpressionStatementContext popCurrent(); // BlockContext - emitCatchOrRecoverClauseForResourceDisposal(primaryExceptionVarName, true); - emitCatchOrRecoverClauseForResourceDisposal(primaryExceptionVarName, false); + emitCatchClauseForResourceDisposal(primaryExceptionVarName); popStatement(); // TryStatementContext } - private void emitCatchOrRecoverClauseForResourceDisposal(String primaryExceptionVarName, boolean isCatchClause) { + private void emitCatchClauseForResourceDisposal(String primaryExceptionVarName) { // catch (Throwable #suppressedExc) { #primaryExc.addSuppressed(#suppressedExc); } - pushCurrent(new CatchOrRecoverClauseContext(stsCurrent, 0)); - String stsKeyword = isCatchClause ? StaticTSParser.CATCH : StaticTSParser.RECOVER; - stsCurrent.addChild(NodeBuilder.terminalIdentifier(stsKeyword)); + pushCurrent(new CatchClauseContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalIdentifier(StaticTSParser.CATCH)); pushCurrent(new ExceptionParameterContext(stsCurrent, 0)); stsCurrent.addChild(NodeBuilder.terminalIdentifier("suppressedExc")); stsCurrent.addChild(NodeBuilder.typeAnnotation("Throwable")).setParent(stsCurrent); @@ -5172,22 +5174,18 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popSingleExpression(); // CallExpressionContext popStatement(); // ExpressionStatementContext popCurrent(); // BlockContext - popCurrent(); // CatchOrRecoverClauseContext + popCurrent(); // CatchClauseContext } @Override public boolean visit(ThrowStatement javaThrowStatement) { Expression exceptionExpr = javaThrowStatement.getExpression(); - 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()); - } + pushStatement(new ThrowStatementContext(stsCurrent, 0)); + stsCurrent.addChild(NodeBuilder.terminalNode(StaticTSParser.Throw)); + if(checkThrownExceptionSet(javaThrowStatement)) + addThrownException(exceptionExpr.resolveTypeBinding()); + exceptionExpr.accept(this); popStatement(); diff --git a/migrator/src/com/ohos/migrator/staticTS/NodeBuilderBase.java b/migrator/src/com/ohos/migrator/staticTS/NodeBuilderBase.java index 698cfcabdbae8b3adfde6d6cbb2c181162d19323..557f91f3235adf68e5093bc1980fc4792d4f0f1c 100644 --- a/migrator/src/com/ohos/migrator/staticTS/NodeBuilderBase.java +++ b/migrator/src/com/ohos/migrator/staticTS/NodeBuilderBase.java @@ -304,6 +304,13 @@ public class NodeBuilderBase { return typeAnnotation(stsTypeRef); } + public static ThrowsAnnotationContext throwsAnnotation(boolean isThrows) { + ThrowsAnnotationContext stsThrowsAnno = new ThrowsAnnotationContext(null, 0); + stsThrowsAnno.addChild(terminalIdentifier(isThrows ? StaticTSParser.THROWS : StaticTSParser.RETHROWS)); + + return stsThrowsAnno; + } + public static ParameterContext parameter(String stsParamName, String stsParamType) { ParameterContext stsParam = new ParameterContext(null, 0); stsParam.addChild(terminalIdentifier(stsParamName)); diff --git a/migrator/src/com/ohos/migrator/staticTS/NodeClonner.java b/migrator/src/com/ohos/migrator/staticTS/NodeClonner.java index ba254fbac07c9b4e08b7a4d98f70b8bcdb6d5357..ce85006fe47f6ca57d1c7a63464beb49b9032e8b 100644 --- a/migrator/src/com/ohos/migrator/staticTS/NodeClonner.java +++ b/migrator/src/com/ohos/migrator/staticTS/NodeClonner.java @@ -171,14 +171,20 @@ public class NodeClonner { TypeAnnotationContext srcTypeAnnot = srcFunType.typeAnnotation(); cloneFunType.addChild(clone(srcTypeAnnot)).setParent(cloneFunType); - TerminalNode srcIdentifier = srcFunType.Identifier(); - if (srcIdentifier != null) { - cloneFunType.addChild(NodeBuilder.terminalIdentifier(srcIdentifier.getText())); - } + ThrowsAnnotationContext srcThrowsAnno = srcFunType.throwsAnnotation(); + if (srcThrowsAnno != null) cloneFunType.addChild(clone(srcThrowsAnno)).setParent(cloneFunType); return cloneFunType; } + static public ThrowsAnnotationContext clone(ThrowsAnnotationContext srcThowsAnno) { + ThrowsAnnotationContext cloneThrowsAnno = new ThrowsAnnotationContext(null, 0); + + TerminalNode srcIdentifier = srcThowsAnno.Identifier(); + cloneThrowsAnno.addChild(NodeBuilder.terminalIdentifier(srcIdentifier.getText())); + + return cloneThrowsAnno; + } // primaryType // : predefinedType @@ -531,15 +537,7 @@ public class NodeClonner { cloneSwitch.addChild(clone(srcSwitch.caseBlock())).setParent(cloneSwitch); return cloneSwitch; } - - // panicStatement: Panic {this.notLineTerminator()}? singleExpression SemiColon - static public PanicStatementContext clone(PanicStatementContext srcPanic) { - PanicStatementContext clonePanic = new PanicStatementContext(null, 0); - clonePanic.addChild(NodeBuilder.terminalNode(Panic)); - clonePanic.addChild(clone(srcPanic.singleExpression())).setParent(clonePanic); - return clonePanic; - } - + // throwStatement: Throw {this.notLineTerminator()}? singleExpression SemiColon static public ThrowStatementContext clone(ThrowStatementContext srcThrow) { ThrowStatementContext cloneThrow = new ThrowStatementContext(null, 0); @@ -566,31 +564,30 @@ public class NodeClonner { return cloneExceptionParam; } - // catchOrRecoverClause: { CATCH || RECOVER }? Identifier exceptionParameter? block - static public CatchOrRecoverClauseContext clone(CatchOrRecoverClauseContext srcCatchOrRecover) { - CatchOrRecoverClauseContext cloneCatchOrRecover = new CatchOrRecoverClauseContext(null, 0); + // catchClause: CATCH exceptionParameter block + static public CatchClauseContext clone(CatchClauseContext srcCatch) { + CatchClauseContext cloneCatch = new CatchClauseContext(null, 0); - cloneCatchOrRecover.addChild(NodeBuilder.terminalIdentifier(srcCatchOrRecover.Identifier().getText())); + cloneCatch.addChild(NodeBuilder.terminalIdentifier(srcCatch.Identifier().getText())); - ExceptionParameterContext srcExeptionParam = srcCatchOrRecover.exceptionParameter(); + ExceptionParameterContext srcExeptionParam = srcCatch.exceptionParameter(); if (srcExeptionParam != null) { - cloneCatchOrRecover.addChild(clone(srcExeptionParam)).setParent(cloneCatchOrRecover); + cloneCatch.addChild(clone(srcExeptionParam)).setParent(cloneCatch); } - cloneCatchOrRecover.addChild(clone(srcCatchOrRecover.block())).setParent(cloneCatchOrRecover); + cloneCatch.addChild(clone(srcCatch.block())).setParent(cloneCatch); - return cloneCatchOrRecover; + return cloneCatch; } - // trapStatement: Trap block catchOrRecoverClause+ - // tryStatement: Try block catchOrRecoverClause+ + // tryStatement: Try block (catchClause+ | catchClause* defaultCatch) static public TryStatementContext clone(TryStatementContext srcTry) { TryStatementContext cloneTry = new TryStatementContext(null, 0); cloneTry.addChild(NodeBuilder.terminalNode(Try)); cloneTry.addChild(clone(srcTry.block())).setParent(cloneTry); - for (CatchOrRecoverClauseContext srcCatchOrRecover : srcTry.catchOrRecoverClause()) { - cloneTry.addChild(clone(srcCatchOrRecover)).setParent(cloneTry); + for (CatchClauseContext srcCatch : srcTry.catchClause()) { + cloneTry.addChild(clone(srcCatch)).setParent(cloneTry); } return cloneTry; @@ -613,10 +610,9 @@ public class NodeClonner { // | returnStatement // | labelledStatement // | switchStatement - // | panicStatement // | throwStatement // | deferStatement - // | trapStatement + // | tryStatement // | expressionStatement static public StatementContext clone(StatementContext srcStmt) { StatementContext cloneStmt = new StatementContext(null, 0); @@ -675,12 +671,6 @@ public class NodeClonner { return cloneStmt; } - PanicStatementContext srcPanic = srcStmt.panicStatement(); - if (srcPanic != null) { - cloneStmt.addChild(clone(srcPanic)).setParent(cloneStmt); - return cloneStmt; - } - ThrowStatementContext srcThrow = srcStmt.throwStatement(); if (srcThrow != null) { cloneStmt.addChild(clone(srcThrow)).setParent(cloneStmt); @@ -963,9 +953,9 @@ public class NodeClonner { cloneConstructor.addChild(clone(srcParamsList)).setParent(cloneConstructor); } - TerminalNode srcThrows = srcConstructor.Identifier(); - if (srcThrows != null) { - cloneConstructor.addChild(NodeBuilder.terminalIdentifier(srcThrows.getText())); + ThrowsAnnotationContext srcThrowsAnno = srcConstructor.throwsAnnotation(); + if (srcThrowsAnno != null) { + cloneConstructor.addChild(clone(srcThrowsAnno)).setParent(cloneConstructor); } ConstructorBodyContext srcConstBody = srcConstructor.constructorBody(); @@ -1063,9 +1053,9 @@ public class NodeClonner { cloneSignature.addChild(clone(srcSignature.typeAnnotation())).setParent(cloneSignature); - TerminalNode srcIdentifier = srcSignature.Identifier(); - if (srcIdentifier != null) { - cloneSignature.addChild(NodeBuilder.terminalIdentifier(srcIdentifier.getText())); + ThrowsAnnotationContext srcThrowsAnno = srcSignature.throwsAnnotation(); + if (srcThrowsAnno != null) { + cloneSignature.addChild(clone(srcThrowsAnno)).setParent(cloneSignature); } return cloneSignature; @@ -1532,6 +1522,10 @@ public class NodeClonner { } cloneLambda.addChild(clone(srcLambda.typeAnnotation())).setParent(cloneLambda); + + ThrowsAnnotationContext srcThrowsAnno = srcLambda.throwsAnnotation(); + if (srcThrowsAnno != null) cloneLambda.addChild(clone(srcThrowsAnno)).setParent(cloneLambda); + cloneLambda.addChild(clone(srcLambda.lambdaBody())).setParent(cloneLambda); return cloneLambda; diff --git a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 index 9365d52c51d2580c157dfc68e843af9baeb9c8ae..2b62e1ee9adbdbd5a0cf767fc69404521e76fca0 100644 --- a/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 +++ b/migrator/src/com/ohos/migrator/staticTS/parser/StaticTSParser.g4 @@ -121,8 +121,7 @@ classMember ; constructorDeclaration - : Constructor typeParameters? OpenParen parameterList? CloseParen - ({ this.next(StaticTSParser.THROWS) || this.next(StaticTSParser.RETHROWS) }? Identifier)? constructorBody + : Constructor typeParameters? OpenParen parameterList? CloseParen throwsAnnotation? constructorBody ; parameterList @@ -178,8 +177,11 @@ classInitializer ; signature - : typeParameters? OpenParen parameterList? CloseParen typeAnnotation - ({ this.next(StaticTSParser.THROWS) || this.next(StaticTSParser.RETHROWS) }? Identifier)? + : typeParameters? OpenParen parameterList? CloseParen typeAnnotation throwsAnnotation? + ; + +throwsAnnotation + : { this.next(StaticTSParser.THROWS) || this.next(StaticTSParser.RETHROWS) }? Identifier ; // Interfaces @@ -283,8 +285,7 @@ typeReferencePart ; functionType - : OpenParen parameterList? CloseParen typeAnnotation - ({ this.next(StaticTSParser.THROWS) || this.next(StaticTSParser.RETHROWS) }? Identifier)? + : OpenParen parameterList? CloseParen typeAnnotation throwsAnnotation? ; // Generics @@ -335,7 +336,6 @@ statement | returnStatement | labelledStatement | switchStatement - | panicStatement | throwStatement | deferStatement | tryStatement @@ -402,27 +402,26 @@ defaultClause : { this.next(StaticTSParser.DEFAULT) }? Identifier ':' statement* ; -panicStatement - : Panic {this.notLineTerminator()}? singleExpression SemiColon? - ; - throwStatement : Throw {this.notLineTerminator()}? singleExpression SemiColon? ; tryStatement - : Try block catchOrRecoverClause+ + : Try block (catchClause+ | catchClause* defaultCatch) ; -catchOrRecoverClause - : { this.next(StaticTSParser.CATCH) || this.next(StaticTSParser.RECOVER) }? Identifier - exceptionParameter? block +catchClause + : { this.next(StaticTSParser.CATCH) }? Identifier exceptionParameter block ; exceptionParameter : OpenParen Identifier typeAnnotation CloseParen ; +defaultCatch + : { this.next(StaticTSParser.CATCH) }? Identifier (OpenParen Identifier CloseParen)? block + ; + deferStatement : Defer statement ; @@ -433,7 +432,7 @@ expressionStatement // Expressions singleExpression - : OpenParen parameterList? CloseParen typeAnnotation Arrow lambdaBody # LambdaExpression + : OpenParen parameterList? CloseParen typeAnnotation throwsAnnotation? Arrow lambdaBody # LambdaExpression | singleExpression indexExpression # ArrayAccessExpression | singleExpression Dot Identifier # MemberAccessExpression | New typeArguments? typeReference arguments? classBody? # NewClassInstanceExpression diff --git a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java index c0c439c81d4066dac3e1d65e137abc49c8bd3eda..4335790568d61d34a2e1693919464ca0ba3a260a 100644 --- a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java +++ b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java @@ -471,6 +471,9 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { TypeAnnotationContext stsTypeAnno = stsFunctionType.typeAnnotation(); visitTypeAnnotation(stsTypeAnno); + ThrowsAnnotationContext stsThrowsAnno = stsFunctionType.throwsAnnotation(); + if (stsThrowsAnno != null) visitThrowsAnnotation(stsThrowsAnno); + writeTrailingComments(stsFunctionType); return null; } @@ -513,24 +516,31 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { visitTypeAnnotation(stsSignature.typeAnnotation()); - TerminalNode stsThrowsIdentifier = stsSignature.Identifier(); - if (stsThrowsIdentifier != null) { - String stsThrowsIdText = stsThrowsIdentifier.getText(); - if (StaticTSParser.THROWS.equals(stsThrowsIdText) || - StaticTSParser.RETHROWS.equals(stsThrowsIdText)) { - sb.append(' ').append(stsThrowsIdText).append(' '); + ThrowsAnnotationContext stsThrowsAnno = stsSignature.throwsAnnotation(); + if (stsThrowsAnno != null) visitThrowsAnnotation(stsThrowsAnno); + + writeTrailingComments(stsSignature); + return null; + } + + @Override + public Void visitThrowsAnnotation(ThrowsAnnotationContext stsThrowsAnno) { + TerminalNode stsIdentifier = stsThrowsAnno.Identifier(); + if (stsIdentifier != null) { + String stsIdentifierText = stsIdentifier.getText(); + if (StaticTSParser.THROWS.equals(stsIdentifierText) || + StaticTSParser.RETHROWS.equals(stsIdentifierText)) { + sb.append(' ').append(stsIdentifierText).append(' '); } else { - reportError("Unexpected token " + stsThrowsIdText + - " in function or method signature", stsSignature); + reportError("Unexpected token " + stsIdentifierText + + " in throws/rethrows annotation", stsThrowsAnno); } } - writeTrailingComments(stsSignature); return null; } - // accessibilityModifier: Public | Private | Protected @Override public Void visitAccessibilityModifier(AccessibilityModifierContext stsAccessibilityModifier) { @@ -565,20 +575,13 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { sb.append(')'); - TerminalNode stsThrowsIdentifier = stsConstructorDeclaration.Identifier(); - if (stsThrowsIdentifier != null) { - String stsThrowsIdText = stsThrowsIdentifier.getText(); - if (StaticTSParser.THROWS.equals(stsThrowsIdText) || - StaticTSParser.RETHROWS.equals(stsThrowsIdText)) { - sb.append(' ').append(stsThrowsIdText); - } - else { - reportError("Unexpected token " + stsThrowsIdText + - " in constructor declaration", stsConstructorDeclaration); - } - } + ThrowsAnnotationContext stsThrowsAnno = stsConstructorDeclaration.throwsAnnotation(); + if (stsThrowsAnno != null) + visitThrowsAnnotation(stsThrowsAnno); + else + sb.append(' '); - sb.append(" {\n"); + sb.append("{\n"); indentIncrement(); visitConstructorBody(stsConstructorDeclaration.constructorBody()); @@ -1540,19 +1543,6 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { return null; } - @Override - public Void visitPanicStatement(PanicStatementContext stsPanicStatement) { - doNeededIndent(); - writeLeadingComments(stsPanicStatement); - - sb.append(stsPanicStatement.Panic().getText()).append(' '); - stsPanicStatement.singleExpression().accept(this); - sb.append(";\n"); - - writeTrailingComments(stsPanicStatement); - return null; - } - // tryStatement: Try block catchOrRecoverClause+; @Override public Void visitTryStatement(TryStatementContext stsTryStatement) { @@ -1563,12 +1553,16 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { visitBlock(stsTryStatement.block()); - List stsCatchesOrRecovers = stsTryStatement.catchOrRecoverClause(); - assert(stsCatchesOrRecovers != null && !stsCatchesOrRecovers.isEmpty()); - for (CatchOrRecoverClauseContext stsCatchOrRecover : stsCatchesOrRecovers) { - visitCatchOrRecoverClause(stsCatchOrRecover); + List stsCatches = stsTryStatement.catchClause(); + if (stsCatches != null) { + for (CatchClauseContext stsCatch : stsCatches) { + visitCatchClause(stsCatch); + } } + DefaultCatchContext stsDefaultCatch = stsTryStatement.defaultCatch(); + if (stsDefaultCatch != null) visitDefaultCatch(stsDefaultCatch); + sb.append('\n'); writeTrailingComments(stsTryStatement); @@ -1578,28 +1572,27 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { // catchOrRecoverClause: (Catch|Recover) exceptionParameter? block @Override - public Void visitCatchOrRecoverClause(CatchOrRecoverClauseContext stsCatchOrRecoverClause) { + public Void visitCatchClause(CatchClauseContext stsCatchClause) { doNeededIndent(); - writeLeadingComments(stsCatchOrRecoverClause); + writeLeadingComments(stsCatchClause); - String stsCatchOrRecoverKeyword = stsCatchOrRecoverClause.Identifier().getText(); - if (!StaticTSParser.CATCH.equals(stsCatchOrRecoverKeyword) && - !StaticTSParser.RECOVER.equals(stsCatchOrRecoverKeyword)) { - reportError("Unexpected keyword " + stsCatchOrRecoverKeyword + " in catch or recover clause", stsCatchOrRecoverClause); - stsCatchOrRecoverKeyword = StaticTSParser.CATCH; + String stsCatchKeyword = stsCatchClause.Identifier().getText(); + if (!StaticTSParser.CATCH.equals(stsCatchKeyword)) { + reportError("Unexpected keyword " + stsCatchKeyword + " in catch clause", stsCatchClause); + stsCatchKeyword = StaticTSParser.CATCH; } - sb.append(stsCatchOrRecoverKeyword).append(' '); + sb.append(stsCatchKeyword).append(' '); - ExceptionParameterContext stsExceptionParam = stsCatchOrRecoverClause.exceptionParameter(); + ExceptionParameterContext stsExceptionParam = stsCatchClause.exceptionParameter(); if (stsExceptionParam != null) { visitExceptionParameter(stsExceptionParam); } - BlockContext stsBlock = stsCatchOrRecoverClause.block(); + BlockContext stsBlock = stsCatchClause.block(); assert(stsBlock != null); visitBlock(stsBlock); - writeTrailingComments(stsCatchOrRecoverClause); + writeTrailingComments(stsCatchClause); return null; } @@ -1615,6 +1608,27 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { return null; } + @Override + public Void visitDefaultCatch(DefaultCatchContext stsDefaultCatch) { + doNeededIndent(); + writeLeadingComments(stsDefaultCatch); + + String stsCatchKeyword = stsDefaultCatch.Identifier(0).getText(); + if (!StaticTSParser.CATCH.equals(stsCatchKeyword)) { + reportError("Unexpected keyword " + stsCatchKeyword + " in default catch clause", stsDefaultCatch); + stsCatchKeyword = StaticTSParser.CATCH; + } + sb.append(stsCatchKeyword).append(' '); + + if (stsDefaultCatch.Identifier().size() > 1) + sb.append('(').append(stsDefaultCatch.Identifier(1).getText()).append(") "); + + visitBlock(stsDefaultCatch.block()); + + writeTrailingComments(stsDefaultCatch); + return null; + } + // functionDeclaration: Function Identifier signature block @Override public Void visitFunctionDeclaration(FunctionDeclarationContext stsFunctionDeclaration) { @@ -2407,6 +2421,9 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor { visitTypeAnnotation(stsLambdaExpression.typeAnnotation()); + ThrowsAnnotationContext stsThrowsAnno = stsLambdaExpression.throwsAnnotation(); + if (stsThrowsAnno != null) visitThrowsAnnotation(stsThrowsAnno); + sb.append(stsLambdaExpression.Arrow().getText()); visitLambdaBody(stsLambdaExpression.lambdaBody()); diff --git a/migrator/test/java/method_invocation.java.sts b/migrator/test/java/method_invocation.java.sts index c89ba32e84591e39ea14aa89305e717ff094c8e4..94ae246cd4def2e1d8cddec9c107a5190659aef6 100755 --- a/migrator/test/java/method_invocation.java.sts +++ b/migrator/test/java/method_invocation.java.sts @@ -23,7 +23,7 @@ open class SuperClass { open class SubClass1 extends SuperClass { override foo(): void { - panic new UnsupportedOperationException(); + throw new UnsupportedOperationException(); } tweak : Runnable = new Runnable() { public override run(): void { @@ -40,7 +40,7 @@ interface SuperInterface { open class SubClass2 implements SuperInterface { public override foo(): void { - panic new UnsupportedOperationException(); + throw new UnsupportedOperationException(); } open tweak(): void { SuperInterface.super.foo(); // Gets the 'println' behavior @@ -49,7 +49,7 @@ open class SubClass2 implements SuperInterface { open class SubClass3 implements SuperInterface { public override foo(): void { - panic new UnsupportedOperationException(); + throw 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 0113235e20010414bbddf58fe92c314084458f86..ffd88a63d5daf3ec964e302d48bfc91da1f03428 100644 --- a/migrator/test/java/method_references.java.sts +++ b/migrator/test/java/method_references.java.sts @@ -247,9 +247,9 @@ open class MethodReferencesExamples { public static methodReferencesWithExceptions(): void { try { - let createExceptions : TryFunction0 = (): com.ohos.migrator.tests.java.MethodReferencesExamples.Exceptions => new Exceptions(); + let createExceptions : TryFunction0 = (): com.ohos.migrator.tests.java.MethodReferencesExamples.Exceptions throws => new Exceptions(); let exceptions : Exceptions = createExceptions.apply(); - let getNameFun : TryFunction1 = (__migrator_lambda_param_1 : com.ohos.migrator.tests.java.MethodReferencesExamples.Exceptions): String => __migrator_lambda_param_1.getName(); + let getNameFun : TryFunction1 = (__migrator_lambda_param_1 : com.ohos.migrator.tests.java.MethodReferencesExamples.Exceptions): String throws => __migrator_lambda_param_1.getName(); let name : String = getNameFun.apply(exceptions); } catch (ex : MyException) { diff --git a/migrator/test/java/throw_statement.java.sts b/migrator/test/java/throw_statement.java.sts index 07c5d348a81fd06e8c1b7daec5939da732fcdbb6..2889cc5cecb562c45363947efbbe529f3c26d99d 100644 --- a/migrator/test/java/throw_statement.java.sts +++ b/migrator/test/java/throw_statement.java.sts @@ -25,7 +25,7 @@ export open class throw_statement { return i / j; } public open divide_test(l : long): int { - if (l > i) panic new Panic(); + if (l > i) throw new Panic(); return (i / l) as int; } } diff --git a/migrator/test/java/throws_test.java b/migrator/test/java/throws_test.java index baaaf0b455324a5b2f85213d8c76c2f7c499287d..b832b456447023019df2c2197946425a4fc4abfe 100644 --- a/migrator/test/java/throws_test.java +++ b/migrator/test/java/throws_test.java @@ -80,7 +80,7 @@ class Test { catch( MyException e ) {} } - // no throws - all excepyions are catched + // no throws - all exceptions are catched public static void test3(String s) { try { SubClass1 sc1 = new SubClass1(s); @@ -88,7 +88,7 @@ class Test { catch( MyException | AnotherException e) {} } - // no throws - only panic + // no throws - only runtime exceptions public static void test4(String s) { try { SubClass2 sc2 = new SubClass2(s); @@ -96,7 +96,7 @@ class Test { catch( MyException | AnotherException e) {} } - // no throws - only panic + // no throws - only runtime exceptions public static void test5(String s) { try { SubClass2 sc2 = new SubClass2(s); diff --git a/migrator/test/java/throws_test.java.sts b/migrator/test/java/throws_test.java.sts index ebb49104d11588224dae91779b9c790cbd6ef3bb..36e494c5a8f914e4dd6b9c630fe394d51eb7bb67 100644 --- a/migrator/test/java/throws_test.java.sts +++ b/migrator/test/java/throws_test.java.sts @@ -47,7 +47,7 @@ open class SubClass1 extends SuperClass { } override foo(): void { - panic new UnsupportedOperationException(); + throw new UnsupportedOperationException(); } public open run(): void { foo(); @@ -60,7 +60,7 @@ open class SubClass1 extends SuperClass { open class SubClass2 extends SubClass1 { public constructor(s : String) throws { super(s); - if (s == "!") panic new UnsupportedOperationException(); + if (s == "!") throw new UnsupportedOperationException(); } public override foo(): void { @@ -90,7 +90,7 @@ open class Test { } } -// no throws - all excepyions are catched +// no throws - all exceptions are catched public static test3(s : String): void { try { let sc1 : SubClass1 = new SubClass1(s); @@ -101,7 +101,7 @@ open class Test { } } -// no throws - only panic +// no throws - only runtime exceptions public static test4(s : String): void { try { let sc2 : SubClass2 = new SubClass2(s); @@ -112,7 +112,7 @@ open class Test { } } -// no throws - only panic +// no throws - only runtime exceptions public static test5(s : String): void { try { let sc2 : SubClass2 = new SubClass2(s); diff --git a/migrator/test/java/try_catch_finally.java.sts b/migrator/test/java/try_catch_finally.java.sts index cde0c182a4f11958abbb2ee9005e541cfca29619..5a589a38eb1b6c7cdeacc3576b36cb6efee5d992 100644 --- a/migrator/test/java/try_catch_finally.java.sts +++ b/migrator/test/java/try_catch_finally.java.sts @@ -51,16 +51,16 @@ export open class try_catch_finally { blowUp(); let t : try_catch_finally = new try_catch_finally(); } - recover (n : NullPointerException) { + catch (n : NullPointerException) { System.out.println("Caught NullPointerException"); } catch (b : BlewIt) { System.out.println("Caught BlewIt or IllegalArgumentException"); } - recover (b : IllegalArgumentException) { + catch (b : IllegalArgumentException) { System.out.println("Caught BlewIt or IllegalArgumentException"); } - recover (r : RuntimeException) { + catch (r : RuntimeException) { System.out.println("Caught RuntimeException"); } catch (e : Exception) { diff --git a/migrator/test/java/try_with_resources.java.sts b/migrator/test/java/try_with_resources.java.sts index f0fa4fb1c8ff869bd49c843f79c31c81d1e5f10e..e37cc96ecfb5c8414057e5b14d5bb574dd5cc9bf 100644 --- a/migrator/test/java/try_with_resources.java.sts +++ b/migrator/test/java/try_with_resources.java.sts @@ -40,10 +40,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res0.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res0.addSuppressed(suppressedExc); - } - } else { fr.close(); @@ -60,10 +56,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res1.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res1.addSuppressed(suppressedExc); - } - } else { br.close(); @@ -75,21 +67,11 @@ open class TryWithResources { primaryExc_res1 = t; throw t; } - recover (t : Throwable) { - primaryExc_res1 = t; - throw t; - } - } catch (t : Throwable) { primaryExc_res0 = t; throw t; } - recover (t : Throwable) { - primaryExc_res0 = t; - throw t; - } - } } // with catch block @@ -107,10 +89,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res0.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res0.addSuppressed(suppressedExc); - } - } else { stmt.close(); @@ -126,11 +104,6 @@ open class TryWithResources { primaryExc_res0 = t; throw t; } - recover (t : Throwable) { - primaryExc_res0 = t; - throw t; - } - } catch (e : SQLException) { System.err.println("SQLState: " + e.getSQLState()); @@ -158,10 +131,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res0.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res0.addSuppressed(suppressedExc); - } - } else { fr.close(); @@ -178,10 +147,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res1.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res1.addSuppressed(suppressedExc); - } - } else { br.close(); @@ -193,21 +158,11 @@ open class TryWithResources { primaryExc_res1 = t; throw t; } - recover (t : Throwable) { - primaryExc_res1 = t; - throw t; - } - } catch (t : Throwable) { primaryExc_res0 = t; throw t; } - recover (t : Throwable) { - primaryExc_res0 = t; - throw t; - } - } } // with catch and finally block @@ -227,10 +182,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res0.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res0.addSuppressed(suppressedExc); - } - } else { scanner.close(); @@ -245,11 +196,6 @@ open class TryWithResources { primaryExc_res0 = t; throw t; } - recover (t : Throwable) { - primaryExc_res0 = t; - throw t; - } - } catch (fnfe : FileNotFoundException) { fnfe.printStackTrace(); @@ -272,9 +218,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res0.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res0.addSuppressed(suppressedExc); - } } else { @@ -291,10 +234,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res1.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res1.addSuppressed(suppressedExc); - } - } else { writer.close(); @@ -310,21 +249,11 @@ open class TryWithResources { primaryExc_res1 = t; throw t; } - recover (t : Throwable) { - primaryExc_res1 = t; - throw t; - } - } catch (t : Throwable) { primaryExc_res0 = t; throw t; } - recover (t : Throwable) { - primaryExc_res0 = t; - throw t; - } - } } catch (ex : Exception) { @@ -352,10 +281,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res0.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res0.addSuppressed(suppressedExc); - } - } else { this.y2.close(); @@ -371,10 +296,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res1.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res1.addSuppressed(suppressedExc); - } - } else { super.yz.close(); @@ -391,10 +312,6 @@ open class TryWithResources { catch (suppressedExc : Throwable) { primaryExc_res2.addSuppressed(suppressedExc); } - recover (suppressedExc : Throwable) { - primaryExc_res2.addSuppressed(suppressedExc); - } - } else { z.yz.close(); @@ -406,32 +323,17 @@ open class TryWithResources { primaryExc_res2 = t; throw t; } - recover (t : Throwable) { - primaryExc_res2 = t; - throw t; - } - } } catch (t : Throwable) { primaryExc_res1 = t; throw t; } - recover (t : Throwable) { - primaryExc_res1 = t; - throw t; - } - } catch (t : Throwable) { primaryExc_res0 = t; throw t; } - recover (t : Throwable) { - primaryExc_res0 = t; - throw t; - } - } catch (e : IOException) { System.err.println(e.getMessage()); diff --git a/migrator/test/ts/throw_statement.ts b/migrator/test/ts/throw_statement.ts new file mode 100644 index 0000000000000000000000000000000000000000..e47a2a73f70afda1cddd5b83aacbfd6ff6806592 --- /dev/null +++ b/migrator/test/ts/throw_statement.ts @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +class C {} + +function throwsNumber(): never { + throw 1; +} + +function throwsString(): never { + throw "string"; +} + +function throwsObject(): never { + let c = new C; + throw c; +} + +function throwsError(): never { + throw new Error("error"); +} diff --git a/migrator/test/ts/throw_statement.ts.sts b/migrator/test/ts/throw_statement.ts.sts new file mode 100755 index 0000000000000000000000000000000000000000..bd825a9c8c85d00a31eb306e5a259e691300d390 --- /dev/null +++ b/migrator/test/ts/throw_statement.ts.sts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +open class C { +} + +function throwsNumber(): Never { + throw new Error("", 1); +} +function throwsString(): Never { + throw new Error("", "string"); +} +function throwsObject(): Never { + let c = new C(); + throw new Error("", c); +} +function throwsError(): Never { + throw new Error("", new __UnknownType__ /* Error */("error")); +} diff --git a/migrator/test/ts/try_statement.ts b/migrator/test/ts/try_statement.ts new file mode 100644 index 0000000000000000000000000000000000000000..2d0b3c89528c8cb611de1a479792bc6915682ff8 --- /dev/null +++ b/migrator/test/ts/try_statement.ts @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +class C { } + +function foo() : never { + throw new C; +} + +function bar(): void { + try { + foo(); + } + catch { + } + + try { + foo(); + } + catch (e) { + console.log(e); + } + finally { + } + + try { + foo(); + } + finally { + } +} diff --git a/migrator/test/ts/try_statement.ts.sts b/migrator/test/ts/try_statement.ts.sts new file mode 100755 index 0000000000000000000000000000000000000000..779ff4bc40d6432e1c3989a5f557d44bb6aa15fb --- /dev/null +++ b/migrator/test/ts/try_statement.ts.sts @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +open class C { +} + +function foo(): Never { + throw new Error("", new C()); +} +function bar(): void { + try { + foo(); + } + catch { + } + + try { + defer { + } + foo(); + } + catch (e) { + console.log(e); + } + + { + defer { + } + foo(); + } +} diff --git a/migrator/test/ts/unsupported_types.ts.sts b/migrator/test/ts/unsupported_types.ts.sts index 69613e2cda0bdb8e264ddea335e9de27a5a724c1..da14a88d772f018377a6b045c4109119b9b9a5e6 100755 --- a/migrator/test/ts/unsupported_types.ts.sts +++ b/migrator/test/ts/unsupported_types.ts.sts @@ -17,7 +17,7 @@ function foo(x : __UnknownType__ /* string|number */): __UnknownType__ /* [strin return null; } function nonreturning(x : __UnknownType__ /* "string" */): Never { - __untranslated_statement( /* throw 1; */); + throw new Error("", 1); } function bar(x : __UnknownType__ /* any */): __UnknownType__ /* undefined */ { return undefined; diff --git a/migrator/tslinter.cmd b/migrator/tslinter.cmd new file mode 100644 index 0000000000000000000000000000000000000000..b40784b8d94ab2614c3bd248c432e3321edab57d --- /dev/null +++ b/migrator/tslinter.cmd @@ -0,0 +1,19 @@ +:: +:: Copyright (c) 2022-2023 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. +:: +@echo off +@set MIGRATOR_HOME_PATH=%~dp0 + + +node %MIGRATOR_HOME_PATH%./out/typescript/javascript/src/linter/dist/tslinter.js %* diff --git a/migrator/tslinter.sh b/migrator/tslinter.sh new file mode 100644 index 0000000000000000000000000000000000000000..9747f2a445e7798357e9d0a39e6a1afbf52925ec --- /dev/null +++ b/migrator/tslinter.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# +# Copyright (c) 2022-2023 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. +# + +# get absolute path to migrator folder +MIGRATOR_HOME_PATH=`cd $(dirname $0) && pwd` + +# use relative path due to node.js error under cygwin environment +node $(dirname $0)/./out/typescript/javascript/src/linter/dist/tslinter.js $@ diff --git a/migrator/typescript/src/staticts/NodeCloner.ts b/migrator/typescript/src/staticts/NodeCloner.ts index 22bdeed65d807b3e4f5068782fe6604345b29c19..dd6653a9cc3d2d578a3e99e875354f7e46af4051 100755 --- a/migrator/typescript/src/staticts/NodeCloner.ts +++ b/migrator/typescript/src/staticts/NodeCloner.ts @@ -35,12 +35,19 @@ export function cloneSignature(stsSignature: sts.SignatureContext): sts.Signatur stsSignatureClone.addChild(cloneTypeAnnotation(stsTypeAnno)); // Clone throws/rethrows keyword, if exists. - let stsIdentifier = stsSignature.Identifier(); - if (stsIdentifier) stsSignatureClone.addAnyChild(NodeBuilder.terminalIdentifier(stsIdentifier.text)); + let stsThrowsAnno = stsSignature.throwsAnnotation(); + if (stsThrowsAnno) stsSignatureClone.addChild(cloneThrowsAnnotation(stsThrowsAnno)); return stsSignatureClone; } +export function cloneThrowsAnnotation(stsThrowsAnno: sts.ThrowsAnnotationContext): sts.ThrowsAnnotationContext { + let stsThrowsAnnoClone = new sts.ThrowsAnnotationContext(undefined, 0); + stsThrowsAnnoClone.addChild(NodeBuilder.terminalIdentifier(stsThrowsAnno.Identifier().text)); + + return stsThrowsAnnoClone; +} + export function cloneTypeParameters(stsTypeParams: sts.TypeParametersContext): sts.TypeParametersContext { let stsTypeParamsClone = new sts.TypeParametersContext(undefined, 0); @@ -297,8 +304,8 @@ export function cloneFunctionType(stsFunctionType: sts.FunctionTypeContext): sts stsFunctionTypeClone.addChild(cloneTypeAnnotation(stsTypeAnno)); // Clone throws/rethrows keyword, if exists. - let stsIdentifier = stsFunctionType.Identifier(); - if (stsIdentifier) stsFunctionTypeClone.addChild(NodeBuilder.terminalIdentifier(stsIdentifier.text)); + let stsThrowsAnno = stsFunctionType.throwsAnnotation(); + if (stsThrowsAnno) stsFunctionTypeClone.addChild(cloneThrowsAnnotation(stsThrowsAnno)); return stsFunctionTypeClone; } \ No newline at end of file diff --git a/migrator/typescript/src/transpiler/NodeBuilder.ts b/migrator/typescript/src/transpiler/NodeBuilder.ts index d9499862d95af5a1171c83a263a2e818fc608951..ef6e527765f6a36b5981fa0502407403bc1b01fb 100644 --- a/migrator/typescript/src/transpiler/NodeBuilder.ts +++ b/migrator/typescript/src/transpiler/NodeBuilder.ts @@ -771,4 +771,26 @@ export function statementOrLocalDeclaration(stsStmt: StaticTSContextBase): sts.S let stsStmtOrLocalDecl = new sts.StatementOrLocalDeclarationContext(undefined, 0); stsStmtOrLocalDecl.addChild(stsStmt); return stsStmtOrLocalDecl; +} + +export function newClassInstanceExpression(stsType: string | sts.TypeReferenceContext, + ...args: sts.SingleExpressionContext[]): sts.SingleExpressionContext { + if (typeof stsType === 'string') stsType = typeReference(stsType); + + let stsSingeExpr = new sts.SingleExpressionContext(undefined, 0); + let stsNewClassInstExpr = new sts.NewClassInstanceExpressionContext(stsSingeExpr); + + // Add 'new' token and type reference. + stsNewClassInstExpr.addChild(terminalNode(sts.StaticTSParser.New)); + stsNewClassInstExpr.addChild(stsType); + + // Add arguments. + let stsArgs = new sts.ArgumentsContext(stsNewClassInstExpr, 0); + let stsArgList = new sts.ExpressionSequenceContext(stsArgs, 0); + for (let stsArg of args) stsArgList.addChild(stsArg); + stsArgs.addChild(stsArgList); + stsNewClassInstExpr.addChild(stsArgs); + + stsSingeExpr.addChild(stsNewClassInstExpr); + return stsSingeExpr; } \ No newline at end of file diff --git a/migrator/typescript/src/transpiler/TranslationUtils.ts b/migrator/typescript/src/transpiler/TranslationUtils.ts index b49e616c6b656f0cb288eee3f2aadc8729b69ef6..092924e91d69dcb7ff10861bc0d1dde7a7501ba0 100644 --- a/migrator/typescript/src/transpiler/TranslationUtils.ts +++ b/migrator/typescript/src/transpiler/TranslationUtils.ts @@ -21,7 +21,10 @@ import * as NodeCloner from "../staticts/NodeCloner"; export function notStatementBlock(tsNode: ts.Node): boolean { return tsNode && tsNode.kind === ts.SyntaxKind.Block && - (ts.isFunctionLike(tsNode.parent) || ts.isClassStaticBlockDeclaration(tsNode.parent)); + (ts.isFunctionLike(tsNode.parent) || + ts.isClassStaticBlockDeclaration(tsNode.parent) || + ts.isTryStatement(tsNode.parent) || + ts.isCatchClause(tsNode.parent)); } export function isAssignmentOperator(tsBinaryOperator: ts.BinaryOperatorToken): boolean { diff --git a/migrator/typescript/src/transpiler/TypeScriptTransformer.ts b/migrator/typescript/src/transpiler/TypeScriptTransformer.ts index 43c1895bd84752103f769753952b5b2be283e364..a5ec6a77dfe4652d2e3239e9a897050b32997174 100644 --- a/migrator/typescript/src/transpiler/TypeScriptTransformer.ts +++ b/migrator/typescript/src/transpiler/TypeScriptTransformer.ts @@ -353,7 +353,10 @@ export class TypeScriptTransformer { [ts.SyntaxKind.ForOfStatement]: this.visitForOfStatement, [ts.SyntaxKind.WhileStatement]: this.visitWhileStatement, [ts.SyntaxKind.DoStatement]: this.visitDoStatement, - [ts.SyntaxKind.SwitchStatement]: this.visitSwitchStatement + [ts.SyntaxKind.SwitchStatement]: this.visitSwitchStatement, + [ts.SyntaxKind.ThrowStatement]: this.visitThrowStatement, + [ts.SyntaxKind.TryStatement]: this.visitTryStatement, + [ts.SyntaxKind.CatchClause]: this.visitCatchClause } visitNode(tsNode: ts.Node): StaticTSContextBase { @@ -614,9 +617,6 @@ export class TypeScriptTransformer { } visitMethodDeclaration(tsMethodDecl: ts.MethodDeclaration): sts.ClassMemberContext { - // TODO: process method's throws/rethrows clause! - let methodHasThrowsClause = false; - let stsClassMember = new sts.ClassMemberContext(undefined, 0); let tsMethodName = tsMethodDecl.name; @@ -666,6 +666,7 @@ export class TypeScriptTransformer { stsClassMethod.addChild(stsSignature); if (tsMethodDecl.body) { + // Translate method body. stsClassMethod.addChild(this.visitNode(tsMethodDecl.body)); } @@ -693,9 +694,6 @@ export class TypeScriptTransformer { return null; } - // TODO: process method's throws/rethrows clause! - let methodHasThrowsClause = false; - let stsClassMember = new sts.ClassMemberContext(undefined, 0); // Set access modifier. In case of no modifier set 'public'. @@ -1052,9 +1050,12 @@ export class TypeScriptTransformer { stsFunDecl.addChild(NodeBuilder.terminalNode(sts.StaticTSParser.Function)); stsFunDecl.addChild(NodeBuilder.terminalIdentifier(tsFunName)); - stsFunDecl.addChild(this.translateSignature(tsFunDecl)); + + let stsSignature = this.translateSignature(tsFunDecl); + stsFunDecl.addChild(stsSignature); if (tsFunDecl.body) { + // Translate function body. stsFunDecl.addChild(this.visitNode(tsFunDecl.body)); } else { @@ -2732,11 +2733,12 @@ export class TypeScriptTransformer { let stsSignatureParams = stsSignature.parameterList(); if (stsSignatureParams) stsLambdaExpr.addChild(stsSignatureParams); stsLambdaExpr.addChild(stsSignature.typeAnnotation()); - stsLambdaExpr.addChild(NodeBuilder.terminalNode(sts.StaticTSParser.Arrow)); - // Translate body. + // Translate lambda body. let stsLambdaBody = new sts.LambdaBodyContext(stsLambdaExpr, 0); stsLambdaBody.addChild(this.visitNode(tsFunctionExpr.body)); + + stsLambdaExpr.addChild(NodeBuilder.terminalNode(sts.StaticTSParser.Arrow)); stsLambdaExpr.addChild(stsLambdaBody); return stsExpr; @@ -2823,6 +2825,96 @@ export class TypeScriptTransformer { this.reportError("Failed to translate class static block: Multiple static blocks", tsClassStaticBlock); return null; } + + visitThrowStatement(tsThrowStmt: ts.ThrowStatement): sts.StatementContext { + let stsThrowStmt = new sts.ThrowStatementContext(undefined, 0); + stsThrowStmt.addChild(NodeBuilder.terminalNode(sts.StaticTSParser.Throw)); + + // Translate expression being thrown. + let stsExpr = this.visitNode(tsThrowStmt.expression); + if (!stsExpr) stsExpr = this.reportUntranslatedExpression(tsThrowStmt.expression); + + // Wrap expression in Error object, i.e.: + // throw expr --> throw new Error("", expr) + let stsError = NodeBuilder.newClassInstanceExpression("Error", + NodeBuilder.stringLiteral("''"), stsExpr); + stsThrowStmt.addChild(stsError); + + this.stmtTransformed.add(tsThrowStmt); + return NodeBuilder.statement(stsThrowStmt); + } + + visitTryStatement(tsTryStmt: ts.TryStatement): sts.StatementContext { + // Translate try block first as we may have to emit it alone + // in case there are no catch clauses in this try statement. + let stsTryBlock = this.visitNode(tsTryStmt.tryBlock); + + let stsResultStmt: StaticTSContextBase; + if (tsTryStmt.catchClause) { + stsResultStmt = new sts.TryStatementContext(undefined, 0); + stsResultStmt.addChild(NodeBuilder.terminalNode(sts.StaticTSParser.Try)); + stsResultStmt.addChild(stsTryBlock); + + // Translate catch clause. + let stsCatch = this.visitNode(tsTryStmt.catchClause); + stsResultStmt.addChild(stsCatch); + } + else { + // If there are no catch clauses, emit the try block alone. + // The finally clause must be present in this case - it will be + // translated as defer statement and added to the try block below. + stsResultStmt = stsTryBlock; + } + + // Translate finally block, if exists. + // Add it as defer statement to try block. + if (tsTryStmt.finallyBlock) { + let stsDeferStmt = new sts.DeferStatementContext(stsTryBlock, 0); + stsDeferStmt.addChild(NodeBuilder.terminalNode(sts.StaticTSParser.Defer)); + + let stsFinallyBlock = this.visitNode(tsTryStmt.finallyBlock); + stsDeferStmt.addChild(NodeBuilder.statement(stsFinallyBlock)); + + let stsDeferStmtOrLocalDecl = NodeBuilder.statementOrLocalDeclaration( + NodeBuilder.statement(stsDeferStmt)); + stsDeferStmtOrLocalDecl.setParent(stsTryBlock); + stsTryBlock.children.splice(0, 0, stsDeferStmtOrLocalDecl); + } + + this.stmtTransformed.add(tsTryStmt); + return NodeBuilder.statement(stsResultStmt); + } + + visitCatchClause(tsCatch: ts.CatchClause): sts.DefaultCatchContext { + let stsCatch = new sts.DefaultCatchContext(undefined, 0); + stsCatch.addChild(NodeBuilder.terminalIdentifier(sts.StaticTSParser.CATCH)); + + // Translate block first, in case we'll need + // to add a comment to it later (see below). + let stsCatchBlock = this.visitNode(tsCatch.block); + + // Translate exception name. + if (tsCatch.variableDeclaration) { + let tsExceptionName = tsCatch.variableDeclaration.name; + + if (ts.isIdentifier(tsExceptionName)) { + stsCatch.addChild(NodeBuilder.terminalIdentifier(tsExceptionName)); + } + else { + // Warn and emit __InvalidName__. + this.reportError("Failed to translate exception name in catch clause", tsCatch); + stsCatch.addChild(NodeBuilder.invalidIdentifier()); + + // Add comment with original syntax to catch block. + let stsComment = NodeBuilder.multiLineComment("/* Original exception name: " + + tsExceptionName.getText() + " */"); + stsCatchBlock.addLeadingComment(stsComment); + } + } + + stsCatch.addChild(stsCatchBlock); + return stsCatch; + } reportUntranslatedType(tsTypeNode: ts.TypeNode | ts.Expression, typeKind?: string): sts.TypeReferenceContext { // Warn and emit __UnknownType__.