From be36f59aab1a82a62a7adc36a59ef705a95df1f7 Mon Sep 17 00:00:00 2001 From: Lirisman Karina Date: Wed, 20 Sep 2023 14:16:19 +0300 Subject: [PATCH] [System ArkTS] System ArkTS first implementation Signed-off-by: lirismankarina Signed-off-by: ozerovnikita Signed-off-by: zhelyapovaleksey Signed-off-by: lirismankarina --- BUILD.gn | 2 + CMakeLists.txt | 2 + checker/ETSchecker.cpp | 13 + checker/ETSchecker.h | 3 +- checker/ets/etsWarningAnalyzer.cpp | 393 +++++++++++++++++++++++++++++ checker/ets/etsWarningAnalyzer.h | 77 ++++++ es2panda.h | 32 +++ lexer/lexer.h | 2 + parser/ETSNolintParser.cpp | 312 +++++++++++++++++++++++ parser/ETSNolintParser.h | 61 +++++ parser/ETSparser.cpp | 6 + parser/parserImpl.h | 1 + parser/program/program.cpp | 16 ++ parser/program/program.h | 11 +- util/options.cpp | 98 +++++++ 15 files changed, 1027 insertions(+), 2 deletions(-) create mode 100644 checker/ets/etsWarningAnalyzer.cpp create mode 100644 checker/ets/etsWarningAnalyzer.h create mode 100644 parser/ETSNolintParser.cpp create mode 100644 parser/ETSNolintParser.h diff --git a/BUILD.gn b/BUILD.gn index 71bb3f218..2db0dfe8a 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -51,6 +51,7 @@ libes2panda_sources = [ "checker/ets/conversion.cpp", "checker/ets/dynamic.cpp", "checker/ets/enum.cpp", + "checker/ets/etsWarningAnalyzer.cpp", "checker/ets/function.cpp", "checker/ets/helpers.cpp", "checker/ets/narrowingConverter.cpp", @@ -332,6 +333,7 @@ libes2panda_sources = [ "lexer/token/token.cpp", "parser/ASparser.cpp", "parser/ETSparser.cpp", + "parser/ETSNolintParser.cpp", "parser/JSparser.cpp", "parser/TSparser.cpp", "parser/TypedParser.cpp", diff --git a/CMakeLists.txt b/CMakeLists.txt index 323814f5a..f3fab3c13 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -305,6 +305,7 @@ set(ES2PANDA_LIB_SRC parser/JSparser.cpp parser/parserImpl.cpp parser/ETSparser.cpp + parser/ETSNolintParser.cpp parser/TSparser.cpp parser/TypedParser.cpp parser/program/program.cpp @@ -318,6 +319,7 @@ set(ES2PANDA_LIB_SRC checker/TSAnalyzer.cpp checker/JSchecker.cpp checker/ets/aliveAnalyzer.cpp + checker/ets/etsWarningAnalyzer.cpp checker/ets/arithmetic.cpp checker/ets/baseAnalyzer.cpp checker/ets/boxingConverter.cpp diff --git a/checker/ETSchecker.cpp b/checker/ETSchecker.cpp index 489c47992..325b0384b 100644 --- a/checker/ETSchecker.cpp +++ b/checker/ETSchecker.cpp @@ -24,6 +24,7 @@ #include "binder/ETSBinder.h" #include "parser/program/program.h" #include "checker/ets/aliveAnalyzer.h" +#include "checker/ets/etsWarningAnalyzer.h" #include "ir/base/scriptFunction.h" #include "util/helpers.h" @@ -114,6 +115,10 @@ bool ETSChecker::StartChecker([[maybe_unused]] binder::Binder *binder, const Com std::cout << Program()->Dump() << std::endl; } + if (options.has_ets_warnings) { + CheckWarnings(Program(), options); + } + return true; } @@ -141,6 +146,14 @@ void ETSChecker::CheckProgram(parser::Program *program, bool run_analysis) SetProgram(saved_program); } +void ETSChecker::CheckWarnings(parser::Program *program, const CompilerOptions &options) +{ + const auto ets_warning_collection = options.ets_warning_collection; + for (const auto warning : ets_warning_collection) { + ETSWarningAnalyzer(Program()->Ast(), program, warning, options.ets_werror); + } +} + Type *ETSChecker::CheckTypeCached(ir::Expression *expr) { if (expr->TsType() == nullptr) { diff --git a/checker/ETSchecker.h b/checker/ETSchecker.h index 0fd29e70f..4fe9c4d0e 100644 --- a/checker/ETSchecker.h +++ b/checker/ETSchecker.h @@ -311,7 +311,7 @@ public: checker::ETSFunctionType *BuildFunctionSignature(ir::ScriptFunction *func, bool is_construct_sig = false); checker::ETSFunctionType *BuildMethodSignature(ir::MethodDefinition *method); Signature *CheckEveryAbstractSignatureIsOverridden(ETSFunctionType *target, ETSFunctionType *source); - Signature *GetSignatureFromMethodDefinition(const ir::MethodDefinition *method_def); + static Signature *GetSignatureFromMethodDefinition(const ir::MethodDefinition *method_def); void CheckIdenticalOverloads(ETSFunctionType *func, ETSFunctionType *overload, const ir::MethodDefinition *current_func); Signature *AdjustForTypeParameters(Signature *source, Signature *target); @@ -574,6 +574,7 @@ private: ETSObjectType *CreateETSObjectTypeCheckBuiltins(util::StringView name, ir::AstNode *decl_node, ETSObjectFlags flags); void CheckProgram(parser::Program *program, bool run_analysis = false); + void CheckWarnings(parser::Program *program, const CompilerOptions &options); template UType HandleModulo(UType left_value, UType right_value); diff --git a/checker/ets/etsWarningAnalyzer.cpp b/checker/ets/etsWarningAnalyzer.cpp new file mode 100644 index 000000000..4cee294df --- /dev/null +++ b/checker/ets/etsWarningAnalyzer.cpp @@ -0,0 +1,393 @@ + +/** + * Copyright (c) 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. + */ + +#include "etsWarningAnalyzer.h" + +#include "tools/es2panda/parser/program/program.h" +#include "tools/es2panda/util/options.h" +#include "tools/es2panda/ir/expressions/binaryExpression.h" +#include "tools/es2panda/ir/base/methodDefinition.h" +#include "tools/es2panda/ir/base/scriptFunction.h" +#include "tools/es2panda/ir/statements/classDeclaration.h" +#include "tools/es2panda/ir/statements/expressionStatement.h" +#include "tools/es2panda/ir/statements/blockStatement.h" +#include "tools/es2panda/ir/expressions/assignmentExpression.h" +#include "tools/es2panda/ir/expressions/callExpression.h" +#include "tools/es2panda/ir/expressions/identifier.h" +#include "tools/es2panda/ir/expressions/memberExpression.h" +#include "tools/es2panda/ir/ets/etsTypeReferencePart.h" +#include "tools/es2panda/ir/ets/etsTypeReference.h" +#include "tools/es2panda/ir/base/classDefinition.h" +#include "tools/es2panda/ir/statements/forOfStatement.h" +#include "tools/es2panda/ir/statements/variableDeclarator.h" +#include "tools/es2panda/ir/statements/variableDeclaration.h" +#include "tools/es2panda/ir/expressions/updateExpression.h" + +namespace panda::es2panda::checker { + +void ETSWarningAnalyzer::AnalyzeClassDefForFinalModifier(const ir::ClassDefinition *class_def) +{ + ASSERT(class_def != nullptr); + + if (program_ == nullptr || class_def->IsFinal() || class_def->IsAbstract() || class_def->IsStatic() || + class_def->IsGlobal() || class_def->IsExported()) { + return; + } + + const auto statements = program_->Ast()->Statements(); + for (const auto *it : statements) { + if (!it->IsClassDeclaration() || + class_def->Ident()->Name() == it->AsClassDeclaration()->Definition()->Ident()->Name()) { + continue; + } + + const auto *it_as_class_def = it->AsClassDeclaration()->Definition(); + + if (!it_as_class_def->IsGlobal()) { + const auto *super_class = it_as_class_def->Super(); + + if (super_class == nullptr) { + continue; + } + + if (super_class->IsETSTypeReference() && + super_class->AsETSTypeReference()->Part()->Name()->IsIdentifier() && + super_class->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Name() == + class_def->Ident()->Name()) { + return; + } + } + } + + ETSThrowWarning("Suggest 'final' modifier for class", class_def->Ident()->Start()); +} + +void ETSWarningAnalyzer::AnalyzeClassMethodForFinalModifier(const ir::MethodDefinition *method_def, + const ir::ClassDefinition *class_def) +{ + ASSERT(method_def != nullptr && class_def != nullptr); + + if (method_def->IsAbstract() || method_def->IsStatic() || class_def->IsFinal() || program_ == nullptr) { + return; + } + + if (method_def->IsFinal() || method_def->IsConstructor() || + class_def->Ident()->Name() == compiler::Signatures::ETS_GLOBAL) { + return; + } + + bool suggest_final = true; + + const auto statements = program_->Ast()->Statements(); + for (const auto *it : statements) { + if (!it->IsClassDeclaration() || it->AsClassDeclaration()->Definition()->IsGlobal() || + class_def->Ident()->Name() == it->AsClassDeclaration()->Definition()->Ident()->Name()) { + continue; + } + + for (const auto *body_part : it->AsClassDeclaration()->Definition()->Body()) { + if (!body_part->IsMethodDefinition()) { + continue; + } + + const util::StringView body_method_name = + ETSChecker::GetSignatureFromMethodDefinition(body_part->AsMethodDefinition())->Function()->Id()->Name(); + if (body_part->IsOverride() && body_method_name != compiler::Signatures::CTOR && + body_method_name == method_def->Function()->Id()->Name()) { + suggest_final = false; + break; + } + } + } + + if (suggest_final) { + ETSThrowWarning("Suggest 'final' modifier for method", method_def->Function()->Start()); + } +} + +void ETSWarningAnalyzer::ETSWarningSuggestFinal(const ir::AstNode *node) +{ + if (node->IsClassDeclaration() && !program_->NodeContainsETSNolint(node, ETSWarnings::SUGGEST_FINAL)) { + if (node->AsClassDeclaration()->Definition()->IsClassDefinition()) { + AnalyzeClassDefForFinalModifier(node->AsClassDeclaration()->Definition()); + } + + const auto class_body = node->AsClassDeclaration()->Definition()->Body(); + for (const auto *it : class_body) { + if (it->IsMethodDefinition()) { + AnalyzeClassMethodForFinalModifier(it->AsMethodDefinition(), node->AsClassDeclaration()->Definition()); + } + } + } + node->Iterate([&](auto *child_node) { ETSWarningSuggestFinal(child_node); }); +} + +void ETSWarningAnalyzer::ETSWarningsProhibitTopLevelStatements(const ir::AstNode *node) +{ + if (!node->IsClassDeclaration() || + program_->NodeContainsETSNolint(node, ETSWarnings::PROHIBIT_TOP_LEVEL_STATEMENTS)) { + node->Iterate([&](auto *child_node) { ETSWarningsProhibitTopLevelStatements(child_node); }); + return; + } + + const auto *class_def = node->AsClassDeclaration()->Definition(); + if (!class_def->IsGlobal()) { + node->Iterate([&](auto *child_node) { ETSWarningsProhibitTopLevelStatements(child_node); }); + return; + } + + for (const auto *it_body : class_def->Body()) { + if (!it_body->IsMethodDefinition() || + it_body->AsMethodDefinition()->Id()->Name() != compiler::Signatures::INIT_METHOD) { + continue; + } + + for (const auto *statement : + it_body->AsMethodDefinition()->Function()->Body()->AsBlockStatement()->Statements()) { + if (program_->NodeContainsETSNolint(statement, ETSWarnings::PROHIBIT_TOP_LEVEL_STATEMENTS)) { + continue; + } + + if (!statement->IsExpressionStatement()) { + switch (statement->Type()) { + case ir::AstNodeType::ARROW_FUNCTION_EXPRESSION: + case ir::AstNodeType::FUNCTION_DECLARATION: + case ir::AstNodeType::SCRIPT_FUNCTION: + case ir::AstNodeType::ETS_FUNCTION_TYPE: + case ir::AstNodeType::IMPORT_NAMESPACE_SPECIFIER: + case ir::AstNodeType::CLASS_DECLARATION: + case ir::AstNodeType::CLASS_EXPRESSION: + case ir::AstNodeType::VARIABLE_DECLARATION: + case ir::AstNodeType::CLASS_DEFINITION: + case ir::AstNodeType::CLASS_PROPERTY: + break; + default: + ETSThrowWarning("Prohibit top-level statements", statement->Start()); + break; + } + continue; + } + + // TODO: remove all code below after fixing bug with top-level source position in AST + // Just replace all code below with "ETSThrowWarning("Prohibit top-level statements", statement->Start());" + if (statement->AsExpressionStatement()->GetExpression()->IsCallExpression()) { + const auto expr_callee = + statement->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee(); + // TODO: remove this check after fixing bug with top-level source position in AST + if (program_->NodeContainsETSNolint(expr_callee, ETSWarnings::PROHIBIT_TOP_LEVEL_STATEMENTS)) { + continue; + } + lexer::SourcePosition pos = expr_callee->Start(); + if (expr_callee->IsMemberExpression()) { + pos = expr_callee->AsMemberExpression()->Object()->Start(); + ETSThrowWarning("Prohibit top-level statements", pos); + } + } else if (statement->AsExpressionStatement()->GetExpression()->IsAssignmentExpression()) { + const auto assignment_expr = + statement->AsExpressionStatement()->GetExpression()->AsAssignmentExpression(); + // TODO: remove this check after fixing bug with top-level source position in AST + if (program_->NodeContainsETSNolint(assignment_expr->Left(), + ETSWarnings::PROHIBIT_TOP_LEVEL_STATEMENTS)) { + continue; + } + + ETSThrowWarning("Prohibit top-level statements", + assignment_expr->Left()->Start()); + } + } + } +} + +void ETSWarningAnalyzer::ETSWarningBoostEqualityStatement(const ir::AstNode *node) +{ + ASSERT(node != nullptr); + + if (node->IsBinaryExpression() && !program_->NodeContainsETSNolint(node, ETSWarnings::BOOST_EQUALITY_STATEMENT)) { + const auto bin_expr = node->AsBinaryExpression(); + if (bin_expr->OperatorType() == lexer::TokenType::PUNCTUATOR_EQUAL || + bin_expr->OperatorType() == lexer::TokenType::PUNCTUATOR_NOT_EQUAL) { + if (bin_expr->Right()->IsNullLiteral() && !bin_expr->Left()->IsNullLiteral()) { + ETSThrowWarning("Boost Equality Statement. Change sides of binary expression", node->Start()); + } + } + } + node->Iterate([&](auto *child_node) { ETSWarningBoostEqualityStatement(child_node); }); +} + +void ETSWarningAnalyzer::ETSWarningRemoveAsync(const ir::AstNode *node) +{ + if (node->IsMethodDefinition() && !program_->NodeContainsETSNolint(node, ETSWarnings::REMOVE_ASYNC_FUNCTIONS)) { + const auto method_definition = node->AsMethodDefinition(); + if (method_definition->IsAsync()) { + ETSThrowWarning("Replace asynchronous function with coroutine", method_definition->Start()); + } + } + node->Iterate([&](auto *child_node) { ETSWarningRemoveAsync(child_node); }); +} + +void ETSWarningAnalyzer::ETSRemoveLambda(const ir::AstNode *node) +{ + ASSERT(node != nullptr); + + if (node->IsArrowFunctionExpression() && !program_->NodeContainsETSNolint(node, ETSWarnings::REMOVE_LAMBDA)) { + ETSThrowWarning("Replace the lambda function with a regular function", node->Start()); + } + node->Iterate([&](auto *child_node) { ETSRemoveLambda(child_node); }); +} + +void ETSWarningAnalyzer::CheckTypeOfBoxingUnboxing(ir::AstNode *node) +{ + ASSERT(node != nullptr); + const auto flags = node->GetBoxingUnboxingFlags(); + + if ((flags & ir::BoxingUnboxingFlags::BOXING_FLAG) != 0) { + switch (static_cast(flags & ir::BoxingUnboxingFlags::BOXING_FLAG)) { + case ir::BoxingUnboxingFlags::BOX_TO_INT: + ETSThrowWarning("Implicit Boxing to Int" + GetBoxingUnboxingType(node), node->Start()); + break; + case ir::BoxingUnboxingFlags::BOX_TO_BOOLEAN: + ETSThrowWarning("Implicit Boxing to Boolean" + GetBoxingUnboxingType(node), node->Start()); + break; + case ir::BoxingUnboxingFlags::BOX_TO_BYTE: + ETSThrowWarning("Implicit Boxing to Byte" + GetBoxingUnboxingType(node), node->Start()); + break; + case ir::BoxingUnboxingFlags::BOX_TO_CHAR: + ETSThrowWarning("Implicit Boxing to Char" + GetBoxingUnboxingType(node), node->Start()); + break; + case ir::BoxingUnboxingFlags::BOX_TO_DOUBLE: + ETSThrowWarning("Implicit Boxing to Double" + GetBoxingUnboxingType(node), node->Start()); + break; + case ir::BoxingUnboxingFlags::BOX_TO_FLOAT: + ETSThrowWarning("Implicit Boxing to Float" + GetBoxingUnboxingType(node), node->Start()); + break; + case ir::BoxingUnboxingFlags::BOX_TO_LONG: + ETSThrowWarning("Implicit Boxing to Long" + GetBoxingUnboxingType(node), node->Start()); + break; + case ir::BoxingUnboxingFlags::BOX_TO_SHORT: + ETSThrowWarning("Implicit Boxing to Short" + GetBoxingUnboxingType(node), node->Start()); + break; + default: + break; + } + } + + if ((flags & ir::BoxingUnboxingFlags::UNBOXING_FLAG) != 0) { + switch (static_cast(flags & ir::BoxingUnboxingFlags::UNBOXING_FLAG)) { + case ir::BoxingUnboxingFlags::UNBOX_TO_INT: + ETSThrowWarning("Implicit Unboxing to int" + GetBoxingUnboxingType(node), node->Start()); + break; + case ir::BoxingUnboxingFlags::UNBOX_TO_BOOLEAN: + ETSThrowWarning("Implicit Unboxing to boolean" + GetBoxingUnboxingType(node), node->Start()); + break; + case ir::BoxingUnboxingFlags::UNBOX_TO_BYTE: + ETSThrowWarning("Implicit Unboxing to byte" + GetBoxingUnboxingType(node), node->Start()); + break; + case ir::BoxingUnboxingFlags::UNBOX_TO_CHAR: + ETSThrowWarning("Implicit Unboxing to char" + GetBoxingUnboxingType(node), node->Start()); + break; + case ir::BoxingUnboxingFlags::UNBOX_TO_DOUBLE: + ETSThrowWarning("Implicit Unboxing to double" + GetBoxingUnboxingType(node), node->Start()); + break; + case ir::BoxingUnboxingFlags::UNBOX_TO_FLOAT: + ETSThrowWarning("Implicit Unboxing to float" + GetBoxingUnboxingType(node), node->Start()); + break; + case ir::BoxingUnboxingFlags::UNBOX_TO_LONG: + ETSThrowWarning("Implicit Unboxing to long" + GetBoxingUnboxingType(node), node->Start()); + break; + case ir::BoxingUnboxingFlags::UNBOX_TO_SHORT: + ETSThrowWarning("Implicit Unboxing to short" + GetBoxingUnboxingType(node), node->Start()); + break; + default: + break; + } + } +} + +const std::string ETSWarningAnalyzer::GetBoxingUnboxingType(ir::AstNode *node) +{ + ASSERT(node->Parent() != nullptr); + switch (node->Parent()->Type()) { + case ir::AstNodeType::VARIABLE_DECLARATOR: { + return " in Variable Declaration"; + } + case ir::AstNodeType::CALL_EXPRESSION: { + return " in Call Method/Function"; + } + case ir::AstNodeType::SWITCH_STATEMENT: { + return " in Switch-case Statement"; + } + case ir::AstNodeType::ASSIGNMENT_EXPRESSION: { + return " in Assignment Expression"; + } + case ir::AstNodeType::BINARY_EXPRESSION: { + return " in Binary Expression"; + } + case ir::AstNodeType::UNARY_EXPRESSION: { + return " in Unary Expression"; + } + case ir::AstNodeType::UPDATE_EXPRESSION: { + return " in Update Expression"; + } + case ir::AstNodeType::MEMBER_EXPRESSION: { + return " in Member Expression"; + } + default: + return ""; + } +} + +void ETSWarningAnalyzer::ETSWarningImplicitBoxingUnboxing(const ir::AstNode *node) +{ + ASSERT(node != nullptr); + + switch (node->Type()) { + case ir::AstNodeType::VARIABLE_DECLARATOR: + case ir::AstNodeType::SWITCH_STATEMENT: + case ir::AstNodeType::CALL_EXPRESSION: + case ir::AstNodeType::BINARY_EXPRESSION: + case ir::AstNodeType::ASSIGNMENT_EXPRESSION: + case ir::AstNodeType::UNARY_EXPRESSION: + case ir::AstNodeType::UPDATE_EXPRESSION: + case ir::AstNodeType::MEMBER_EXPRESSION: { + if (!program_->NodeContainsETSNolint(node, ETSWarnings::IMPLICIT_BOXING_UNBOXING)) { + node->Iterate([this](auto *child_node) { CheckTypeOfBoxingUnboxing(child_node); }); + } + break; + } + default: { + break; + } + } + + node->Iterate([&](auto *child_node) { ETSWarningImplicitBoxingUnboxing(child_node); }); +} + +void ETSWarningAnalyzer::ETSThrowWarning(const std::string &message, const lexer::SourcePosition &pos) +{ + lexer::LineIndex index(program_->SourceCode()); + lexer::SourceLocation location = index.GetLocation(pos); + + if (ets_werror_) { + throw Error(ErrorType::ETS_WARNING, panda::es2panda::util::BaseName(program_->SourceFile().Utf8()), message, + location.line, location.col); + } + + std::cout << "ETS Warning: " << message << "." + << " [" << panda::es2panda::util::BaseName(program_->SourceFile().Utf8()) << ":" << location.line << ":" + << location.col << "]" << std::endl; +} + +} // namespace panda::es2panda::checker diff --git a/checker/ets/etsWarningAnalyzer.h b/checker/ets/etsWarningAnalyzer.h new file mode 100644 index 000000000..a7422e2c7 --- /dev/null +++ b/checker/ets/etsWarningAnalyzer.h @@ -0,0 +1,77 @@ +/** + * Copyright (c) 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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_ETS_WARNING_ANALYZER_H +#define ES2PANDA_COMPILER_CHECKER_ETS_ETS_WARNING_ANALYZER_H + +#include "tools/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { +class ETSWarningAnalyzer { +public: + ETSWarningAnalyzer(const ir::AstNode *node, parser::Program *program, const ETSWarnings warning, bool ets_werror) + : program_(program), ets_werror_(ets_werror) + { + if (node == nullptr) { + return; + } + + switch (warning) { + case ETSWarnings::SUGGEST_FINAL: + ETSWarningSuggestFinal(node); + break; + case ETSWarnings::PROHIBIT_TOP_LEVEL_STATEMENTS: + ETSWarningsProhibitTopLevelStatements(node); + break; + case ETSWarnings::BOOST_EQUALITY_STATEMENT: + ETSWarningBoostEqualityStatement(node); + break; + case ETSWarnings::REMOVE_ASYNC_FUNCTIONS: + ETSWarningRemoveAsync(node); + break; + case ETSWarnings::REMOVE_LAMBDA: + ETSRemoveLambda(node); + break; + case ETSWarnings::IMPLICIT_BOXING_UNBOXING: + ETSWarningImplicitBoxingUnboxing(node); + break; + default: + break; + } + } + +private: + void ETSThrowWarning(const std::string &message, const lexer::SourcePosition &position); + + void AnalyzeClassDefForFinalModifier(const ir::ClassDefinition *class_def); + void AnalyzeClassMethodForFinalModifier(const ir::MethodDefinition *method_def, + const ir::ClassDefinition *class_def); + + void ETSWarningSuggestFinal(const ir::AstNode *node); + void ETSWarningsProhibitTopLevelStatements(const ir::AstNode *node); + void ETSWarningBoostEqualityStatement(const ir::AstNode *node); + void ETSWarningRemoveAsync(const ir::AstNode *node); + void ETSRemoveLambda(const ir::AstNode *node); + void ETSWarningImplicitBoxingUnboxing(const ir::AstNode *node); + + const std::string GetBoxingUnboxingType(ir::AstNode *node); + void CheckTypeOfBoxingUnboxing(ir::AstNode *node); + + parser::Program *program_; + bool ets_werror_; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/es2panda.h b/es2panda.h index e0bfd9214..d3745079a 100644 --- a/es2panda.h +++ b/es2panda.h @@ -85,6 +85,16 @@ struct SourceFile { // NOLINTEND(misc-non-private-member-variables-in-classes) }; +enum ETSWarnings { + NONE = 0, + IMPLICIT_BOXING_UNBOXING = 1, + PROHIBIT_TOP_LEVEL_STATEMENTS = 2, + BOOST_EQUALITY_STATEMENT = 3, + REMOVE_LAMBDA = 4, + SUGGEST_FINAL = 5, + REMOVE_ASYNC_FUNCTIONS = 6, +}; + struct CompilerOptions { // NOLINTBEGIN(misc-non-private-member-variables-in-classes) bool is_debug {}; @@ -105,6 +115,25 @@ struct CompilerOptions { std::shared_ptr arkts_config {}; CompilationMode compilation_mode {}; // NOLINTEND(misc-non-private-member-variables-in-classes) + + // ETS Warning Groups + bool ets_warnings_all {}; // Enable all ETS-warnings for System ArkTS + bool ets_subset_warnings {}; // Enable only ETS-warnings that keep you in subset + bool ets_nonsubset_warnings {}; // Enable only ETS-warnings that do not keep you in subset + bool has_ets_warnings = false; + + // Subset ETS-Warnings + bool ets_phohibit_top_level_statements {}; + bool ets_boost_equality_statement {}; + bool ets_remove_lambda {}; + bool ets_implicit_boxing_unboxing {}; + + // Non-subset ETS-Warnings + bool ets_suggest_final {}; + bool ets_remove_async {}; + + bool ets_werror {}; // Treat all enabled ETS-warnings as errors + std::vector ets_warning_collection = {}; }; enum class ErrorType { @@ -112,6 +141,7 @@ enum class ErrorType { GENERIC, SYNTAX, TYPE, + ETS_WARNING, }; class Error : public std::exception { @@ -141,6 +171,8 @@ public: return "SyntaxError"; case ErrorType::TYPE: return "TypeError"; + case ErrorType::ETS_WARNING: + return "System ArkTS: warning treated as error."; default: break; } diff --git a/lexer/lexer.h b/lexer/lexer.h index 65951cee7..ff27a096d 100644 --- a/lexer/lexer.h +++ b/lexer/lexer.h @@ -23,6 +23,7 @@ namespace panda::es2panda::parser { class ParserContext; +class ETSNolintParser; } // namespace panda::es2panda::parser namespace panda::es2panda::lexer { @@ -273,6 +274,7 @@ protected: friend class KeywordsUtil; friend class TemplateLiteralParserContext; + friend class parser::ETSNolintParser; LexerPosition &Pos(); const LexerPosition &Pos() const; diff --git a/parser/ETSNolintParser.cpp b/parser/ETSNolintParser.cpp new file mode 100644 index 000000000..4ae5e83bf --- /dev/null +++ b/parser/ETSNolintParser.cpp @@ -0,0 +1,312 @@ +/** + * Copyright (c) 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. + */ + +#include "ETSparser.h" +#include "ETSNolintParser.h" + +#include "tools/es2panda/lexer/lexer.h" +#include "tools/es2panda/ir/module/importNamespaceSpecifier.h" + +namespace panda::es2panda::parser { +ETSNolintParser::ETSNolintParser(const ParserImpl *main_parser) : parser_(main_parser) +{ + line_ = parser_->Lexer()->Line(); + + warnings_map_ = { + {std::u32string(U"ets-suggest-final"), ETSWarnings::SUGGEST_FINAL}, + {std::u32string(U"ets-remove-async"), ETSWarnings::REMOVE_ASYNC_FUNCTIONS}, + {std::u32string(U"ets-remove-lambda"), ETSWarnings::REMOVE_LAMBDA}, + {std::u32string(U"ets-boost-equality-statement"), ETSWarnings::BOOST_EQUALITY_STATEMENT}, + {std::u32string(U"ets-implicit-boxing-unboxing"), ETSWarnings::IMPLICIT_BOXING_UNBOXING}, + {std::u32string(U"ets-phohibit-top-level-statements"), ETSWarnings::PROHIBIT_TOP_LEVEL_STATEMENTS}, + }; +} + +void ETSNolintParser::SetStartPos() +{ + line_ = parser_->Lexer()->Pos().Line(); + start_pos_ = parser_->Lexer()->Pos().Iterator().Index(); + pos_offset_ = start_pos_; + + BackwardSymbol(start_pos_); +} + +void ETSNolintParser::CollectETSNolints() +{ + SetStartPos(); + char32_t cp = PeekSymbol(); + + while (cp != lexer::LEX_CHAR_EOS && cp != lexer::UNICODE_CODE_POINT_MAX && cp != lexer::UNICODE_INVALID_CP) { + if (IsEtsNolint()) { + std::size_t line = line_; + std::set collection; + + if (IsNextLine()) { + collection = ParseETSNolintArgs(); + line += 1; + + } else if (IsBegin()) { + collection = ParseETSNolintArgs(); + for (const auto it : collection) { + applying_collection_.insert(it); + } + + } else if (IsEnd()) { + collection = ParseETSNolintArgs(); + + for (const auto it : collection) { + applying_collection_.erase(it); + } + + cp = PeekSymbol(); + continue; + + } else { + collection = ParseETSNolintArgs(); + } + + AddToETSNolintLinesCollection(line, collection); + } else { + NextSymbol(); + } + + cp = PeekSymbol(); + } + + RewindToStart(); +} + +void ETSNolintParser::ApplyETSNolintsToStatements(ArenaVector &statements) const +{ + for (auto *it : statements) { + ApplyETSNolintsToNodesRecursively(it); + } +} + +void ETSNolintParser::NextSymbol() +{ + if (PeekSymbol() == lexer::LEX_CHAR_LF) { + if (!applying_collection_.empty()) { + AddToETSNolintLinesCollection(line_, applying_collection_); + } + line_++; + } + + pos_offset_++; + parser_->Lexer()->Pos().Iterator().Forward(1); +} + +void ETSNolintParser::BackwardSymbol() +{ + pos_offset_--; + parser_->Lexer()->Pos().Iterator().Backward(1); + + if (PeekSymbol() == lexer::LEX_CHAR_LF) { + line_--; + } +} + +void ETSNolintParser::NextSymbol(std::size_t i) +{ + for (; i > 0; --i) { + NextSymbol(); + } +} + +void ETSNolintParser::BackwardSymbol(std::size_t i) +{ + for (; i > 0; --i) { + BackwardSymbol(); + } +} + +void ETSNolintParser::RewindToStart() const +{ + parser_->Lexer()->Pos().Iterator().Backward(pos_offset_ - start_pos_); +} + +void ETSNolintParser::AddToETSNolintLinesCollection(std::size_t line, const std::set &collection) +{ + const auto search = lines_collection_.find(line); + if (search != lines_collection_.end()) { + search->second.insert(collection.begin(), collection.end()); + return; + } + + lines_collection_.insert({line, collection}); +} + +char32_t ETSNolintParser::PeekSymbol() const +{ + return parser_->Lexer()->Pos().Iterator().Peek(); +} + +bool ETSNolintParser::TryPeekU32String(const std::u32string &u32str) +{ + std::size_t local_pos_offset = 0; + char32_t cp; + + for (const char32_t i : u32str) { + cp = PeekSymbol(); + + if (i != cp) { + BackwardSymbol(local_pos_offset); + return false; + } + + NextSymbol(); + local_pos_offset++; + } + + return true; +} + +bool ETSNolintParser::IsEtsNolint() +{ + static const std::u32string ETSNOLINT_CHAR32T = { + lexer::LEX_CHAR_UPPERCASE_E, lexer::LEX_CHAR_UPPERCASE_T, lexer::LEX_CHAR_UPPERCASE_S, + lexer::LEX_CHAR_UPPERCASE_N, lexer::LEX_CHAR_UPPERCASE_O, lexer::LEX_CHAR_UPPERCASE_L, + lexer::LEX_CHAR_UPPERCASE_I, lexer::LEX_CHAR_UPPERCASE_N, lexer::LEX_CHAR_UPPERCASE_T}; + + char32_t cp; + + for (unsigned long i = 0; i < ETSNOLINT_CHAR32T.length(); i++) { + cp = PeekSymbol(); + + if (ETSNOLINT_CHAR32T[i] != cp) { + return false; + } + + NextSymbol(); + } + + return true; +} + +bool ETSNolintParser::IsNextLine() +{ + static const std::u32string NEXTLINE_CHAR32T = { + lexer::LEX_CHAR_MINUS, lexer::LEX_CHAR_UPPERCASE_N, lexer::LEX_CHAR_UPPERCASE_E, + lexer::LEX_CHAR_UPPERCASE_X, lexer::LEX_CHAR_UPPERCASE_T, lexer::LEX_CHAR_UPPERCASE_L, + lexer::LEX_CHAR_UPPERCASE_I, lexer::LEX_CHAR_UPPERCASE_N, lexer::LEX_CHAR_UPPERCASE_E}; + + return TryPeekU32String(NEXTLINE_CHAR32T); +} + +bool ETSNolintParser::IsBegin() +{ + static const std::u32string BEGIN_CHAR32T = {lexer::LEX_CHAR_MINUS, lexer::LEX_CHAR_UPPERCASE_B, + lexer::LEX_CHAR_UPPERCASE_E, lexer::LEX_CHAR_UPPERCASE_G, + lexer::LEX_CHAR_UPPERCASE_I, lexer::LEX_CHAR_UPPERCASE_N}; + + return TryPeekU32String(BEGIN_CHAR32T); +} + +bool ETSNolintParser::IsEnd() +{ + static const std::u32string END_CHAR32T = {lexer::LEX_CHAR_MINUS, lexer::LEX_CHAR_UPPERCASE_E, + lexer::LEX_CHAR_UPPERCASE_N, lexer::LEX_CHAR_UPPERCASE_D}; + + return TryPeekU32String(END_CHAR32T); +} + +ETSWarnings ETSNolintParser::MapETSNolintArg(const std::u32string &warning_name) const +{ + const auto search = warnings_map_.find(warning_name); + ASSERT(search != warnings_map_.end()); + + return search->second; +} + +bool ETSNolintParser::ValidETSNolintArg(const std::u32string &warning_name) const +{ + return warnings_map_.find(warning_name) != warnings_map_.end(); +} + +std::set ETSNolintParser::ParseETSNolintArgs() +{ + std::set warnings_collection; + + if (PeekSymbol() != lexer::LEX_CHAR_LEFT_PAREN) { + for (const auto &it : warnings_map_) { + warnings_collection.insert(it.second); + } + + return warnings_collection; + } + + NextSymbol(); + char32_t cp = 0; + std::u32string warning_name; + + while (cp != lexer::LEX_CHAR_SP && cp != lexer::LEX_CHAR_LF && cp != lexer::LEX_CHAR_EOS) { + cp = PeekSymbol(); + + if (cp != lexer::LEX_CHAR_MINUS && cp != lexer::LEX_CHAR_COMMA && cp != lexer::LEX_CHAR_RIGHT_PAREN && + (cp < lexer::LEX_CHAR_LOWERCASE_A || cp > lexer::LEX_CHAR_LOWERCASE_Z)) { + const std::string msg = "Unexpected character for ETSNOLINT argument! [VALID ONLY: a-z, '-']."; + throw Error {ErrorType::SYNTAX, parser_->GetProgram()->SourceFile().Utf8(), msg.c_str(), line_ + 1, 0}; + } + + if (cp == lexer::LEX_CHAR_COMMA || cp == lexer::LEX_CHAR_RIGHT_PAREN) { + if (!ValidETSNolintArg(warning_name)) { + const std::string msg = "Invalid argument for ETSNOLINT!"; + throw Error {ErrorType::SYNTAX, parser_->GetProgram()->SourceFile().Utf8(), msg.c_str(), line_ + 1, 0}; + } + + warnings_collection.insert(MapETSNolintArg(warning_name)); + warning_name.clear(); + } else { + warning_name += cp; + } + + if (cp == lexer::LEX_CHAR_RIGHT_PAREN) { + break; + } + + NextSymbol(); + } + + return warnings_collection; +} + +bool ETSNolintParser::IsLineWithETSNolint(const std::size_t line) const +{ + return lines_collection_.find(line) != lines_collection_.end(); +} + +const std::set ETSNolintParser::GetWarningsCollectionByLine(std::size_t line) const +{ + const auto search = lines_collection_.find(line); + return search == lines_collection_.end() ? std::set {} : search->second; +} + +void ETSNolintParser::ApplyETSNolintsToNodesRecursively(ir::AstNode *node) const +{ + if (node == nullptr) { + return; + } + + const std::size_t line = node->Start().line; + + if (IsLineWithETSNolint(line)) { + const std::set warnings_collection = GetWarningsCollectionByLine(line); + + parser_->GetProgram()->AddNodeToETSNolintCollection(node, warnings_collection); + } + + node->Iterate([&](auto *child_node) { ApplyETSNolintsToNodesRecursively(child_node); }); +} +} // namespace panda::es2panda::parser diff --git a/parser/ETSNolintParser.h b/parser/ETSNolintParser.h new file mode 100644 index 000000000..5279f649e --- /dev/null +++ b/parser/ETSNolintParser.h @@ -0,0 +1,61 @@ +/** + * Copyright (c) 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. + */ + +#ifndef ES2PANDA_PARSER_CORE_ETS_NOLINT_PARSER_H +#define ES2PANDA_PARSER_CORE_ETS_NOLINT_PARSER_H + +namespace panda::es2panda::parser { + +class ETSNolintParser { +public: + explicit ETSNolintParser(const ParserImpl *main_parser); + void CollectETSNolints(); + void ApplyETSNolintsToStatements(ArenaVector &statements) const; + +private: + void SetStartPos(); + void NextSymbol(); + void BackwardSymbol(); + void NextSymbol(std::size_t i); + void BackwardSymbol(std::size_t i); + void RewindToStart() const; + + char32_t PeekSymbol() const; + bool TryPeekU32String(const std::u32string &str); + bool IsEtsNolint(); + bool IsNextLine(); + bool IsBegin(); + bool IsEnd(); + + std::set ParseETSNolintArgs(); + bool ValidETSNolintArg(const std::u32string &warning_name) const; + ETSWarnings MapETSNolintArg(const std::u32string &warning_name) const; + + void AddToETSNolintLinesCollection(std::size_t line, const std::set &collection); + bool IsLineWithETSNolint(const std::size_t line) const; + const std::set GetWarningsCollectionByLine(std::size_t line) const; + + void ApplyETSNolintsToNodesRecursively(ir::AstNode *node) const; + + const ParserImpl *parser_; + std::size_t start_pos_ = 0; + std::size_t pos_offset_ = 0; + std::size_t line_ = 0; + std::set applying_collection_; + std::map> lines_collection_; + std::map warnings_map_; +}; +} // namespace panda::es2panda::parser +#endif diff --git a/parser/ETSparser.cpp b/parser/ETSparser.cpp index 17328c831..a5b5b9489 100644 --- a/parser/ETSparser.cpp +++ b/parser/ETSparser.cpp @@ -14,6 +14,7 @@ */ #include "ETSparser.h" +#include "tools/es2panda/parser/ETSNolintParser.h" #include "parser/parserFlags.h" #include "util/arktsconfig.h" @@ -164,6 +165,9 @@ void ETSParser::ParseProgram(ScriptKind kind) void ETSParser::ParseETSGlobalScript(lexer::SourcePosition start_loc, ArenaVector &statements) { + ETSNolintParser etsnolint_parser(this); + etsnolint_parser.CollectETSNolints(); + auto paths = ParseImportDeclarations(statements); // remove external sources from paths because already parsed them @@ -178,6 +182,8 @@ void ETSParser::ParseETSGlobalScript(lexer::SourcePosition start_loc, ArenaVecto ParseSources(paths, false); ParseTopLevelDeclaration(statements); + etsnolint_parser.ApplyETSNolintsToStatements(statements); + auto *ets_script = AllocNode(Allocator(), Binder()->GetScope(), std::move(statements), GetProgram()); Binder()->GetScope()->BindNode(ets_script); ets_script->SetRange({start_loc, Lexer()->GetToken().End()}); diff --git a/parser/parserImpl.h b/parser/parserImpl.h index eaea775b5..f026872fe 100644 --- a/parser/parserImpl.h +++ b/parser/parserImpl.h @@ -245,6 +245,7 @@ protected: friend class SavedParserContext; friend class SavedClassPrivateContext; friend class ArrowFunctionContext; + friend class ETSNolintParser; [[noreturn]] void ThrowParameterModifierError(ir::ModifierFlags status) const; [[noreturn]] void ThrowUnexpectedToken(lexer::TokenType token_type) const; diff --git a/parser/program/program.cpp b/parser/program/program.cpp index f6ec7d2ba..0721b96cb 100644 --- a/parser/program/program.cpp +++ b/parser/program/program.cpp @@ -63,4 +63,20 @@ const binder::GlobalScope *Program::GlobalScope() const return static_cast(ast_->Scope()); } +void Program::AddNodeToETSNolintCollection(const ir::AstNode *node, std::set warnings_collection) +{ + ArenaSet tmp(allocator_->Adapter()); + tmp.insert(warnings_collection.begin(), warnings_collection.end()); + etsnolint_collection_.insert({node, tmp}); +} + +bool Program::NodeContainsETSNolint(const ir::AstNode *node, ETSWarnings warning) +{ + auto node_etsnolints = etsnolint_collection_.find(node); + if (node_etsnolints == etsnolint_collection_.end()) + return false; + + return node_etsnolints->second.find(warning) != node_etsnolints->second.end(); +} + } // namespace panda::es2panda::parser diff --git a/parser/program/program.h b/parser/program/program.h index 4f1078290..585b81f57 100644 --- a/parser/program/program.h +++ b/parser/program/program.h @@ -24,6 +24,8 @@ #include "es2panda.h" +#include + namespace panda::es2panda::ir { class BlockStatement; } // namespace panda::es2panda::ir @@ -38,6 +40,8 @@ enum class ScriptKind { SCRIPT, MODULE, STDLIB }; class Program { public: using ExternalSource = ArenaUnorderedMap>; + using ETSNolintsCollectionMap = ArenaUnorderedMap>; + template static Program NewProgram(ArenaAllocator *allocator) { @@ -49,7 +53,8 @@ public: : allocator_(allocator), binder_(binder), external_sources_(allocator_->Adapter()), - extension_(binder->Extension()) + extension_(binder->Extension()), + etsnolint_collection_(allocator_->Adapter()) { } @@ -217,6 +222,9 @@ public: std::string Dump() const; + void AddNodeToETSNolintCollection(const ir::AstNode *node, std::set warnings_collection); + bool NodeContainsETSNolint(const ir::AstNode *node, ETSWarnings warning); + private: ArenaAllocator *allocator_ {}; binder::Binder *binder_ {}; @@ -233,6 +241,7 @@ private: ScriptKind kind_ {}; ScriptExtension extension_ {}; bool entry_point_ {}; + ETSNolintsCollectionMap etsnolint_collection_; }; } // namespace panda::es2panda::parser diff --git a/util/options.cpp b/util/options.cpp index 3547bd5e5..576f17fc5 100644 --- a/util/options.cpp +++ b/util/options.cpp @@ -55,6 +55,11 @@ static std::unordered_set StringToStringSet(const std::string return res; } +static inline bool ETSWarningsGroupSetter(const panda::PandArg &option) +{ + return !option.WasSet() || (option.WasSet() && option.GetValue()); +} + // NOLINTNEXTLINE(readability-function-size) bool Options::Parse(int argc, const char **argv) { @@ -78,6 +83,28 @@ bool Options::Parse(int argc, const char **argv) panda::PandArg op_ets_module("ets-module", false, "Compile the input as ets-module"); panda::PandArg op_ts_decl_out("gen-ts-decl", "", "For given .ets file, generate .ts interop file"); + // ETS-warnings + panda::PandArg op_ets_warnings_all("ets-warnings-all", false, "Show performance-related ets-warnings"); + panda::PandArg op_ets_werror("ets-werror", false, + "Treat all enabled performance-related ets-warnings as error"); + panda::PandArg op_ets_subset_warnings("ets-subset-warnings", false, + "Show ETS-warnings that keep you in subset"); + panda::PandArg op_ets_nonsubset_warnings("ets-nonsubset-warnings", false, + "Show ETS-warnings that do not keep you in subset"); + panda::PandArg op_ets_suggest_final("ets-suggest-final", false, + "Suggest final keyword warning - ETS non-subset warning"); + panda::PandArg op_ets_phohibit_top_level_statements("ets-phohibit-top-level-statements", false, + "Prohibit top-level statements - ETS subset Warning"); + panda::PandArg op_ets_boost_equality_statement("ets-boost-equality-statement", false, + "Suggest boosting Equality Statements - ETS Subset Warning"); + panda::PandArg op_ets_remove_async( + "ets-remove-async", false, "Suggests replacing async functions with coroutines - ETS Non Subset Warnings"); + panda::PandArg op_ets_remove_lambda( + "ets-remove-lambda", false, "Suggestions to replace lambda with regular functions - ETS Subset Warning"); + panda::PandArg op_ets_implicit_boxing_unboxing( + "ets-implicit-boxing-unboxing", false, + "Check if a program contains implicit boxing or unboxing - ETS Subset Warning"); + auto constexpr DEFAULT_THREAD_COUNT = 2; panda::PandArg op_thread_count("thread", DEFAULT_THREAD_COUNT, "Number of worker threads"); panda::PandArg op_size_stat("dump-size-stat", false, "Dump size statistics"); @@ -121,6 +148,21 @@ bool Options::Parse(int argc, const char **argv) argparser_->Add(&arkts_config); argparser_->Add(&op_ts_decl_out); + argparser_->Add(&op_ets_warnings_all); + argparser_->Add(&op_ets_werror); + argparser_->Add(&op_ets_subset_warnings); + argparser_->Add(&op_ets_nonsubset_warnings); + + // ETS-subset warnings + argparser_->Add(&op_ets_phohibit_top_level_statements); + argparser_->Add(&op_ets_boost_equality_statement); + argparser_->Add(&op_ets_remove_lambda); + argparser_->Add(&op_ets_implicit_boxing_unboxing); + + // ETS-non-subset warnings + argparser_->Add(&op_ets_suggest_final); + argparser_->Add(&op_ets_remove_async); + argparser_->PushBackTail(&input_file); argparser_->EnableTail(); argparser_->EnableRemainder(); @@ -301,6 +343,62 @@ bool Options::Parse(int argc, const char **argv) compiler_options_.dump_before_phases = StringToStringSet(dump_before_phases.GetValue()); compiler_options_.dump_after_phases = StringToStringSet(dump_after_phases.GetValue()); + // ETS-Warnings + compiler_options_.ets_subset_warnings = op_ets_subset_warnings.GetValue(); + compiler_options_.ets_werror = op_ets_werror.GetValue(); + compiler_options_.ets_nonsubset_warnings = op_ets_nonsubset_warnings.GetValue(); + compiler_options_.ets_warnings_all = op_ets_warnings_all.GetValue(); + + if (compiler_options_.ets_warnings_all || compiler_options_.ets_subset_warnings) { + // Adding subset warnings + compiler_options_.ets_phohibit_top_level_statements = + ETSWarningsGroupSetter(op_ets_phohibit_top_level_statements); + compiler_options_.ets_boost_equality_statement = ETSWarningsGroupSetter(op_ets_boost_equality_statement); + compiler_options_.ets_remove_lambda = ETSWarningsGroupSetter(op_ets_remove_lambda); + compiler_options_.ets_implicit_boxing_unboxing = ETSWarningsGroupSetter(op_ets_implicit_boxing_unboxing); + } + + if (compiler_options_.ets_warnings_all || compiler_options_.ets_nonsubset_warnings) { + // Adding non-subset warnings + compiler_options_.ets_suggest_final = ETSWarningsGroupSetter(op_ets_suggest_final); + compiler_options_.ets_remove_async = ETSWarningsGroupSetter(op_ets_remove_async); + } + + if (!compiler_options_.ets_warnings_all && !compiler_options_.ets_subset_warnings && + !compiler_options_.ets_nonsubset_warnings) { + // If no warnings groups enabled - check all if enabled + compiler_options_.ets_suggest_final = op_ets_suggest_final.GetValue(); + compiler_options_.ets_phohibit_top_level_statements = op_ets_phohibit_top_level_statements.GetValue(); + compiler_options_.ets_boost_equality_statement = op_ets_boost_equality_statement.GetValue(); + compiler_options_.ets_remove_async = op_ets_remove_async.GetValue(); + compiler_options_.ets_remove_lambda = op_ets_remove_lambda.GetValue(); + compiler_options_.ets_implicit_boxing_unboxing = op_ets_implicit_boxing_unboxing.GetValue(); + } + + // Pushing enabled warnings to warning collection + if (compiler_options_.ets_suggest_final) { + compiler_options_.ets_warning_collection.push_back(ETSWarnings::SUGGEST_FINAL); + } + if (compiler_options_.ets_phohibit_top_level_statements) { + compiler_options_.ets_warning_collection.push_back(ETSWarnings::PROHIBIT_TOP_LEVEL_STATEMENTS); + } + if (compiler_options_.ets_boost_equality_statement) { + compiler_options_.ets_warning_collection.push_back(ETSWarnings::BOOST_EQUALITY_STATEMENT); + } + if (compiler_options_.ets_remove_async) { + compiler_options_.ets_warning_collection.push_back(ETSWarnings::REMOVE_ASYNC_FUNCTIONS); + } + if (compiler_options_.ets_remove_lambda) { + compiler_options_.ets_warning_collection.push_back(ETSWarnings::REMOVE_LAMBDA); + } + if (compiler_options_.ets_implicit_boxing_unboxing) { + compiler_options_.ets_warning_collection.push_back(ETSWarnings::IMPLICIT_BOXING_UNBOXING); + } + + if (!compiler_options_.ets_warning_collection.empty()) { + compiler_options_.has_ets_warnings = true; + } + return true; } } // namespace panda::es2panda::util -- Gitee