From e8e9beb27e01cf0165757dae34a74f4d0937039c Mon Sep 17 00:00:00 2001 From: ZhongNing Date: Tue, 27 May 2025 15:16:54 +0800 Subject: [PATCH 001/209] fix issue for arkts-no-classes-as-obj Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICAO3W Test scenarios: fix issue arkts-no-classes-as-obj Signed-off-by: ZhongNing --- ets2panda/linter/src/lib/TypeScriptLinter.ts | 14 +++++-- .../linter/test/main/class_as_object.ets | 11 ++++- .../test/main/class_as_object.ets.arkts2.json | 42 +++---------------- .../linter/test/main/class_as_object.ets.json | 40 ------------------ 4 files changed, 27 insertions(+), 80 deletions(-) diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index e4e7c7ee91..f1fdb343ff 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -3953,12 +3953,20 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } } + this.handleIllegalSymbolUsage(tsIdentifier, tsIdentSym) + } + + private handleIllegalSymbolUsage(tsIdentifier: ts.Identifier, tsIdentSym: ts.Symbol): void { if (tsIdentSym.flags & ts.SymbolFlags.ValueModule) { this.incrementCounters(tsIdentifier, FaultID.NamespaceAsObject); } else { - // missing EnumAsObject - const faultId = this.options.arkts2 ? FaultID.ClassAsObjectError : FaultID.ClassAsObject; - this.incrementCounters(tsIdentifier, faultId); + const typeName = tsIdentifier.getText(); + const isWrapperObject = typeName === 'Number' || typeName === 'String' || typeName === 'Boolean'; + + if (!isWrapperObject) { + const faultId = this.options.arkts2 ? FaultID.ClassAsObjectError : FaultID.ClassAsObject; + this.incrementCounters(tsIdentifier, faultId); + } } } diff --git a/ets2panda/linter/test/main/class_as_object.ets b/ets2panda/linter/test/main/class_as_object.ets index fcc5a36250..a2bdc36a95 100644 --- a/ets2panda/linter/test/main/class_as_object.ets +++ b/ets2panda/linter/test/main/class_as_object.ets @@ -203,4 +203,13 @@ function parse(type: "number" | "boolean", value: string): number | boolean { } function format(input: string | number): string[] | number[] { return typeof input === "string" ? input.split("") : input.toString().split("").map(Number); -} \ No newline at end of file +} + +let version: string = "1.2" +let a1 = version.split('.').map(Number); + +let version2: string = "1.2" +let a2 = version2.split('.').map(String); + +let version3: string = "1.2" +let a3 = version3.split('.').map(Boolean); \ No newline at end of file diff --git a/ets2panda/linter/test/main/class_as_object.ets.arkts2.json b/ets2panda/linter/test/main/class_as_object.ets.arkts2.json index 3bf41adaeb..64c0b7ef62 100644 --- a/ets2panda/linter/test/main/class_as_object.ets.arkts2.json +++ b/ets2panda/linter/test/main/class_as_object.ets.arkts2.json @@ -394,36 +394,6 @@ "rule": "Classes cannot be used as objects (arkts-no-classes-as-obj)", "severity": "ERROR" }, - { - "line": 129, - "column": 15, - "endLine": 129, - "endColumn": 21, - "problem": "ClassAsObjectError", - "suggest": "", - "rule": "Classes cannot be used as objects (arkts-no-classes-as-obj)", - "severity": "ERROR" - }, - { - "line": 130, - "column": 15, - "endLine": 130, - "endColumn": 22, - "problem": "ClassAsObjectError", - "suggest": "", - "rule": "Classes cannot be used as objects (arkts-no-classes-as-obj)", - "severity": "ERROR" - }, - { - "line": 131, - "column": 15, - "endLine": 131, - "endColumn": 21, - "problem": "ClassAsObjectError", - "suggest": "", - "rule": "Classes cannot be used as objects (arkts-no-classes-as-obj)", - "severity": "ERROR" - }, { "line": 132, "column": 15, @@ -905,13 +875,13 @@ "severity": "ERROR" }, { - "line": 205, - "column": 87, - "endLine": 205, - "endColumn": 93, - "problem": "ClassAsObjectError", + "line": 209, + "column": 5, + "endLine": 209, + "endColumn": 40, + "problem": "NumericSemantics", "suggest": "", - "rule": "Classes cannot be used as objects (arkts-no-classes-as-obj)", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" } ] diff --git a/ets2panda/linter/test/main/class_as_object.ets.json b/ets2panda/linter/test/main/class_as_object.ets.json index cb35d61776..5bfa876a0a 100644 --- a/ets2panda/linter/test/main/class_as_object.ets.json +++ b/ets2panda/linter/test/main/class_as_object.ets.json @@ -212,36 +212,6 @@ "rule": "Classes cannot be used as objects (arkts-no-classes-as-obj)", "severity": "WARNING" }, - { - "line": 129, - "column": 15, - "endLine": 129, - "endColumn": 21, - "problem": "ClassAsObject", - "suggest": "", - "rule": "Classes cannot be used as objects (arkts-no-classes-as-obj)", - "severity": "WARNING" - }, - { - "line": 130, - "column": 15, - "endLine": 130, - "endColumn": 22, - "problem": "ClassAsObject", - "suggest": "", - "rule": "Classes cannot be used as objects (arkts-no-classes-as-obj)", - "severity": "WARNING" - }, - { - "line": 131, - "column": 15, - "endLine": 131, - "endColumn": 21, - "problem": "ClassAsObject", - "suggest": "", - "rule": "Classes cannot be used as objects (arkts-no-classes-as-obj)", - "severity": "WARNING" - }, { "line": 132, "column": 15, @@ -661,16 +631,6 @@ "suggest": "", "rule": "Classes cannot be used as objects (arkts-no-classes-as-obj)", "severity": "WARNING" - }, - { - "line": 205, - "column": 87, - "endLine": 205, - "endColumn": 93, - "problem": "ClassAsObject", - "suggest": "", - "rule": "Classes cannot be used as objects (arkts-no-classes-as-obj)", - "severity": "WARNING" } ] } \ No newline at end of file -- Gitee From 1c7c554c56293168eaba61ef97bd583a81ca49ec Mon Sep 17 00:00:00 2001 From: Denis Slynko Date: Thu, 29 May 2025 11:07:53 +0300 Subject: [PATCH 002/209] [ArkTS] Rework Class.ofCaller Remove implementation of `GlobalClassHandler::FormDependentInitTriggers`. Right now its not used in any scenarios, but could be reused in future for `import "path"` feature (see #26183) Issue: #ICAJX5 Signed-off-by: Denis Slynko --- .../ets/topLevelStmts/globalClassHandler.cpp | 23 ++++--------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp index a914f8ad66..ff2f8abf1b 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp @@ -431,26 +431,11 @@ ArenaVector GlobalClassHandler::FormInitMethodStatements(parser return statements; } -void GlobalClassHandler::FormDependentInitTriggers(ArenaVector &statements, - const ModuleDependencies *moduleDependencies) +void GlobalClassHandler::FormDependentInitTriggers([[maybe_unused]] ArenaVector &statements, + [[maybe_unused]] const ModuleDependencies *moduleDependencies) { - auto const sequence = [&statements](ir::Statement *stmt) { statements.push_back(stmt); }; - - auto triggerInitOf = [this, sequence, initialized = false](parser::Program *prog) mutable { - if (!initialized) { - initialized = true; - sequence(parser_->CreateFormattedStatement("const __linker = Class.ofCaller().getLinker();")); - } - auto name = std::string(prog->ModulePrefix()).append(Signatures::ETS_GLOBAL); - sequence(parser_->CreateFormattedStatement("__linker.loadClass(\"" + name + "\", true);")); - }; - - for (auto depProg : *moduleDependencies) { - if (util::Helpers::IsStdLib(depProg)) { - continue; - } - triggerInitOf(depProg); - } + // NOTE(dslynko, #26183): leaving this function for later reuse in `import "path"` feature, + // which would initialize the dependency. } ir::ClassStaticBlock *GlobalClassHandler::CreateStaticBlock(ir::ClassDefinition *classDef) -- Gitee From b8bd8a1f337e689178bf2d406daef7cc75625cb1 Mon Sep 17 00:00:00 2001 From: tolgayakar Date: Tue, 3 Jun 2025 12:07:00 +0300 Subject: [PATCH 003/209] Fix no CTE on unions overlap Issue: https://gitee.com/openharmony/arkcompiler_runtime_core/issues/ICANTK Signed-off-by: tolgayakar --- ets2panda/checker/types/ets/etsUnionType.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ets2panda/checker/types/ets/etsUnionType.cpp b/ets2panda/checker/types/ets/etsUnionType.cpp index 2bbdf54442..2b20af44a4 100644 --- a/ets2panda/checker/types/ets/etsUnionType.cpp +++ b/ets2panda/checker/types/ets/etsUnionType.cpp @@ -759,6 +759,12 @@ bool ETSUnionType::IsOverlapWith(TypeRelation *relation, Type *type) if (type->IsETSUnionType() && type->AsETSUnionType()->IsOverlapWith(relation, ct)) { return true; } + if (type->IsETSObjectType() && ct->IsETSObjectType()) { + if (type->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_NUMERIC) && + ct->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_NUMERIC)) { + return true; + } + } if (relation->IsSupertypeOf(ct, type) || relation->IsSupertypeOf(type, ct)) { return true; } -- Gitee From ede1ef27b39a147879d70ac5d337a2d5df5b1599 Mon Sep 17 00:00:00 2001 From: Vivien Voros Date: Tue, 3 Jun 2025 18:30:40 +0200 Subject: [PATCH 004/209] Increasing coverage of diagnostic errors - 2 Removing unnecessary, unused code Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICCC0N Related Internal Issue: #26188 Change-Id: I839bf2a0948f06ae610934e874c845b08710abc3 Signed-off-by: Vivien Voros --- ets2panda/parser/ETSparser.cpp | 48 +++------------------------ ets2panda/parser/ETSparser.h | 3 +- ets2panda/parser/ETSparserClasses.cpp | 35 ------------------- ets2panda/parser/statementParser.cpp | 2 +- 4 files changed, 6 insertions(+), 82 deletions(-) diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 71fd3ae939..99039876c6 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -756,43 +756,6 @@ ir::TSTypeAliasDeclaration *ETSParser::ParseTypeAliasDeclaration() return typeAliasDecl; } -std::pair ETSParser::CheckDefaultParameters(const ir::ScriptFunction *const function) -{ - bool hasOptionalParameters = false; - bool hasRestParameter = false; - std::size_t requiredParametersNumber = 0U; - - for (auto *const it : function->Params()) { - auto const *const param = it->AsETSParameterExpression(); - - if (param->IsRestParameter()) { - hasRestParameter = true; - continue; - } - - if (hasRestParameter) { - LogError(diagnostic::REST_PARAM_LAST, {}, param->Start()); - } - - if (param->IsOptional()) { - hasOptionalParameters = true; - continue; - } - - if (hasOptionalParameters) { - LogError(diagnostic::REQUIRED_PARAM_AFTER_DEFAULT, {}, param->Start()); - } - - ++requiredParametersNumber; - } - - if (hasOptionalParameters && hasRestParameter) { - LogError(diagnostic::REST_AND_DEFAULT_SAME_TIME, {}, function->Start()); - } - - return std::make_pair(hasOptionalParameters, requiredParametersNumber); -} - std::string ETSParser::PrimitiveTypeToName(ir::PrimitiveType type) const { switch (type) { @@ -1361,7 +1324,8 @@ bool ETSParser::ParseNamedSpecifiesImport(ArenaVector *re auto *imported = ExpectIdentifier(); ir::Identifier *local = nullptr; - if (CheckModuleAsModifier() && Lexer()->TryEatTokenType(lexer::TokenType::KEYW_AS)) { + CheckModuleAsModifier(); + if (Lexer()->TryEatTokenType(lexer::TokenType::KEYW_AS)) { if (Lexer()->TryEatTokenType(lexer::TokenType::KEYW_DEFAULT)) { auto *exportedAnonyConst = AllocNode(imported, imported->Clone(Allocator(), nullptr)); exportedAnonyConst->SetDefault(); @@ -1422,9 +1386,7 @@ void ETSParser::ParseNameSpaceSpecifier(ArenaVector *specifiers, lexer::SourcePosition namespaceStart = Lexer()->GetToken().Start(); Lexer()->NextToken(); // eat `*` character - if (!CheckModuleAsModifier()) { - LogError(diagnostic::UNEXPECTED_TOKEN); - } + CheckModuleAsModifier(); // Note (oeotvos) As a temporary solution we allow the stdlib to use namespace import without an alias, but this // should be handled at some point. @@ -1487,13 +1449,11 @@ ir::AstNode *ETSParser::ParseImportDefaultSpecifier(ArenaVector * return nullptr; } -bool ETSParser::CheckModuleAsModifier() +void ETSParser::CheckModuleAsModifier() { if ((Lexer()->GetToken().Flags() & lexer::TokenFlags::HAS_ESCAPE) != 0U) { LogError(diagnostic::ESCAPE_SEQUENCES_IN_AS); } - - return true; } ir::AnnotatedExpression *ETSParser::GetAnnotatedExpressionFromParam() diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index 6ca2d6d6c8..d1dd448c37 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -260,7 +260,6 @@ private: ir::TypeNode *ParseETSTupleType(TypeAnnotationParsingOptions *options); ir::TypeNode *ParseTsArrayType(ir::TypeNode *typeNode, TypeAnnotationParsingOptions *options); bool ParseTriplePeriod(bool spreadTypePresent); - std::pair CheckDefaultParameters(const ir::ScriptFunction *function); std::string PrimitiveTypeToName(ir::PrimitiveType type) const; std::string GetNameForTypeNode(const ir::TypeNode *typeAnnotation) const; std::string GetNameForETSUnionType(const ir::TypeNode *typeAnnotation) const; @@ -300,7 +299,7 @@ private: ir::AstNode *ParseJsDocInfoInInterfaceBody(); ir::AstNode *ParseAnnotationsInInterfaceBody(); void ParseNameSpaceSpecifier(ArenaVector *specifiers, bool isReExport = false); - bool CheckModuleAsModifier(); + void CheckModuleAsModifier(); bool IsFixedArrayTypeNode(ir::AstNode *node); ir::Expression *ParseFunctionParameterExpression(ir::AnnotatedExpression *paramIdent, bool isOptional); std::pair TypeAnnotationValue(ir::TypeNode *typeAnnotation); diff --git a/ets2panda/parser/ETSparserClasses.cpp b/ets2panda/parser/ETSparserClasses.cpp index ec767160ae..1a6aa6e0f2 100644 --- a/ets2panda/parser/ETSparserClasses.cpp +++ b/ets2panda/parser/ETSparserClasses.cpp @@ -113,11 +113,6 @@ ir::ModifierFlags ETSParser::ParseClassModifiers() while (IsClassModifier(Lexer()->GetToken().KeywordType())) { ir::ModifierFlags currentFlag = ir::ModifierFlags::NONE; - lexer::TokenFlags tokenFlags = Lexer()->GetToken().Flags(); - if ((tokenFlags & lexer::TokenFlags::HAS_ESCAPE) != 0) { - LogError(diagnostic::KEYWORD_CONTAINS_ESCAPED_CHARS); // Lexer will do it. - } - switch (Lexer()->GetToken().KeywordType()) { case lexer::TokenType::KEYW_STATIC: { currentFlag = ir::ModifierFlags::STATIC; @@ -201,11 +196,6 @@ std::tuple ETSParser::ParseClassMemberAccessModif return {ir::ModifierFlags::NONE, false, false}; } - lexer::TokenFlags tokenFlags = Lexer()->GetToken().Flags(); - if ((tokenFlags & lexer::TokenFlags::HAS_ESCAPE) != 0) { - LogError(diagnostic::KEYWORD_CONTAINS_ESCAPED_CHARS); // Lexer will do it. - } - ir::ModifierFlags accessFlag = ir::ModifierFlags::NONE; const auto token = Lexer()->GetToken(); @@ -266,11 +256,6 @@ ir::ModifierFlags ETSParser::ParseClassFieldModifiers(bool seenStatic) ir::ModifierFlags currentFlag; - lexer::TokenFlags tokenFlags = Lexer()->GetToken().Flags(); - if ((tokenFlags & lexer::TokenFlags::HAS_ESCAPE) != 0) { - LogError(diagnostic::KEYWORD_CONTAINS_ESCAPED_CHARS); // Lexer will do it. - } - switch (Lexer()->GetToken().KeywordType()) { case lexer::TokenType::KEYW_STATIC: { currentFlag = ir::ModifierFlags::STATIC; @@ -403,11 +388,6 @@ ir::ModifierFlags ETSParser::ParseClassMethodModifiers(bool seenStatic) ir::ModifierFlags currentFlag = ir::ModifierFlags::NONE; - lexer::TokenFlags tokenFlags = Lexer()->GetToken().Flags(); - if ((tokenFlags & lexer::TokenFlags::HAS_ESCAPE) != 0) { - LogError(diagnostic::KEYWORD_CONTAINS_ESCAPED_CHARS); // Lexer will do it. - } - currentFlag = ParseClassMethodModifierFlag(); if ((flags & currentFlag) != 0) { LogError(diagnostic::DUPLICATED_MODIFIER); @@ -854,16 +834,6 @@ ir::TSInterfaceDeclaration *ETSParser::ParseInterfaceBody(ir::Identifier *name, lexer::SourcePosition bodyStart = Lexer()->GetToken().Start(); auto members = ParseTypeLiteralOrInterface(); - - for (auto &member : members) { - if (member->Type() == ir::AstNodeType::CLASS_DECLARATION || - member->Type() == ir::AstNodeType::STRUCT_DECLARATION || - member->Type() == ir::AstNodeType::TS_ENUM_DECLARATION || - member->Type() == ir::AstNodeType::TS_INTERFACE_DECLARATION) { - LogError(diagnostic::IMPROPER_NESTING_INTERFACE); - } - } - auto *body = AllocNode(std::move(members)); body->SetRange({bodyStart, Lexer()->GetToken().End()}); @@ -1042,11 +1012,6 @@ ir::AstNode *ETSParser::ParseInterfaceField() ParseInterfaceModifiers(fieldModifiers, optionalField); auto *typeAnnotation = ParseInterfaceTypeAnnotation(name); - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_EQUAL && - Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { - LogError(diagnostic::INITIALIZERS_INTERFACE_PROPS); - Lexer()->NextToken(); // Error processing: eat '='. - } auto *field = AllocNode(name, nullptr, typeAnnotation->Clone(Allocator(), nullptr), fieldModifiers, Allocator(), false); if (optionalField) { diff --git a/ets2panda/parser/statementParser.cpp b/ets2panda/parser/statementParser.cpp index ff4089f8bd..b3d4d898ca 100644 --- a/ets2panda/parser/statementParser.cpp +++ b/ets2panda/parser/statementParser.cpp @@ -297,7 +297,7 @@ ir::Statement *ParserImpl::ParsePotentialExpressionStatement(StatementParsingFla ir::Statement *ParserImpl::ParseStructStatement([[maybe_unused]] StatementParsingFlags flags, ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags modFlags) { - LogError(diagnostic::ILLEGAL_START_EXPRESSION); + LogError(diagnostic::ILLEGAL_START_STRUCT); return ParseStructDeclaration(modifiers, modFlags); } -- Gitee From 43938523b75156aeab2688af2069bc504befa390 Mon Sep 17 00:00:00 2001 From: Torok Gergo Date: Tue, 3 Jun 2025 11:39:54 +0200 Subject: [PATCH 005/209] Fixing async assertion error Reason: Async methods with optional parameter emitted assertion error. Description: Replace SetAnnotations to AddAnnotations so the previous data doest'n get lost Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICC9SZ Signed-off-by: Torok Gergo --- ets2panda/compiler/core/ETSemitter.cpp | 2 +- .../test/runtime/ets/asyncWithDefaultParam.ets | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 ets2panda/test/runtime/ets/asyncWithDefaultParam.ets diff --git a/ets2panda/compiler/core/ETSemitter.cpp b/ets2panda/compiler/core/ETSemitter.cpp index 3edebf6826..852fc67da7 100644 --- a/ets2panda/compiler/core/ETSemitter.cpp +++ b/ets2panda/compiler/core/ETSemitter.cpp @@ -291,7 +291,7 @@ void ETSEmitter::GenAnnotation() if (scriptFunc->IsAsyncFunc()) { std::vector annotations; annotations.push_back(GenAnnotationAsync(scriptFunc)); - func.metadata->SetAnnotations(std::move(annotations)); + func.metadata->AddAnnotations(annotations); } Program()->AddToFunctionTable(std::move(func)); } diff --git a/ets2panda/test/runtime/ets/asyncWithDefaultParam.ets b/ets2panda/test/runtime/ets/asyncWithDefaultParam.ets new file mode 100644 index 0000000000..1082ea3a1a --- /dev/null +++ b/ets2panda/test/runtime/ets/asyncWithDefaultParam.ets @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 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. + */ + +async function emitAsync1(args: int | undefined = 1): Promise {} +async function emitAsync2(args?: int): Promise {} -- Gitee From 03167a379eac3be6c3ab9dcca4dca6f9d070b4dd Mon Sep 17 00:00:00 2001 From: mozgovoykirill Date: Fri, 16 May 2025 18:08:12 +0300 Subject: [PATCH 006/209] Static library libes2panda-public for windows Issue:#IC8FIB Testing:'ninja all tests' Signed-off-by: mozgovoykirill --- ets2panda/public/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ets2panda/public/CMakeLists.txt b/ets2panda/public/CMakeLists.txt index 12227ac6fe..cb015aa58c 100644 --- a/ets2panda/public/CMakeLists.txt +++ b/ets2panda/public/CMakeLists.txt @@ -629,6 +629,9 @@ set(ES2PANDA_PUBLIC_SOURCES ../util/plugin.cpp ) +if (PANDA_TARGET_WINDOWS) + set(CMAKE_STATIC_LIBRARY_SUFFIX ".lib") +endif() panda_add_library(es2panda-public ${PANDA_DEFAULT_LIB_TYPE} ${ES2PANDA_PUBLIC_SOURCES}) add_dependencies(es2panda-lib gen_api) -- Gitee From 7856b7dd59387eafb318771e834e13194ff17c0f Mon Sep 17 00:00:00 2001 From: nadolskyanton Date: Thu, 5 Jun 2025 15:55:00 +0300 Subject: [PATCH 007/209] SrcDumper: fix improper export dump Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICCZ1A Description: Fixed SrcDump for export statement Signed-off-by: nadolskyanton --- .../ir/module/importNamespaceSpecifier.cpp | 4 +- .../srcdumper/srcdumper-ets-ignored.txt | 159 ++---------------- 2 files changed, 20 insertions(+), 143 deletions(-) diff --git a/ets2panda/ir/module/importNamespaceSpecifier.cpp b/ets2panda/ir/module/importNamespaceSpecifier.cpp index 5519952e54..4425928858 100644 --- a/ets2panda/ir/module/importNamespaceSpecifier.cpp +++ b/ets2panda/ir/module/importNamespaceSpecifier.cpp @@ -43,7 +43,9 @@ void ImportNamespaceSpecifier::Dump(ir::AstDumper *dumper) const void ImportNamespaceSpecifier::Dump(ir::SrcDumper *dumper) const { dumper->Add("* "); - dumper->Add("as "); + if (!local_->Name().Empty()) { + dumper->Add("as "); + } local_->Dump(dumper); } diff --git a/ets2panda/test/test-lists/srcdumper/srcdumper-ets-ignored.txt b/ets2panda/test/test-lists/srcdumper/srcdumper-ets-ignored.txt index 218f408204..41eeda0c92 100644 --- a/ets2panda/test/test-lists/srcdumper/srcdumper-ets-ignored.txt +++ b/ets2panda/test/test-lists/srcdumper/srcdumper-ets-ignored.txt @@ -7,160 +7,35 @@ parser/ets/string_template_3.ets parser/ets/string_template_4.ets # FailKind.SRC_DUMPER_FAIL (Issue #20458) -runtime/ets/annotation_tests/AnnotationForDifferentTypes.ets -runtime/ets/annotation_tests/AnnotationForTypesInDifferentCase.ets -ast/compiler/ets/async_import_1.ets -ast/compiler/ets/optionalClassProperty1.ets -ast/compiler/ets/ambient_interface/use_interface.ets -ast/parser/ets/import_tests/enum/import.ets +ast/compiler/ets/namespace_tests/Import_ambient_namespace.ets +ast/compiler/ets/namespace_tests/declare_namespace.ets ast/parser/ets/import_tests/export_and_import_class.ets ast/parser/ets/import_tests/export_and_import_top_level.ets -ast/parser/ets/re_export/import_11.ets -ast/parser/ets/re_export/import_12.ets -ast/parser/ets/re_export/export_5.ets -ast/parser/ets/re_export/export_6.ets -ast/parser/ets/re_export/re_export_11.ets -ast/parser/ets/re_export/re_export_12.ets -ast/parser/ets/re_export/re_export_5.ets -ast/parser/ets/re_export/re_export_7.ets -ast/parser/ets/record_lower_phase_external_main.ets -ast/parser/ets/unresolved_reference_argname_main.ets -compiler/ets/abstractNewClassInstanceExpression.ets -runtime/ets/implicit_package_import_1.ets -runtime/ets/implicit_package_import_2.ets -compiler/ets/implicit_package_import/package_test_1/package_module_1.ets -compiler/ets/implicit_package_import/package_test_1/package_module_2.ets -compiler/ets/implicit_package_import/package_test_2/subpackage_1/package_module_1.ets -compiler/ets/implicit_package_import/package_test_2/subpackage_1/package_module_2.ets -compiler/ets/import_tests/asyncfunc_lambda_main.ets -compiler/ets/import_tests/enum_import.ets -compiler/ets/import_tests/generic_typealias_func_type.ets -compiler/ets/import_tests/import_class_with_getters_setters.ets -compiler/ets/import_tests/infer_imported_function_return_type.ets -compiler/ets/import_tests/re-export_with_alias/import_aliased_re-export.ets -compiler/ets/import_tests/re-export_with_alias/re-export_with_alias.ets -compiler/ets/import_tests/selective_export_tests/import_interface.ets -compiler/ets/import_tests/selective_export_tests/import_selective_exported.ets -compiler/ets/import_tests/selective_export_tests/selective_import_with_alias_1.ets -compiler/ets/import_tests/selective_export_tests/selective_import_with_alias_2.ets -compiler/ets/import_type.ets -runtime/ets/CastPrimitive.ets -runtime/ets/ClassNewInstance.ets -runtime/ets/conditionalExpressionGenericLUB.ets -runtime/ets/dynmicImportUnimplemented.ets -runtime/ets/finallyTryAbruptedByContinue.ets -runtime/ets/funcRefWithRestArguments.ets -runtime/ets/generics_1.ets -runtime/ets/labeledStatement.ets -runtime/ets/newArrayCreationUnionType.ets -runtime/ets/type_param_in_union.ets -ast/parser/ets/re_export/import_18.ets -ast/parser/ets/re_export/import_19.ets -ast/parser/ets/re_export/import_20.ets -ast/parser/ets/re_export/re_export_13.ets -ast/parser/ets/re_export/re_export_14.ets -ast/parser/ets/re_export/re_export_15.ets -ast/parser/ets/re_export/re_export_16.ets +compiler/ets/generic_arrayaslist.ets +compiler/ets/returnTypeGenericArray.ets parser/ets/ambient_indexer_1.ets parser/ets/ambient_indexer_6.ets -parser/ets/conversions.ets -parser/ets/declare_namespace.ets -runtime/ets/namespace_tests/namespace_import_type_test/namespace_export.ets -parser/ets/declare_namespace_2.ets -parser/ets/declare_namespace_3.ets -parser/ets/declare_namespace_4.ets -ast/compiler/ets/namespace_tests/declare_namespace.ets -ast/compiler/ets/namespace_tests/Import_ambient_namespace.ets -parser/ets/import_tests/diamond/test1.ets -parser/ets/import_tests/diamond/test2.ets -parser/ets/import_tests/diamond/test3.ets -parser/ets/import_tests/duplicated/extdef.ets -parser/ets/import_tests/duplicated/extusedef.ets -parser/ets/import_tests/import_alias/import_alias_1.ets -parser/ets/import_tests/import_all_type_alias.ets -parser/ets/import_tests/import_diff_paths.ets -parser/ets/import_tests/import_extension/import_extension.ets -parser/ets/import_tests/import_function_overload.ets -parser/ets/import_tests/import_interface_test.ets -parser/ets/import_tests/import_interface_test_2.ets -parser/ets/import_tests/modules/module1/src/re_export_file.ets -parser/ets/import_tests/modules/module2/src/import_file.ets -parser/ets/import_tests/modules/module2/src/re_export_file_2.ets -parser/ets/import_tests/modules/test_lib2.ets -parser/ets/import_tests/relative_import/Line.ets -parser/ets/import_tests/relative_import/alias1.ets -parser/ets/import_tests/repeat.ets -parser/ets/import_tests/subsequent_relative_imports/folder1/file1.ets -parser/ets/import_tests/subsequent_relative_imports/folder2/file2.ets +parser/ets/array_creation_expression.ets parser/ets/labeledDoWhileStatement.ets parser/ets/labeledForStatement.ets parser/ets/labeledSwitchStatement.ets parser/ets/labeledWhileStatement.ets -parser/ets/lambda_import_alias_1-2.ets -parser/ets/lambda_import_alias_1.ets -parser/ets/promiseCasting.ets -parser/ets/re_export/diamond/B.ets -parser/ets/re_export/diamond/B2.ets -parser/ets/re_export/diamond/C.ets -parser/ets/re_export/diamond/C2.ets -parser/ets/re_export/diamond/D.ets -parser/ets/re_export/diamond/D2.ets -parser/ets/re_export/folder/re_export_6.ets -parser/ets/re_export/folder/re_export_7.ets -parser/ets/re_export/folderIndex/index.ets -parser/ets/re_export/folderIndex2/index.ets -parser/ets/re_export/import.ets -parser/ets/re_export/import_10.ets -parser/ets/re_export/import_11.ets -parser/ets/re_export/import_12.ets -parser/ets/re_export/import_13.ets -parser/ets/re_export/import_14.ets -parser/ets/re_export/import_15.ets -parser/ets/re_export/import_2.ets -parser/ets/re_export/import_3.ets -parser/ets/re_export/import_6.ets -parser/ets/re_export/import_7.ets -parser/ets/re_export/import_8.ets -parser/ets/re_export/import_9.ets -parser/ets/re_export/re_export.ets -parser/ets/re_export/re_export_10.ets -parser/ets/re_export/re_export_11.ets -parser/ets/re_export/re_export_12.ets -parser/ets/re_export/re_export_2.ets -parser/ets/re_export/re_export_3.ets -parser/ets/re_export/re_export_4.ets -parser/ets/re_export/re_export_5.ets -parser/ets/re_export/re_export_7.ets -parser/ets/re_export/re_export_8.ets -parser/ets/re_export/re_export_9.ets -parser/ets/selective_export/import_1.ets -parser/ets/selective_export/import_2.ets -parser/ets/selective_export/import_3.ets -parser/ets/selective_export/import_4.ets -parser/ets/test-type-alias-call8.ets -parser/ets/import_tests/packages/import_package_with_alias/import_package_with_alias.ets -parser/ets/re_export/import_index.ets -parser/ets/re_export/import_index_2.ets -parser/ets/re_export/import_index_3.ets -parser/ets/import_folder.ets -parser/ets/import_tests/import_relative_path.ets -runtime/ets/Multiline_string_escape_char.ets +runtime/ets/ClassNewInstance.ets runtime/ets/Multiline_string.ets +runtime/ets/Multiline_string_escape_char.ets +runtime/ets/finallyTryAbruptedByContinue.ets runtime/ets/generic-set.ets -compiler/ets/generic_arrayaslist.ets -compiler/ets/returnTypeGenericArray.ets -parser/ets/array_creation_expression.ets -runtime/ets/re_export/export/reexport_elements1.ets -runtime/ets/re_export/export/reexport_elements2.ets -runtime/ets/re_export/import.ets -ast/compiler/ets/package_initializer_warning/P3/P3.ets -ast/compiler/ets/package_initializer_warning/main_test.ets -runtime/ets/import_declare_type_alias.ets -ast/compiler/ets/import_type_without_export.ets -ast/compiler/ets/type_binding_01.ets -ast/compiler/ets/type_binding_02.ets +runtime/ets/generics_1.ets +runtime/ets/labeledStatement.ets +runtime/ets/namespace_tests/namespace_import_type_test/namespace_export.ets +runtime/ets/newArrayCreationUnionType.ets + # FailKind.ES2PANDA_FAIL +compiler/ets/abstractNewClassInstanceExpression.ets +runtime/ets/conditionalExpressionGenericLUB.ets +runtime/ets/funcRefWithRestArguments.ets +runtime/ets/type_param_in_union.ets runtime/ets/StringFasta.ets runtime/ets/struct-identifier.ets runtime/ets/struct-init2.ets -- Gitee From 2c8ac346703921a7d60060f8e3a58e9dbdc2e114 Mon Sep 17 00:00:00 2001 From: lijincheng Date: Thu, 5 Jun 2025 12:25:20 +0800 Subject: [PATCH 008/209] Bugfix for json annotation 1. move Setannotation outside Issue:https://gitee.com/openharmony/arkcompiler_runtime_core/issues/ICAATS Signed-off-by: lijincheng --- ets2panda/compiler/core/ETSemitter.cpp | 5 ++++- .../test/runtime/ets/AnnotationOfClassPropertyInherit.ets | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ets2panda/compiler/core/ETSemitter.cpp b/ets2panda/compiler/core/ETSemitter.cpp index 8f0b822ef9..eee0620420 100644 --- a/ets2panda/compiler/core/ETSemitter.cpp +++ b/ets2panda/compiler/core/ETSemitter.cpp @@ -437,11 +437,14 @@ void ETSEmitter::GenClassField(const ir::ClassProperty *prop, pandasm::Record &c field.type = PandasmTypeWithRank(prop->TsType()); field.metadata->SetAccessFlags(TranslateModifierFlags(prop->Modifiers())); + if (!external) { + field.metadata->SetAnnotations(GenCustomAnnotations(prop->Annotations(), field.name)); + } + if (external || prop->IsDeclare()) { field.metadata->SetAttribute(Signatures::EXTERNAL); } else if (prop->TsType()->IsETSPrimitiveType() || prop->TsType()->IsETSStringType()) { EmitDefaultFieldValue(field, prop->Value()); - field.metadata->SetAnnotations(GenCustomAnnotations(prop->Annotations(), field.name)); } classRecord.fieldList.emplace_back(std::move(field)); diff --git a/ets2panda/test/runtime/ets/AnnotationOfClassPropertyInherit.ets b/ets2panda/test/runtime/ets/AnnotationOfClassPropertyInherit.ets index f7f39edabb..1a10d2134b 100644 --- a/ets2panda/test/runtime/ets/AnnotationOfClassPropertyInherit.ets +++ b/ets2panda/test/runtime/ets/AnnotationOfClassPropertyInherit.ets @@ -13,12 +13,12 @@ * limitations under the License. */ -@interface JSONRename { +@interface JSONRenameTest { name:string = "" } class A { - @JSONRename("ID") + @JSONRenameTest("ID") name2: string = "" pwd2: string = "" } -- Gitee From 1de9a4b96ad00b663a7068918e7fd78f715b6010 Mon Sep 17 00:00:00 2001 From: zmw Date: Sat, 7 Jun 2025 14:53:23 +0800 Subject: [PATCH 009/209] Fix assert string to bool Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICDBZ7 Description: Fix assert string to bool Signed-off-by: zmw --- ets2panda/lsp/src/code_fix_provider.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ets2panda/lsp/src/code_fix_provider.cpp b/ets2panda/lsp/src/code_fix_provider.cpp index 1843912767..0aacb84467 100644 --- a/ets2panda/lsp/src/code_fix_provider.cpp +++ b/ets2panda/lsp/src/code_fix_provider.cpp @@ -28,9 +28,8 @@ namespace ark::es2panda::lsp { void CodeFixProvider::RegisterCodeFix(const std::string &aliasName, std::unique_ptr registration) { - if (aliasName.empty()) { - ASSERT("Alias name cannot be empty"); - } + (void)aliasName; + ASSERT(!aliasName.empty()); auto shared = std::shared_ptr(std::move(registration)); for (auto error : shared->GetErrorCodes()) { -- Gitee From 0d63d8a670698d48228b72db4fac58cdef91c187 Mon Sep 17 00:00:00 2001 From: sniperc96 Date: Sat, 7 Jun 2025 17:55:29 +0800 Subject: [PATCH 010/209] fix bug:arkui-no-bidirectional-data-binding Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICDDJO Signed-off-by: sniperc96 --- ets2panda/linter/src/lib/TypeScriptLinter.ts | 46 ++--- .../test/main/double_excla_binding_3.ets | 32 ++++ .../main/double_excla_binding_3.ets.args.json | 21 +++ .../double_excla_binding_3.ets.arkts2.json | 88 ++++++++++ .../double_excla_binding_3.ets.autofix.json | 165 ++++++++++++++++++ .../test/main/double_excla_binding_3.ets.json | 17 ++ .../double_excla_binding_3.ets.migrate.ets | 34 ++++ .../double_excla_binding_3.ets.migrate.json | 17 ++ 8 files changed, 400 insertions(+), 20 deletions(-) create mode 100644 ets2panda/linter/test/main/double_excla_binding_3.ets create mode 100644 ets2panda/linter/test/main/double_excla_binding_3.ets.args.json create mode 100644 ets2panda/linter/test/main/double_excla_binding_3.ets.arkts2.json create mode 100644 ets2panda/linter/test/main/double_excla_binding_3.ets.autofix.json create mode 100644 ets2panda/linter/test/main/double_excla_binding_3.ets.json create mode 100644 ets2panda/linter/test/main/double_excla_binding_3.ets.migrate.ets create mode 100644 ets2panda/linter/test/main/double_excla_binding_3.ets.migrate.json diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index ec2c5e4463..19ff79d1f8 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -6576,6 +6576,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { !ts.isNonNullExpression(node) || !ts.isNonNullExpression(node.expression) || ts.isNonNullExpression(node.parent) || + ts.isPropertyAccessExpression(node.parent) || ts.isNonNullExpression(node.expression.expression) ) { return; @@ -6583,26 +6584,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const statement = ts.findAncestor(node, ts.isExpressionStatement); if (statement && this.isCustomComponent(statement)) { - let currentParam: ts.Identifier | undefined; - if (ts.isPropertyAccessExpression(node.expression.expression)) { - currentParam = node.expression.expression.name as ts.Identifier; - } - - let customParam: ts.Identifier | undefined; - if (ts.isPropertyAssignment(node.parent)) { - customParam = node.parent.name as ts.Identifier; - } - - if (!currentParam || !customParam) { - return; - } - - const originalExpr = node.parent.parent; - if (!ts.isObjectLiteralExpression(originalExpr)) { - return; - } - const autofix = this.autofixer?.fixCustomBidirectionalBinding(originalExpr, currentParam, customParam); - this.incrementCounters(node, FaultID.DoubleExclaBindingNotSupported, autofix); + this.handleCustomBidirectionalBinding(node, node.expression); } else { const autofix = this.autofixer?.fixNativeBidirectionalBinding(node, this.interfacesNeedToImport); this.incrementCounters(node, FaultID.DoubleExclaBindingNotSupported, autofix); @@ -6631,6 +6613,30 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return this.interfacesAlreadyImported.has(callExpr.expression.getText()); } + private handleCustomBidirectionalBinding(firstExpr: ts.NonNullExpression, secondExpr: ts.NonNullExpression): void { + let currentParam: ts.Identifier | undefined; + if (ts.isPropertyAccessExpression(secondExpr.expression)) { + currentParam = secondExpr.expression.name as ts.Identifier; + } + + let customParam: ts.Identifier | undefined; + if (ts.isPropertyAssignment(firstExpr.parent)) { + customParam = firstExpr.parent.name as ts.Identifier; + } + + if (!currentParam || !customParam) { + return; + } + + const originalExpr = firstExpr.parent.parent; + if (!ts.isObjectLiteralExpression(originalExpr)) { + return; + } + + const autofix = this.autofixer?.fixCustomBidirectionalBinding(originalExpr, currentParam, customParam); + this.incrementCounters(firstExpr, FaultID.DoubleExclaBindingNotSupported, autofix); + } + private handleDoubleDollar(node: ts.Node): void { if (!this.options.arkts2) { return; diff --git a/ets2panda/linter/test/main/double_excla_binding_3.ets b/ets2panda/linter/test/main/double_excla_binding_3.ets new file mode 100644 index 0000000000..8c9dcc1e87 --- /dev/null +++ b/ets2panda/linter/test/main/double_excla_binding_3.ets @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 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 User { + name: string = "Jack" +} + +@Entry +@Component +struct MyComponent { + @State user: User = new User() + + build() { + Row() { + Text(this.user!.name) + Text(this.user!!.name) + Text(this.user!!!.name) + } + } +} \ No newline at end of file diff --git a/ets2panda/linter/test/main/double_excla_binding_3.ets.args.json b/ets2panda/linter/test/main/double_excla_binding_3.ets.args.json new file mode 100644 index 0000000000..30973c00a2 --- /dev/null +++ b/ets2panda/linter/test/main/double_excla_binding_3.ets.args.json @@ -0,0 +1,21 @@ +{ + "copyright": [ + "Copyright (c) 2025 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." + ], + "mode": { + "arkts2": "", + "autofix": "--arkts-2", + "migrate": "--arkts-2" + } +} \ No newline at end of file diff --git a/ets2panda/linter/test/main/double_excla_binding_3.ets.arkts2.json b/ets2panda/linter/test/main/double_excla_binding_3.ets.arkts2.json new file mode 100644 index 0000000000..592f7eb23d --- /dev/null +++ b/ets2panda/linter/test/main/double_excla_binding_3.ets.arkts2.json @@ -0,0 +1,88 @@ +{ + "copyright": [ + "Copyright (c) 2025 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." + ], + "result": [ + { + "line": 20, + "column": 2, + "endLine": 20, + "endColumn": 7, + "problem": "UIInterfaceImport", + "suggest": "", + "rule": "ArkUI interface should be imported before using (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 21, + "column": 2, + "endLine": 21, + "endColumn": 11, + "problem": "UIInterfaceImport", + "suggest": "", + "rule": "ArkUI interface should be imported before using (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 23, + "column": 4, + "endLine": 23, + "endColumn": 9, + "problem": "UIInterfaceImport", + "suggest": "", + "rule": "ArkUI interface should be imported before using (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 26, + "column": 5, + "endLine": 26, + "endColumn": 8, + "problem": "UIInterfaceImport", + "suggest": "", + "rule": "ArkUI interface should be imported before using (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 27, + "column": 7, + "endLine": 27, + "endColumn": 11, + "problem": "UIInterfaceImport", + "suggest": "", + "rule": "ArkUI interface should be imported before using (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 28, + "column": 7, + "endLine": 28, + "endColumn": 11, + "problem": "UIInterfaceImport", + "suggest": "", + "rule": "ArkUI interface should be imported before using (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 29, + "column": 7, + "endLine": 29, + "endColumn": 11, + "problem": "UIInterfaceImport", + "suggest": "", + "rule": "ArkUI interface should be imported before using (arkui-modular-interface)", + "severity": "ERROR" + } + ] +} \ No newline at end of file diff --git a/ets2panda/linter/test/main/double_excla_binding_3.ets.autofix.json b/ets2panda/linter/test/main/double_excla_binding_3.ets.autofix.json new file mode 100644 index 0000000000..31a6345741 --- /dev/null +++ b/ets2panda/linter/test/main/double_excla_binding_3.ets.autofix.json @@ -0,0 +1,165 @@ +{ + "copyright": [ + "Copyright (c) 2025 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." + ], + "result": [ + { + "line": 20, + "column": 2, + "endLine": 20, + "endColumn": 7, + "problem": "UIInterfaceImport", + "autofix": [ + { + "start": 603, + "end": 603, + "replacementText": "\n\nimport { Entry, Component, State, Row, Text } from '@kit.ArkUI';", + "line": 29, + "column": 7, + "endLine": 29, + "endColumn": 11 + } + ], + "suggest": "", + "rule": "ArkUI interface should be imported before using (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 21, + "column": 2, + "endLine": 21, + "endColumn": 11, + "problem": "UIInterfaceImport", + "autofix": [ + { + "start": 603, + "end": 603, + "replacementText": "\n\nimport { Entry, Component, State, Row, Text } from '@kit.ArkUI';", + "line": 29, + "column": 7, + "endLine": 29, + "endColumn": 11 + } + ], + "suggest": "", + "rule": "ArkUI interface should be imported before using (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 23, + "column": 4, + "endLine": 23, + "endColumn": 9, + "problem": "UIInterfaceImport", + "autofix": [ + { + "start": 603, + "end": 603, + "replacementText": "\n\nimport { Entry, Component, State, Row, Text } from '@kit.ArkUI';", + "line": 29, + "column": 7, + "endLine": 29, + "endColumn": 11 + } + ], + "suggest": "", + "rule": "ArkUI interface should be imported before using (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 26, + "column": 5, + "endLine": 26, + "endColumn": 8, + "problem": "UIInterfaceImport", + "autofix": [ + { + "start": 603, + "end": 603, + "replacementText": "\n\nimport { Entry, Component, State, Row, Text } from '@kit.ArkUI';", + "line": 29, + "column": 7, + "endLine": 29, + "endColumn": 11 + } + ], + "suggest": "", + "rule": "ArkUI interface should be imported before using (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 27, + "column": 7, + "endLine": 27, + "endColumn": 11, + "problem": "UIInterfaceImport", + "autofix": [ + { + "start": 603, + "end": 603, + "replacementText": "\n\nimport { Entry, Component, State, Row, Text } from '@kit.ArkUI';", + "line": 29, + "column": 7, + "endLine": 29, + "endColumn": 11 + } + ], + "suggest": "", + "rule": "ArkUI interface should be imported before using (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 28, + "column": 7, + "endLine": 28, + "endColumn": 11, + "problem": "UIInterfaceImport", + "autofix": [ + { + "start": 603, + "end": 603, + "replacementText": "\n\nimport { Entry, Component, State, Row, Text } from '@kit.ArkUI';", + "line": 29, + "column": 7, + "endLine": 29, + "endColumn": 11 + } + ], + "suggest": "", + "rule": "ArkUI interface should be imported before using (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 29, + "column": 7, + "endLine": 29, + "endColumn": 11, + "problem": "UIInterfaceImport", + "autofix": [ + { + "start": 603, + "end": 603, + "replacementText": "\n\nimport { Entry, Component, State, Row, Text } from '@kit.ArkUI';", + "line": 29, + "column": 7, + "endLine": 29, + "endColumn": 11 + } + ], + "suggest": "", + "rule": "ArkUI interface should be imported before using (arkui-modular-interface)", + "severity": "ERROR" + } + ] +} \ No newline at end of file diff --git a/ets2panda/linter/test/main/double_excla_binding_3.ets.json b/ets2panda/linter/test/main/double_excla_binding_3.ets.json new file mode 100644 index 0000000000..b7a8809e02 --- /dev/null +++ b/ets2panda/linter/test/main/double_excla_binding_3.ets.json @@ -0,0 +1,17 @@ +{ + "copyright": [ + "Copyright (c) 2025 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." + ], + "result": [] +} \ No newline at end of file diff --git a/ets2panda/linter/test/main/double_excla_binding_3.ets.migrate.ets b/ets2panda/linter/test/main/double_excla_binding_3.ets.migrate.ets new file mode 100644 index 0000000000..b646a64c49 --- /dev/null +++ b/ets2panda/linter/test/main/double_excla_binding_3.ets.migrate.ets @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 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. + */ + +import { Entry, Component, State, Row, Text } from '@kit.ArkUI'; + +class User { + name: string = "Jack" +} + +@Entry +@Component +struct MyComponent { + @State user: User = new User() + + build() { + Row() { + Text(this.user!.name) + Text(this.user!!.name) + Text(this.user!!!.name) + } + } +} \ No newline at end of file diff --git a/ets2panda/linter/test/main/double_excla_binding_3.ets.migrate.json b/ets2panda/linter/test/main/double_excla_binding_3.ets.migrate.json new file mode 100644 index 0000000000..b7a8809e02 --- /dev/null +++ b/ets2panda/linter/test/main/double_excla_binding_3.ets.migrate.json @@ -0,0 +1,17 @@ +{ + "copyright": [ + "Copyright (c) 2025 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." + ], + "result": [] +} \ No newline at end of file -- Gitee From 047b3e55465c4f92564b9365282d925b8e1ccc83 Mon Sep 17 00:00:00 2001 From: lijunru Date: Mon, 9 Jun 2025 15:06:18 +0800 Subject: [PATCH 011/209] Fix might be unused parameter Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICDOG3 Signed-off-by: lijunru --- ets2panda/lsp/src/isolated_declaration.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ets2panda/lsp/src/isolated_declaration.cpp b/ets2panda/lsp/src/isolated_declaration.cpp index 621b219c41..d4df74d45d 100644 --- a/ets2panda/lsp/src/isolated_declaration.cpp +++ b/ets2panda/lsp/src/isolated_declaration.cpp @@ -49,7 +49,8 @@ std::optional GenUnionType(const checker::ETSUnionType *unionType, const char splitChar); template -std::vector FilterUnionTypes(const ArenaVector &originTypes, checker::ETSChecker *checker) +std::vector FilterUnionTypes(const ArenaVector &originTypes, + [[maybe_unused]] checker::ETSChecker *checker) { if (originTypes.empty()) { return {}; -- Gitee From 8a700433472e560fa889a9ab6e2e1a67a5de31f8 Mon Sep 17 00:00:00 2001 From: zhongning5 Date: Thu, 5 Jun 2025 13:47:38 +0800 Subject: [PATCH 012/209] fix arkts-unsupport-prop-name-from-value Issue:https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICCLTN Test scenarios:Fix bugs for fix arkts-unsupport-prop-name-from-value Signed-off-by: zhongning5 --- ets2panda/linter/src/lib/TypeScriptLinter.ts | 18 +++-- .../test/main/class_as_object.ets.arkts2.json | 20 ++++++ .../literals_as_prop_names.ets.arkts2.json | 50 +++++++++++++ .../literals_as_prop_names.ets.autofix.json | 50 +++++++++++++ .../literals_as_prop_names.ets.migrate.json | 10 +++ .../linter/test/main/prop_name_from_value.ets | 31 +++++++- .../main/prop_name_from_value.ets.arkts2.json | 70 +++++++++++++++++++ .../property_access_by_index.ets.arkts2.json | 30 ++++++++ 8 files changed, 271 insertions(+), 8 deletions(-) diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index e2ebe7badf..fb5a2c8428 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -8928,22 +8928,30 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return; } - if (!ts.isIdentifier(node.expression) || !ts.isNumericLiteral(node.argumentExpression)) { - return; - } - const symbol = this.tsUtils.trueSymbolAtLocation(node.expression); if (!symbol?.declarations) { return; } for (const decl of symbol.declarations) { - if (ts.isEnumDeclaration(decl)) { + if (ts.isEnumDeclaration(decl) && this.shouldIncrementCounters(node)) { this.incrementCounters(node, FaultID.UnsupportPropNameFromValue); return; } } } + private shouldIncrementCounters(node: ts.ElementAccessExpression): boolean { + const indexExpr = node.argumentExpression; + if (!indexExpr) { + return false; + } + if (ts.isStringLiteral(indexExpr) || ts.isNumericLiteral(indexExpr)) { + return true; + } + const type = this.tsTypeChecker.getTypeAtLocation(indexExpr); + const typeString = this.tsTypeChecker.typeToString(type); + return typeString === 'number' || typeString === 'string'; + } private handleMakeObserved(node: ts.PropertyAccessExpression): void { if (!this.options.arkts2) { diff --git a/ets2panda/linter/test/main/class_as_object.ets.arkts2.json b/ets2panda/linter/test/main/class_as_object.ets.arkts2.json index 3bf41adaeb..40f9e25a11 100644 --- a/ets2panda/linter/test/main/class_as_object.ets.arkts2.json +++ b/ets2panda/linter/test/main/class_as_object.ets.arkts2.json @@ -334,6 +334,26 @@ "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", "severity": "ERROR" }, + { + "line": 102, + "column": 13, + "endLine": 102, + "endColumn": 23, + "problem": "UnsupportPropNameFromValue", + "suggest": "", + "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", + "severity": "ERROR" + }, + { + "line": 114, + "column": 18, + "endLine": 114, + "endColumn": 25, + "problem": "UnsupportPropNameFromValue", + "suggest": "", + "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", + "severity": "ERROR" + }, { "line": 116, "column": 10, diff --git a/ets2panda/linter/test/main/literals_as_prop_names.ets.arkts2.json b/ets2panda/linter/test/main/literals_as_prop_names.ets.arkts2.json index 0293db338b..79102a9b70 100755 --- a/ets2panda/linter/test/main/literals_as_prop_names.ets.arkts2.json +++ b/ets2panda/linter/test/main/literals_as_prop_names.ets.arkts2.json @@ -304,6 +304,26 @@ "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" }, + { + "line": 86, + "column": 1, + "endLine": 86, + "endColumn": 33, + "problem": "UnsupportPropNameFromValue", + "suggest": "", + "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", + "severity": "ERROR" + }, + { + "line": 88, + "column": 1, + "endLine": 88, + "endColumn": 40, + "problem": "UnsupportPropNameFromValue", + "suggest": "", + "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", + "severity": "ERROR" + }, { "line": 92, "column": 4, @@ -364,6 +384,16 @@ "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" }, + { + "line": 105, + "column": 14, + "endLine": 105, + "endColumn": 31, + "problem": "UnsupportPropNameFromValue", + "suggest": "", + "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", + "severity": "ERROR" + }, { "line": 106, "column": 5, @@ -374,6 +404,16 @@ "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" }, + { + "line": 106, + "column": 15, + "endLine": 106, + "endColumn": 35, + "problem": "UnsupportPropNameFromValue", + "suggest": "", + "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", + "severity": "ERROR" + }, { "line": 109, "column": 1, @@ -394,6 +434,16 @@ "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", "severity": "ERROR" }, + { + "line": 118, + "column": 18, + "endLine": 118, + "endColumn": 35, + "problem": "UnsupportPropNameFromValue", + "suggest": "", + "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", + "severity": "ERROR" + }, { "line": 125, "column": 22, diff --git a/ets2panda/linter/test/main/literals_as_prop_names.ets.autofix.json b/ets2panda/linter/test/main/literals_as_prop_names.ets.autofix.json index 4c937491cd..82e0ac288a 100644 --- a/ets2panda/linter/test/main/literals_as_prop_names.ets.autofix.json +++ b/ets2panda/linter/test/main/literals_as_prop_names.ets.autofix.json @@ -697,6 +697,26 @@ "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" }, + { + "line": 86, + "column": 1, + "endLine": 86, + "endColumn": 33, + "problem": "UnsupportPropNameFromValue", + "suggest": "", + "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", + "severity": "ERROR" + }, + { + "line": 88, + "column": 1, + "endLine": 88, + "endColumn": 40, + "problem": "UnsupportPropNameFromValue", + "suggest": "", + "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", + "severity": "ERROR" + }, { "line": 92, "column": 4, @@ -841,6 +861,16 @@ "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" }, + { + "line": 105, + "column": 14, + "endLine": 105, + "endColumn": 31, + "problem": "UnsupportPropNameFromValue", + "suggest": "", + "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", + "severity": "ERROR" + }, { "line": 106, "column": 5, @@ -862,6 +892,16 @@ "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" }, + { + "line": 106, + "column": 15, + "endLine": 106, + "endColumn": 35, + "problem": "UnsupportPropNameFromValue", + "suggest": "", + "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", + "severity": "ERROR" + }, { "line": 109, "column": 1, @@ -913,6 +953,16 @@ "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", "severity": "ERROR" }, + { + "line": 118, + "column": 18, + "endLine": 118, + "endColumn": 35, + "problem": "UnsupportPropNameFromValue", + "suggest": "", + "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", + "severity": "ERROR" + }, { "line": 125, "column": 22, diff --git a/ets2panda/linter/test/main/literals_as_prop_names.ets.migrate.json b/ets2panda/linter/test/main/literals_as_prop_names.ets.migrate.json index 112cbe6bb0..97c0791cc5 100644 --- a/ets2panda/linter/test/main/literals_as_prop_names.ets.migrate.json +++ b/ets2panda/linter/test/main/literals_as_prop_names.ets.migrate.json @@ -94,6 +94,16 @@ "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", "severity": "ERROR" }, + { + "line": 92, + "column": 1, + "endLine": 92, + "endColumn": 33, + "problem": "UnsupportPropNameFromValue", + "suggest": "", + "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", + "severity": "ERROR" + }, { "line": 28, "column": 11, diff --git a/ets2panda/linter/test/main/prop_name_from_value.ets b/ets2panda/linter/test/main/prop_name_from_value.ets index bdfdc1a80d..63c685415b 100644 --- a/ets2panda/linter/test/main/prop_name_from_value.ets +++ b/ets2panda/linter/test/main/prop_name_from_value.ets @@ -20,6 +20,31 @@ enum TEST { } const arr = ['a', 'b', 'c']; -const val = TEST[1]; -const value: number = TEST.A; //legal -const arrVal = arr[1]; //legal \ No newline at end of file +const val = TEST[1]; //error +const value: number = TEST.A; +const arrVal = arr[1]; +let a = 1; +let b = 2.3; +let c = "str"; +let d3 = TEST[TEST.A]; +let d4 = TEST[a]; //error +let d5 = TEST[b]; //error +let d2 = TEST['A']; //error +enum E { A, B, C } +console.log(E[E.A]); +function foo(e: E) { + console.log(E[e]); +} +foo(E.B); +console.log(E[2 as E]); +enum Color { Red, Green = 10, Blue } +enum E1 { One = 1, one = 1, oNe = 1 } +console.log(E1[1 as E1]) +let c1: Color = Color.Green; +console.log(c1.toString()) +console.log(Color[c1]); +enum G { + A = 1, + B = 2 +} +console.log(G[G.A]); \ No newline at end of file diff --git a/ets2panda/linter/test/main/prop_name_from_value.ets.arkts2.json b/ets2panda/linter/test/main/prop_name_from_value.ets.arkts2.json index 62d4d681bf..8cd1ddc908 100644 --- a/ets2panda/linter/test/main/prop_name_from_value.ets.arkts2.json +++ b/ets2panda/linter/test/main/prop_name_from_value.ets.arkts2.json @@ -33,6 +33,76 @@ "suggest": "", "rule": "Array bound not checked. (arkts-runtime-array-check)", "severity": "ERROR" + }, + { + "line": 26, + "column": 5, + "endLine": 26, + "endColumn": 10, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 26, + "column": 9, + "endLine": 26, + "endColumn": 10, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 27, + "column": 5, + "endLine": 27, + "endColumn": 12, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 30, + "column": 10, + "endLine": 30, + "endColumn": 17, + "problem": "UnsupportPropNameFromValue", + "suggest": "", + "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", + "severity": "ERROR" + }, + { + "line": 31, + "column": 10, + "endLine": 31, + "endColumn": 17, + "problem": "UnsupportPropNameFromValue", + "suggest": "", + "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", + "severity": "ERROR" + }, + { + "line": 32, + "column": 5, + "endLine": 32, + "endColumn": 19, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 32, + "column": 10, + "endLine": 32, + "endColumn": 19, + "problem": "UnsupportPropNameFromValue", + "suggest": "", + "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", + "severity": "ERROR" } ] } \ No newline at end of file diff --git a/ets2panda/linter/test/main/property_access_by_index.ets.arkts2.json b/ets2panda/linter/test/main/property_access_by_index.ets.arkts2.json index eaf2af73c9..2a1abb3490 100644 --- a/ets2panda/linter/test/main/property_access_by_index.ets.arkts2.json +++ b/ets2panda/linter/test/main/property_access_by_index.ets.arkts2.json @@ -684,6 +684,36 @@ "rule": "Array bound not checked. (arkts-runtime-array-check)", "severity": "ERROR" }, + { + "line": 97, + "column": 1, + "endLine": 97, + "endColumn": 18, + "problem": "UnsupportPropNameFromValue", + "suggest": "", + "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", + "severity": "ERROR" + }, + { + "line": 98, + "column": 1, + "endLine": 98, + "endColumn": 17, + "problem": "UnsupportPropNameFromValue", + "suggest": "", + "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", + "severity": "ERROR" + }, + { + "line": 99, + "column": 1, + "endLine": 99, + "endColumn": 17, + "problem": "UnsupportPropNameFromValue", + "suggest": "", + "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", + "severity": "ERROR" + }, { "line": 105, "column": 31, -- Gitee From e759a08e780e22fef985c8aa57f34370bccb31be Mon Sep 17 00:00:00 2001 From: xudan16 Date: Sun, 8 Jun 2025 10:47:31 +0800 Subject: [PATCH 013/209] sync homecheck to fix some issues Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICDFCK Signed-off-by: xudan16 --- ets2panda/linter/arkanalyzer/OAT.xml | 1 + ets2panda/linter/arkanalyzer/src/Config.ts | 1 + ets2panda/linter/arkanalyzer/src/Scene.ts | 31 ++- .../callgraph/algorithm/AbstractAnalysis.ts | 19 +- .../algorithm/ClassHierarchyAnalysis.ts | 7 +- .../callgraph/algorithm/RapidTypeAnalysis.ts | 3 +- .../src/callgraph/common/Statistics.ts | 5 +- .../src/callgraph/model/CallGraph.ts | 66 +----- .../src/callgraph/model/CallSite.ts | 64 ++++++ .../model/builder/CallGraphBuilder.ts | 21 +- .../src/callgraph/pointerAnalysis/PTAUtils.ts | 1 + .../callgraph/pointerAnalysis/PagBuilder.ts | 38 ++-- .../pointerAnalysis/PointerAnalysis.ts | 3 +- .../pointerAnalysis/PointerAnalysisConfig.ts | 9 + .../linter/arkanalyzer/src/core/base/Expr.ts | 39 +++- .../linter/arkanalyzer/src/core/base/Local.ts | 10 +- .../src/core/common/ArkIRTransformer.ts | 9 - .../src/core/common/IRInference.ts | 22 +- .../arkanalyzer/src/core/common/ModelUtils.ts | 24 +-- .../arkanalyzer/src/core/common/SdkUtils.ts | 40 ++-- .../src/core/common/TypeInference.ts | 55 +++-- .../arkanalyzer/src/core/common/ValueUtil.ts | 8 + .../src/core/dataflow/DataflowSolver.ts | 3 +- .../src/core/graph/builder/CfgBuilder.ts | 3 + .../src/core/graph/builder/TrapBuilder.ts | 47 +++-- .../arkanalyzer/src/core/model/ArkImport.ts | 2 +- .../arkanalyzer/src/core/model/ArkMethod.ts | 82 +++++--- .../src/core/model/builder/ArkClassBuilder.ts | 16 +- .../src/core/model/builder/ArkFieldBuilder.ts | 4 +- .../src/core/model/builder/ArkFileBuilder.ts | 4 +- .../core/model/builder/ArkMethodBuilder.ts | 11 +- .../core/model/builder/ArkNamespaceBuilder.ts | 8 +- .../src/core/model/builder/BodyBuilder.ts | 2 + .../arkanalyzer/src/save/JsonPrinter.ts | 104 +++++++--- .../arkanalyzer/src/utils/SparseBitVector.ts | 1 - ets2panda/linter/arkanalyzer/typedoc.json | 1 + ets2panda/linter/homecheck/src/Index.ts | 2 +- .../checker/migration/AppStorageGetCheck.ts | 2 +- .../checker/migration/CustomBuilderCheck.ts | 4 +- .../checker/migration/InteropAssignCheck.ts | 6 +- .../migration/InteropBackwardDFACheck.ts | 2 +- .../migration/InteropBoxedTypeCheck.ts | 2 +- .../migration/InteropJSModifyPropertyCheck.ts | 6 +- .../checker/migration/ModifyStateVarCheck.ts | 2 +- .../src/checker/migration/NoTSLikeAsCheck.ts | 196 +++++++++--------- .../checker/migration/ObjectLiteralCheck.ts | 7 +- .../migration/ObservedDecoratorCheck.ts | 6 +- .../src/checker/migration/ThisBindCheck.ts | 2 +- .../homecheck/src/checker/migration/Utils.ts | 33 ++- .../src/tools/migrationTool/MigrationTool.ts | 12 +- .../src/utils/common/CheckerStorage.ts | 5 + .../homecheck/src/utils/common/FileUtils.ts | 4 +- ets2panda/linter/src/cli/LinterCLI.ts | 3 +- 53 files changed, 661 insertions(+), 397 deletions(-) create mode 100644 ets2panda/linter/arkanalyzer/src/callgraph/model/CallSite.ts diff --git a/ets2panda/linter/arkanalyzer/OAT.xml b/ets2panda/linter/arkanalyzer/OAT.xml index 6420939360..a33eba98c9 100644 --- a/ets2panda/linter/arkanalyzer/OAT.xml +++ b/ets2panda/linter/arkanalyzer/OAT.xml @@ -19,6 +19,7 @@ + diff --git a/ets2panda/linter/arkanalyzer/src/Config.ts b/ets2panda/linter/arkanalyzer/src/Config.ts index bff8ddf474..1a222ff665 100644 --- a/ets2panda/linter/arkanalyzer/src/Config.ts +++ b/ets2panda/linter/arkanalyzer/src/Config.ts @@ -86,6 +86,7 @@ export class SceneConfig { public buildConfig(targetProjectName: string, targetProjectDirectory: string, sdks: Sdk[], fullFilePath?: string[]): void { this.targetProjectName = targetProjectName; this.targetProjectDirectory = targetProjectDirectory; + this.projectFiles = getAllFiles(targetProjectDirectory, this.options.supportFileExts!, this.options.ignoreFileNames); this.sdksObj = sdks; if (fullFilePath) { this.projectFiles.push(...fullFilePath); diff --git a/ets2panda/linter/arkanalyzer/src/Scene.ts b/ets2panda/linter/arkanalyzer/src/Scene.ts index 72c7828226..84ef44b99a 100644 --- a/ets2panda/linter/arkanalyzer/src/Scene.ts +++ b/ets2panda/linter/arkanalyzer/src/Scene.ts @@ -41,6 +41,8 @@ import { ImportInfo } from './core/model/ArkImport'; import { ALL, CONSTRUCTOR_NAME, TSCONFIG_JSON } from './core/common/TSConst'; import { BUILD_PROFILE_JSON5, OH_PACKAGE_JSON5 } from './core/common/EtsConst'; import { SdkUtils } from './core/common/SdkUtils'; +import { PointerAnalysisConfig } from './callgraph/pointerAnalysis/PointerAnalysisConfig'; +import { ValueUtil } from './core/common/ValueUtil'; const logger = Logger.getLogger(LOG_MODULE_TYPE.ARKANALYZER, 'Scene'); @@ -99,6 +101,17 @@ export class Scene { constructor() {} + /* + * Set all static field to be null, then all related objects could be freed by GC. + * This method could be called before drop Scene. + */ + public dispose(): void { + PointerAnalysisConfig.dispose(); + SdkUtils.dispose(); + ValueUtil.dispose(); + ModelUtils.dispose(); + } + public getOptions(): SceneOptions { return this.options; } @@ -322,12 +335,13 @@ export class Scene { } } + ModelUtils.dispose(); this.buildStage = SceneBuildStage.METHOD_DONE; } private genArkFiles(): void { this.projectFiles.forEach(file => { - logger.info('=== parse file:', file); + logger.trace('=== parse file:', file); try { const arkFile: ArkFile = new ArkFile(FileUtils.getFileLanguage(file, this.fileLanguages)); arkFile.setScene(this); @@ -469,9 +483,11 @@ export class Scene { } private findDependenciesByRule(originPath: string, arkFile: ArkFile): void { - const extNameArray = ['.ets', '.ts', '.d.ets', '.d.ts', '.js']; - if (!this.findFilesByPathArray(originPath, this.indexPathArray, arkFile) && !this.findFilesByExtNameArray(originPath, extNameArray, arkFile)) { - logger.info(originPath + 'module mapperInfo is not found!'); + if ( + !this.findFilesByPathArray(originPath, this.indexPathArray, arkFile) && + !this.findFilesByExtNameArray(originPath, this.options.supportFileExts!, arkFile) + ) { + logger.trace(originPath + 'module mapperInfo is not found!'); } } @@ -542,7 +558,7 @@ export class Scene { this.addFileNode2DependencyGrap(originPath, arkFile); } if (!this.findFilesByPathArray(originPath, this.indexPathArray, arkFile)) { - logger.info(originPath + 'module mapperInfo is not found!'); + logger.trace(originPath + 'module mapperInfo is not found!'); } } } @@ -574,7 +590,7 @@ export class Scene { private buildSdk(sdkName: string, sdkPath: string): void { const allFiles = getAllFiles(sdkPath, this.options.supportFileExts!, this.options.ignoreFileNames); allFiles.forEach(file => { - logger.info('=== parse sdk file:', file); + logger.trace('=== parse sdk file:', file); try { const arkFile: ArkFile = new ArkFile(FileUtils.getFileLanguage(file, this.fileLanguages)); arkFile.setScene(this); @@ -1044,6 +1060,7 @@ export class Scene { this.getMethodsMap(true); this.buildStage = SceneBuildStage.TYPE_INFERRED; } + SdkUtils.dispose(); } /** @@ -1458,7 +1475,7 @@ export class ModuleScene { private genArkFiles(supportFileExts: string[]): void { getAllFiles(this.modulePath, supportFileExts, this.projectScene.getOptions().ignoreFileNames).forEach(file => { - logger.info('=== parse file:', file); + logger.trace('=== parse file:', file); try { const arkFile: ArkFile = new ArkFile(FileUtils.getFileLanguage(file, this.projectScene.getFileLanguages())); arkFile.setScene(this.projectScene); diff --git a/ets2panda/linter/arkanalyzer/src/callgraph/algorithm/AbstractAnalysis.ts b/ets2panda/linter/arkanalyzer/src/callgraph/algorithm/AbstractAnalysis.ts index 4fb8a6f7b7..9a3e7fa8e1 100644 --- a/ets2panda/linter/arkanalyzer/src/callgraph/algorithm/AbstractAnalysis.ts +++ b/ets2panda/linter/arkanalyzer/src/callgraph/algorithm/AbstractAnalysis.ts @@ -30,13 +30,14 @@ const logger = Logger.getLogger(LOG_MODULE_TYPE.ARKANALYZER, 'CG'); export abstract class AbstractAnalysis { protected scene: Scene; - protected cg!: CallGraph; + protected cg: CallGraph; protected cgBuilder!: CallGraphBuilder; protected workList: FuncID[] = []; protected processedMethod!: IPtsCollection; - constructor(s: Scene) { + constructor(s: Scene, cg: CallGraph) { this.scene = s; + this.cg = cg; } public getScene(): Scene { @@ -96,11 +97,13 @@ export abstract class AbstractAnalysis { } public projectStart(displayGeneratedMethod: boolean): void { - this.scene.getMethods().forEach((method) => { - let cgNode = this.cg.getCallGraphNodeByMethod(method.getSignature()) as CallGraphNode; + this.cgBuilder.buildCGNodes(this.scene.getMethods()); + + for (let n of this.cg.getNodesIter()) { + let cgNode = n as CallGraphNode; if (cgNode.isSdkMethod()) { - return; + continue; } this.preProcessMethod(cgNode.getID()); @@ -108,7 +111,9 @@ export abstract class AbstractAnalysis { this.processMethod(cgNode.getID()).forEach((cs: CallSite) => { this.processCallSite(cgNode.getID(), cs, displayGeneratedMethod, true); }); - }); + } + + this.cgBuilder.setEntries(); } private processCallSite(method: FuncID, cs: CallSite, displayGeneratedMethod: boolean, isProject: boolean = false): void { @@ -128,7 +133,7 @@ export abstract class AbstractAnalysis { if (displayGeneratedMethod || !me?.isGenerated()) { this.workList.push(cs.calleeFuncID); - logger.info(`New workList item ${cs.calleeFuncID}: ${this.cg.getArkMethodByFuncID(cs.calleeFuncID)?.getSignature().toString()}`); + logger.trace(`New workList item ${cs.calleeFuncID}: ${this.cg.getArkMethodByFuncID(cs.calleeFuncID)?.getSignature().toString()}`); } } diff --git a/ets2panda/linter/arkanalyzer/src/callgraph/algorithm/ClassHierarchyAnalysis.ts b/ets2panda/linter/arkanalyzer/src/callgraph/algorithm/ClassHierarchyAnalysis.ts index 029d85541e..df58f9e571 100644 --- a/ets2panda/linter/arkanalyzer/src/callgraph/algorithm/ClassHierarchyAnalysis.ts +++ b/ets2panda/linter/arkanalyzer/src/callgraph/algorithm/ClassHierarchyAnalysis.ts @@ -20,11 +20,12 @@ import { ArkClass } from '../../core/model/ArkClass'; import { NodeID } from '../../core/graph/BaseExplicitGraph'; import { CallGraph, CallSite } from '../model/CallGraph'; import { AbstractAnalysis } from './AbstractAnalysis'; +import { CallGraphBuilder } from '../model/builder/CallGraphBuilder'; export class ClassHierarchyAnalysis extends AbstractAnalysis { - constructor(scene: Scene, cg: CallGraph) { - super(scene); - this.cg = cg; + constructor(scene: Scene, cg: CallGraph, cb: CallGraphBuilder) { + super(scene, cg); + this.cgBuilder = cb; } public resolveCall(callerMethod: NodeID, invokeStmt: Stmt): CallSite[] { diff --git a/ets2panda/linter/arkanalyzer/src/callgraph/algorithm/RapidTypeAnalysis.ts b/ets2panda/linter/arkanalyzer/src/callgraph/algorithm/RapidTypeAnalysis.ts index b4ecc267ac..b14816d26b 100644 --- a/ets2panda/linter/arkanalyzer/src/callgraph/algorithm/RapidTypeAnalysis.ts +++ b/ets2panda/linter/arkanalyzer/src/callgraph/algorithm/RapidTypeAnalysis.ts @@ -33,8 +33,7 @@ export class RapidTypeAnalysis extends AbstractAnalysis { private ignoredCalls: Map> = new Map(); constructor(scene: Scene, cg: CallGraph) { - super(scene); - this.cg = cg; + super(scene, cg); } public resolveCall(callerMethod: NodeID, invokeStmt: Stmt): CallSite[] { diff --git a/ets2panda/linter/arkanalyzer/src/callgraph/common/Statistics.ts b/ets2panda/linter/arkanalyzer/src/callgraph/common/Statistics.ts index 61246908ad..112539b168 100644 --- a/ets2panda/linter/arkanalyzer/src/callgraph/common/Statistics.ts +++ b/ets2panda/linter/arkanalyzer/src/callgraph/common/Statistics.ts @@ -196,6 +196,7 @@ export class CGStat extends StatTraits { numVirtual: number = 0; numIntrinsic: number = 0; numConstructor: number = 0; + numBlank: number = 0; public startStat(): void { this.startTime = new Date().getTime(); @@ -221,6 +222,7 @@ export class CGStat extends StatTraits { this.numIntrinsic++; break; default: + this.numBlank++; } this.numTotalNode++; } @@ -232,7 +234,8 @@ export class CGStat extends StatTraits { output = output + `Real function\t\t${this.numReal}\n`; output = output + `Intrinsic function\t${this.numIntrinsic}\n`; output = output + `Constructor function\t${this.numConstructor}\n`; - output = output + `Blank function\t\t${this.numVirtual}\n`; + output = output + `Virtual function\t\t${this.numVirtual}\n`; + output = output + `Blank function\t\t${this.numBlank}\n`; output = output + `Total\t\t\t${this.numTotalNode}\n`; return output; } diff --git a/ets2panda/linter/arkanalyzer/src/callgraph/model/CallGraph.ts b/ets2panda/linter/arkanalyzer/src/callgraph/model/CallGraph.ts index 954f47804a..0ddeb63007 100644 --- a/ets2panda/linter/arkanalyzer/src/callgraph/model/CallGraph.ts +++ b/ets2panda/linter/arkanalyzer/src/callgraph/model/CallGraph.ts @@ -15,63 +15,27 @@ import { MethodSignature } from '../../core/model/ArkSignature'; import { Stmt } from '../../core/base/Stmt'; -import { Value } from '../../core/base/Value'; import { Scene } from '../../Scene'; import { ArkMethod } from '../../core/model/ArkMethod'; import { GraphPrinter } from '../../save/GraphPrinter'; import { PrinterBuilder } from '../../save/PrinterBuilder'; import { BaseEdge, BaseNode, BaseExplicitGraph, NodeID } from '../../core/graph/BaseExplicitGraph'; import { CGStat } from '../common/Statistics'; -import { ContextID } from '../pointerAnalysis/Context'; import { UNKNOWN_FILE_NAME } from '../../core/common/Const'; +import { CallSite, CallSiteID, DynCallSite, ICallSite } from './CallSite'; export type Method = MethodSignature; -export type CallSiteID = number; export type FuncID = number; type StmtSet = Set; +export { CallSite, DynCallSite, ICallSite }; + export enum CallGraphNodeKind { - real, + real, // method from project and has body vitual, - intrinsic, - constructor, -} - -export class CallSite { - public callStmt: Stmt; - public args: Value[] | undefined; - public calleeFuncID: FuncID; - public callerFuncID: FuncID; - - constructor(s: Stmt, a: Value[] | undefined, ce: FuncID, cr: FuncID) { - this.callStmt = s; - this.args = a; - this.calleeFuncID = ce; - this.callerFuncID = cr; - } -} - -export class DynCallSite { - public callerFuncID: FuncID; - public callStmt: Stmt; - public args: Value[] | undefined; - public protentialCalleeFuncID: FuncID | undefined; - - constructor(caller: FuncID, s: Stmt, a: Value[] | undefined, ptcCallee: FuncID | undefined) { - this.callerFuncID = caller; - this.callStmt = s; - this.args = a; - this.protentialCalleeFuncID = ptcCallee; - } -} - -export class CSCallSite extends CallSite { - public cid: ContextID; - - constructor(id: ContextID, cs: CallSite) { - super(cs.callStmt, cs.args, cs.calleeFuncID, cs.callerFuncID); - this.cid = id; - } + intrinsic, // method created by AA, which arkMethod.isGenrated is true + constructor, // constructor + blank, // method without body } export class CallGraphEdge extends BaseEdge { @@ -119,7 +83,6 @@ export class CallGraphEdge extends BaseEdge { export class CallGraphNode extends BaseNode { private method: Method; private ifSdkMethod: boolean = false; - private isBlank: boolean = false; constructor(id: number, m: Method, k: CallGraphNodeKind = CallGraphNodeKind.real) { super(id, k); @@ -139,11 +102,7 @@ export class CallGraphNode extends BaseNode { } public get isBlankMethod(): boolean { - return this.isBlank; - } - - public set isBlankMethod(is: boolean) { - this.isBlank = is; + return this.kind === CallGraphNodeKind.blank; } public getDotAttr(): string { @@ -195,11 +154,6 @@ export class CallGraph extends BaseExplicitGraph { // check if sdk method cgNode.setSdkMethod(this.scene.hasSdkFile(method.getDeclaringClassSignature().getDeclaringFileSignature())); - let arkMethod = this.scene.getMethod(method); - if (!arkMethod || !arkMethod.getCfg()) { - cgNode.isBlankMethod = true; - } - this.addNode(cgNode); this.methodToCGNodeMap.set(method.toString(), cgNode.getID()); this.cgStat.addNodeStat(kind); @@ -285,7 +239,7 @@ export class CallGraph extends BaseExplicitGraph { } let args = callStmt.getInvokeExpr()?.getArgs(); - let cs = new DynCallSite(callerNode.getID(), callStmt, args, calleeNode?.getID()); + let cs = new DynCallSite(callStmt, args, calleeNode?.getID(), callerNode.getID()); this.stmtToDynCallSitemap.set(callStmt, cs); } @@ -467,4 +421,4 @@ export class CallGraph extends BaseExplicitGraph { public getGraphName(): string { return 'CG'; } -} +} \ No newline at end of file diff --git a/ets2panda/linter/arkanalyzer/src/callgraph/model/CallSite.ts b/ets2panda/linter/arkanalyzer/src/callgraph/model/CallSite.ts new file mode 100644 index 0000000000..40dbb3b492 --- /dev/null +++ b/ets2panda/linter/arkanalyzer/src/callgraph/model/CallSite.ts @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025 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. + */ + +import { Stmt } from '../../core/base/Stmt'; +import { Value } from '../../core/base/Value'; +import { ContextID } from '../pointerAnalysis/Context'; +import { FuncID } from './CallGraph'; + +export type CallSiteID = number; + +export interface ICallSite { + callStmt: Stmt; + args: Value[] | undefined; + callerFuncID: FuncID; +} + +export class CallSite implements ICallSite { + public callStmt: Stmt; + public args: Value[] | undefined; + public calleeFuncID: FuncID; + public callerFuncID: FuncID; + + constructor(s: Stmt, a: Value[] | undefined, ce: FuncID, cr: FuncID) { + this.callStmt = s; + this.args = a; + this.calleeFuncID = ce; + this.callerFuncID = cr; + } +} + +export class DynCallSite implements ICallSite { + public callStmt: Stmt; + public args: Value[] | undefined; + public protentialCalleeFuncID: FuncID | undefined; + public callerFuncID: FuncID; + + constructor(s: Stmt, a: Value[] | undefined, ptcCallee: FuncID | undefined, caller: FuncID) { + this.callerFuncID = caller; + this.callStmt = s; + this.args = a; + this.protentialCalleeFuncID = ptcCallee; + } +} + +export class CSCallSite extends CallSite { + public cid: ContextID; + + constructor(id: ContextID, cs: CallSite) { + super(cs.callStmt, cs.args, cs.calleeFuncID, cs.callerFuncID); + this.cid = id; + } +} \ No newline at end of file diff --git a/ets2panda/linter/arkanalyzer/src/callgraph/model/builder/CallGraphBuilder.ts b/ets2panda/linter/arkanalyzer/src/callgraph/model/builder/CallGraphBuilder.ts index c631c4333f..5947b9c66e 100644 --- a/ets2panda/linter/arkanalyzer/src/callgraph/model/builder/CallGraphBuilder.ts +++ b/ets2panda/linter/arkanalyzer/src/callgraph/model/builder/CallGraphBuilder.ts @@ -38,19 +38,27 @@ export class CallGraphBuilder { this.setEntries(); } - public buildDirectCallGraph(methods: ArkMethod[]): void { + /* + * Create CG Node for ArkMethods + */ + public buildCGNodes(methods: ArkMethod[]): void { for (const method of methods) { let m = method.getSignature(); let kind = CallGraphNodeKind.real; if (method.isGenerated()) { kind = CallGraphNodeKind.intrinsic; - } - if (method.getName() === 'constructor') { + } else if (method.getBody() === undefined || method.getCfg() === undefined) { + kind = CallGraphNodeKind.blank; + } else if (method.getName() === 'constructor') { kind = CallGraphNodeKind.constructor; } this.cg.addCallGraphNode(m, kind); } + } + + public buildDirectCallGraph(methods: ArkMethod[]): void { + this.buildCGNodes(methods); for (const method of methods) { let cfg = method.getCfg(); @@ -70,8 +78,7 @@ export class CallGraphBuilder { if (callee && invokeExpr instanceof ArkStaticInvokeExpr) { this.cg.addDirectOrSpecialCallEdge(method.getSignature(), callee, stmt); } else if ( - callee && - invokeExpr instanceof ArkInstanceInvokeExpr && + callee && invokeExpr instanceof ArkInstanceInvokeExpr && (this.isConstructor(callee) || this.scene.getMethod(callee)?.isGenerated()) ) { this.cg.addDirectOrSpecialCallEdge(method.getSignature(), callee, stmt, false); @@ -89,12 +96,12 @@ export class CallGraphBuilder { }); this.cg.setEntries(cgEntries); - let classHierarchyAnalysis: ClassHierarchyAnalysis = new ClassHierarchyAnalysis(this.scene, this.cg); + let classHierarchyAnalysis: ClassHierarchyAnalysis = new ClassHierarchyAnalysis(this.scene, this.cg, this); classHierarchyAnalysis.start(displayGeneratedMethod); } public buildCHA4WholeProject(displayGeneratedMethod: boolean = false): void { - let classHierarchyAnalysis: ClassHierarchyAnalysis = new ClassHierarchyAnalysis(this.scene, this.cg); + let classHierarchyAnalysis: ClassHierarchyAnalysis = new ClassHierarchyAnalysis(this.scene, this.cg, this); classHierarchyAnalysis.projectStart(displayGeneratedMethod); } diff --git a/ets2panda/linter/arkanalyzer/src/callgraph/pointerAnalysis/PTAUtils.ts b/ets2panda/linter/arkanalyzer/src/callgraph/pointerAnalysis/PTAUtils.ts index a8940d5d3c..0c120d6000 100644 --- a/ets2panda/linter/arkanalyzer/src/callgraph/pointerAnalysis/PTAUtils.ts +++ b/ets2panda/linter/arkanalyzer/src/callgraph/pointerAnalysis/PTAUtils.ts @@ -51,6 +51,7 @@ export function getBuiltInApiType(method: MethodSignature): BuiltApiType { return BuiltApiType.FunctionApply; case 'bind': return BuiltApiType.FunctionBind; + default: } } } diff --git a/ets2panda/linter/arkanalyzer/src/callgraph/pointerAnalysis/PagBuilder.ts b/ets2panda/linter/arkanalyzer/src/callgraph/pointerAnalysis/PagBuilder.ts index bd3917b090..5249cd8d2c 100644 --- a/ets2panda/linter/arkanalyzer/src/callgraph/pointerAnalysis/PagBuilder.ts +++ b/ets2panda/linter/arkanalyzer/src/callgraph/pointerAnalysis/PagBuilder.ts @@ -13,7 +13,7 @@ * limitations under the License. */ -import { CallGraph, CallGraphNode, CallGraphNodeKind, CallSite, DynCallSite, FuncID } from '../model/CallGraph'; +import { CallGraph, CallGraphNode, CallGraphNodeKind, CallSite, DynCallSite, FuncID, ICallSite } from '../model/CallGraph'; import { Scene } from '../../Scene'; import { ArkAssignStmt, ArkInvokeStmt, ArkReturnStmt, Stmt } from '../../core/base/Stmt'; import { @@ -527,7 +527,7 @@ export class PagBuilder { }); } - public addDynamicCallEdge(cs: DynCallSite | CallSite, baseClassPTNode: NodeID, cid: ContextID): NodeID[] { + public addDynamicCallEdge(cs: ICallSite, baseClassPTNode: NodeID, cid: ContextID): NodeID[] { let srcNodes: NodeID[] = []; let ivkExpr = cs.callStmt.getInvokeExpr(); @@ -577,7 +577,7 @@ export class PagBuilder { * all possible callee methods of a dynamic call site * handle both PtrInvokeExpr and InstanceInvokeExpr */ - private getDynamicCallee(ptNode: PagNode, value: Value, ivkExpr: AbstractInvokeExpr, cs: DynCallSite | CallSite): ArkMethod[] { + private getDynamicCallee(ptNode: PagNode, value: Value, ivkExpr: AbstractInvokeExpr, cs: ICallSite): ArkMethod[] { let callee: ArkMethod[] = []; if (ptNode instanceof PagFuncNode) { @@ -646,7 +646,10 @@ export class PagBuilder { // Pass base's pts to callee's this pointer if (!dstCGNode.isSdkMethod() && ivkExpr instanceof ArkInstanceInvokeExpr) { let srcBaseNode = this.addThisRefCallEdge(baseClassPTNode, cid, ivkExpr.getBase(), callee!, calleeCid, staticCS.callerFuncID); - srcNodes.push(srcBaseNode); + + if (srcBaseNode !== -1) { + srcNodes.push(srcBaseNode); + } } else if (!dstCGNode.isSdkMethod() && ivkExpr instanceof ArkPtrInvokeExpr) { let originCS = (ptNode as PagFuncNode).getCS(); if (!originCS) { @@ -712,6 +715,7 @@ export class PagBuilder { */ this.handleFunctionBind(staticCS, cid, baseClassPTNode, srcNodes); break; + default: } return srcNodes; @@ -799,7 +803,11 @@ export class PagBuilder { private addThisEdge(staticCS: CallSite, cid: ContextID, realCallee: ArkMethod, srcNodes: NodeID[], baseClassPTNode: NodeID, calleeCid: ContextID): void { if (!(staticCS.args![0] instanceof NullConstant) && !realCallee.isStatic()) { - srcNodes.push(this.addThisRefCallEdge(baseClassPTNode, cid, staticCS.args![0] as Local, realCallee, calleeCid, staticCS.callerFuncID)); + let srcNodeID = this.addThisRefCallEdge(baseClassPTNode, cid, staticCS.args![0] as Local, realCallee, calleeCid, staticCS.callerFuncID); + + if (srcNodeID !== -1) { + srcNodes.push(srcNodeID); + } } } @@ -915,6 +923,10 @@ export class PagBuilder { callerFunID: FuncID ): NodeID { let thisRefNodeID = this.recordThisRefNode(baseClassPTNode, callee, calleeCid); + if (thisRefNodeID === -1) { + return -1; + } + let thisRefNode = this.pag.getNode(thisRefNodeID) as PagThisRefNode; let srcBaseLocal = baseLocal; srcBaseLocal = this.getRealThisLocal(srcBaseLocal, callerFunID); @@ -1233,7 +1245,7 @@ export class PagBuilder { let sdkParamInvokeStmt = new ArkInvokeStmt(new ArkPtrInvokeExpr((arg.getType() as FunctionType).getMethodSignature(), paramValue as Local, [])); // create new DynCallSite - let sdkParamCallSite = new DynCallSite(funcID, sdkParamInvokeStmt, undefined, undefined); + let sdkParamCallSite = new DynCallSite(sdkParamInvokeStmt, undefined, undefined, funcID); dstPagNode.addRelatedDynCallSite(sdkParamCallSite); } @@ -1542,7 +1554,7 @@ export class PagBuilder { * process Storage API * @returns boolean: check if the cs represent a Storage API, no matter the API will success or fail */ - private processStorage(cs: CallSite | DynCallSite, calleeCGNode: CallGraphNode, cid: ContextID): boolean { + private processStorage(cs: ICallSite, calleeCGNode: CallGraphNode, cid: ContextID): boolean { let storageName = calleeCGNode.getMethod().getDeclaringClassSignature().getClassName(); let storageType: StorageType = this.getStorageType(storageName, cs, cid); @@ -1570,7 +1582,7 @@ export class PagBuilder { return false; } - private processStorageSetOrCreate(cs: CallSite | DynCallSite, cid: ContextID): void { + private processStorageSetOrCreate(cs: ICallSite, cid: ContextID): void { let propertyStr = this.getPropertyName(cs.args![0]); if (!propertyStr) { return; @@ -1583,7 +1595,7 @@ export class PagBuilder { this.addPropertyLinkEdge(propertyNode, storageObj, cid, cs.callStmt, StorageLinkEdgeType.Local2Property); } - private processStorageLink(cs: CallSite | DynCallSite, cid: ContextID): void { + private processStorageLink(cs: ICallSite, cid: ContextID): void { let propertyStr = this.getPropertyName(cs.args![0]); if (!propertyStr) { return; @@ -1601,7 +1613,7 @@ export class PagBuilder { this.pag.addPagEdge(linkedOpNode, propertyNode, PagEdgeKind.Copy); } - private processStorageProp(cs: CallSite | DynCallSite, cid: ContextID): void { + private processStorageProp(cs: ICallSite, cid: ContextID): void { let propertyStr = this.getPropertyName(cs.args![0]); if (!propertyStr) { return; @@ -1618,7 +1630,7 @@ export class PagBuilder { this.pag.addPagEdge(propertyNode, linkedOpNode, PagEdgeKind.Copy); } - private processStorageSet(cs: CallSite | DynCallSite, cid: ContextID): void { + private processStorageSet(cs: ICallSite, cid: ContextID): void { let ivkExpr: AbstractInvokeExpr = cs.callStmt.getInvokeExpr()!; if (ivkExpr instanceof ArkInstanceInvokeExpr) { let base = ivkExpr.getBase(); @@ -1634,7 +1646,7 @@ export class PagBuilder { } } - private processStorageGet(cs: CallSite | DynCallSite, cid: ContextID): void { + private processStorageGet(cs: ICallSite, cid: ContextID): void { if (!(cs.callStmt instanceof ArkAssignStmt)) { return; } @@ -1686,7 +1698,7 @@ export class PagBuilder { * @param cid: for search PAG node in SubscribedAbstractProperty * @returns StorageType enum */ - private getStorageType(storageName: string, cs: CallSite | DynCallSite, cid: ContextID): StorageType { + private getStorageType(storageName: string, cs: ICallSite, cid: ContextID): StorageType { switch (storageName) { case 'AppStorage': return StorageType.APP_STORAGE; diff --git a/ets2panda/linter/arkanalyzer/src/callgraph/pointerAnalysis/PointerAnalysis.ts b/ets2panda/linter/arkanalyzer/src/callgraph/pointerAnalysis/PointerAnalysis.ts index 902a05b902..4fc4a16471 100644 --- a/ets2panda/linter/arkanalyzer/src/callgraph/pointerAnalysis/PointerAnalysis.ts +++ b/ets2panda/linter/arkanalyzer/src/callgraph/pointerAnalysis/PointerAnalysis.ts @@ -47,9 +47,8 @@ export class PointerAnalysis extends AbstractAnalysis { private config: PointerAnalysisConfig; constructor(p: Pag, cg: CallGraph, s: Scene, config: PointerAnalysisConfig) { - super(s); + super(s, cg); this.pag = p; - this.cg = cg; this.ptd = new DiffPTData>(config.ptsCollectionCtor); this.pagBuilder = new PagBuilder(this.pag, this.cg, s, config.kLimit, config.analysisScale); this.cgBuilder = new CallGraphBuilder(this.cg, s); diff --git a/ets2panda/linter/arkanalyzer/src/callgraph/pointerAnalysis/PointerAnalysisConfig.ts b/ets2panda/linter/arkanalyzer/src/callgraph/pointerAnalysis/PointerAnalysisConfig.ts index 1e68c981db..0dad1053cf 100644 --- a/ets2panda/linter/arkanalyzer/src/callgraph/pointerAnalysis/PointerAnalysisConfig.ts +++ b/ets2panda/linter/arkanalyzer/src/callgraph/pointerAnalysis/PointerAnalysisConfig.ts @@ -64,6 +64,15 @@ export class PointerAnalysisConfig { } } + /* + * Set static field to be null, then all related objects could be freed by GC. + * Class PointerAnalysisConfig has been exported by ArkAnalyzer, the dispose method should be called by users themselves before free this class. + */ + public static dispose(): void { + // @ts-ignore + this.instance = null; + } + /* * Create Singleton instance * The instance can be created multi-times and be overwrited diff --git a/ets2panda/linter/arkanalyzer/src/core/base/Expr.ts b/ets2panda/linter/arkanalyzer/src/core/base/Expr.ts index dcf4695331..310e822863 100644 --- a/ets2panda/linter/arkanalyzer/src/core/base/Expr.ts +++ b/ets2panda/linter/arkanalyzer/src/core/base/Expr.ts @@ -40,8 +40,9 @@ import { ArkMethod } from '../model/ArkMethod'; import { UNKNOWN_FILE_NAME } from '../common/Const'; import { IRInference } from '../common/IRInference'; import { ImportInfo } from '../model/ArkImport'; -import { ArkClass } from '../model/ArkClass'; +import { ArkClass, ClassCategory } from '../model/ArkClass'; import { ArkField } from '../model/ArkField'; +import { ModelUtils } from '../common/ModelUtils'; /** * @category core/base/expr @@ -342,14 +343,30 @@ export class ArkNewExpr extends AbstractExpr { const classSignature = this.classType.getClassSignature(); if (classSignature.getDeclaringFileSignature().getFileName() === UNKNOWN_FILE_NAME) { const className = classSignature.getClassName(); - let type = TypeInference.inferUnclearRefName(className, arkMethod.getDeclaringArkClass()); + let type: Type | null | undefined = ModelUtils.findDeclaredLocal(new Local(className), arkMethod, 1)?.getType(); + if (TypeInference.isUnclearType(type)) { + type = TypeInference.inferUnclearRefName(className, arkMethod.getDeclaringArkClass()); + } if (type && type instanceof ClassType) { - let realGenericTypes = this.classType.getRealGenericTypes(); - this.classType = realGenericTypes ? new ClassType(type.getClassSignature(), realGenericTypes) : type; + const instanceType = this.constructorSignature(type, arkMethod) ?? type; + this.classType.setClassSignature(instanceType.getClassSignature()); + TypeInference.inferRealGenericTypes(this.classType.getRealGenericTypes(), arkMethod.getDeclaringArkClass()); } } return this; } + + private constructorSignature(type: ClassType, arkMethod: ArkMethod): ClassType | undefined { + const classConstructor = arkMethod.getDeclaringArkFile().getScene().getClass(type.getClassSignature()); + if (classConstructor?.getCategory() === ClassCategory.INTERFACE) { + const type = classConstructor.getMethodWithName('construct-signature')?.getReturnType(); + if (type) { + const returnType = TypeInference.replaceAliasType(type); + return returnType instanceof ClassType ? returnType : undefined; + } + } + return undefined; + } } export class ArkNewArrayExpr extends AbstractExpr { @@ -695,9 +712,13 @@ export abstract class AbstractBinopExpr extends AbstractExpr { case '^': case '<<': case '>>': + if (op1Type === NumberType.getInstance() && op2Type === NumberType.getInstance()) { + type = NumberType.getInstance(); + } if (op1Type === BigIntType.getInstance() && op2Type === BigIntType.getInstance()) { type = BigIntType.getInstance(); } + break; case '>>>': if (op1Type === NumberType.getInstance() && op2Type === NumberType.getInstance()) { type = NumberType.getInstance(); @@ -1042,10 +1063,14 @@ export class AliasTypeExpr extends AbstractExpr { public getType(): Type { function getTypeOfImportInfo(importInfo: ImportInfo): Type { const arkExport = importInfo.getLazyExportInfo()?.getArkExport(); - if (arkExport) { - return TypeInference.parseArkExport2Type(arkExport) ?? UnknownType.getInstance(); + const importClauseName = importInfo.getImportClauseName(); + let type; + if (importClauseName.includes('.') && arkExport instanceof ArkClass) { + type = TypeInference.inferUnclearRefName(importClauseName, arkExport); + } else if (arkExport) { + type = TypeInference.parseArkExport2Type(arkExport); } - return UnknownType.getInstance(); + return type ?? UnknownType.getInstance(); } const operator = this.getOriginalObject(); diff --git a/ets2panda/linter/arkanalyzer/src/core/base/Local.ts b/ets2panda/linter/arkanalyzer/src/core/base/Local.ts index aa4fbebdf0..10bb189627 100644 --- a/ets2panda/linter/arkanalyzer/src/core/base/Local.ts +++ b/ets2panda/linter/arkanalyzer/src/core/base/Local.ts @@ -14,7 +14,7 @@ */ import { Stmt } from './Stmt'; -import { ClassType, Type, UnknownType } from './Type'; +import { ClassType, FunctionType, Type, UnknownType } from './Type'; import { Value } from './Value'; import { TypeInference } from '../common/TypeInference'; import { ArkExport, ExportType } from '../model/ArkExport'; @@ -54,11 +54,17 @@ export class Local implements Value, ArkExport { const declaringArkClass = arkMethod.getDeclaringArkClass(); this.type = new ClassType(declaringArkClass.getSignature(), declaringArkClass.getRealTypes()); } else if (TypeInference.isUnclearType(this.type)) { - const type = TypeInference.inferBaseType(this.name, arkMethod.getDeclaringArkClass()) ?? ModelUtils.findDeclaredLocal(this, arkMethod)?.getType(); + const type = TypeInference.inferBaseType(this.name, arkMethod.getDeclaringArkClass()) ?? + ModelUtils.findDeclaredLocal(this, arkMethod)?.getType(); if (type) { this.type = type; } } + if (this.type instanceof FunctionType) { + this.type.getMethodSignature().getMethodSubSignature().getParameters() + .forEach(p => TypeInference.inferParameterType(p, arkMethod)); + TypeInference.inferSignatureReturnType(this.type.getMethodSignature(), arkMethod); + } return this; } diff --git a/ets2panda/linter/arkanalyzer/src/core/common/ArkIRTransformer.ts b/ets2panda/linter/arkanalyzer/src/core/common/ArkIRTransformer.ts index 31f9ecf635..c0a61f1f5d 100644 --- a/ets2panda/linter/arkanalyzer/src/core/common/ArkIRTransformer.ts +++ b/ets2panda/linter/arkanalyzer/src/core/common/ArkIRTransformer.ts @@ -46,7 +46,6 @@ import { DEFAULT, PROMISE } from './TSConst'; import { buildGenericType, buildModifiers, buildTypeParameters } from '../model/builder/builderUtils'; import { ArkValueTransformer } from './ArkValueTransformer'; import { ImportInfo } from '../model/ArkImport'; -import { TypeInference } from './TypeInference'; import { AbstractTypeExpr } from '../base/TypeExpr'; import { buildNormalArkClassFromArkMethod } from '../model/builder/ArkClassBuilder'; import { ArkClass } from '../model/ArkClass'; @@ -339,12 +338,6 @@ export class ArkIRTransformer { let expr: AliasTypeExpr; if (ts.isImportTypeNode(rightOp)) { expr = this.resolveImportTypeNode(rightOp); - const typeObject = expr.getOriginalObject(); - if (typeObject instanceof ImportInfo && typeObject.getLazyExportInfo() !== null) { - const arkExport = typeObject.getLazyExportInfo()!.getArkExport(); - rightType = TypeInference.parseArkExport2Type(arkExport) ?? UnknownType.getInstance(); - aliasType.setOriginalType(rightType); - } } else if (ts.isTypeQueryNode(rightOp)) { const localName = rightOp.exprName.getText(this.sourceFile); const originalLocal = Array.from(this.arkValueTransformer.getLocals()).find(local => local.getName() === localName); @@ -402,8 +395,6 @@ export class ArkIRTransformer { importInfo.build(importClauseName, importType, importFrom, LineColPosition.buildFromNode(importTypeNode, this.sourceFile), 0); importInfo.setDeclaringArkFile(this.declaringMethod.getDeclaringArkFile()); - // Function getLazyExportInfo will automatically try to infer the export info if it's undefined at the beginning. - importInfo.getLazyExportInfo(); return new AliasTypeExpr(importInfo, importTypeNode.isTypeOf); } diff --git a/ets2panda/linter/arkanalyzer/src/core/common/IRInference.ts b/ets2panda/linter/arkanalyzer/src/core/common/IRInference.ts index 0808347490..a9642db052 100644 --- a/ets2panda/linter/arkanalyzer/src/core/common/IRInference.ts +++ b/ets2panda/linter/arkanalyzer/src/core/common/IRInference.ts @@ -63,8 +63,7 @@ import { ArkArrayRef, ArkInstanceFieldRef, ArkParameterRef, - ArkStaticFieldRef, - GlobalRef + ArkStaticFieldRef } from '../base/Ref'; import { Value } from '../base/Value'; import { Constant } from '../base/Constant'; @@ -130,6 +129,7 @@ export class IRInference { } return 0; }); + arkClass.getAllHeritageClasses(); methods.forEach(arkMethod => TypeInference.inferTypeInMethod(arkMethod)); }); this.inferExportInfos(file); @@ -283,6 +283,11 @@ export class IRInference { private static inferBase(instance: ArkInstanceFieldRef | ArkInstanceInvokeExpr, arkMethod: ArkMethod): void { const base = instance.getBase(); if (base.getName() === THIS_NAME) { + const name = instance instanceof ArkInstanceFieldRef ? instance.getFieldName() : + instance.getMethodSignature().getMethodSubSignature().getMethodName(); + if (name.includes('.')) { + return; + } const declaringArkClass = arkMethod.getDeclaringArkClass(); if (declaringArkClass.isAnonymousClass()) { let newBase = this.inferThisLocal(arkMethod); @@ -293,14 +298,6 @@ export class IRInference { base.setType(new ClassType(declaringArkClass.getSignature(), declaringArkClass.getRealTypes())); } } else { - const value = arkMethod.getBody()?.getUsedGlobals()?.get(base.getName()); - if (value instanceof GlobalRef && !value.getRef()) { - const arkExport = ModelUtils.findGlobalRef(base.getName(), arkMethod); - if (arkExport instanceof Local) { - arkExport.getUsedStmts().push(...base.getUsedStmts()); - value.setRef(arkExport); - } - } this.inferLocal(instance.getBase(), arkMethod); } } @@ -686,7 +683,7 @@ export class IRInference { private static assignAnonMethod(anonMethod: ArkMethod | null, declaredMethod: ArkMethod | null): void { if (declaredMethod && anonMethod) { - anonMethod.setImplementationSignature(declaredMethod.matchMethodSignature(anonMethod.getSubSignature().getParameters())); + anonMethod.setDeclareSignatures(declaredMethod.matchMethodSignature(anonMethod.getSubSignature().getParameters())); } } @@ -815,7 +812,8 @@ export class IRInference { public static inferParameterRef(ref: ArkParameterRef, arkMethod: ArkMethod): AbstractRef { const paramType = ref.getType(); if (paramType instanceof UnknownType || paramType instanceof UnclearReferenceType) { - const type1 = arkMethod.getSignature().getMethodSubSignature().getParameters()[ref.getIndex()]?.getType(); + const signature = arkMethod.getDeclareSignatures()?.at(0) ?? arkMethod.getSignature(); + const type1 = signature.getMethodSubSignature().getParameters()[ref.getIndex()]?.getType(); if (!TypeInference.isUnclearType(type1)) { ref.setType(type1); return ref; diff --git a/ets2panda/linter/arkanalyzer/src/core/common/ModelUtils.ts b/ets2panda/linter/arkanalyzer/src/core/common/ModelUtils.ts index 7b90129608..41eb1a39f4 100644 --- a/ets2panda/linter/arkanalyzer/src/core/common/ModelUtils.ts +++ b/ets2panda/linter/arkanalyzer/src/core/common/ModelUtils.ts @@ -37,14 +37,7 @@ import path from 'path'; import { Sdk } from '../../Config'; import { ALL, DEFAULT, THIS_NAME } from './TSConst'; import { buildDefaultExportInfo } from '../model/builder/ArkExportBuilder'; -import { - AnnotationNamespaceType, - ClassType, - FunctionType, - Type, - UnclearReferenceType, - UnknownType -} from '../base/Type'; +import { AnnotationNamespaceType, ClassType, FunctionType, Type, UnclearReferenceType, UnknownType } from '../base/Type'; import { Scene } from '../../Scene'; import { DEFAULT_ARK_CLASS_NAME, DEFAULT_ARK_METHOD_NAME, NAME_DELIMITER, TEMP_LOCAL_PREFIX } from './Const'; import { EMPTY_STRING } from './ValueUtil'; @@ -56,6 +49,14 @@ import { SdkUtils } from './SdkUtils'; export class ModelUtils { public static implicitArkUIBuilderMethods: Set = new Set(); + /* + * Set static field to be null, then all related objects could be freed by GC. + * Static field implicitArkUIBuilderMethods is only internally used by ArkAnalyzer build method body, the dispose method should be called after build all body. + */ + public static dispose(): void { + this.implicitArkUIBuilderMethods.clear(); + } + public static getMethodSignatureFromArkClass(arkClass: ArkClass, methodName: string): MethodSignature | null { for (const arkMethod of arkClass.getMethods()) { if (arkMethod.getName() === methodName) { @@ -570,8 +571,7 @@ export function getArkFile(im: FromInfo): ArkFile | null | undefined { export function findExportInfo(fromInfo: FromInfo): ExportInfo | null { let file = getArkFile(fromInfo); if (!file) { - logger.warn(`${fromInfo.getOriginName()} ${fromInfo.getFrom()} file not found: - ${fromInfo.getDeclaringArkFile()?.getFileSignature()?.toString()}`); + logger.warn(`${fromInfo.getOriginName()} ${fromInfo.getFrom()} file not found: ${fromInfo.getDeclaringArkFile()?.getFileSignature()?.toString()}`); return null; } if (fileSignatureCompare(file.getFileSignature(), fromInfo.getDeclaringArkFile().getFileSignature())) { @@ -623,8 +623,8 @@ export function findArkExport(exportInfo: ExportInfo | undefined): ArkExport | n if (arkExport) { exportInfo.setArkExport(arkExport); } else { - logger.warn(`${exportInfo.getExportClauseName()} get arkExport fail from ${exportInfo.getFrom()} at - ${exportInfo.getDeclaringArkFile().getFileSignature().toString()}`); + const file = exportInfo.getDeclaringArkFile().getFileSignature().toString(); + logger.warn(`${exportInfo.getExportClauseName()} get arkExport fail from ${exportInfo.getFrom()} at ${file}`); } return arkExport || null; } diff --git a/ets2panda/linter/arkanalyzer/src/core/common/SdkUtils.ts b/ets2panda/linter/arkanalyzer/src/core/common/SdkUtils.ts index 84f1859878..644983c544 100644 --- a/ets2panda/linter/arkanalyzer/src/core/common/SdkUtils.ts +++ b/ets2panda/linter/arkanalyzer/src/core/common/SdkUtils.ts @@ -28,11 +28,22 @@ import { ClassType } from '../base/Type'; import { AbstractFieldRef } from '../base/Ref'; import { ArkNamespace } from '../model/ArkNamespace'; import { TypeInference } from './TypeInference'; +import Logger, { LOG_MODULE_TYPE } from '../../utils/logger'; + +const logger = Logger.getLogger(LOG_MODULE_TYPE.ARKANALYZER, 'SdkUtils'); export class SdkUtils { private static sdkImportMap: Map = new Map(); + /* + * Set static field to be null, then all related objects could be freed by GC. + * Class SdkUtils is only internally used by ArkAnalyzer type inference, the dispose method should be called at the end of type inference. + */ + public static dispose(): void { + this.sdkImportMap.clear(); + } + public static buildSdkImportMap(file: ArkFile): void { const fileName = path.basename(file.getName()); if (fileName.startsWith('@')) { @@ -84,15 +95,18 @@ export class SdkUtils { private static loadClass(globalMap: Map, cls: ArkClass): void { const old = globalMap.get(cls.getName()); - if (old instanceof ArkClass) { + if (old instanceof ArkClass && old.getDeclaringArkFile().getProjectName() === cls.getDeclaringArkFile().getProjectName()) { if (old.getCategory() === ClassCategory.CLASS) { - this.copyMethod(cls, old); + this.copyMembers(cls, old); } else { - this.copyMethod(old, cls); + this.copyMembers(old, cls); globalMap.delete(cls.getName()); globalMap.set(cls.getName(), cls); } - } else if (!old) { + } else { + if (old) { + logger.error(`${old.getSignature()} is override`); + } globalMap.set(cls.getName(), cls); } } @@ -105,10 +119,7 @@ export class SdkUtils { const instance = globalMap.get(name + 'Interface'); const attr = globalMap.get(name + COMPONENT_ATTRIBUTE); if (attr instanceof ArkClass && instance instanceof ArkClass) { - instance - .getMethods() - .filter(m => !attr.getMethodWithName(m.getName())) - .forEach(m => attr.addMethod(m)); + this.copyMembers(instance, attr); globalMap.set(name, attr); return; } @@ -119,15 +130,12 @@ export class SdkUtils { } else if (old instanceof ArkClass && local.getType() instanceof ClassType) { const localConstructor = scene.getClass((local.getType() as ClassType).getClassSignature()); if (localConstructor) { - localConstructor - .getMethods() - .filter(m => !old.getMethodWithName(m.getName())) - .forEach(m => old.addMethod(m)); + this.copyMembers(localConstructor, old); } } } - private static copyMethod(from: ArkClass, to: ArkClass): void { + private static copyMembers(from: ArkClass, to: ArkClass): void { from.getMethods().forEach(method => { const dist = method.isStatic() ? to.getStaticMethodWithName(method.getName()) : to.getMethodWithName(method.getName()); const distSignatures = dist?.getDeclareSignatures(); @@ -137,6 +145,12 @@ export class SdkUtils { to.addMethod(method); } }); + from.getFields().forEach(field => { + const dist = field.isStatic() ? to.getStaticFieldWithName(field.getName()) : to.getFieldWithName(field.getName()); + if (!dist) { + to.addField(field); + } + }); } public static computeGlobalThis(leftOp: AbstractFieldRef, arkMethod: ArkMethod): void { diff --git a/ets2panda/linter/arkanalyzer/src/core/common/TypeInference.ts b/ets2panda/linter/arkanalyzer/src/core/common/TypeInference.ts index e754272cbf..07fc7faf50 100644 --- a/ets2panda/linter/arkanalyzer/src/core/common/TypeInference.ts +++ b/ets2panda/linter/arkanalyzer/src/core/common/TypeInference.ts @@ -16,7 +16,14 @@ import Logger, { LOG_MODULE_TYPE } from '../../utils/logger'; import { AbstractExpr, ArkInstanceInvokeExpr, ArkPtrInvokeExpr, ArkStaticInvokeExpr } from '../base/Expr'; import { Local } from '../base/Local'; -import { AbstractFieldRef, AbstractRef, ArkArrayRef, ArkInstanceFieldRef, ArkParameterRef, ArkStaticFieldRef } from '../base/Ref'; +import { + AbstractFieldRef, + AbstractRef, + ArkArrayRef, + ArkInstanceFieldRef, + ArkParameterRef, + ArkStaticFieldRef, GlobalRef +} from '../base/Ref'; import { ArkAliasTypeDefineStmt, ArkAssignStmt, ArkReturnStmt, Stmt } from '../base/Stmt'; import { AliasType, @@ -54,7 +61,7 @@ import { ANY_KEYWORD, BIGINT_KEYWORD, BOOLEAN_KEYWORD, - CONSTRUCTOR_NAME, + CONSTRUCTOR_NAME, DEFAULT, GLOBAL_THIS_NAME, NEVER_KEYWORD, NULL_KEYWORD, @@ -157,7 +164,7 @@ export class TypeInference { type = leftOpType; } } else if (leftOpType instanceof AnnotationNamespaceType) { - type = this.inferUnclearRefName(leftOpType.getOriginType(), declaringArkClass); + type = this.inferBaseType(leftOpType.getOriginType(), declaringArkClass); } else if (leftOpType instanceof UnclearReferenceType) { type = this.inferUnclearRefType(leftOpType, declaringArkClass); } @@ -185,6 +192,15 @@ export class TypeInference { signatures.forEach(s => this.inferSignatureReturnType(s, arkMethod)); return; } + body.getUsedGlobals()?.forEach((value, key) => { + if (value instanceof GlobalRef && !value.getRef()) { + const arkExport = ModelUtils.findGlobalRef(key, arkMethod); + if (arkExport instanceof Local) { + arkExport.getUsedStmts().push(...value.getUsedStmts()); + value.setRef(arkExport); + } + } + }); const cfg = body.getCfg(); for (const block of cfg.getBlocks()) { for (const stmt of block.getStmts()) { @@ -387,7 +403,8 @@ export class TypeInference { public static isUnclearType(type: Type | null | undefined): boolean { // TODO: For UnionType, IntersectionType and TupleType, it should recurse check every item of them. - if (!type || type instanceof UnknownType || type instanceof UnclearReferenceType || type instanceof NullType || type instanceof UndefinedType) { + if (!type || type instanceof UnknownType || type instanceof UnclearReferenceType || type instanceof NullType || + type instanceof UndefinedType || type instanceof GenericType) { return true; } else if ( type instanceof ClassType && @@ -488,7 +505,7 @@ export class TypeInference { return value.getType(); } - private static inferParameterType(param: MethodParameter, arkMethod: ArkMethod): void { + public static inferParameterType(param: MethodParameter, arkMethod: ArkMethod): void { let pType = param.getType(); const arkClass = arkMethod.getDeclaringArkClass(); let type; @@ -703,7 +720,7 @@ export class TypeInference { } propertyType = new EnumValueType(property.getSignature(), constant); } else { - propertyType = property.getType(); + propertyType = this.replaceTypeWithReal(property.getType(), baseType.getRealGenericTypes()); } } else if (property) { propertyType = this.parseArkExport2Type(property); @@ -728,6 +745,8 @@ export class TypeInference { public static inferBaseType(baseName: string, arkClass: ArkClass): Type | null { if (SUPER_NAME === baseName) { return this.parseArkExport2Type(arkClass.getSuperClass()); + } else if (DEFAULT === baseName) { + return this.parseArkExport2Type(arkClass.getDeclaringArkFile().getExportInfoBy(DEFAULT)?.getArkExport()); } const field = ModelUtils.getDefaultClass(arkClass)?.getDefaultArkMethod()?.getBody()?.getLocals()?.get(baseName); if (field && !this.isUnclearType(field.getType())) { @@ -750,14 +769,12 @@ export class TypeInference { ModelUtils.getClassWithName(typeName, arkClass) ?? ModelUtils.getDefaultClass(arkClass)?.getDefaultArkMethod()?.getBody()?.getAliasTypeByName(typeName) ?? ModelUtils.getArkExportInImportInfoWithName(typeName, arkClass.getDeclaringArkFile()); - if (arkExport instanceof ArkClass || arkExport instanceof AliasType) { - return this.parseArkExport2Type(arkExport); - } - if (!arkClass.getDeclaringArkFile().getImportInfoBy(typeName)) { + if (!arkExport && !arkClass.getDeclaringArkFile().getImportInfoBy(typeName)) { arkExport = arkClass.getDeclaringArkFile().getScene().getSdkGlobal(typeName); } - if (arkExport instanceof ArkClass || arkExport instanceof AliasType) { - return this.parseArkExport2Type(arkExport); + const type = this.parseArkExport2Type(arkExport); + if (type instanceof ClassType || type instanceof AliasType) { + return type; } return null; } @@ -860,12 +877,14 @@ export class TypeInference { .getParameters() .filter(p => !p.getName().startsWith(LEXICAL_ENV_NAME_PREFIX)) .forEach((p, i) => { - let type = params?.[i]?.getType(); - if (type instanceof GenericType && realTypes) { - type = realTypes?.[type.getIndex()]; - } - if (type) { - p.setType(type); + if (this.isUnclearType(p.getType())) { + let type = params?.[i]?.getType(); + if (type instanceof GenericType && realTypes) { + type = realTypes?.[type.getIndex()]; + } + if (type) { + p.setType(type); + } } }); } diff --git a/ets2panda/linter/arkanalyzer/src/core/common/ValueUtil.ts b/ets2panda/linter/arkanalyzer/src/core/common/ValueUtil.ts index 1731b701b0..8a29e565b8 100644 --- a/ets2panda/linter/arkanalyzer/src/core/common/ValueUtil.ts +++ b/ets2panda/linter/arkanalyzer/src/core/common/ValueUtil.ts @@ -21,6 +21,14 @@ export class ValueUtil { private static readonly NumberConstantCache: Map = new Map(); public static readonly EMPTY_STRING_CONSTANT = new StringConstant(EMPTY_STRING); + /* + * Set static field to be null, then all related objects could be freed by GC. + * Class SdkUtils is only internally used by ArkAnalyzer, the dispose method should be called by users themselves before drop Scene. + */ + public static dispose(): void { + this.NumberConstantCache.clear(); + } + public static getOrCreateNumberConst(n: number): Constant { let constant = this.NumberConstantCache.get(n); if (constant === undefined) { diff --git a/ets2panda/linter/arkanalyzer/src/core/dataflow/DataflowSolver.ts b/ets2panda/linter/arkanalyzer/src/core/dataflow/DataflowSolver.ts index 523dd9a41b..325fa23634 100644 --- a/ets2panda/linter/arkanalyzer/src/core/dataflow/DataflowSolver.ts +++ b/ets2panda/linter/arkanalyzer/src/core/dataflow/DataflowSolver.ts @@ -24,6 +24,7 @@ import { CallGraph } from '../../callgraph/model/CallGraph'; import { ClassHierarchyAnalysis } from '../../callgraph/algorithm/ClassHierarchyAnalysis'; import { addCfg2Stmt } from '../../utils/entryMethodUtils'; import { getRecallMethodInParam } from './Util'; +import { CallGraphBuilder } from '../../callgraph/model/builder/CallGraphBuilder'; /* this program is roughly an implementation of the paper: Practical Extensions to the IFDS Algorithm. @@ -88,7 +89,7 @@ export abstract class DataflowSolver { // build CHA let cg = new CallGraph(this.scene); - this.CHA = new ClassHierarchyAnalysis(this.scene, cg); + this.CHA = new ClassHierarchyAnalysis(this.scene, cg, new CallGraphBuilder(cg, this.scene)); this.buildStmtMapInClass(); this.setCfg4AllStmt(); return; diff --git a/ets2panda/linter/arkanalyzer/src/core/graph/builder/CfgBuilder.ts b/ets2panda/linter/arkanalyzer/src/core/graph/builder/CfgBuilder.ts index 5cd44402ec..13ff5584cc 100644 --- a/ets2panda/linter/arkanalyzer/src/core/graph/builder/CfgBuilder.ts +++ b/ets2panda/linter/arkanalyzer/src/core/graph/builder/CfgBuilder.ts @@ -677,6 +677,9 @@ export class CfgBuilder { for (let i = stmt.nexts.length - 1; i >= 0; i--) { stmtQueue.push(stmt.nexts[i]); } + if (stmt.afterSwitch && stmt.afterSwitch.lasts.size == 0) { + stmtQueue.push(stmt.afterSwitch); + } } else if (stmt instanceof TryStatementBuilder) { if (stmt.finallyStatement) { stmtQueue.push(stmt.finallyStatement); diff --git a/ets2panda/linter/arkanalyzer/src/core/graph/builder/TrapBuilder.ts b/ets2panda/linter/arkanalyzer/src/core/graph/builder/TrapBuilder.ts index 160df9fdc0..9094994dc5 100644 --- a/ets2panda/linter/arkanalyzer/src/core/graph/builder/TrapBuilder.ts +++ b/ets2panda/linter/arkanalyzer/src/core/graph/builder/TrapBuilder.ts @@ -19,7 +19,15 @@ import { Trap } from '../../base/Trap'; import { ArkCaughtExceptionRef } from '../../base/Ref'; import { UnknownType } from '../../base/Type'; import { FullPosition } from '../../base/Position'; -import { ArkAssignStmt, ArkIfStmt, ArkInvokeStmt, ArkReturnStmt, ArkReturnVoidStmt, ArkThrowStmt, Stmt } from '../../base/Stmt'; +import { + ArkAssignStmt, + ArkIfStmt, + ArkInvokeStmt, + ArkReturnStmt, + ArkReturnVoidStmt, + ArkThrowStmt, + Stmt, +} from '../../base/Stmt'; import { BlockBuilder, TryStatementBuilder } from './CfgBuilder'; import Logger, { LOG_MODULE_TYPE } from '../../../utils/logger'; @@ -217,16 +225,17 @@ export class TrapBuilder { bfsBlocks.push(currBlock); const childList = currBlockBuilder.nexts; - if (childList.length === 0 || (childList.length !== 0 && childList[0] === endBlockBuilder)) { - if (childList[0] === endBlockBuilder) { - tailBlocks.push(currBlock); - continue; - } - } if (childList.length !== 0) { for (const child of childList) { - queue.push(child); + // A tail block's successor may be within the traversal range + if (child === endBlockBuilder) { + tailBlocks.push(currBlock); + } else { + queue.push(child); + } } + } else { + tailBlocks.push(currBlock); } } return { bfsBlocks, tailBlocks }; @@ -247,19 +256,16 @@ export class TrapBuilder { copyFinallyBfsBlocks[0].getPredecessors().splice(0, finallyPredecessorsCnt); const throwStmt = new ArkThrowStmt(exceptionValue); let copyFinallyTailBlocks = copyFinallyBfsBlocks.splice(copyFinallyBfsBlocks.length - finallyTailBlocks.length, finallyTailBlocks.length); - copyFinallyTailBlocks.forEach((copyFinallyTailBlock: BasicBlock) => { - const successorsCnt = copyFinallyTailBlock.getSuccessors().length; - copyFinallyTailBlock.getSuccessors().splice(0, successorsCnt); - }); if (copyFinallyTailBlocks.length > 1) { const newCopyFinallyTailBlock = new BasicBlock(); copyFinallyTailBlocks.forEach((copyFinallyTailBlock: BasicBlock) => { copyFinallyTailBlock.addSuccessorBlock(newCopyFinallyTailBlock); newCopyFinallyTailBlock.addPredecessorBlock(copyFinallyTailBlock); }); + copyFinallyBfsBlocks.push(...copyFinallyTailBlocks); copyFinallyTailBlocks = [newCopyFinallyTailBlock]; } - copyFinallyTailBlocks[0]?.addStmt(throwStmt); + copyFinallyTailBlocks[0].addStmt(throwStmt); copyFinallyBfsBlocks.push(...copyFinallyTailBlocks); copyFinallyBfsBlocks.forEach((copyFinallyBfsBlock: BasicBlock) => { basicBlockSet.add(copyFinallyBfsBlock); @@ -281,12 +287,19 @@ export class TrapBuilder { for (const sourceBlock of sourceBlocks) { const targetBlock = sourceToTarget.get(sourceBlock)!; for (const predecessor of sourceBlock.getPredecessors()) { - const targetPredecessor = sourceToTarget.get(predecessor)!; - targetBlock.addPredecessorBlock(targetPredecessor); + const targetPredecessor = sourceToTarget.get(predecessor); + // Only include blocks within the copy range, so that predecessor and successor relationships to + // external blocks can be trimmed + if (targetPredecessor) { + targetBlock.addPredecessorBlock(targetPredecessor); + } + } for (const successor of sourceBlock.getSuccessors()) { - const targetSuccessor = sourceToTarget.get(successor)!; - targetBlock.addSuccessorBlock(targetSuccessor); + const targetSuccessor = sourceToTarget.get(successor); + if (targetSuccessor) { + targetBlock.addSuccessorBlock(targetSuccessor); + } } } return targetBlocks; diff --git a/ets2panda/linter/arkanalyzer/src/core/model/ArkImport.ts b/ets2panda/linter/arkanalyzer/src/core/model/ArkImport.ts index 8ff3ff50ac..05c5c24a80 100644 --- a/ets2panda/linter/arkanalyzer/src/core/model/ArkImport.ts +++ b/ets2panda/linter/arkanalyzer/src/core/model/ArkImport.ts @@ -72,7 +72,7 @@ export class ImportInfo extends ArkBaseModel implements FromInfo { * @returns The export information. If there is no export information, the return will be a **null**. */ public getLazyExportInfo(): ExportInfo | null { - if (this.lazyExportInfo === undefined) { + if (this.lazyExportInfo === undefined && this.declaringArkFile.getScene().getStage() >= 2) { this.lazyExportInfo = findExportInfo(this); } return this.lazyExportInfo || null; diff --git a/ets2panda/linter/arkanalyzer/src/core/model/ArkMethod.ts b/ets2panda/linter/arkanalyzer/src/core/model/ArkMethod.ts index f3476d3567..12682223ba 100644 --- a/ets2panda/linter/arkanalyzer/src/core/model/ArkMethod.ts +++ b/ets2panda/linter/arkanalyzer/src/core/model/ArkMethod.ts @@ -15,7 +15,16 @@ import { ArkParameterRef, ArkThisRef } from '../base/Ref'; import { ArkAssignStmt, ArkReturnStmt, Stmt } from '../base/Stmt'; -import { ClassType, EnumValueType, FunctionType, GenericType, LiteralType, Type, UnionType } from '../base/Type'; +import { + AliasType, + ClassType, + EnumValueType, + FunctionType, + GenericType, + LiteralType, + Type, + UnionType +} from '../base/Type'; import { Value } from '../base/Value'; import { Cfg } from '../graph/Cfg'; import { ViewTree } from '../graph/ViewTree'; @@ -24,17 +33,17 @@ import { ArkClass, ClassCategory } from './ArkClass'; import { MethodSignature, MethodSubSignature } from './ArkSignature'; import { BodyBuilder } from './builder/BodyBuilder'; import { ArkExport, ExportType } from './ArkExport'; -import { ANONYMOUS_METHOD_PREFIX, DEFAULT_ARK_METHOD_NAME } from '../common/Const'; +import { ANONYMOUS_METHOD_PREFIX, DEFAULT_ARK_METHOD_NAME, LEXICAL_ENV_NAME_PREFIX } from '../common/Const'; import { getColNo, getLineNo, LineCol, setCol, setLine } from '../base/Position'; import { ArkBaseModel, ModifierType } from './ArkBaseModel'; import { ArkError, ArkErrorCode } from '../common/ArkError'; import { CALL_BACK } from '../common/EtsConst'; -import { Scene } from '../../Scene'; import { Constant } from '../base/Constant'; import { Local } from '../base/Local'; import { ArkFile, Language } from './ArkFile'; import { CONSTRUCTOR_NAME } from '../common/TSConst'; import { MethodParameter } from './builder/ArkMethodBuilder'; +import { TypeInference } from '../common/TypeInference'; export const arkMethodNodeKind = [ 'MethodDeclaration', @@ -623,45 +632,41 @@ export class ArkMethod extends ArkBaseModel implements ArkExport { } return args.length >= min && args.length <= max; }); - const scene = this.getDeclaringArkFile().getScene(); return ( - signatures?.find(p => { - const parameters = p.getMethodSubSignature().getParameters(); - for (let i = 0; i < parameters.length; i++) { - if (!args[i]) { - return parameters[i].isOptional(); - } - const isMatched = this.matchParam(parameters[i].getType(), args[i], scene); - if (!isMatched) { - return false; - } - } - return true; - }) ?? + signatures?.find(p => this.isMatched(p.getMethodSubSignature().getParameters(), args)) ?? signatures?.[0] ?? this.getSignature() ); } - private matchParam(paramType: Type, arg: Value, scene: Scene): boolean { - const argType = arg.getType(); - if (arg instanceof Local) { - const stmt = arg.getDeclaringStmt(); - if (stmt instanceof ArkAssignStmt && stmt.getRightOp() instanceof Constant) { - arg = stmt.getRightOp(); + private isMatched(parameters: MethodParameter[], args: Value[], isArrowFunc: boolean = false): boolean { + for (let i = 0; i < parameters.length; i++) { + if (!args[i]) { + return isArrowFunc ? true : parameters[i].isOptional(); } + const isMatched = this.matchParam(parameters[i].getType(), args[i]); + if (!isMatched) { + return false; + } + } + return true; + } + + private matchParam(paramType: Type, arg: Value): boolean { + arg = ArkMethod.parseArg(arg); + const argType = arg.getType(); + if (paramType instanceof AliasType && !(argType instanceof AliasType)) { + paramType = TypeInference.replaceAliasType(paramType); } if (paramType instanceof UnionType) { - let matched = false; - for (const e of paramType.getTypes()) { - if (argType.constructor === e.constructor) { - matched = true; - break; - } - } - return matched; + return !!paramType.getTypes().find(p => this.matchParam(p, arg)); } else if (argType instanceof FunctionType && paramType instanceof FunctionType) { - return argType.getMethodSignature().getParamLength() === paramType.getMethodSignature().getParamLength(); + if (argType.getMethodSignature().getParamLength() > paramType.getMethodSignature().getParamLength()) { + return false; + } + const parameters = paramType.getMethodSignature().getMethodSubSignature().getParameters(); + const args = argType.getMethodSignature().getMethodSubSignature().getParameters().filter(p => !p.getName().startsWith(LEXICAL_ENV_NAME_PREFIX)); + return this.isMatched(parameters, args, true); } else if (paramType instanceof ClassType && paramType.getClassSignature().getClassName().includes(CALL_BACK)) { return argType instanceof FunctionType; } else if (paramType instanceof LiteralType && arg instanceof Constant) { @@ -684,6 +689,19 @@ export class ArkMethod extends ArkBaseModel implements ArkExport { return argType.constructor === paramType.constructor; } + private static parseArg(arg: Value): Value { + if (arg instanceof Local) { + const stmt = arg.getDeclaringStmt(); + const argType = arg.getType(); + if (argType instanceof EnumValueType && argType.getConstant()) { + arg = argType.getConstant()!; + } else if (stmt instanceof ArkAssignStmt && stmt.getRightOp() instanceof Constant) { + arg = stmt.getRightOp(); + } + } + return arg; + } + public getOuterMethod(): ArkMethod | undefined { return this.outerMethod; } diff --git a/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkClassBuilder.ts b/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkClassBuilder.ts index 7c3f169384..48a7217d1a 100644 --- a/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkClassBuilder.ts +++ b/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkClassBuilder.ts @@ -370,7 +370,17 @@ function buildArkClassMembers(clsNode: ClassLikeNode, cls: ArkClass, sourceFile: const instanceInitStmts: Stmt[] = []; let staticBlockId = 0; clsNode.members.forEach(member => { - if (ts.isPropertyDeclaration(member) || ts.isPropertySignature(member)) { + if ( + ts.isMethodDeclaration(member) || + ts.isConstructorDeclaration(member) || + ts.isMethodSignature(member) || + ts.isConstructSignatureDeclaration(member) || + ts.isAccessor(member) || + ts.isCallSignatureDeclaration(member) + ) { + // these node types have been handled at the beginning of this function by calling buildMethodsForClass + return; + } else if (ts.isPropertyDeclaration(member) || ts.isPropertySignature(member)) { const arkField = buildProperty2ArkField(member, sourceFile, cls); if (ts.isClassDeclaration(clsNode) || ts.isClassExpression(clsNode) || ts.isStructDeclaration(clsNode)) { if (arkField.isStatic()) { @@ -395,9 +405,9 @@ function buildArkClassMembers(clsNode: ClassLikeNode, cls: ArkClass, sourceFile: const staticBlockInvokeExpr = new ArkStaticInvokeExpr(currStaticBlockMethodSig, []); staticInitStmts.push(new ArkInvokeStmt(staticBlockInvokeExpr)); } else if (ts.isSemicolonClassElement(member)) { - logger.debug('Skip these members.'); + logger.trace('Skip these members.'); } else { - logger.warn('Please contact developers to support new member type!'); + logger.warn(`Please contact developers to support new member in class: ${cls.getSignature().toString()}, member: ${member.getText()}!`); } }); if (ts.isClassDeclaration(clsNode) || ts.isClassExpression(clsNode) || ts.isStructDeclaration(clsNode)) { diff --git a/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkFieldBuilder.ts b/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkFieldBuilder.ts index ede55e7c93..b41b7dd419 100644 --- a/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkFieldBuilder.ts +++ b/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkFieldBuilder.ts @@ -47,7 +47,7 @@ export function buildProperty2ArkField( } else if (ts.isPropertyAccessExpression(member.name.expression)) { fieldName = handlePropertyAccessExpression(member.name.expression); } else { - logger.warn('Other property expression type found!'); + logger.warn(`Other property expression type found: ${member.name.expression.getText()}!`); } } else if (member.name && (ts.isIdentifier(member.name) || ts.isLiteralExpression(member.name))) { fieldName = member.name.text; @@ -56,7 +56,7 @@ export function buildProperty2ArkField( fieldName = propertyName.substring(1); field.addModifier(ModifierType.PRIVATE); } else { - logger.warn('Other type of property name found!'); + logger.warn(`Other type of property name found: ${member.getText()}!`); } let fieldType: Type = UnknownType.getInstance(); diff --git a/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkFileBuilder.ts b/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkFileBuilder.ts index 1e201453b1..386cbca085 100644 --- a/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkFileBuilder.ts +++ b/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkFileBuilder.ts @@ -110,7 +110,7 @@ function buildArkFile(arkFile: ArkFile, astRoot: ts.SourceFile): void { } // TODO: Check else if (ts.isMethodDeclaration(child)) { - logger.warn('This is a MethodDeclaration in ArkFile.'); + logger.trace('This is a MethodDeclaration in ArkFile.'); let mthd: ArkMethod = new ArkMethod(); buildArkMethodFromArkClass(child, arkFile.getDefaultClass(), mthd, astRoot); @@ -143,7 +143,7 @@ function buildArkFile(arkFile: ArkFile, astRoot: ts.SourceFile): void { } else if (ts.isExpressionStatement(child) && ts.isStringLiteral(child.expression)) { child.expression.text.trim() === ARKTS_STATIC_MARK && arkFile.setLanguage(Language.ARKTS1_2); } else { - logger.info('Child joined default method of arkFile: ', ts.SyntaxKind[child.kind]); + logger.trace('Child joined default method of arkFile: ', ts.SyntaxKind[child.kind]); } }); diff --git a/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkMethodBuilder.ts b/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkMethodBuilder.ts index 29221c377c..cb00c3dff7 100644 --- a/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkMethodBuilder.ts +++ b/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkMethodBuilder.ts @@ -113,14 +113,13 @@ export function buildArkMethodFromArkClass( mtd.setImplementationSignature(methodSignature); mtd.setLine(line + 1); mtd.setColumn(character + 1); + let bodyBuilder = new BodyBuilder(mtd.getSignature(), methodNode, mtd, sourceFile); + mtd.setBodyBuilder(bodyBuilder); } else { mtd.setDeclareSignatures(methodSignature); mtd.setDeclareLinesAndCols([line + 1], [character + 1]); } - let bodyBuilder = new BodyBuilder(mtd.getSignature(), methodNode, mtd, sourceFile); - mtd.setBodyBuilder(bodyBuilder); - if (mtd.hasBuilderDecorator()) { mtd.setViewTree(buildViewTree(mtd)); } else if (declaringClass.hasComponentDecorator() && mtd.getSubSignature().toString() === 'build()' && !mtd.isStatic()) { @@ -430,10 +429,11 @@ export function addInitInConstructor(constructor: ArkMethod): void { if (!thisLocal) { return; } - const blocks = constructor.getCfg()?.getBlocks(); - if (!blocks) { + const cfg = constructor.getCfg(); + if (cfg === undefined) { return; } + const blocks = cfg.getBlocks(); const firstBlockStmts = [...blocks][0].getStmts(); let index = 0; for (let i = 0; i < firstBlockStmts.length; i++) { @@ -454,6 +454,7 @@ export function addInitInConstructor(constructor: ArkMethod): void { const initInvokeStmt = new ArkInvokeStmt( new ArkInstanceInvokeExpr(thisLocal, constructor.getDeclaringArkClass().getInstanceInitMethod().getSignature(), []) ); + initInvokeStmt.setCfg(cfg); firstBlockStmts.splice(index, 0, initInvokeStmt); } diff --git a/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkNamespaceBuilder.ts b/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkNamespaceBuilder.ts index 930a0bba21..b336fe921b 100644 --- a/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkNamespaceBuilder.ts +++ b/ets2panda/linter/arkanalyzer/src/core/model/builder/ArkNamespaceBuilder.ts @@ -69,12 +69,12 @@ export function buildArkNamespace(node: ts.ModuleDeclaration, declaringInstance: // NamespaceDeclaration extends ModuleDeclaration //TODO: Check else if (ts.isModuleDeclaration(node.body)) { - logger.warn('This ModuleBody is an NamespaceDeclaration.'); + logger.trace('This ModuleBody is an NamespaceDeclaration.'); let childNs: ArkNamespace = new ArkNamespace(); buildArkNamespace(node.body, ns, childNs, sourceFile); ns.addNamespace(childNs); } else if (ts.isIdentifier(node.body)) { - logger.warn('ModuleBody is Identifier.'); + logger.warn('ModuleBody is Identifier'); } else { logger.warn('JSDocNamespaceDeclaration found.'); } @@ -108,7 +108,7 @@ function buildNamespaceMembers(node: ts.ModuleBlock, namespace: ArkNamespace, so } // TODO: Check else if (ts.isMethodDeclaration(child)) { - logger.warn('This is a MethodDeclaration in ArkNamespace.'); + logger.trace('This is a MethodDeclaration in ArkNamespace.'); let mthd: ArkMethod = new ArkMethod(); buildArkMethodFromArkClass(child, namespace.getDefaultClass(), mthd, sourceFile); @@ -131,7 +131,7 @@ function buildNamespaceMembers(node: ts.ModuleBlock, namespace: ArkNamespace, so } else if (ts.isVariableStatement(child) && isExported(child.modifiers)) { buildExportVariableStatement(child, sourceFile, namespace.getDeclaringArkFile(), namespace).forEach(item => namespace.addExportInfo(item)); } else { - logger.info('Child joined default method of arkFile: ', ts.SyntaxKind[child.kind]); + logger.trace('Child joined default method of arkFile: ', ts.SyntaxKind[child.kind]); // join default method } }); diff --git a/ets2panda/linter/arkanalyzer/src/core/model/builder/BodyBuilder.ts b/ets2panda/linter/arkanalyzer/src/core/model/builder/BodyBuilder.ts index 77b28a411f..8a6286bd30 100644 --- a/ets2panda/linter/arkanalyzer/src/core/model/builder/BodyBuilder.ts +++ b/ets2panda/linter/arkanalyzer/src/core/model/builder/BodyBuilder.ts @@ -571,6 +571,7 @@ export class BodyBuilder { const closuresLocal = new Local(closuresParam.getName(), lexicalEnv); body.addLocal(closuresLocal.getName(), closuresLocal); let assignStmt = new ArkAssignStmt(closuresLocal, parameterRef); + assignStmt.setCfg(body.getCfg()); stmts.splice(index, 0, assignStmt); closuresLocal.setDeclaringStmt(assignStmt); @@ -590,6 +591,7 @@ export class BodyBuilder { index++; const closureFieldRef = new ClosureFieldRef(closuresParam, closure.getName(), closure.getType()); let assignStmt = new ArkAssignStmt(local, closureFieldRef); + assignStmt.setCfg(body.getCfg()); stmts.splice(index, 0, assignStmt); local.setDeclaringStmt(assignStmt); closuresLocal.addUsedStmt(assignStmt); diff --git a/ets2panda/linter/arkanalyzer/src/save/JsonPrinter.ts b/ets2panda/linter/arkanalyzer/src/save/JsonPrinter.ts index 283de26011..e9c2696bf8 100644 --- a/ets2panda/linter/arkanalyzer/src/save/JsonPrinter.ts +++ b/ets2panda/linter/arkanalyzer/src/save/JsonPrinter.ts @@ -22,20 +22,20 @@ import { ArkField } from '../core/model/ArkField'; import { AliasType, AnnotationNamespaceType, - AnnotationType, AnnotationTypeQueryType, AnyType, ArrayType, BigIntType, BooleanType, ClassType, + EnumValueType, FunctionType, GenericType, + IntersectionType, LiteralType, NeverType, NullType, NumberType, - PrimitiveType, StringType, TupleType, Type, @@ -46,11 +46,16 @@ import { VoidType, } from '../core/base/Type'; import { Value } from '../core/base/Value'; -import { ArkAssignStmt, ArkIfStmt, ArkInvokeStmt, ArkReturnStmt, ArkReturnVoidStmt, ArkThrowStmt, Stmt } from '../core/base/Stmt'; import { - AbstractBinopExpr, - AbstractExpr, - AbstractInvokeExpr, + ArkAssignStmt, + ArkIfStmt, + ArkInvokeStmt, + ArkReturnStmt, + ArkReturnVoidStmt, + ArkThrowStmt, + Stmt, +} from '../core/base/Stmt'; +import { ArkAwaitExpr, ArkCastExpr, ArkConditionExpr, @@ -73,13 +78,12 @@ import { ImportInfo } from '../core/model/ArkImport'; import { ExportInfo } from '../core/model/ArkExport'; import { AliasTypeSignature, ClassSignature, FieldSignature, FileSignature, MethodSignature, NamespaceSignature } from '../core/model/ArkSignature'; import { LineColPosition } from '../core/base/Position'; -import { AbstractFieldRef, AbstractRef, ArkArrayRef, ArkInstanceFieldRef, ArkParameterRef, ArkStaticFieldRef, ArkThisRef } from '../core/base/Ref'; +import { ArkArrayRef, ArkCaughtExceptionRef, ArkInstanceFieldRef, ArkParameterRef, ArkStaticFieldRef, ArkThisRef, ClosureFieldRef, GlobalRef } from '../core/base/Ref'; import { Local } from '../core/base/Local'; import { Cfg } from '../core/graph/Cfg'; import { BasicBlock } from '../core/graph/BasicBlock'; import { ArkBody } from '../core/model/ArkBody'; import { Decorator } from '../core/base/Decorator'; -import util from 'util'; export class JsonPrinter extends Printer { constructor(private arkFile: ArkFile) { @@ -113,8 +117,9 @@ export class JsonPrinter extends Printer { return { signature: this.serializeClassSignature(clazz.getSignature()), modifiers: clazz.getModifiers(), - decorators: clazz.getDecorators().map(decorator => this.serializeDecorator(decorator)), - typeParameters: clazz.getGenericsTypes()?.map(type => this.serializeType(type)), + decorators: clazz.getDecorators().map((decorator) => this.serializeDecorator(decorator)), + typeParameters: clazz.getGenericsTypes()?.map((type) => this.serializeType(type)), + category: clazz.getCategory(), superClassName: clazz.getSuperClassName(), implementedInterfaceNames: clazz.getImplementedInterfaceNames(), fields: clazz.getFields().map(field => this.serializeField(field)), @@ -155,6 +160,7 @@ export class JsonPrinter extends Printer { name: parameter.getName(), type: this.serializeType(parameter.getType()), isOptional: parameter.isOptional(), + isRest: parameter.hasDotDotDotToken(), }; } @@ -220,6 +226,11 @@ export class JsonPrinter extends Printer { _: 'UnionType', types: type.getTypes().map(type => this.serializeType(type)), }; + } else if (type instanceof IntersectionType) { + return { + _: 'IntersectionType', + types: type.getTypes().map((type) => this.serializeType(type)), + }; } else if (type instanceof TupleType) { return { _: 'TupleType', @@ -254,8 +265,6 @@ export class JsonPrinter extends Printer { _: 'LiteralType', literal: type.getLiteralName(), }; - } else if (type instanceof PrimitiveType) { - throw new Error('Unhandled PrimitiveType: ' + util.inspect(type, { showHidden: true, depth: null })); } else if (type instanceof ClassType) { return { _: 'ClassType', @@ -281,13 +290,13 @@ export class JsonPrinter extends Printer { typeParameters: type.getGenericTypes().map(type => this.serializeType(type)), }; } else if (type instanceof GenericType) { - let defaultType = type.getDefaultType(); let constraint = type.getConstraint(); + let defaultType = type.getDefaultType(); return { _: 'GenericType', name: type.getName(), - defaultType: defaultType && this.serializeType(defaultType), constraint: constraint && this.serializeType(constraint), + defaultType: defaultType && this.serializeType(defaultType), }; } else if (type instanceof AliasType) { return { @@ -307,10 +316,19 @@ export class JsonPrinter extends Printer { _: 'AnnotationTypeQueryType', originType: type.getOriginType(), }; - } else if (type instanceof AnnotationType) { - throw new Error('Unhandled AnnotationType: ' + util.inspect(type, { showHidden: true, depth: null })); + } else if (type instanceof EnumValueType) { + const c = type.getConstant(); + return { + _: 'EnumValueType', + signature: this.serializeFieldSignature(type.getFieldSignature()), + constant: c && this.serializeValue(c), + }; } else { - throw new Error('Unhandled Type: ' + util.inspect(type, { showHidden: true, depth: null })); + console.warn(`Unhandled Type: ${type.constructor.name} (${type.toString()})`); + return { + _: type.constructor.name, + text: type.toString(), + }; } } @@ -415,6 +433,13 @@ export class JsonPrinter extends Printer { }; } + private serializeConstant(constant: Constant): object { + return { + value: constant.getValue(), + type: this.serializeType(constant.getType()), + }; + } + private serializeValue(value: Value): object { if (value === undefined) { throw new Error('Value is undefined'); @@ -428,8 +453,7 @@ export class JsonPrinter extends Printer { } else if (value instanceof Constant) { return { _: 'Constant', - value: value.getValue(), - type: this.serializeType(value.getType()), + ...this.serializeConstant(value), }; } else if (value instanceof ArkNewExpr) { return { @@ -498,8 +522,6 @@ export class JsonPrinter extends Printer { left: this.serializeValue(value.getOp1()), right: this.serializeValue(value.getOp2()), }; - } else if (value instanceof AbstractBinopExpr) { - return new Error('Unhandled BinopExpr: ' + util.inspect(value, { showHidden: true, depth: null })); } else if (value instanceof ArkUnopExpr) { return { _: 'UnopExpr', @@ -526,8 +548,6 @@ export class JsonPrinter extends Printer { method: this.serializeMethodSignature(value.getMethodSignature()), args: value.getArgs().map(arg => this.serializeValue(arg)), }; - } else if (value instanceof AbstractInvokeExpr) { - throw new Error('Unhandled CallExpr: ' + util.inspect(value, { showHidden: true, depth: null })); } else if (value instanceof ArkThisRef) { return { _: 'ThisRef', @@ -546,6 +566,25 @@ export class JsonPrinter extends Printer { index: this.serializeValue(value.getIndex()), type: this.serializeType(value.getType()), }; + } else if (value instanceof ArkCaughtExceptionRef) { + return { + _: 'CaughtExceptionRef', + type: this.serializeType(value.getType()), + }; + } else if (value instanceof GlobalRef) { + let ref = value.getRef(); + return { + _: 'GlobalRef', + name: value.getName(), + ref: ref ? this.serializeValue(ref) : null, + }; + } else if (value instanceof ClosureFieldRef) { + return { + _: 'ClosureFieldRef', + base: this.serializeLocal(value.getBase()), + fieldName: value.getFieldName(), + type: this.serializeType(value.getType()), + }; } else if (value instanceof ArkInstanceFieldRef) { return { _: 'InstanceFieldRef', @@ -557,14 +596,13 @@ export class JsonPrinter extends Printer { _: 'StaticFieldRef', field: this.serializeFieldSignature(value.getFieldSignature()), }; - } else if (value instanceof AbstractFieldRef) { - throw new Error('Unhandled FieldRef: ' + util.inspect(value, { showHidden: true, depth: null })); - } else if (value instanceof AbstractRef) { - throw new Error('Unhandled Ref: ' + util.inspect(value, { showHidden: true, depth: null })); - } else if (value instanceof AbstractExpr) { - throw new Error('Unhandled Expr: ' + util.inspect(value, { showHidden: true, depth: null })); } else { - throw new Error('Unhandled Value: ' + util.inspect(value, { showHidden: true, depth: null })); + console.warn(`Unhandled Value: ${value.constructor.name} (${value.toString()})`); + return { + _: value.constructor.name, + text: value.toString(), + type: this.serializeType(value.getType()), + }; } } @@ -600,7 +638,11 @@ export class JsonPrinter extends Printer { arg: this.serializeValue(stmt.getOp()), }; } else { - throw new Error('Unhandled Stmt: ' + util.inspect(stmt, { showHidden: true, depth: null })); + console.warn(`Unhandled Stmt: ${stmt.constructor.name} (${stmt.toString()})`); + return { + _: stmt.constructor.name, + text: stmt.toString(), + }; } } } diff --git a/ets2panda/linter/arkanalyzer/src/utils/SparseBitVector.ts b/ets2panda/linter/arkanalyzer/src/utils/SparseBitVector.ts index fcb5c816ac..313fb88f35 100644 --- a/ets2panda/linter/arkanalyzer/src/utils/SparseBitVector.ts +++ b/ets2panda/linter/arkanalyzer/src/utils/SparseBitVector.ts @@ -538,7 +538,6 @@ export class SparseBitVector { return changed; } - // Dump as string toString(): string { let ar = [...this]; return ar.toString(); diff --git a/ets2panda/linter/arkanalyzer/typedoc.json b/ets2panda/linter/arkanalyzer/typedoc.json index 1b08d68d69..e582cf129b 100644 --- a/ets2panda/linter/arkanalyzer/typedoc.json +++ b/ets2panda/linter/arkanalyzer/typedoc.json @@ -16,6 +16,7 @@ ], "excludeInternal": true, "useTsLinkResolution": true, + "plugin": "typedoc-plugin-markdown", "out": "docs/api_docs", "readme": "./README.en.md" } \ No newline at end of file diff --git a/ets2panda/linter/homecheck/src/Index.ts b/ets2panda/linter/homecheck/src/Index.ts index 6ad78b6bfe..b3228e9bd5 100644 --- a/ets2panda/linter/homecheck/src/Index.ts +++ b/ets2panda/linter/homecheck/src/Index.ts @@ -42,4 +42,4 @@ export { Utils } from './utils/common/Utils'; // tools export { runTool, Tools } from './tools/toolEntry'; -export { MigrationTool } from './tools/migrationTool/MigrationTool'; +export { MigrationTool } from './tools/migrationTool/MigrationTool'; \ No newline at end of file diff --git a/ets2panda/linter/homecheck/src/checker/migration/AppStorageGetCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/AppStorageGetCheck.ts index 693f891412..8e1ef29f16 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/AppStorageGetCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/AppStorageGetCheck.ts @@ -139,7 +139,7 @@ export class AppStorageGetCheck implements BaseChecker { } private getLineAndColumn(stmt: Stmt, operand: Value): WarnInfo { - const arkFile = stmt.getCfg()?.getDeclaringMethod().getDeclaringArkFile(); + const arkFile = stmt.getCfg().getDeclaringMethod().getDeclaringArkFile(); const originPosition = stmt.getOperandOriginalPosition(operand); if (arkFile && originPosition) { const originPath = arkFile.getFilePath(); diff --git a/ets2panda/linter/homecheck/src/checker/migration/CustomBuilderCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/CustomBuilderCheck.ts index b8dcb06db7..ac46794b55 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/CustomBuilderCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/CustomBuilderCheck.ts @@ -208,7 +208,7 @@ export class CustomBuilderCheck implements BaseChecker { } private getLineAndColumn(stmt: Stmt, operand: Value): WarnInfo { - const arkFile = stmt.getCfg()?.getDeclaringMethod().getDeclaringArkFile(); + const arkFile = stmt.getCfg().getDeclaringMethod().getDeclaringArkFile(); const originPosition = stmt.getOperandOriginalPosition(operand); if (arkFile && originPosition) { const originPath = arkFile.getFilePath(); @@ -229,7 +229,7 @@ export class CustomBuilderCheck implements BaseChecker { fixPosition.endLine = endPosition.line; fixPosition.endCol = endPosition.col; } - const arkFile = stmt.getCfg()?.getDeclaringMethod().getDeclaringArkFile(); + const arkFile = stmt.getCfg().getDeclaringMethod().getDeclaringArkFile(); const sourceFile = AstTreeUtils.getASTNode(arkFile.getName(), arkFile.getCode()); const range = FixUtils.getRangeWithAst(sourceFile, fixPosition); ruleFix.range = range; diff --git a/ets2panda/linter/homecheck/src/checker/migration/InteropAssignCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/InteropAssignCheck.ts index d956fe529c..a17b9064ba 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/InteropAssignCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/InteropAssignCheck.ts @@ -98,7 +98,7 @@ export class InteropAssignCheck implements BaseChecker { callsites.forEach(cs => { let hasTargetArg = false; const invoke = cs.getInvokeExpr()!; - const csMethod = cs.getCfg()?.getDeclaringMethod(); + const csMethod = cs.getCfg().getDeclaringMethod(); invoke.getArgs().forEach(arg => { const argTy = arg.getType(); if (argTy instanceof PrimitiveType || this.isBoxedType(argTy)) { @@ -149,7 +149,7 @@ export class InteropAssignCheck implements BaseChecker { const desc = `${this.metaData.description} (${RULE_ID})`; const severity = this.metaData.severity; const ruleId = this.rule.ruleId; - const filePath = assign.getCfg()?.getDeclaringMethod().getDeclaringArkFile()?.getFilePath() ?? ''; + const filePath = assign.getCfg().getDeclaringMethod().getDeclaringArkFile()?.getFilePath() ?? ''; const defeats = new Defects(line, column, column, problem, desc, severity, ruleId, filePath, '', true, false, false); this.issues.push(new IssueReport(defeats, undefined)); }); @@ -265,8 +265,6 @@ export class InteropAssignCheck implements BaseChecker { } if (file) { return file.getLanguage(); - } else { - logger.error(`fail to identify which file the type definition ${type.toString()} is in.`); } return undefined; } diff --git a/ets2panda/linter/homecheck/src/checker/migration/InteropBackwardDFACheck.ts b/ets2panda/linter/homecheck/src/checker/migration/InteropBackwardDFACheck.ts index 9651894a32..85a045b7f0 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/InteropBackwardDFACheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/InteropBackwardDFACheck.ts @@ -214,7 +214,7 @@ export class InteropBackwardDFACheck implements BaseChecker { private reportIssue(objDefInfo: ObjDefInfo, apiLang: Language, isReflect: boolean) { const problemStmt = objDefInfo.problemStmt; - const problemStmtMtd = problemStmt.getCfg()?.getDeclaringMethod(); + const problemStmtMtd = problemStmt.getCfg().getDeclaringMethod(); const problemStmtLang = problemStmtMtd?.getLanguage(); const objLanguage = objDefInfo.objLanguage; if (objLanguage === Language.UNKNOWN || problemStmtLang === Language.UNKNOWN) { diff --git a/ets2panda/linter/homecheck/src/checker/migration/InteropBoxedTypeCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/InteropBoxedTypeCheck.ts index 42b4dc0973..d0a1c9b10f 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/InteropBoxedTypeCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/InteropBoxedTypeCheck.ts @@ -40,7 +40,7 @@ import { WarnInfo } from '../../utils/common/Utils'; import { Language } from 'arkanalyzer/lib/core/model/ArkFile'; import { getLanguageStr } from './Utils'; -const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'ObservedDecoratorCheck'); +const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'InteropBoxedTypeCheck'); const gMetaData: BaseMetaData = { severity: 1, ruleDocPath: '', diff --git a/ets2panda/linter/homecheck/src/checker/migration/InteropJSModifyPropertyCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/InteropJSModifyPropertyCheck.ts index 3b912361f2..16ea7584bc 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/InteropJSModifyPropertyCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/InteropJSModifyPropertyCheck.ts @@ -276,10 +276,8 @@ export class InteropJSModifyPropertyCheck implements BaseChecker { } if (file) { return file.getLanguage(); - } else { - logger.error(`fail to identify which file the type definition ${type.toString()} is in.`); - return Language.UNKNOWN; } + return Language.UNKNOWN; } private reportIssue(problemStmt: Stmt) { @@ -289,7 +287,7 @@ export class InteropJSModifyPropertyCheck implements BaseChecker { const desc = `${this.metaData.description} (${RULE_ID})`; const severity = this.metaData.severity; const ruleId = this.rule.ruleId; - const filePath = problemStmt.getCfg()?.getDeclaringMethod().getDeclaringArkFile()?.getFilePath() ?? ''; + const filePath = problemStmt.getCfg().getDeclaringMethod().getDeclaringArkFile()?.getFilePath() ?? ''; const defeats = new Defects( line, column, diff --git a/ets2panda/linter/homecheck/src/checker/migration/ModifyStateVarCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/ModifyStateVarCheck.ts index c25cc59611..dfabd40fe0 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/ModifyStateVarCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/ModifyStateVarCheck.ts @@ -171,7 +171,7 @@ export class ModifyStateVarCheck implements BaseChecker { } private getLineAndColumn(stmt: Stmt, operand: Value): WarnInfo { - const arkFile = stmt.getCfg()?.getDeclaringMethod().getDeclaringArkFile(); + const arkFile = stmt.getCfg().getDeclaringMethod().getDeclaringArkFile(); const originPosition = stmt.getOperandOriginalPosition(operand); if (arkFile && originPosition) { const originPath = arkFile.getFilePath(); diff --git a/ets2panda/linter/homecheck/src/checker/migration/NoTSLikeAsCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/NoTSLikeAsCheck.ts index f45c63723c..7375978f11 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/NoTSLikeAsCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/NoTSLikeAsCheck.ts @@ -37,6 +37,11 @@ import { BasicBlock, ArkIfStmt, ArkUnopExpr, + RelationalBinaryOperator, + LineColPosition, + UnaryOperator, + ArkNormalBinopExpr, + NormalBinaryOperator, } from 'arkanalyzer/lib'; import Logger, { LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger'; import { BaseChecker, BaseMetaData } from '../BaseChecker'; @@ -47,6 +52,7 @@ import { CALL_DEPTH_LIMIT, getGlobalsDefineInDefaultMethod, GlobalCallGraphHelpe import { WarnInfo } from '../../utils/common/Utils'; import { ClassCategory } from 'arkanalyzer/lib/core/model/ArkClass'; import { Language } from 'arkanalyzer/lib/core/model/ArkFile'; +import { BooleanConstant } from 'arkanalyzer/lib/core/base/Constant'; const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'NoTSLikeAsCheck'); const gMetaData: BaseMetaData = { @@ -55,6 +61,12 @@ const gMetaData: BaseMetaData = { description: '', }; +enum TypeAssuranceCondition { + Positive, + Negative, + NotExist, +} + export class NoTSLikeAsCheck implements BaseChecker { readonly metaData: BaseMetaData = gMetaData; public rule: Rule; @@ -181,21 +193,19 @@ export class NoTSLikeAsCheck implements BaseChecker { return false; } for (const block of cfg.getBlocks()) { - // 这里仅判断了cast op是否进行了instanceof判断,如果op是由op1赋值,op1进行了instanceof判断,此处不认为是做了有效检查 - // TODO: 还需进行复杂条件中包含类型守卫判断的情况,涉及&&,||等的复合 - const positiveCheck = this.isCastExprWithTypeAssurancePositive(block, castExpr); - const negativeCheck = this.isCastExprWithTypeAssuranceNegative(block, castExpr); - if (!(positiveCheck || negativeCheck)) { + // 这里仅判断了cast op是否进行了instanceof判断,如果op是由op1赋值,op1进行了instanceof判断,此处不认为是做了有效检查,因为此赋值链可能很长且中途发生类型变化,极易判断错误 + const checkRes = this.checkTypeAssuranceInBasicBlock(block, castExpr); + if (checkRes === TypeAssuranceCondition.NotExist) { continue; } let checkedBB: Set = new Set(); let needCheckBB: number[] = []; checkedBB.add(block.getId()); const allSuccessors = block.getSuccessors(); - if (allSuccessors.length > 0 && positiveCheck) { + if (allSuccessors.length > 0 && checkRes === TypeAssuranceCondition.Positive) { needCheckBB.push(allSuccessors[0].getId()); } - if (allSuccessors.length > 1 && negativeCheck) { + if (allSuccessors.length > 1 && checkRes === TypeAssuranceCondition.Negative) { needCheckBB.push(allSuccessors[1].getId()); } while (needCheckBB.length > 0) { @@ -221,26 +231,7 @@ export class NoTSLikeAsCheck implements BaseChecker { return false; } - private isStmtInBlock(stmt: Stmt, block: BasicBlock): boolean { - for (const s of block.getStmts()) { - if (s === stmt) { - return true; - } - } - return false; - } - - private getBlockWithId(id: number, cfg: Cfg): BasicBlock | null { - const blocks = cfg.getBlocks(); - for (const bb of blocks) { - if (bb.getId() === id) { - return bb; - } - } - return null; - } - - private isCastExprWithTypeAssurancePositive(bb: BasicBlock, castExpr: ArkCastExpr): boolean { + private checkTypeAssuranceInBasicBlock(bb: BasicBlock, castExpr: ArkCastExpr): TypeAssuranceCondition { for (const stmt of bb.getStmts()) { if (!(stmt instanceof ArkIfStmt)) { continue; @@ -248,98 +239,109 @@ export class NoTSLikeAsCheck implements BaseChecker { const conditionExpr = stmt.getConditionExpr(); const op1 = conditionExpr.getOp1(); const op2 = conditionExpr.getOp2(); - if (op1 instanceof Local) { - const declareStmt = op1.getDeclaringStmt(); - if (declareStmt !== null && this.isStmtWithTypeAssurancePositive(declareStmt, castExpr)) { - return true; - } - } - if (op2 instanceof Local) { - const declareStmt = op2.getDeclaringStmt(); - if (declareStmt !== null && this.isStmtWithTypeAssurancePositive(declareStmt, castExpr)) { - return true; - } + const operator = conditionExpr.getOperator(); + // 对于if (i instanceof A)这种条件语句,op1总是临时变量,op2总是false,操作符总是!= + if (!(op1 instanceof Local && op2 instanceof BooleanConstant && op2.getValue() === 'false' && operator === RelationalBinaryOperator.InEquality)) { + break; } + return this.checkTypeAssuranceWithLocal(op1, castExpr, stmt.getOriginPositionInfo(), true); } - return false; + return TypeAssuranceCondition.NotExist; } - private isCastExprWithTypeAssuranceNegative(bb: BasicBlock, castExpr: ArkCastExpr): boolean { - for (const stmt of bb.getStmts()) { - if (!(stmt instanceof ArkIfStmt)) { - continue; + private checkTypeAssuranceWithLocal(operand: Local, castExpr: ArkCastExpr, ifStmtPos: LineColPosition, shouldBe: boolean): TypeAssuranceCondition { + const declaringStmt = operand.getDeclaringStmt(); + if (declaringStmt === null) { + return TypeAssuranceCondition.NotExist; + } + // if语句中的所有条件遵从三地址码原则拆分成多个语句时,所有语句的位置信息是一致的,不一致时表示是条件语句之前的赋值或声明情况,不在本判断范围内 + const stmtPos = declaringStmt.getOriginPositionInfo(); + if (stmtPos.getLineNo() !== ifStmtPos.getLineNo() || stmtPos.getColNo() !== ifStmtPos.getColNo()) { + return TypeAssuranceCondition.NotExist; + } + if (!(declaringStmt instanceof ArkAssignStmt)) { + return TypeAssuranceCondition.NotExist; + } + const rightOp = declaringStmt.getRightOp(); + if (rightOp instanceof ArkInstanceOfExpr) { + if (this.isTypeAssuranceMatchCast(rightOp, castExpr)) { + if (shouldBe) { + return TypeAssuranceCondition.Positive; + } else { + return TypeAssuranceCondition.Negative; + } } - const conditionExpr = stmt.getConditionExpr(); - const op1 = conditionExpr.getOp1(); - const op2 = conditionExpr.getOp2(); - if (op1 instanceof Local) { - const declareStmt = op1.getDeclaringStmt(); - if (declareStmt !== null && this.isStmtWithTypeAssuranceNegative(declareStmt, castExpr)) { - return true; + return TypeAssuranceCondition.NotExist; + } + if (rightOp instanceof ArkUnopExpr && rightOp.getOperator() === UnaryOperator.LogicalNot) { + const unaryOp = rightOp.getOp(); + if (unaryOp instanceof Local) { + return this.checkTypeAssuranceWithLocal(unaryOp, castExpr, ifStmtPos, !shouldBe); + } + return TypeAssuranceCondition.NotExist; + } + if (rightOp instanceof ArkNormalBinopExpr) { + const op1 = rightOp.getOp1(); + const op2 = rightOp.getOp2(); + const operator = rightOp.getOperator(); + // 这里仅判断&&和||两种逻辑运算符的场景,其他场景在包含类型守卫判断的条件语句中不常见,暂不考虑 + let res: TypeAssuranceCondition; + if (operator === NormalBinaryOperator.LogicalAnd) { + if (op1 instanceof Local) { + res = this.checkTypeAssuranceWithLocal(op1, castExpr, ifStmtPos, shouldBe); + if (res !== TypeAssuranceCondition.NotExist) { + return res; + } } + if (op2 instanceof Local) { + res = this.checkTypeAssuranceWithLocal(op2, castExpr, ifStmtPos, shouldBe); + if (res !== TypeAssuranceCondition.NotExist) { + return res; + } + } + return TypeAssuranceCondition.NotExist; } - if (op2 instanceof Local) { - const declareStmt = op2.getDeclaringStmt(); - if (declareStmt !== null && this.isStmtWithTypeAssuranceNegative(declareStmt, castExpr)) { - return true; + if (operator === NormalBinaryOperator.LogicalOr) { + // a or b,不论a或b里是类型守卫判断,均无法保证分支中的类型明确 + if (shouldBe) { + return TypeAssuranceCondition.NotExist; } } } - return false; + return TypeAssuranceCondition.NotExist; } - private isStmtWithTypeAssurancePositive(declareStmt: Stmt, castExpr: ArkCastExpr): boolean { - if (!(declareStmt instanceof ArkAssignStmt)) { - return false; - } - const rightOp = declareStmt.getRightOp(); - if (!(rightOp instanceof ArkInstanceOfExpr)) { - return false; - } + private isTypeAssuranceMatchCast(instanceOfExpr: ArkInstanceOfExpr, castExpr: ArkCastExpr): boolean { const castOp = castExpr.getOp(); const castType = castExpr.getType(); - const instanceofType = rightOp.getCheckType(); + const instanceofType = instanceOfExpr.getCheckType(); if (castType.getTypeString() !== instanceofType.getTypeString()) { return false; } - const instanceofOp = rightOp.getOp(); + const instanceofOp = instanceOfExpr.getOp(); if (!(castOp instanceof Local && instanceofOp instanceof Local)) { return false; } return castOp.getName() === instanceofOp.getName(); } - private isStmtWithTypeAssuranceNegative(declareStmt: Stmt, castExpr: ArkCastExpr): boolean { - if (!(declareStmt instanceof ArkAssignStmt)) { - return false; - } - const rightOp = declareStmt.getRightOp(); - if (!(rightOp instanceof ArkUnopExpr && rightOp.getOperator() === '!')) { - return false; - } - const unaryOp = rightOp.getOp(); - if (!(unaryOp instanceof Local)) { - return false; - } - const unaryOpDeclareStmt = unaryOp.getDeclaringStmt(); - if (unaryOpDeclareStmt === null || !(unaryOpDeclareStmt instanceof ArkAssignStmt)) { - return false; - } - const unaryOpRightOp = unaryOpDeclareStmt.getRightOp(); - if (!(unaryOpRightOp instanceof ArkInstanceOfExpr)) { - return false; - } - const castOp = castExpr.getOp(); - const castType = castExpr.getType(); - const instanceofType = unaryOpRightOp.getCheckType(); - if (castType.getTypeString() !== instanceofType.getTypeString()) { - return false; + private isStmtInBlock(stmt: Stmt, block: BasicBlock): boolean { + for (const s of block.getStmts()) { + if (s === stmt) { + return true; + } } - const instanceofOp = unaryOpRightOp.getOp(); - if (!(castOp instanceof Local && instanceofOp instanceof Local)) { - return false; + return false; + } + + private getBlockWithId(id: number, cfg: Cfg): BasicBlock | null { + const blocks = cfg.getBlocks(); + for (const bb of blocks) { + if (bb.getId() === id) { + return bb; + } } - return castOp.getName() === instanceofOp.getName(); + return null; } private checkFromStmt( @@ -401,9 +403,7 @@ export class NoTSLikeAsCheck implements BaseChecker { const paramRef = this.isFromParameter(currentStmt); if (paramRef) { const paramIdx = paramRef.getIndex(); - const callsites = this.cg.getInvokeStmtByMethod( - currentStmt.getCfg().getDeclaringMethod().getSignature() - ); + const callsites = this.cg.getInvokeStmtByMethod(currentStmt.getCfg().getDeclaringMethod().getSignature()); this.processCallsites(callsites); const argDefs = this.collectArgDefs(paramIdx, callsites); for (const stmt of argDefs) { @@ -568,7 +568,7 @@ export class NoTSLikeAsCheck implements BaseChecker { } private getLineAndColumn(stmt: Stmt, operand: Value): WarnInfo { - const arkFile = stmt.getCfg()?.getDeclaringMethod().getDeclaringArkFile(); + const arkFile = stmt.getCfg().getDeclaringMethod().getDeclaringArkFile(); const originPosition = stmt.getOperandOriginalPosition(operand); if (arkFile && originPosition) { const originPath = arkFile.getFilePath(); diff --git a/ets2panda/linter/homecheck/src/checker/migration/ObjectLiteralCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/ObjectLiteralCheck.ts index 66a5c66380..b582c90aaf 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/ObjectLiteralCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/ObjectLiteralCheck.ts @@ -68,7 +68,7 @@ export class ObjectLiteralCheck implements BaseChecker { for (let arkFile of scene.getFiles()) { const topLevelVarMap: Map = new Map(); - this.collectImportedVar(topLevelVarMap, arkFile); + this.collectImportedVar(topLevelVarMap, arkFile, scene); this.collectTopLevelVar(topLevelVarMap, arkFile, scene); const handleClass = (cls: ArkClass): void => { @@ -106,7 +106,7 @@ export class ObjectLiteralCheck implements BaseChecker { } } - private collectImportedVar(importVarMap: Map, file: ArkFile) { + private collectImportedVar(importVarMap: Map, file: ArkFile, scene: Scene) { file.getImportInfos().forEach(importInfo => { const exportInfo = importInfo.getLazyExportInfo(); if (exportInfo === null) { @@ -120,6 +120,7 @@ export class ObjectLiteralCheck implements BaseChecker { if (!declaringStmt) { return; } + DVFGHelper.buildSingleDVFG(declaringStmt.getCfg().getDeclaringMethod(), scene); importVarMap.set(arkExport.getName(), [declaringStmt]); }); } @@ -382,7 +383,7 @@ export class ObjectLiteralCheck implements BaseChecker { } private getLineAndColumn(stmt: Stmt, operand: Value): WarnInfo { - const arkFile = stmt.getCfg()?.getDeclaringMethod().getDeclaringArkFile(); + const arkFile = stmt.getCfg().getDeclaringMethod().getDeclaringArkFile(); const originPosition = stmt.getOperandOriginalPosition(operand); if (arkFile && originPosition) { const originPath = arkFile.getFilePath(); diff --git a/ets2panda/linter/homecheck/src/checker/migration/ObservedDecoratorCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/ObservedDecoratorCheck.ts index a6a56e9b4d..8f9c5cdb03 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/ObservedDecoratorCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/ObservedDecoratorCheck.ts @@ -266,7 +266,7 @@ export class ObservedDecoratorCheck implements BaseChecker { canFindAllTargets: boolean = true ): string { if (issueClass === null || !canFindAllTargets) { - return `can not find all classes, please check this field manually`; + return `can not find all classes, please check this field manually (arkui-data-observation)`; } const fieldLine = field.getOriginPosition().getLineNo(); const fieldColumn = field.getOriginPosition().getColNo(); @@ -275,10 +275,10 @@ export class ObservedDecoratorCheck implements BaseChecker { const issueClassSig = issueClass.getDeclaringArkFile().getFileSignature(); let res = `but it's not be annotated by @Observed (arkui-data-observation)`; if (fileSignatureCompare(fieldFileSig, issueClassSig)) { - res = `The class is used by state property in [${fieldLine}, ${fieldColumn}], ` + res; + res = `Class ${issueClass.getName()} is used by state property in [${fieldLine}, ${fieldColumn}], ` + res; } else { const filePath = path.normalize(fieldFileSig.getFileName()); - res = `The class is used by state property in file ${filePath} [${fieldLine}, ${fieldColumn}], ` + res; + res = `Class ${issueClass.getName()} is used by state property in file ${filePath} [${fieldLine}, ${fieldColumn}], ` + res; } return res; } diff --git a/ets2panda/linter/homecheck/src/checker/migration/ThisBindCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/ThisBindCheck.ts index af8657687c..b290beab8f 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/ThisBindCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/ThisBindCheck.ts @@ -348,7 +348,7 @@ export class ThisBindCheck implements BaseChecker { } private getLineAndColumn(stmt: ArkAssignStmt, operand: Value): WarnInfo { - const arkFile = stmt.getCfg()?.getDeclaringMethod().getDeclaringArkFile(); + const arkFile = stmt.getCfg().getDeclaringMethod().getDeclaringArkFile(); const originPosition = stmt.getOperandOriginalPosition(operand); if (arkFile && originPosition) { const originPath = arkFile.getFilePath(); diff --git a/ets2panda/linter/homecheck/src/checker/migration/Utils.ts b/ets2panda/linter/homecheck/src/checker/migration/Utils.ts index 0992bcbe88..02f114bd0f 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/Utils.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/Utils.ts @@ -13,7 +13,18 @@ * limitations under the License. */ -import { ArkAssignStmt, ArkMethod, CallGraph, CallGraphBuilder, Local, LOG_MODULE_TYPE, Logger, Scene, Stmt, Value } from 'arkanalyzer/lib'; +import { + ArkAssignStmt, + ArkMethod, + CallGraph, + CallGraphBuilder, + Local, + LOG_MODULE_TYPE, + Logger, + Scene, + Stmt, + Value, +} from 'arkanalyzer/lib'; import { WarnInfo } from '../../utils/common/Utils'; import { Language } from 'arkanalyzer/lib/core/model/ArkFile'; import { DVFG, DVFGNode } from 'arkanalyzer/lib/VFG/DVFG'; @@ -25,6 +36,10 @@ export const CALL_DEPTH_LIMIT = 2; export class CallGraphHelper { private static cgInstance: CallGraph | null = null; + public static dispose(): void { + this.cgInstance = null; + } + public static getCGInstance(scene: Scene): CallGraph { if (!this.cgInstance) { this.cgInstance = new CallGraph(scene); @@ -36,6 +51,10 @@ export class CallGraphHelper { export class GlobalCallGraphHelper { private static cgInstance: CallGraph | null = null; + public static dispose(): void { + this.cgInstance = null; + } + public static getCGInstance(scene: Scene): CallGraph { if (!this.cgInstance) { this.cgInstance = new CallGraph(scene); @@ -51,6 +70,14 @@ export class DVFGHelper { private static dvfgBuilder: DVFGBuilder; private static built: Set = new Set(); + public static dispose(): void { + // @ts-ignore + this.dvfgInstance = null; + // @ts-ignore + this.dvfgBuilder = null; + this.built.clear(); + } + private static createDVFGInstance(scene: Scene): void { if (!this.dvfgInstance) { this.dvfgInstance = new DVFG(GlobalCallGraphHelper.getCGInstance(scene)); @@ -117,7 +144,7 @@ export function getLanguageStr(language: Language): string { } export function getLineAndColumn(stmt: Stmt, operand: Value): WarnInfo { - const arkFile = stmt.getCfg()?.getDeclaringMethod().getDeclaringArkFile(); + const arkFile = stmt.getCfg().getDeclaringMethod().getDeclaringArkFile(); const originPosition = stmt.getOperandOriginalPosition(operand); if (arkFile && originPosition) { const originPath = arkFile.getFilePath(); @@ -126,7 +153,7 @@ export function getLineAndColumn(stmt: Stmt, operand: Value): WarnInfo { const endCol = startCol; return { line, startCol, endCol, filePath: originPath }; } else { - logger.debug('ArkFile is null.'); + logger.debug('ArkFile or operand position is null.'); } return { line: -1, startCol: -1, endCol: -1, filePath: '' }; } diff --git a/ets2panda/linter/homecheck/src/tools/migrationTool/MigrationTool.ts b/ets2panda/linter/homecheck/src/tools/migrationTool/MigrationTool.ts index 5c3f6478ed..7be52a159a 100644 --- a/ets2panda/linter/homecheck/src/tools/migrationTool/MigrationTool.ts +++ b/ets2panda/linter/homecheck/src/tools/migrationTool/MigrationTool.ts @@ -21,7 +21,8 @@ import { CheckerStorage } from '../../utils/common/CheckerStorage'; import Logger, { LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger'; import { FileUtils } from '../../utils/common/FileUtils'; import { DefaultMessage } from '../../model/Message'; -import { FileIssues } from "../../model/Defects"; +import { FileIssues } from '../../model/Defects'; +import { CallGraphHelper, DVFGHelper, GlobalCallGraphHelper } from '../../checker/migration/Utils'; const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'MigrationTool'); @@ -68,7 +69,16 @@ export class MigrationTool { await this.checkEntry.runAll(); let result = this.checkEntry.sortIssues(); + this.dispose(); logger.info(`MigrationTool run end`); return result; } + + private dispose(): void { + CallGraphHelper.dispose(); + GlobalCallGraphHelper.dispose(); + DVFGHelper.dispose(); + CheckerStorage.dispose(); + this.checkEntry.scene.dispose(); + } } \ No newline at end of file diff --git a/ets2panda/linter/homecheck/src/utils/common/CheckerStorage.ts b/ets2panda/linter/homecheck/src/utils/common/CheckerStorage.ts index f3bedd5017..922b716e95 100644 --- a/ets2panda/linter/homecheck/src/utils/common/CheckerStorage.ts +++ b/ets2panda/linter/homecheck/src/utils/common/CheckerStorage.ts @@ -21,6 +21,11 @@ export class CheckerStorage { private apiVersion: number = 16; private product: string = ''; + public static dispose(): void { + // @ts-ignore + this.instance = null; + } + /** * 获取 CheckerStorage 的单例实例 * @returns {CheckerStorage} CheckerStorage 的单例实例 diff --git a/ets2panda/linter/homecheck/src/utils/common/FileUtils.ts b/ets2panda/linter/homecheck/src/utils/common/FileUtils.ts index 48b06a414d..f17425f284 100644 --- a/ets2panda/linter/homecheck/src/utils/common/FileUtils.ts +++ b/ets2panda/linter/homecheck/src/utils/common/FileUtils.ts @@ -232,7 +232,7 @@ export class FileUtils { } private static shouldSkipFile(fileName: string): boolean { - return ['oh_modules', 'node_modules', 'hvigorfile.ts', 'ohosTest'].includes(fileName); + return ['oh_modules', 'node_modules', 'hvigorfile.ts', 'hvigorfile.js', 'hvigor-wrapper.js', 'ohosTest'].includes(fileName); } private static shouldAddFile(filePath: string, exts: string[]): boolean { @@ -310,4 +310,4 @@ export class FileUtils { export enum WriteFileMode { OVERWRITE, APPEND -} \ No newline at end of file +} diff --git a/ets2panda/linter/src/cli/LinterCLI.ts b/ets2panda/linter/src/cli/LinterCLI.ts index 45bd9fddcd..b7c4dc169c 100644 --- a/ets2panda/linter/src/cli/LinterCLI.ts +++ b/ets2panda/linter/src/cli/LinterCLI.ts @@ -58,9 +58,10 @@ async function runIdeInteractiveMode(cmdOptions: CommandLineOptions): Promise Date: Tue, 10 Jun 2025 10:01:14 +0800 Subject: [PATCH 014/209] Update Kfl 0609 Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICDVLQ Signed-off-by: chenlong --- test262/ignored-test262-fastverify-x64-aot-pgo.txt | 3 +++ test262/ignored-test262-other-fastverify-qemu-int.txt | 3 +++ 2 files changed, 6 insertions(+) diff --git a/test262/ignored-test262-fastverify-x64-aot-pgo.txt b/test262/ignored-test262-fastverify-x64-aot-pgo.txt index 3850582fdc..7a848c57ea 100644 --- a/test262/ignored-test262-fastverify-x64-aot-pgo.txt +++ b/test262/ignored-test262-fastverify-x64-aot-pgo.txt @@ -1 +1,4 @@ # Known failure list for test262 - fastverify-x64-aot-pgo + +#19208 +test262/data/test_es2021/language/module-code/instn-iee-err-circular-as.js \ No newline at end of file diff --git a/test262/ignored-test262-other-fastverify-qemu-int.txt b/test262/ignored-test262-other-fastverify-qemu-int.txt index c3f6889c84..4c0ee96b91 100644 --- a/test262/ignored-test262-other-fastverify-qemu-int.txt +++ b/test262/ignored-test262-other-fastverify-qemu-int.txt @@ -57,3 +57,6 @@ test262/data/other_tests/built-ins/Date/prototype/setSeconds/this-value-invalid- #21819 test262/data/other_tests/built-ins/parseFloat/S15.1.2.3_A6.js test262/data/other_tests/built-ins/parseInt/S15.1.2.2_A8.js + +#25907 +test262/data/other_tests/language/expressions/class/elements/syntax/valid/grammar-privatename-classelementname-initializer-alt.js -- Gitee From 75d5646fbe0258f39a691cc18faa202c5bfeb643 Mon Sep 17 00:00:00 2001 From: Tamas Toth Date: Tue, 3 Jun 2025 12:55:24 +0200 Subject: [PATCH 015/209] Throw error when setter return type is void Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICCAJQ Fixes #25831 internal issue Change-Id: I185d3df441f95b639d335c198d12b6b6f4ec1ebf Signed-off-by: Tamas Toth --- ets2panda/parser/ETSparserClasses.cpp | 5 ++++ .../parser/ets/setter_with_return_type.ets | 28 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 ets2panda/test/ast/parser/ets/setter_with_return_type.ets diff --git a/ets2panda/parser/ETSparserClasses.cpp b/ets2panda/parser/ETSparserClasses.cpp index 0876670671..f85dfa2b20 100644 --- a/ets2panda/parser/ETSparserClasses.cpp +++ b/ets2panda/parser/ETSparserClasses.cpp @@ -833,6 +833,11 @@ ir::MethodDefinition *ETSParser::ParseInterfaceGetterSetterMethod(const ir::Modi method->Function()->SetIdent(method->Id()->Clone(Allocator(), nullptr)); method->Function()->AddModifier(method->Modifiers()); + bool hasReturn = method->Function()->ReturnTypeAnnotation() != nullptr; + if (hasReturn && methodKind == ir::MethodDefinitionKind::SET) { + LogError(diagnostic::SETTER_NO_RETURN_TYPE, {}, method->Function()->Range().start); + } + return method; } diff --git a/ets2panda/test/ast/parser/ets/setter_with_return_type.ets b/ets2panda/test/ast/parser/ets/setter_with_return_type.ets new file mode 100644 index 0000000000..6764147803 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/setter_with_return_type.ets @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 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{ + n: number = 42 +} + +interface I{ + get n(): number + set n(v:number):void +} + +class D extends C implements I{ +} + +/* @@? 22:10 Error SyntaxError: Setter must not have return type even if it is void. */ -- Gitee From 8a34bc04bdb28d7c6ee5a7daedc0580def2629bc Mon Sep 17 00:00:00 2001 From: xingshunxiang Date: Sun, 8 Jun 2025 19:29:14 +0800 Subject: [PATCH 016/209] Fix internal class and interface crash Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICDGTU?from=project-issue Description: a bug introduced by ast-cache, we no need to collect the internal class to the record table. Reason: a bug introduced by ast-cache, we no need to collect the internal class to the record table. Tests: ninja tests passed tests/tests-u-runner/runner.sh --ets-cts --show-progress --build-dir x64.release --processes=all passed tests/tests-u-runner/runner.sh --ets-func-tests --show-progress --build-dir x64.release --processes=all passed tests/tests-u-runner/runner.sh --astchecker --show-progress --build-dir x64.release --processes=all passed tests/tests-u-runner/runner.sh --ets-runtime --show-progress --build-dir x64.release --processes=all passed tests/tests-u-runner/runner.sh --parser --no-js --show-progress --build-dir x64.release --processes=all passed Signed-off-by: xingshunxiang --- ets2panda/varbinder/varbinder.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ets2panda/varbinder/varbinder.cpp b/ets2panda/varbinder/varbinder.cpp index 5d754a612a..fc48436145 100644 --- a/ets2panda/varbinder/varbinder.cpp +++ b/ets2panda/varbinder/varbinder.cpp @@ -476,8 +476,7 @@ void VarBinder::VisitScriptFunction(ir::ScriptFunction *func) auto stmt = func->Body()->AsBlockStatement()->Statements(); auto scopeCtx = LexicalScope::Enter(this, funcScope); std::function doNode = [&](ir::AstNode *node) { - if (node->IsTSInterfaceDeclaration() || node->IsClassDeclaration() || node->IsTSEnumDeclaration() || - node->IsAnnotationDeclaration()) { + if (node->IsTSInterfaceDeclaration() || node->IsTSEnumDeclaration()) { ResolveReference(node); } node->Iterate([&](ir::AstNode *child) { doNode(child); }); -- Gitee From 4e2c53c5a6f5ba0b22b7f0a90952de54d7dbb645 Mon Sep 17 00:00:00 2001 From: Boglarka Date: Tue, 3 Jun 2025 14:45:52 +0200 Subject: [PATCH 017/209] Add error for invalid typeof and instanceof Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/IC9IO1 Reason: Typeof keyword in type annotation and instanceof with a type on the left side is invalid. Description: Added checks for these cases and error logging. Change-Id: Iee44ecfe838a60c13738bf54226a0e73c566bd00 Signed-off-by: Haag Boglarka --- ets2panda/checker/ets/validateHelpers.cpp | 7 ++++- ets2panda/parser/ETSparserTypes.cpp | 6 +++++ .../ast/parser/ets/instanceof_on_type.ets | 27 +++++++++++++++++++ .../ast/parser/ets/typeof_in_annotation.ets | 24 +++++++++++++++++ ets2panda/util/diagnostic/syntax.yaml | 8 ++++++ 5 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 ets2panda/test/ast/parser/ets/instanceof_on_type.ets create mode 100644 ets2panda/test/ast/parser/ets/typeof_in_annotation.ets diff --git a/ets2panda/checker/ets/validateHelpers.cpp b/ets2panda/checker/ets/validateHelpers.cpp index f3ad9a385b..bd0a6ceb9b 100644 --- a/ets2panda/checker/ets/validateHelpers.cpp +++ b/ets2panda/checker/ets/validateHelpers.cpp @@ -129,7 +129,8 @@ bool ETSChecker::ValidateBinaryExpressionIdentifier(ir::Identifier *const ident, const auto *const binaryExpr = ident->Parent()->AsBinaryExpression(); bool isFinished = false; - if (binaryExpr->OperatorType() == lexer::TokenType::KEYW_INSTANCEOF && binaryExpr->Left() == ident) { + bool isInstanceOfKeyword = binaryExpr->OperatorType() == lexer::TokenType::KEYW_INSTANCEOF; + if (isInstanceOfKeyword && binaryExpr->Left() == ident) { if (!IsReferenceType(type)) { std::ignore = TypeError(ident->Variable(), diagnostic::INSTANCEOF_NONOBJECT, {ident->Name()}, ident->Start()); @@ -145,6 +146,10 @@ bool ETSChecker::ValidateBinaryExpressionIdentifier(ir::Identifier *const ident, } isFinished = true; } + if (isInstanceOfKeyword && ident->Variable()->HasFlag(varbinder::VariableFlags::CLASS_OR_INTERFACE | + varbinder::VariableFlags::TYPE_ALIAS)) { + LogError(diagnostic::WRONG_LEFT_OF_INSTANCEOF, {}, ident->Start()); + } return isFinished; } diff --git a/ets2panda/parser/ETSparserTypes.cpp b/ets2panda/parser/ETSparserTypes.cpp index fde14c8669..946e7611ed 100644 --- a/ets2panda/parser/ETSparserTypes.cpp +++ b/ets2panda/parser/ETSparserTypes.cpp @@ -540,6 +540,12 @@ bool ETSParser::ParseReadonlyInTypeAnnotation() ir::TypeNode *ETSParser::ParseTypeAnnotation(TypeAnnotationParsingOptions *options) { const auto startPos = Lexer()->GetToken().Start(); + if ((*options & + (TypeAnnotationParsingOptions::DISALLOW_UNION | TypeAnnotationParsingOptions::ANNOTATION_NOT_ALLOW)) == 0 && + Lexer()->TryEatTokenFromKeywordType(lexer::TokenType::KEYW_TYPEOF)) { + LogError(diagnostic::TYPEOF_IN_ANNOTATION); + return AllocBrokenType(Lexer()->GetToken().Loc()); + } // if there is prefix readonly parameter type, change the return result to ETSTypeReference, like Readonly<> if (!Lexer()->TryEatTokenFromKeywordType(lexer::TokenType::KEYW_READONLY)) { return ParseTypeAnnotationNoPreferParam(options); diff --git a/ets2panda/test/ast/parser/ets/instanceof_on_type.ets b/ets2panda/test/ast/parser/ets/instanceof_on_type.ets new file mode 100644 index 0000000000..cb4b9dcc7b --- /dev/null +++ b/ets2panda/test/ast/parser/ets/instanceof_on_type.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 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 X {} +type B = X + +let a = (new X()) instanceof Object +let b = (new X()) instanceof X +let c = X instanceof Object +let d = X instanceof X +let f = B instanceof Object + +/* @@? 21:9 Error SyntaxError: The left operand of 'instanceof' operator cannot be a type. */ +/* @@? 22:9 Error SyntaxError: The left operand of 'instanceof' operator cannot be a type. */ +/* @@? 23:9 Error SyntaxError: The left operand of 'instanceof' operator cannot be a type. */ diff --git a/ets2panda/test/ast/parser/ets/typeof_in_annotation.ets b/ets2panda/test/ast/parser/ets/typeof_in_annotation.ets new file mode 100644 index 0000000000..2ab98e4b55 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/typeof_in_annotation.ets @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 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. + */ + +let n1 = 42 +let s1 = "foo" +let n2: typeof n1 +let s2: typeof s1 + +/* @@? 18:16 Error SyntaxError: Result of 'typeof' operator is not supported to be used as type annotation. */ +/* @@? 18:16 Error SyntaxError: Unexpected token 'n1'. */ +/* @@? 19:16 Error SyntaxError: Result of 'typeof' operator is not supported to be used as type annotation. */ +/* @@? 19:16 Error SyntaxError: Unexpected token 's1'. */ diff --git a/ets2panda/util/diagnostic/syntax.yaml b/ets2panda/util/diagnostic/syntax.yaml index c8550ea251..114c25c8bb 100644 --- a/ets2panda/util/diagnostic/syntax.yaml +++ b/ets2panda/util/diagnostic/syntax.yaml @@ -1243,3 +1243,11 @@ syntax: - name: ERROR_ARKTS_NO_AMBIENT_DECLS id: 308 message: "Ambient module declaration is not supported!" + +- name: TYPEOF_IN_ANNOTATION + id: 309 + message: "Result of 'typeof' operator is not supported to be used as type annotation." + +- name: WRONG_LEFT_OF_INSTANCEOF + id: 310 + message: "The left operand of 'instanceof' operator cannot be a type." -- Gitee From d9672c4eafe7fd25aac679cce4ce187c1bf9818d Mon Sep 17 00:00:00 2001 From: Boglarka Date: Thu, 29 May 2025 10:14:32 +0200 Subject: [PATCH 018/209] Add error for 'as const' Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICBFV0 Reason: Typeof keyword in type annotation and instanceof with a type on the left side is invalid. Description: Added checks for these cases and error logging. Change-Id: Iee44ecfe838a60c13738bf54226a0e73c566bd00 Signed-off-by: Haag Boglarka --- ets2panda/parser/ETSparserExpressions.cpp | 5 ++++- ets2panda/test/ast/parser/ets/string_literal_const_cast.ets | 2 +- ets2panda/util/diagnostic/syntax.yaml | 4 ++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ets2panda/parser/ETSparserExpressions.cpp b/ets2panda/parser/ETSparserExpressions.cpp index 70d4452803..6e2790d75c 100644 --- a/ets2panda/parser/ETSparserExpressions.cpp +++ b/ets2panda/parser/ETSparserExpressions.cpp @@ -584,7 +584,10 @@ ir::Expression *ETSParser::ParsePotentialAsExpression(ir::Expression *primaryExp { ES2PANDA_ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_AS); Lexer()->NextToken(); - + if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CONST) { + LogError(diagnostic::AS_CONST_USAGE); + return nullptr; + } TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR | TypeAnnotationParsingOptions::ANNOTATION_NOT_ALLOW; ir::TypeNode *type = ParseTypeAnnotation(&options); diff --git a/ets2panda/test/ast/parser/ets/string_literal_const_cast.ets b/ets2panda/test/ast/parser/ets/string_literal_const_cast.ets index 899f906944..d265e85557 100644 --- a/ets2panda/test/ast/parser/ets/string_literal_const_cast.ets +++ b/ets2panda/test/ast/parser/ets/string_literal_const_cast.ets @@ -15,7 +15,7 @@ let x = "literal str" as const -/* @@? 16:26 Error SyntaxError: Invalid Type. */ +/* @@? 16:26 Error SyntaxError: 'as const' assertion is not supported. */ /* @@? 16:26 Error SyntaxError: Unexpected token 'const'. */ /* @@? 23:1 Error SyntaxError: Identifier expected, got 'end of stream'. */ /* @@? 23:1 Error SyntaxError: Variable must be initialized or it's type must be declared. */ diff --git a/ets2panda/util/diagnostic/syntax.yaml b/ets2panda/util/diagnostic/syntax.yaml index 114c25c8bb..c414e118a3 100644 --- a/ets2panda/util/diagnostic/syntax.yaml +++ b/ets2panda/util/diagnostic/syntax.yaml @@ -1251,3 +1251,7 @@ syntax: - name: WRONG_LEFT_OF_INSTANCEOF id: 310 message: "The left operand of 'instanceof' operator cannot be a type." + +- name: AS_CONST_USAGE + id: 311 + message: "'as const' assertion is not supported." -- Gitee From e521a6109b48ad79965aefa20f199f5e5592fd4e Mon Sep 17 00:00:00 2001 From: Gabor Aron Takacs Date: Thu, 29 May 2025 13:29:08 +0200 Subject: [PATCH 019/209] Add diagnostics for require and import Fixes #24594 internal issue. Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICBHKQ Change-Id: Iee44ecfe838a60c13738bf54226a0e73c566bd00 Signed-off-by: Gabor Aron Takacs --- ets2panda/checker/ets/object.cpp | 4 ++++ ets2panda/parser/ETSparser.cpp | 8 +++++++ .../test/ast/parser/ets/import_assertion.ets | 22 +++++++++++++++++++ .../test/ast/parser/ets/import_require.ets | 21 ++++++++++++++++++ .../parser/ets/interface_extends_class.ets | 20 +++++++++++++++++ ets2panda/util/diagnostic/semantic.yaml | 4 ++++ ets2panda/util/diagnostic/syntax.yaml | 8 +++++++ 7 files changed, 87 insertions(+) create mode 100644 ets2panda/test/ast/parser/ets/import_assertion.ets create mode 100644 ets2panda/test/ast/parser/ets/import_require.ets create mode 100644 ets2panda/test/ast/parser/ets/interface_extends_class.ets diff --git a/ets2panda/checker/ets/object.cpp b/ets2panda/checker/ets/object.cpp index b656a25717..b4fa16bc27 100644 --- a/ets2panda/checker/ets/object.cpp +++ b/ets2panda/checker/ets/object.cpp @@ -188,6 +188,10 @@ bool ETSChecker::ComputeSuperType(ETSObjectType *type) void ETSChecker::ValidateImplementedInterface(ETSObjectType *type, Type *interface, std::unordered_set *extendsSet, const lexer::SourcePosition &pos) { + if (interface->IsETSObjectType() && interface->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::CLASS)) { + LogError(diagnostic::INTERFACE_EXTENDS_CLASS, {}, pos); + return; + } if (!interface->IsETSObjectType() || !interface->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INTERFACE)) { LogError(diagnostic::NOT_INTERFACE, {}, pos); return; diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 36001a7946..9a591d8e19 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -1191,6 +1191,10 @@ ir::ETSImportDeclaration *ETSParser::ParseImportPathBuildImport(ArenaVector(GetContext().GetProgram()), importFlags); importDeclaration->SetRange({startLoc, importPathStringLiteral->End()}); + if (Lexer()->GetToken().Ident().Is("assert")) { + LogError(diagnostic::ERROR_ARKTS_NO_IMPORT_ASSERTIONS); + return importDeclaration; + } ConsumeSemicolon(importDeclaration); return importDeclaration; } @@ -1494,6 +1498,10 @@ ir::AstNode *ETSParser::ParseImportDefaultSpecifier(ArenaVector * } } + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { + LogError(diagnostic::ERROR_ARKTS_NO_REQUIRE); + return nullptr; + } if (Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_FROM) { LogExpectedToken(lexer::TokenType::KEYW_FROM); Lexer()->NextToken(); // eat 'from' diff --git a/ets2panda/test/ast/parser/ets/import_assertion.ets b/ets2panda/test/ast/parser/ets/import_assertion.ets new file mode 100644 index 0000000000..bbf4ed4a28 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/import_assertion.ets @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025 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. + */ + +import * as Pt from "mod" /* @@ label1 */assert /* @@ label2 */{ type: /* @@ label3 */"json" } + + +/* @@@ label1 Error SyntaxError: Import assertion is not supported, please use the ordinary import syntax instead! */ +/* @@@ label1 Error TypeError: Unresolved reference assert */ +/* @@@ label2 Error SyntaxError: Unexpected token '{'. */ +/* @@@ label3 Error SyntaxError: Label must be followed by a loop statement. */ diff --git a/ets2panda/test/ast/parser/ets/import_require.ets b/ets2panda/test/ast/parser/ets/import_require.ets new file mode 100644 index 0000000000..ad8766f57b --- /dev/null +++ b/ets2panda/test/ast/parser/ets/import_require.ets @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 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. + */ + +import m /* @@ label1 */= /* @@ label2 */require("mod") + +/* @@@ label1 Error SyntaxError: Importing by 'require' and 'import' assignment is not supported, use 'import * as ... from ...' form instead! */ +/* @@@ label1 Error SyntaxError: Unexpected token '='. */ +/* @@@ label2 Error SyntaxError: Unexpected token 'require'. */ +/* @@@ label2 Error TypeError: Unresolved reference require */ diff --git a/ets2panda/test/ast/parser/ets/interface_extends_class.ets b/ets2panda/test/ast/parser/ets/interface_extends_class.ets new file mode 100644 index 0000000000..6e88716f0c --- /dev/null +++ b/ets2panda/test/ast/parser/ets/interface_extends_class.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 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 A {} + +interface BInterface extends /* @@ label */A {} + +/* @@@ label Error TypeError: Interfaces cannot extend classes, only other interfaces. */ diff --git a/ets2panda/util/diagnostic/semantic.yaml b/ets2panda/util/diagnostic/semantic.yaml index 7565ace3dd..f9f32109e0 100644 --- a/ets2panda/util/diagnostic/semantic.yaml +++ b/ets2panda/util/diagnostic/semantic.yaml @@ -1474,3 +1474,7 @@ semantic: - name: SUPER_NOT_ACCESSIBLE id: 372 message: "Class field '{}' defined by the parent class is not accessible in the child class via super." + +- name: INTERFACE_EXTENDS_CLASS + id: 373 + message: "Interfaces cannot extend classes, only other interfaces." diff --git a/ets2panda/util/diagnostic/syntax.yaml b/ets2panda/util/diagnostic/syntax.yaml index c414e118a3..9187a67b9b 100644 --- a/ets2panda/util/diagnostic/syntax.yaml +++ b/ets2panda/util/diagnostic/syntax.yaml @@ -1255,3 +1255,11 @@ syntax: - name: AS_CONST_USAGE id: 311 message: "'as const' assertion is not supported." + +- name: ERROR_ARKTS_NO_REQUIRE + id: 312 + message: "Importing by 'require' and 'import' assignment is not supported, use 'import * as ... from ...' form instead!" + +- name: ERROR_ARKTS_NO_IMPORT_ASSERTIONS + id: 313 + message: "Import assertion is not supported, please use the ordinary import syntax instead!" -- Gitee From 9459de149bd5b2fd62e819a94918ea402678daae Mon Sep 17 00:00:00 2001 From: "peter.pronai" Date: Mon, 26 May 2025 10:12:58 +0000 Subject: [PATCH 020/209] Add diagnostic for generator function Fixes #24865 internal issue. Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICAN1E Change-Id: Iee44ecfe838a60c13738bf54226a0e73c566bd00 Signed-off-by: peter.pronai --- ets2panda/parser/ETSparser.cpp | 1 + .../test/ast/parser/ets/generator_function.ets | 17 +++++++++++++++++ ets2panda/util/diagnostic/syntax.yaml | 4 ++++ 3 files changed, 22 insertions(+) create mode 100644 ets2panda/test/ast/parser/ets/generator_function.ets diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 9a591d8e19..d1ce81f9f8 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -2121,6 +2121,7 @@ ir::FunctionDeclaration *ETSParser::ParseFunctionDeclaration(bool canBeAnonymous } if (Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_MULTIPLY)) { + LogError(diagnostic::GENERATOR_FUNCTION); newStatus |= ParserStatus::GENERATOR_FUNCTION; } diff --git a/ets2panda/test/ast/parser/ets/generator_function.ets b/ets2panda/test/ast/parser/ets/generator_function.ets new file mode 100644 index 0000000000..7f865bb644 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/generator_function.ets @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2025 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. + */ + +function* f() {} +/* @@? 16:11 Error SyntaxError: Generator functions are not supported, please use async/await mechanism for multitasking */ diff --git a/ets2panda/util/diagnostic/syntax.yaml b/ets2panda/util/diagnostic/syntax.yaml index 9187a67b9b..049af2e5ec 100644 --- a/ets2panda/util/diagnostic/syntax.yaml +++ b/ets2panda/util/diagnostic/syntax.yaml @@ -1263,3 +1263,7 @@ syntax: - name: ERROR_ARKTS_NO_IMPORT_ASSERTIONS id: 313 message: "Import assertion is not supported, please use the ordinary import syntax instead!" + +- name: GENERATOR_FUNCTION + id: 314 + message: "Generator functions are not supported, please use async/await mechanism for multitasking" -- Gitee From 9935e7c06caae29d2e133e3345fcc8928ce8e148 Mon Sep 17 00:00:00 2001 From: oh-rgx Date: Thu, 5 Jun 2025 17:24:41 +0800 Subject: [PATCH 021/209] fix diagnostic flush Issue: #ICDC8T Signed-off-by: oh-rgx --- ets2panda/public/es2panda_lib.cpp | 10 +--------- .../ast_verifier_check_struct_declaration_test.cpp | 2 +- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/ets2panda/public/es2panda_lib.cpp b/ets2panda/public/es2panda_lib.cpp index 14a173532e..3ba94058e7 100644 --- a/ets2panda/public/es2panda_lib.cpp +++ b/ets2panda/public/es2panda_lib.cpp @@ -500,10 +500,7 @@ __attribute__((unused)) static Context *Parse(Context *ctx) ctx->parser->ParseScript(*ctx->sourceFile, ctx->config->options->GetCompilationMode() == CompilationMode::GEN_STD_LIB); } - ctx->state = !ctx->diagnosticEngine->IsAnyError() ? ES2PANDA_STATE_PARSED : ES2PANDA_STATE_ERROR; - if (ctx->state == ES2PANDA_STATE_ERROR) { - ctx->diagnosticEngine->FlushDiagnostic(); - } + ctx->state = ES2PANDA_STATE_PARSED; ctx->phaseManager->SetCurrentPhaseIdToAfterParse(); return ctx; } @@ -535,7 +532,6 @@ __attribute__((unused)) static Context *Check(Context *ctx) } if (ctx->state == ES2PANDA_STATE_ERROR) { - ctx->diagnosticEngine->FlushDiagnostic(); return ctx; } @@ -579,7 +575,6 @@ __attribute__((unused)) static Context *Lower(Context *ctx) } if (ctx->state == ES2PANDA_STATE_ERROR) { - ctx->diagnosticEngine->FlushDiagnostic(); return ctx; } @@ -688,9 +683,6 @@ extern "C" __attribute__((unused)) es2panda_Context *ProceedToState(es2panda_Con break; } - if (ctx->state == ES2PANDA_STATE_ERROR) { - ctx->diagnosticEngine->FlushDiagnostic(); - } return reinterpret_cast(ctx); } diff --git a/ets2panda/test/unit/public/ast_verifier_check_struct_declaration_test.cpp b/ets2panda/test/unit/public/ast_verifier_check_struct_declaration_test.cpp index dbdd1b433c..288cafaf20 100644 --- a/ets2panda/test/unit/public/ast_verifier_check_struct_declaration_test.cpp +++ b/ets2panda/test/unit/public/ast_verifier_check_struct_declaration_test.cpp @@ -163,7 +163,7 @@ TEST_F(ASTVerifierTest, StructInStruct) } )"; - CONTEXT(ES2PANDA_STATE_PARSED, ES2PANDA_STATE_ERROR, text) + CONTEXT(ES2PANDA_STATE_PARSED, text) { ASSERT_TRUE(GetImpl()->IsAnyError(GetContext())); } -- Gitee From e5dfcb98fd9fe30243ae7287f19b4cc86ca9afaf Mon Sep 17 00:00:00 2001 From: yaohaosen Date: Wed, 4 Jun 2025 20:58:50 +0800 Subject: [PATCH 022/209] [LSP] Support UI Plugin Code Fixes Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICC5VX Signed-off-by: yaohaosen --- ets2panda/bindings/native/src/lsp.cpp | 68 +++++++ .../bindings/src/Es2pandaNativeModule.ts | 31 ++- ets2panda/bindings/src/buildConfigGenerate.ts | 19 +- ets2panda/bindings/src/lspNode.ts | 37 ++++ ets2panda/bindings/src/lsp_helper.ts | 39 +++- ets2panda/lsp/BUILD.gn | 1 + ets2panda/lsp/CMakeLists.txt | 1 + ets2panda/lsp/include/api.h | 6 +- ets2panda/lsp/include/cancellation_token.h | 1 + ets2panda/lsp/include/internal_api.h | 41 ++++ .../register_code_fix/ui_plugin_suggest.h | 39 ++++ ets2panda/lsp/src/api.cpp | 18 +- ets2panda/lsp/src/internal_api.cpp | 17 +- .../register_code_fix/ui_plugin_suggest.cpp | 117 ++++++++++++ ets2panda/test/unit/lsp/CMakeLists.txt | 4 + .../unit/lsp/code_fix/ui_plugin_suggest.cpp | 180 ++++++++++++++++++ .../unit/lsp/code_fix_registration_test.cpp | 2 +- ets2panda/test/unit/lsp/get_diagnostics.cpp | 18 +- ets2panda/util/diagnostic.h | 5 + 19 files changed, 619 insertions(+), 25 deletions(-) create mode 100644 ets2panda/lsp/include/register_code_fix/ui_plugin_suggest.h create mode 100644 ets2panda/lsp/src/register_code_fix/ui_plugin_suggest.cpp create mode 100644 ets2panda/test/unit/lsp/code_fix/ui_plugin_suggest.cpp diff --git a/ets2panda/bindings/native/src/lsp.cpp b/ets2panda/bindings/native/src/lsp.cpp index 286efef597..f8f6c9c669 100644 --- a/ets2panda/bindings/native/src/lsp.cpp +++ b/ets2panda/bindings/native/src/lsp.cpp @@ -1258,6 +1258,74 @@ KInt impl_getTypeFromTypeHierarchies(KNativePointer infoPtr) } TS_INTEROP_1(getTypeFromTypeHierarchies, KInt, KNativePointer) +KNativePointer impl_getCodeFixesAtPosition(KNativePointer context, KInt startPosition, KInt endPosition, + KInt *errorCodesPtr, KInt codeLength) +{ + CodeFixOptions emptyOptions; + std::vector errorCodesInt; + if (errorCodesPtr != nullptr && codeLength > 0) { + // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic,-warnings-as-errors) + errorCodesInt = std::vector(reinterpret_cast(errorCodesPtr), + reinterpret_cast(errorCodesPtr) + codeLength); + // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic,-warnings-as-errors) + } + LSPAPI const *ctx = GetImpl(); + auto autofix = ctx->getCodeFixesAtPosition(reinterpret_cast(context), startPosition, + endPosition, errorCodesInt, emptyOptions); + return new std::vector(autofix); +} +TS_INTEROP_5(getCodeFixesAtPosition, KNativePointer, KNativePointer, KInt, KInt, KInt *, KInt) + +KNativePointer impl_getCodeFixActionInfos(KNativePointer codeFixActionInfoListPtr) +{ + auto *getCodeFixActionInfoList = reinterpret_cast(codeFixActionInfoListPtr); + std::vector ptrs; + for (auto &el : getCodeFixActionInfoList->infos_) { + ptrs.push_back(new CodeFixActionInfo(el)); + } + return new std::vector(ptrs); +} +TS_INTEROP_1(getCodeFixActionInfos, KNativePointer, KNativePointer) + +KNativePointer impl_getFileTextChangesFromCodeActionInfo(KNativePointer infoPtr) +{ + auto *info = reinterpret_cast(infoPtr); + std::vector ptrs; + for (auto &el : info->changes_) { + ptrs.push_back(new FileTextChanges(el)); + } + return new std::vector(ptrs); +} +TS_INTEROP_1(getFileTextChangesFromCodeActionInfo, KNativePointer, KNativePointer) + +KNativePointer impl_getDescriptionFromCodeActionInfo(KNativePointer infoPtr) +{ + auto *info = reinterpret_cast(infoPtr); + return new std::string(info->description_); +} +TS_INTEROP_1(getDescriptionFromCodeActionInfo, KNativePointer, KNativePointer) + +KNativePointer impl_getFixNameFromCodeFixActionInfo(KNativePointer infoPtr) +{ + auto *info = reinterpret_cast(infoPtr); + return new std::string(info->fixName_); +} +TS_INTEROP_1(getFixNameFromCodeFixActionInfo, KNativePointer, KNativePointer) + +KNativePointer impl_getFixIdFromCodeFixActionInfo(KNativePointer infoPtr) +{ + auto *info = reinterpret_cast(infoPtr); + return new std::string(info->fixId_); +} +TS_INTEROP_1(getFixIdFromCodeFixActionInfo, KNativePointer, KNativePointer) + +KNativePointer impl_getFixAllDescriptionFromCodeFixActionInfo(KNativePointer infoPtr) +{ + auto *info = reinterpret_cast(infoPtr); + return new std::string(info->fixAllDescription_); +} +TS_INTEROP_1(getFixAllDescriptionFromCodeFixActionInfo, KNativePointer, KNativePointer) + KNativePointer impl_getSpanOfEnclosingComment(KNativePointer context, KInt position, KBoolean onlyMultiLine) { LSPAPI const *ctx = GetImpl(); diff --git a/ets2panda/bindings/src/Es2pandaNativeModule.ts b/ets2panda/bindings/src/Es2pandaNativeModule.ts index 210ad83e1c..881b164a26 100644 --- a/ets2panda/bindings/src/Es2pandaNativeModule.ts +++ b/ets2panda/bindings/src/Es2pandaNativeModule.ts @@ -14,7 +14,7 @@ import * as fs from 'fs'; import * as path from 'path'; -import { KNativePointer as KPtr, KInt, KBoolean, KNativePointer, KDouble, KUInt, KStringPtr } from './InteropTypes'; +import { KNativePointer as KPtr, KInt, KBoolean, KNativePointer, KDouble, KUInt, KStringPtr, KInt32ArrayPtr } from './InteropTypes'; import { Es2pandaNativeModule as GeneratedEs2pandaNativeModule } from './generated/Es2pandaNativeModule'; import { loadNativeModuleLibrary, registerNativeModuleLibraryName } from './loadLibraries'; import { throwError } from './utils'; @@ -720,6 +720,35 @@ export class Es2pandaNativeModule { throw new Error('Not implemented'); } + _getCodeFixesAtPosition(context: KNativePointer, startPosition: KInt, endPosition: KInt, + errorCodesPtr: KInt32ArrayPtr, codeLength: KInt): KPtr { + throw new Error('Not implemented'); + } + + _getCodeFixActionInfos(infoPtr: KNativePointer): KPtr { + throw new Error('Not implemented'); + } + + _getFileTextChangesFromCodeActionInfo(infoPtr: KNativePointer): KPtr { + throw new Error('Not implemented'); + } + + _getDescriptionFromCodeActionInfo(infoPtr: KNativePointer): KPtr { + throw new Error('Not implemented'); + } + + _getFixNameFromCodeFixActionInfo(infoPtr: KNativePointer): KPtr { + throw new Error('Not implemented'); + } + + _getFixIdFromCodeFixActionInfo(infoPtr: KNativePointer): KPtr { + throw new Error('Not implemented'); + } + + _getFixAllDescriptionFromCodeFixActionInfo(infoPtr: KNativePointer): KPtr { + throw new Error('Not implemented'); + } + _getInlayHintText(ptr: KPtr): KPtr { throw new Error('Not implemented'); } diff --git a/ets2panda/bindings/src/buildConfigGenerate.ts b/ets2panda/bindings/src/buildConfigGenerate.ts index 4d1b1c34d1..478196c6aa 100644 --- a/ets2panda/bindings/src/buildConfigGenerate.ts +++ b/ets2panda/bindings/src/buildConfigGenerate.ts @@ -161,6 +161,19 @@ function getModuleDependencies(modulePath: string, visited = new Set()): return Array.from(new Set([...dependencies, ...nestedDependencies])); } +function createMapEntryForPlugin(buildSdkPath: string, pluginName: string): string { + return path.join(buildSdkPath, 'build-tools', 'ui-plugins', 'lib', pluginName, 'index'); +} + +function createPluginMap(buildSdkPath: string): Record { + let pluginMap: Record = {}; + const pluginList: string[] = ['ui-syntax-plugins', 'ui-plugins', 'memo-plugins']; + for (const plugin of pluginList) { + pluginMap[plugin] = createMapEntryForPlugin(buildSdkPath, plugin); + } + return pluginMap; +} + export function generateBuildConfigs( buildSdkPath: string, projectRoot: string, @@ -179,6 +192,7 @@ export function generateBuildConfigs( for (const module of definedModules) { const modulePath = module.srcPath; const compileFiles = new Set(getEtsFiles(modulePath)); + const pluginMap = createPluginMap(buildSdkPath); // Get recursive dependencies const dependencies = getModuleDependencies(modulePath); @@ -187,10 +201,7 @@ export function generateBuildConfigs( } allBuildConfigs[module.name] = { - plugins: { - 'ui-plugins': path.join(buildSdkPath, 'build-tools', 'ui-plugins', 'lib', 'ui-plugins', 'index'), - 'memo-plugin': path.join(buildSdkPath, 'build-tools', 'ui-plugins', 'lib', 'memo-plugins', 'index') - }, + plugins: pluginMap, arkts: {}, arktsGlobal: {}, compileFiles: Array.from(compileFiles), diff --git a/ets2panda/bindings/src/lspNode.ts b/ets2panda/bindings/src/lspNode.ts index 17f846fce2..5f305aa2d6 100644 --- a/ets2panda/bindings/src/lspNode.ts +++ b/ets2panda/bindings/src/lspNode.ts @@ -644,6 +644,43 @@ export class FileTextChanges extends LspNode { readonly textChanges: TextChange[]; } +export class CodeActionInfo extends LspNode { + constructor(peer: KNativePointer) { + super(peer); + this.changes = new NativePtrDecoder() + .decode(global.es2panda._getFileTextChangesFromCodeActionInfo(peer)) + .map((elPeer: KNativePointer) => { + return new FileTextChanges(elPeer); + }); + this.description = unpackString(global.es2panda._getDescriptionFromCodeActionInfo(peer)); + } + readonly changes: FileTextChanges[]; + readonly description: String; +} + +export class CodeFixActionInfo extends CodeActionInfo { + constructor(peer: KNativePointer) { + super(peer); + this.fixName = unpackString(global.es2panda._getFixNameFromCodeFixActionInfo(peer)); + this.fixId_ = unpackString(global.es2panda._getFixIdFromCodeFixActionInfo(peer)); + this.fixAllDescription_ = unpackString(global.es2panda._getFixAllDescriptionFromCodeFixActionInfo(peer)); + } + readonly fixName: String; + readonly fixId_: String; + readonly fixAllDescription_: String; +} + +export class CodeFixActionInfoList extends LspNode { + constructor(peer: KNativePointer) { + super(peer); + this.codeFixActionInfos = new NativePtrDecoder() + .decode(global.es2panda._getCodeFixActionInfos(peer)) + .map((elPeer: KNativePointer) => { + return new CodeFixActionInfo(elPeer); + }); + } + readonly codeFixActionInfos: CodeFixActionInfo[]; +} export class LspFileTextChanges extends LspNode { constructor(peer: KNativePointer) { diff --git a/ets2panda/bindings/src/lsp_helper.ts b/ets2panda/bindings/src/lsp_helper.ts index b543a2b07e..7effce3147 100644 --- a/ets2panda/bindings/src/lsp_helper.ts +++ b/ets2panda/bindings/src/lsp_helper.ts @@ -40,7 +40,9 @@ import { LspInlayHint, LspInlayHintList, TextSpan, - LspSignatureHelpItems + LspSignatureHelpItems, + CodeFixActionInfo, + CodeFixActionInfoList } from './lspNode'; import { passStringArray, unpackString } from './private'; import { Es2pandaContextState } from './generated/Es2pandaEnums'; @@ -111,6 +113,16 @@ export class Lsp { return getSource.replace(/\r\n/g, '\n'); } + private getModuleNameFromFilename(filePath: string): string { + const projectRoot = this.projectPath; + if (!filePath.startsWith(projectRoot)) { + return ''; + } + const relativePath = path.relative(projectRoot, filePath); + const parts = relativePath.split(path.sep); + return parts[0] || ''; + } + getDefinitionAtPosition(filename: String, offset: number): LspDefinitionData { let lspDriverHelper = new LspDriverHelper(); let filePath = path.resolve(filename.valueOf()); @@ -529,6 +541,9 @@ export class Lsp { let localCfg = lspDriverHelper.createCfg(ets2pandaCmd, filePath, this.pandaLibPath); const source = this.getFileSource(filePath); let localCtx = lspDriverHelper.createCtx(source, filePath, localCfg); + const moduleName = this.getModuleNameFromFilename(filePath); + const buildConfig = this.moduleToBuildConfig[moduleName]; + PluginDriver.getInstance().getPluginContext().setProjectConfig(buildConfig); PluginDriver.getInstance().getPluginContext().setContextPtr(localCtx); lspDriverHelper.proceedToState(localCtx, Es2pandaContextState.ES2PANDA_STATE_PARSED); PluginDriver.getInstance().runPluginHook(PluginHook.PARSED); @@ -683,6 +698,28 @@ export class Lsp { return new LspTextSpan(ptr); } + getCodeFixesAtPosition(filename: String, start: number, end: number, errorCodes: number[]): CodeFixActionInfo[] { + let lspDriverHelper = new LspDriverHelper(); + let filePath = path.resolve(filename.valueOf()); + let arktsconfig = this.fileNameToArktsconfig[filePath]; + let ets2pandaCmd = ets2pandaCmdPrefix.concat(arktsconfig); + let localCfg = lspDriverHelper.createCfg(ets2pandaCmd, filePath, this.pandaLibPath); + const source = this.getFileSource(filePath); + let localCtx = lspDriverHelper.createCtx(source, filePath, localCfg); + PluginDriver.getInstance().getPluginContext().setContextPtr(localCtx); + lspDriverHelper.proceedToState(localCtx, Es2pandaContextState.ES2PANDA_STATE_PARSED); + PluginDriver.getInstance().runPluginHook(PluginHook.PARSED); + lspDriverHelper.proceedToState(localCtx, Es2pandaContextState.ES2PANDA_STATE_CHECKED); + let ptr = global.es2panda._getCodeFixesAtPosition(localCtx, start, end, new Int32Array(errorCodes), errorCodes.length); + PluginDriver.getInstance().runPluginHook(PluginHook.CLEAN); + lspDriverHelper.destroyContext(localCtx); + lspDriverHelper.destroyConfig(localCfg); + const codeFixActionInfoList = new CodeFixActionInfoList(ptr); + const codeFixActionInfos: CodeFixActionInfo[] = []; + codeFixActionInfos.push(...codeFixActionInfoList.codeFixActionInfos); + return codeFixActionInfos; + } + provideInlayHints(filename: String, span: TextSpan): LspInlayHint[] { let lspDriverHelper = new LspDriverHelper(); let filePath = path.resolve(filename.valueOf()); diff --git a/ets2panda/lsp/BUILD.gn b/ets2panda/lsp/BUILD.gn index 5cd817c9c5..ff8b060335 100644 --- a/ets2panda/lsp/BUILD.gn +++ b/ets2panda/lsp/BUILD.gn @@ -83,6 +83,7 @@ ohos_source_set("libes2panda_lsp_static") { "src/register_code_fix/forgetten_this_property_access.cpp", "src/register_code_fix/import_fixes.cpp", "src/rename.cpp", + "src/register_code_fix/ui_plugin_suggest.cpp", "src/script_element_kind.cpp", "src/services/services.cpp", "src/services/text_change/change_tracker.cpp", diff --git a/ets2panda/lsp/CMakeLists.txt b/ets2panda/lsp/CMakeLists.txt index f9e2e474c8..9cd9dab4f2 100644 --- a/ets2panda/lsp/CMakeLists.txt +++ b/ets2panda/lsp/CMakeLists.txt @@ -65,6 +65,7 @@ set(ES2PANDA_LSP_SRC ./src/register_code_fix/fix_nan_equality.cpp ./src/register_code_fix/forgetten_this_property_access.cpp ./src/register_code_fix/import_fixes.cpp + ./src/register_code_fix/ui_plugin_suggest.cpp ./src/get_name_or_dotted_name_span.cpp ) diff --git a/ets2panda/lsp/include/api.h b/ets2panda/lsp/include/api.h index b49cab1586..bd47d74f9d 100644 --- a/ets2panda/lsp/include/api.h +++ b/ets2panda/lsp/include/api.h @@ -480,6 +480,10 @@ struct CodeFixActionInfo : CodeActionInfo { std::string fixAllDescription_ = {}; }; +struct CodeFixActionInfoList { + std::vector infos_; +}; + struct CodeFixOptions { ark::es2panda::lsp::CancellationToken token; ark::es2panda::lsp::FormatCodeSettings options; @@ -538,7 +542,7 @@ typedef struct LSPAPI { ark::es2panda::lsp::CancellationToken *cancellationToken); InlayHintList (*provideInlayHints)(es2panda_Context *context, const TextSpan *span); SignatureHelpItems (*getSignatureHelpItems)(es2panda_Context *context, size_t position); - std::vector (*getCodeFixesAtPosition)(const char *fileName, size_t start_position, + std::vector (*getCodeFixesAtPosition)(es2panda_Context *context, size_t start_position, size_t end_position, std::vector &errorCodes, CodeFixOptions &codeFixOptions); CombinedCodeActionsInfo (*getCombinedCodeFix)(const char *fileName, const std::string &fixId, diff --git a/ets2panda/lsp/include/cancellation_token.h b/ets2panda/lsp/include/cancellation_token.h index a6a9209127..942f7f957e 100644 --- a/ets2panda/lsp/include/cancellation_token.h +++ b/ets2panda/lsp/include/cancellation_token.h @@ -32,6 +32,7 @@ public: bool IsCancellationRequested(); bool ThrottledCancellationCheck(); CancellationToken(time_t designatedThrottleTime, HostCancellationToken *hostCancellationToken); + CancellationToken() : lastCancellationTime_(0), throttleTime_(0), host_(nullptr) {} private: time_t lastCancellationTime_; diff --git a/ets2panda/lsp/include/internal_api.h b/ets2panda/lsp/include/internal_api.h index 9d1f8ff9b6..b021c901da 100644 --- a/ets2panda/lsp/include/internal_api.h +++ b/ets2panda/lsp/include/internal_api.h @@ -52,6 +52,47 @@ public: impl_->DestroyContext(context); } + const es2panda_DiagnosticKind *CreateDiagnosticKind(es2panda_Context *context, const char *dmessage, + es2panda_PluginDiagnosticType etype) + { + return impl_->CreateDiagnosticKind(context, dmessage, etype); + } + + es2panda_SuggestionInfo *CreateSuggestionInfo(es2panda_Context *context, const es2panda_DiagnosticKind *kind, + const char **args, size_t argc, const char *substitutionCode) + { + return impl_->CreateSuggestionInfo(context, kind, args, argc, substitutionCode); + } + + es2panda_DiagnosticInfo *CreateDiagnosticInfo(es2panda_Context *context, const es2panda_DiagnosticKind *kind, + const char **args, size_t argc) + { + return impl_->CreateDiagnosticInfo(context, kind, args, argc); + } + + es2panda_SourcePosition *CreateSourcePosition(es2panda_Context *context, size_t index, size_t line) + { + return impl_->CreateSourcePosition(context, index, line); + } + + es2panda_SourceRange *CreateSourceRange(es2panda_Context *context, es2panda_SourcePosition *start, + es2panda_SourcePosition *end) + { + return impl_->CreateSourceRange(context, start, end); + } + + void LogDiagnosticWithSuggestion(es2panda_Context *context, const es2panda_DiagnosticInfo *diagnosticInfo, + const es2panda_SuggestionInfo *suggestionInfo, es2panda_SourceRange *range) + { + return impl_->LogDiagnosticWithSuggestion(context, diagnosticInfo, suggestionInfo, range); + } + + void LogDiagnostic(es2panda_Context *context, const es2panda_DiagnosticKind *ekind, const char **args, size_t argc, + es2panda_SourcePosition *pos) + { + return impl_->LogDiagnostic(context, ekind, args, argc, pos); + } + NO_COPY_SEMANTIC(Initializer); NO_MOVE_SEMANTIC(Initializer); diff --git a/ets2panda/lsp/include/register_code_fix/ui_plugin_suggest.h b/ets2panda/lsp/include/register_code_fix/ui_plugin_suggest.h new file mode 100644 index 0000000000..31ebf572bb --- /dev/null +++ b/ets2panda/lsp/include/register_code_fix/ui_plugin_suggest.h @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2025 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 IMPORT_FIXES_H +#define IMPORT_FIXES_H + +#include +#include +#include "lsp/include/code_fixes/code_fix_types.h" +#include "lsp/include/services/text_change/change_tracker.h" +#include "lsp/include/types.h" + +namespace ark::es2panda::lsp { + +class UIPluginSuggest : public CodeFixRegistration { +public: + UIPluginSuggest(); + + static std::vector GetUIPluginCodeFixes(es2panda_Context *context, size_t pos, bool isAll); + + std::vector GetCodeActions(const CodeFixContext &context) override; + + CombinedCodeActions GetAllCodeActions(const CodeFixAllContext &codeFixAll) override; +}; + +} // namespace ark::es2panda::lsp +#endif diff --git a/ets2panda/lsp/src/api.cpp b/ets2panda/lsp/src/api.cpp index 7bee9e715d..23acef7f97 100644 --- a/ets2panda/lsp/src/api.cpp +++ b/ets2panda/lsp/src/api.cpp @@ -187,9 +187,19 @@ DiagnosticReferences GetSyntacticDiagnostics(es2panda_Context *context) DiagnosticReferences result {}; auto ctx = reinterpret_cast(context); const auto &diagnostics = ctx->diagnosticEngine->GetDiagnosticStorage(util::DiagnosticType::SYNTAX); + const auto &diagnosticsPluginError = + ctx->diagnosticEngine->GetDiagnosticStorage(util::DiagnosticType::PLUGIN_ERROR); + const auto &diagnosticsPluginWarning = + ctx->diagnosticEngine->GetDiagnosticStorage(util::DiagnosticType::PLUGIN_WARNING); for (const auto &diagnostic : diagnostics) { result.diagnostic.push_back(CreateDiagnosticForError(context, *diagnostic)); } + for (const auto &diagnostic : diagnosticsPluginError) { + result.diagnostic.push_back(CreateDiagnosticForError(context, *diagnostic)); + } + for (const auto &diagnostic : diagnosticsPluginWarning) { + result.diagnostic.push_back(CreateDiagnosticForError(context, *diagnostic)); + } return result; } @@ -372,14 +382,12 @@ SignatureHelpItems GetSignatureHelpItems(es2panda_Context *context, size_t posit auto cancellationToken = ark::es2panda::lsp::CancellationToken(defaultTime, nullptr); return ark::es2panda::lsp::GetSignatureHelpItems(context, position, invokedReason, cancellationToken); } -std::vector GetCodeFixesAtPosition(const char *fileName, size_t startPosition, size_t endPosition, - std::vector &errorCodes, CodeFixOptions &codeFixOptions) +std::vector GetCodeFixesAtPosition(es2panda_Context *context, size_t startPosition, + size_t endPosition, std::vector &errorCodes, + CodeFixOptions &codeFixOptions) { - Initializer initializer = Initializer(); - auto context = initializer.CreateContext(fileName, ES2PANDA_STATE_CHECKED); auto result = ark::es2panda::lsp::GetCodeFixesAtPositionImpl(context, startPosition, endPosition, errorCodes, codeFixOptions); - initializer.DestroyContext(context); return result; } diff --git a/ets2panda/lsp/src/internal_api.cpp b/ets2panda/lsp/src/internal_api.cpp index 05c9922c14..795777e89e 100644 --- a/ets2panda/lsp/src/internal_api.cpp +++ b/ets2panda/lsp/src/internal_api.cpp @@ -510,16 +510,27 @@ std::string GetOwnerId(ir::AstNode *node) DiagnosticSeverity GetSeverity(util::DiagnosticType errorType) { ES2PANDA_ASSERT(errorType != util::DiagnosticType::INVALID); - if (errorType == util::DiagnosticType::WARNING) { + if (errorType == util::DiagnosticType::WARNING || errorType == util::DiagnosticType::PLUGIN_WARNING) { return DiagnosticSeverity::Warning; } if (errorType == util::DiagnosticType::SYNTAX || errorType == util::DiagnosticType::SEMANTIC || - errorType == util::DiagnosticType::FATAL || errorType == util::DiagnosticType::ARKTS_CONFIG_ERROR) { + errorType == util::DiagnosticType::FATAL || errorType == util::DiagnosticType::ARKTS_CONFIG_ERROR || + errorType == util::DiagnosticType::PLUGIN_ERROR) { return DiagnosticSeverity::Error; } throw std::runtime_error("Unknown error type!"); } +// Temp design only support UI Plugin Diag. +int CreateCodeForDiagnostic(const util::DiagnosticBase *error) +{ + const int uiCode = 4000; + if (error->Type() == util::DiagnosticType::PLUGIN_ERROR || error->Type() == util::DiagnosticType::PLUGIN_WARNING) { + return uiCode; + } + return 1; +} + Diagnostic CreateDiagnosticForError(es2panda_Context *context, const util::DiagnosticBase &error) { auto ctx = reinterpret_cast(context); @@ -543,7 +554,7 @@ Diagnostic CreateDiagnosticForError(es2panda_Context *context, const util::Diagn auto range = Range(Position(sourceStartLocation.line, sourceStartLocation.col), Position(sourceEndLocation.line, sourceEndLocation.col)); auto severity = GetSeverity(error.Type()); - auto code = 1; + auto code = CreateCodeForDiagnostic(&error); std::string message = error.Message(); auto codeDescription = CodeDescription("test code description"); auto tags = std::vector(); diff --git a/ets2panda/lsp/src/register_code_fix/ui_plugin_suggest.cpp b/ets2panda/lsp/src/register_code_fix/ui_plugin_suggest.cpp new file mode 100644 index 0000000000..cb5f93b9dd --- /dev/null +++ b/ets2panda/lsp/src/register_code_fix/ui_plugin_suggest.cpp @@ -0,0 +1,117 @@ +/** + * Copyright (c) 2025 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 "lsp/include/register_code_fix/ui_plugin_suggest.h" +#include +#include +#include "lsp/include/code_fix_provider.h" +#include "lsp/include/internal_api.h" + +namespace ark::es2panda::lsp { +const int G_UI_PLUGIN_SUGGEST_CODE = 4000; // change this to the error code you want to handle + +UIPluginSuggest::UIPluginSuggest() +{ + const char *uiPluginSuggestId = "UIPluginSuggest"; + SetErrorCodes({G_UI_PLUGIN_SUGGEST_CODE}); + SetFixIds({uiPluginSuggestId}); +} + +std::vector GetTextChangesFromSuggestions(const ark::es2panda::util::Diagnostic *diag, size_t pos, + bool isAll) +{ + std::vector textChanges; + if (!diag->HasSuggestions()) { + return textChanges; + } + for (auto suggestion : diag->Suggestion()) { + auto sourceStart = suggestion->SourceRange()->start.index; + auto sourceEnd = suggestion->SourceRange()->end.index; + auto span = TextSpan(sourceStart, sourceEnd); + if (isAll) { + textChanges.emplace_back(TextChange(span, suggestion->SubstitutionCode())); + } else if (pos >= sourceStart && pos <= sourceEnd) { + textChanges.emplace_back(TextChange(span, suggestion->SubstitutionCode())); + } + } + return textChanges; +} + +std::vector GetUIPluginCodeFixesByDiagType(public_lib::Context *ctx, size_t pos, + util::DiagnosticType type, bool isAll) +{ + auto filename = ctx->sourceFileName; + std::vector res; + const auto &diagnostics = ctx->diagnosticEngine->GetDiagnosticStorage(type); + auto diagnosticStorage = reinterpret_cast(&diagnostics); + // NOLINTNEXTLINE(modernize-loop-convert,-warnings-as-errors) + for (size_t i = 0; i < diagnosticStorage->size(); ++i) { + auto diag = reinterpret_cast(&(*(*diagnosticStorage)[i])); + auto textChanges = GetTextChangesFromSuggestions(diag, pos, isAll); + FileTextChanges fileTextChanges(filename, textChanges); + res.emplace_back(fileTextChanges); + } + return res; +} + +std::vector UIPluginSuggest::GetUIPluginCodeFixes(es2panda_Context *context, size_t pos, bool isAll) +{ + if (context == nullptr) { + return {}; + } + auto ctx = reinterpret_cast(context); + std::vector res; + auto errorFixes = GetUIPluginCodeFixesByDiagType(ctx, pos, util::DiagnosticType::PLUGIN_ERROR, isAll); + res.insert(res.end(), errorFixes.begin(), errorFixes.end()); + auto warningFixes = GetUIPluginCodeFixesByDiagType(ctx, pos, util::DiagnosticType::PLUGIN_WARNING, isAll); + res.insert(res.end(), warningFixes.begin(), warningFixes.end()); + return res; +} + +std::vector UIPluginSuggest::GetCodeActions(const CodeFixContext &context) +{ + std::vector returnedActions; + auto changes = GetUIPluginCodeFixes(context.context, context.span.start, false); + if (!changes.empty()) { + CodeFixAction codeAction; + codeAction.fixName = "Fix"; + codeAction.description = "Fix Description"; + codeAction.changes = changes; + codeAction.fixId = "UI_PLUGIN_SUGGEST"; + codeAction.fixAllDescription = "Fix All Description"; + InstallPackageAction codeActionCommand; + codeActionCommand.file = reinterpret_cast(context.context)->sourceFileName; + codeActionCommand.packageName = ""; + codeAction.commands.push_back(codeActionCommand); + returnedActions.push_back(codeAction); + } + return returnedActions; +} + +CombinedCodeActions UIPluginSuggest::GetAllCodeActions(const CodeFixAllContext &codeFixAll) +{ + CombinedCodeActions combinedCodeActions; + auto changes = GetUIPluginCodeFixes(codeFixAll.context, 0, true); + combinedCodeActions.changes = changes; + InstallPackageAction codeActionCommand; + codeActionCommand.file = reinterpret_cast(codeFixAll.context)->sourceFileName; + codeActionCommand.packageName = ""; + combinedCodeActions.commands.push_back(codeActionCommand); + + return combinedCodeActions; +} +// NOLINTNEXTLINE(fuchsia-statically-constructed-objects, cert-err58-cpp) +AutoCodeFixRegister g_uiPluginSuggest("UIPluginSuggest"); +} // namespace ark::es2panda::lsp diff --git a/ets2panda/test/unit/lsp/CMakeLists.txt b/ets2panda/test/unit/lsp/CMakeLists.txt index 739388e5a4..8106544cc6 100644 --- a/ets2panda/test/unit/lsp/CMakeLists.txt +++ b/ets2panda/test/unit/lsp/CMakeLists.txt @@ -140,6 +140,10 @@ ets2panda_add_gtest(lsp_api_completions_test CPP_SOURCES get_completions.cpp ) +ets2panda_add_gtest(lsp_api_ui_suggest_test CPP_SOURCES + code_fix/ui_plugin_suggest.cpp +) + ets2panda_add_gtest(lsp_api_test_get_class_hierarchy_info CPP_SOURCES class_hierarchy_info_test.cpp ) diff --git a/ets2panda/test/unit/lsp/code_fix/ui_plugin_suggest.cpp b/ets2panda/test/unit/lsp/code_fix/ui_plugin_suggest.cpp new file mode 100644 index 0000000000..93c0d77ff8 --- /dev/null +++ b/ets2panda/test/unit/lsp/code_fix/ui_plugin_suggest.cpp @@ -0,0 +1,180 @@ +/** + * Copyright (c) 2025 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 "../lsp_api_test.h" + +#include + +#include "ir/astNode.h" +#include "lsp/include/register_code_fix/ui_plugin_suggest.h" +#include "lsp/include/internal_api.h" +#include "public/es2panda_lib.h" +#include "public/public.h" + +namespace { + +class LspUISuggestionTests : public LSPAPITests {}; + +using ark::es2panda::lsp::Initializer; + +void AssertDiagnosticContainsCodeAndMessage(const DiagnosticReferences &suggest, const int code, const char *dmessage) +{ + bool found = false; + for (auto diag : suggest.diagnostic) { + if (std::get(diag.code_) == code) { + if (diag.message_ == dmessage) { + found = true; + } + } + } + ASSERT_TRUE(found) << "Expected code: " << code << " not found"; +} + +TEST_F(LspUISuggestionTests, UIPluginsErrorTest1) +{ + using ark::es2panda::ir::AstNode; + using ark::es2panda::public_lib::Context; + Initializer initializer = Initializer(); + std::vector files = {"ui_error1.ets"}; + std::vector texts = {R"delimiter(function main() {})delimiter"}; + auto filePaths = CreateTempFile(files, texts); + auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED); + LSPAPI const *lspApi = GetImpl(); + int const offset = 11; + // NOLINTNEXTLINE + const char *params[] = { + "a", + }; + const char *dmessage1 = "origin {}"; + const size_t argc1 = 1; + const char *substitutionCode = "replace b"; + const char *dmessage2 = "error"; + const size_t argc0 = 0; + const size_t index1 = 0; + const size_t line1 = 0; + const size_t index2 = 15; + const size_t line2 = 0; + const int code = 4000; + auto suggestionkind = initializer.CreateDiagnosticKind(ctx, dmessage1, ES2PANDA_PLUGIN_SUGGESTION); + auto suggestionInfo = initializer.CreateSuggestionInfo(ctx, suggestionkind, params, argc1, substitutionCode); + auto diagnostikind = initializer.CreateDiagnosticKind(ctx, dmessage2, ES2PANDA_PLUGIN_ERROR); + auto diagnosticInfo = initializer.CreateDiagnosticInfo(ctx, diagnostikind, nullptr, argc0); + es2panda_SourcePosition *left = initializer.CreateSourcePosition(ctx, index1, line1); + es2panda_SourcePosition *right = initializer.CreateSourcePosition(ctx, index2, line2); + es2panda_SourceRange *range = initializer.CreateSourceRange(ctx, left, right); + initializer.LogDiagnosticWithSuggestion(ctx, diagnosticInfo, suggestionInfo, range); + auto suggest = lspApi->getSyntacticDiagnostics(ctx); + AssertDiagnosticContainsCodeAndMessage(suggest, code, dmessage2); + auto result = ark::es2panda::lsp::UIPluginSuggest::GetUIPluginCodeFixes(ctx, offset, false); + ASSERT_EQ(result.at(0).textChanges.at(0).newText, substitutionCode); + std::vector codes; + codes.emplace_back(code); + CodeFixOptions emptyOptions; + auto fix = ark::es2panda::lsp::GetCodeFixesAtPositionImpl(ctx, index1, index2, codes, emptyOptions); + ASSERT_EQ(fix.at(0).changes_.at(0).textChanges.at(0).newText, substitutionCode); + + initializer.DestroyContext(ctx); +} + +TEST_F(LspUISuggestionTests, UIPluginsErrorTest2) +{ + using ark::es2panda::ir::AstNode; + using ark::es2panda::public_lib::Context; + Initializer initializer = Initializer(); + std::vector files = {"ui_error2.ets"}; + std::vector texts = {R"delimiter(function main() {})delimiter"}; + auto filePaths = CreateTempFile(files, texts); + auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED); + LSPAPI const *lspApi = GetImpl(); + // NOLINTNEXTLINE + const char *params[] = { + "a", + }; + const size_t argc1 = 1; + const char *dmessage2 = "origin {}"; + const char *dmessage1 = "origin a"; + const size_t index1 = 0; + const size_t line1 = 0; + const int code = 4000; + auto diagnostikind = initializer.CreateDiagnosticKind(ctx, dmessage2, ES2PANDA_PLUGIN_ERROR); + es2panda_SourcePosition *left = initializer.CreateSourcePosition(ctx, index1, line1); + + initializer.LogDiagnostic(ctx, diagnostikind, params, argc1, left); + auto suggest = lspApi->getSyntacticDiagnostics(ctx); + AssertDiagnosticContainsCodeAndMessage(suggest, code, dmessage1); + std::vector codes; + codes.emplace_back(code); + CodeFixOptions emptyOptions; + auto fix = ark::es2panda::lsp::GetCodeFixesAtPositionImpl(ctx, index1, index1, codes, emptyOptions); + ASSERT_TRUE(fix.at(0).changes_.at(0).textChanges.empty()); + + initializer.DestroyContext(ctx); +} + +TEST_F(LspUISuggestionTests, UIPluginsErrorTest3) +{ + using ark::es2panda::ir::AstNode; + using ark::es2panda::public_lib::Context; + Initializer initializer = Initializer(); + std::vector files = {"ui_error3.ets"}; + std::vector texts = {R"delimiter(function main() {})delimiter"}; + auto filePaths = CreateTempFile(files, texts); + auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED); + LSPAPI const *lspApi = GetImpl(); + const char *dmessage1 = "origin a"; + const char *substitutionCode = "replace b"; + const char *dmessage2 = "error"; + const size_t argc0 = 0; + const size_t index1 = 0; + const size_t line1 = 0; + const size_t index2 = 15; + const size_t line2 = 0; + const int code = 4000; + auto suggestionkind = initializer.CreateDiagnosticKind(ctx, dmessage1, ES2PANDA_PLUGIN_SUGGESTION); + auto suggestionInfo = initializer.CreateSuggestionInfo(ctx, suggestionkind, nullptr, argc0, substitutionCode); + auto diagnostikind = initializer.CreateDiagnosticKind(ctx, dmessage2, ES2PANDA_PLUGIN_ERROR); + auto diagnosticInfo = initializer.CreateDiagnosticInfo(ctx, diagnostikind, nullptr, argc0); + es2panda_SourcePosition *left = initializer.CreateSourcePosition(ctx, index1, line1); + es2panda_SourcePosition *right = initializer.CreateSourcePosition(ctx, index2, line2); + es2panda_SourceRange *range = initializer.CreateSourceRange(ctx, left, right); + initializer.LogDiagnosticWithSuggestion(ctx, diagnosticInfo, suggestionInfo, range); + + const char *substitutionCode2 = "replace c"; + auto suggestionkind2 = initializer.CreateDiagnosticKind(ctx, dmessage1, ES2PANDA_PLUGIN_SUGGESTION); + auto suggestionInfo2 = initializer.CreateSuggestionInfo(ctx, suggestionkind2, nullptr, argc0, substitutionCode2); + auto diagnostikind2 = initializer.CreateDiagnosticKind(ctx, dmessage2, ES2PANDA_PLUGIN_ERROR); + auto diagnosticInfo2 = initializer.CreateDiagnosticInfo(ctx, diagnostikind2, nullptr, argc0); + es2panda_SourcePosition *left2 = initializer.CreateSourcePosition(ctx, index1, line1); + es2panda_SourcePosition *right2 = initializer.CreateSourcePosition(ctx, index2, line2); + es2panda_SourceRange *range2 = initializer.CreateSourceRange(ctx, left2, right2); + initializer.LogDiagnosticWithSuggestion(ctx, diagnosticInfo2, suggestionInfo2, range2); + + auto suggest = lspApi->getSyntacticDiagnostics(ctx); + AssertDiagnosticContainsCodeAndMessage(suggest, code, dmessage2); + AssertDiagnosticContainsCodeAndMessage(suggest, code, dmessage2); + std::vector codes; + codes.emplace_back(code); + CodeFixOptions emptyOptions; + const std::string fixId = "UIPluginSuggest"; + auto fix = ark::es2panda::lsp::GetCodeFixesAtPositionImpl(ctx, index1, index1, codes, emptyOptions); + ASSERT_FALSE(fix.at(0).changes_.at(0).textChanges.empty()); + auto fixAll = ark::es2panda::lsp::GetCombinedCodeFixImpl(ctx, fixId, emptyOptions); + const size_t expectedCount = 2; + ASSERT_EQ(fixAll.changes_.size(), expectedCount); + + initializer.DestroyContext(ctx); +} + +} // namespace diff --git a/ets2panda/test/unit/lsp/code_fix_registration_test.cpp b/ets2panda/test/unit/lsp/code_fix_registration_test.cpp index 1918c0c7a5..7e5b793cce 100644 --- a/ets2panda/test/unit/lsp/code_fix_registration_test.cpp +++ b/ets2panda/test/unit/lsp/code_fix_registration_test.cpp @@ -25,6 +25,6 @@ TEST(RefactorProviderRegistrationTest, RegistersConvertFunctionRefactor) const auto &fixIdToRegistration = provider.GetFixIdToRegistration(); EXPECT_FALSE(errors.empty()); EXPECT_FALSE(fixIdToRegistration.empty()); - EXPECT_EQ(errors.size(), 6); + EXPECT_EQ(errors.size(), fixIdToRegistration.size()); } } // namespace \ No newline at end of file diff --git a/ets2panda/test/unit/lsp/get_diagnostics.cpp b/ets2panda/test/unit/lsp/get_diagnostics.cpp index 8308130c35..0f6185e48d 100644 --- a/ets2panda/test/unit/lsp/get_diagnostics.cpp +++ b/ets2panda/test/unit/lsp/get_diagnostics.cpp @@ -61,7 +61,7 @@ add("1", 2);)"); ASSERT_EQ(result.diagnostic[thirdIndex].range_.end.line_, expectedFirstEndLine); ASSERT_EQ(result.diagnostic[thirdIndex].range_.end.character_, expectedFirstEndCharacter); ASSERT_EQ(result.diagnostic[thirdIndex].severity_, DiagnosticSeverity::Error); - ASSERT_EQ(std::get(result.diagnostic[thirdIndex].code_), 1); + ASSERT_NE(std::get(result.diagnostic[thirdIndex].code_), 0); ASSERT_EQ(result.diagnostic[thirdIndex].message_, R"(Type '"hello"' cannot be assigned to type 'Double')"); ASSERT_EQ(result.diagnostic[thirdIndex].codeDescription_.href_, "test code description"); auto const expectedSecondStartLine = 5; @@ -73,7 +73,7 @@ add("1", 2);)"); ASSERT_EQ(result.diagnostic[0].range_.end.line_, expectedSecondEndLine); ASSERT_EQ(result.diagnostic[0].range_.end.character_, expectedSecondEndCharacter); ASSERT_EQ(result.diagnostic[0].severity_, DiagnosticSeverity::Error); - ASSERT_EQ(std::get(result.diagnostic[0].code_), 1); + ASSERT_NE(std::get(result.diagnostic[0].code_), 0); ASSERT_EQ(result.diagnostic[0].message_, R"(Type '"1"' is not compatible with type 'Double' at index 1)"); ASSERT_EQ(result.diagnostic[0].codeDescription_.href_, "test code description"); } @@ -116,7 +116,7 @@ let res = add(n, n);)"); ASSERT_EQ(result.diagnostic[0].range_.end.line_, expectedFirstEndLine); ASSERT_EQ(result.diagnostic[0].range_.end.character_, expectedFirstEndCharacter); ASSERT_EQ(result.diagnostic[0].severity_, DiagnosticSeverity::Error); - ASSERT_EQ(std::get(result.diagnostic[0].code_), 1); + ASSERT_NE(std::get(result.diagnostic[0].code_), 0); auto const expectedSecondStartLine = 1; auto const expectedSecondStartCharacter = 14; auto const expectedSecondEndLine = 1; @@ -126,7 +126,7 @@ let res = add(n, n);)"); ASSERT_EQ(result.diagnostic[1].range_.end.line_, expectedSecondEndLine); ASSERT_EQ(result.diagnostic[1].range_.end.character_, expectedSecondEndCharacter); ASSERT_EQ(result.diagnostic[1].severity_, DiagnosticSeverity::Error); - ASSERT_EQ(std::get(result.diagnostic[1].code_), 1); + ASSERT_NE(std::get(result.diagnostic[1].code_), 0); auto const thirdIndex = 2; auto const expectedThirdStartLine = 1; auto const expectedThirdStartCharacter = 14; @@ -137,7 +137,7 @@ let res = add(n, n);)"); ASSERT_EQ(result.diagnostic[thirdIndex].range_.end.line_, expectedThirdEndLine); ASSERT_EQ(result.diagnostic[thirdIndex].range_.end.character_, expectedThirdEndCharacter); ASSERT_EQ(result.diagnostic[thirdIndex].severity_, DiagnosticSeverity::Error); - ASSERT_EQ(std::get(result.diagnostic[thirdIndex].code_), 1); + ASSERT_NE(std::get(result.diagnostic[thirdIndex].code_), 0); ASSERT_EQ(result.diagnostic[thirdIndex].message_, R"(Unexpected token ':'.)"); } @@ -163,7 +163,7 @@ let res = add(n, n);)"); ASSERT_EQ(result.diagnostic[forthIndex].range_.end.line_, expectedForthEndLine); ASSERT_EQ(result.diagnostic[forthIndex].range_.end.character_, expectedForthEndCharacter); ASSERT_EQ(result.diagnostic[forthIndex].severity_, DiagnosticSeverity::Error); - ASSERT_EQ(std::get(result.diagnostic[forthIndex].code_), 1); + ASSERT_NE(std::get(result.diagnostic[forthIndex].code_), 0); ASSERT_EQ(result.diagnostic[forthIndex].message_, R"(Unexpected token ','.)"); ASSERT_EQ(result.diagnostic[forthIndex].codeDescription_.href_, "test code description"); auto const fifthIndex = 8; @@ -176,7 +176,7 @@ let res = add(n, n);)"); ASSERT_EQ(result.diagnostic[fifthIndex].range_.end.line_, expectedFifthEndLine); ASSERT_EQ(result.diagnostic[fifthIndex].range_.end.character_, expectedFifthEndCharacter); ASSERT_EQ(result.diagnostic[fifthIndex].severity_, DiagnosticSeverity::Error); - ASSERT_EQ(std::get(result.diagnostic[fifthIndex].code_), 1); + ASSERT_NE(std::get(result.diagnostic[fifthIndex].code_), 0); ASSERT_EQ(result.diagnostic[fifthIndex].message_, R"(Label must be followed by a loop statement.)"); ASSERT_EQ(result.diagnostic[fifthIndex].codeDescription_.href_, "test code description"); } @@ -203,7 +203,7 @@ let res = add(n, n);)"); ASSERT_EQ(result.diagnostic[sixthIndex].range_.end.line_, expectedSixthEndLine); ASSERT_EQ(result.diagnostic[sixthIndex].range_.end.character_, expectedSixthEndCharacter); ASSERT_EQ(result.diagnostic[sixthIndex].severity_, DiagnosticSeverity::Error); - ASSERT_EQ(std::get(result.diagnostic[sixthIndex].code_), 1); + ASSERT_NE(std::get(result.diagnostic[sixthIndex].code_), 0); ASSERT_EQ(result.diagnostic[sixthIndex].message_, R"(Unexpected token ')'.)"); ASSERT_EQ(result.diagnostic[sixthIndex].codeDescription_.href_, "test code description"); auto const sevenIndex = 12; @@ -216,7 +216,7 @@ let res = add(n, n);)"); ASSERT_EQ(result.diagnostic[sevenIndex].range_.end.line_, expectedSeventhEndLine); ASSERT_EQ(result.diagnostic[sevenIndex].range_.end.character_, expectedSeventhEndCharacter); ASSERT_EQ(result.diagnostic[sevenIndex].severity_, DiagnosticSeverity::Error); - ASSERT_EQ(std::get(result.diagnostic[sevenIndex].code_), 1); + ASSERT_NE(std::get(result.diagnostic[sevenIndex].code_), 0); ASSERT_EQ(result.diagnostic[sevenIndex].message_, R"(return keyword should be used in function body.)"); ASSERT_EQ(result.diagnostic[sevenIndex].codeDescription_.href_, "test code description"); } diff --git a/ets2panda/util/diagnostic.h b/ets2panda/util/diagnostic.h index cb4c70a256..a3d9bf4d19 100644 --- a/ets2panda/util/diagnostic.h +++ b/ets2panda/util/diagnostic.h @@ -220,6 +220,11 @@ public: DiagnosticType Type() const override; std::string Message() const override; + bool HasSuggestions() const + { + return suggestions_ != nullptr; + } + const std::vector &Suggestion() const { return *suggestions_; -- Gitee From 3811e9211c51d636320c28c70ea0ec4b22b1d6fc Mon Sep 17 00:00:00 2001 From: Ocean Date: Fri, 30 May 2025 18:21:25 +0800 Subject: [PATCH 023/209] Support Isolated Declgen with Plugin API Issue:https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/IC906D Reason: In the hope of speeding up compiler process Description: 1. generate decl file with error info 2. carry out some isolated declaration specific check 3. do not parse import path in import statement 4. carry some type deduction for the return type of function Signed-off-by: Ocean --- ets2panda/BUILD.gn | 4 +- ets2panda/CMakeLists.txt | 10 +- ets2panda/bindings/native/src/bridges.cpp | 8 +- .../bindings/src/Es2pandaNativeModule.ts | 3 +- ets2panda/bindings/src/driver_helper.ts | 6 +- ets2panda/compiler/core/compilerImpl.cpp | 69 +--------- ets2panda/compiler/core/compilerImpl.h | 2 +- .../ets/insertOptionalParametersAnnotation.h | 3 +- ets2panda/declgen_ets2ts/BUILD.gn | 1 + ets2panda/declgen_ets2ts/CMakeLists.txt | 1 + ets2panda/declgen_ets2ts/declgenEts2Ts.cpp | 13 +- ets2panda/declgen_ets2ts/declgenEts2Ts.h | 10 +- .../isolatedDeclgenChecker.cpp} | 128 ++++++++---------- .../isolatedDeclgenChecker.h} | 18 ++- .../isolated_declgen.yaml | 16 +-- ets2panda/declgen_ets2ts/main.cpp | 34 +---- .../build_system/src/build/base_mode.ts | 1 + .../build_system/src/build/declgen_worker.ts | 1 + ets2panda/ir/astNode.cpp | 7 - ets2panda/ir/astNode.h | 1 - ets2panda/ir/base/classProperty.cpp | 5 - ets2panda/ir/base/scriptFunction.cpp | 5 +- ets2panda/ir/base/scriptFunction.h | 11 -- ets2panda/ir/srcDump.cpp | 4 +- ets2panda/ir/srcDump.h | 7 +- ets2panda/parser/ETSparser.cpp | 8 +- ets2panda/public/CMakeLists.txt | 1 + ets2panda/public/es2panda_lib.cpp | 7 +- ets2panda/public/es2panda_lib.h | 2 +- ets2panda/public/public.h | 3 - ...eturn_type_with_import_symbol-expected.txt | 26 ---- ...tion_return_type_with_literal-expected.txt | 16 --- ...ion_return_type_with_variable-expected.txt | 16 --- .../isolated_interface-expected.txt | 36 ----- .../isolated_namespace-expected.txt | 25 ---- ets2panda/test/unit/CMakeLists.txt | 1 + ets2panda/test/unit/declgen/CMakeLists.txt | 89 ++++++++++++ ...eturn_type_with_import_symbol-expected.txt | 7 + ...nction_return_type_with_import_symbol.ets} | 12 +- .../test_ets2ts_isolated_class-expected.txt | 18 +++ .../test_ets2ts_isolated_class.ets} | 0 .../test_ets2ts_isolated_enum-expected.txt | 11 ++ .../test_ets2ts_isolated_enum.ets} | 14 +- ...ction_with_optional_parameter-expected.txt | 2 + ...ated_function_with_optional_parameter.ets} | 0 ...est_ets2ts_isolated_interface-expected.txt | 14 ++ .../test_ets2ts_isolated_interface.ets} | 2 +- .../test_ets2ts_isolated_module-expected.txt | 6 + .../test_ets2ts_isolated_module.ets} | 23 +++- ...est_ets2ts_isolated_namespace-expected.txt | 5 + .../test_ets2ts_isolated_namespace.ets} | 0 .../declgen/test_ets2ts_isolated_declgen.cpp} | 54 ++++++-- ets2panda/test/unit/declgen/util.cpp | 83 ++++++++++++ .../declgen/util.h} | 40 +++--- ets2panda/test/unit/sizeof_node_test.cpp | 3 +- ets2panda/util/diagnostic.cpp | 4 +- ets2panda/util/diagnostic.h | 2 +- ets2panda/util/diagnosticEngine.cpp | 2 +- ets2panda/util/options.yaml | 4 - ets2panda/varbinder/ETSBinder.cpp | 9 +- 60 files changed, 483 insertions(+), 430 deletions(-) rename ets2panda/{checker/IsolatedDeclgenChecker.cpp => declgen_ets2ts/isolatedDeclgenChecker.cpp} (75%) rename ets2panda/{checker/IsolatedDeclgenChecker.h => declgen_ets2ts/isolatedDeclgenChecker.h} (90%) rename ets2panda/{util/diagnostic => declgen_ets2ts}/isolated_declgen.yaml (88%) delete mode 100644 ets2panda/test/isolated_declgen/infer_function_return_type_with_import_symbol-expected.txt delete mode 100644 ets2panda/test/isolated_declgen/infer_function_return_type_with_literal-expected.txt delete mode 100644 ets2panda/test/isolated_declgen/infer_function_return_type_with_variable-expected.txt delete mode 100644 ets2panda/test/isolated_declgen/isolated_interface-expected.txt delete mode 100644 ets2panda/test/isolated_declgen/isolated_namespace-expected.txt create mode 100644 ets2panda/test/unit/declgen/CMakeLists.txt create mode 100644 ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_infer_function_return_type_with_import_symbol-expected.txt rename ets2panda/test/{isolated_declgen/infer_function_return_type_with_import_symbol.ets => unit/declgen/ets2ts_isolated/test_ets2ts_infer_function_return_type_with_import_symbol.ets} (84%) create mode 100644 ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_class-expected.txt rename ets2panda/test/{isolated_declgen/isolated_class.ets => unit/declgen/ets2ts_isolated/test_ets2ts_isolated_class.ets} (100%) create mode 100644 ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_enum-expected.txt rename ets2panda/test/{isolated_declgen/isolated_function_with_optional_parameter-expected.txt => unit/declgen/ets2ts_isolated/test_ets2ts_isolated_enum.ets} (80%) create mode 100644 ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_function_with_optional_parameter-expected.txt rename ets2panda/test/{isolated_declgen/isolated_function_with_optional_parameter.ets => unit/declgen/ets2ts_isolated/test_ets2ts_isolated_function_with_optional_parameter.ets} (100%) create mode 100644 ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_interface-expected.txt rename ets2panda/test/{isolated_declgen/isolated_interface.ets => unit/declgen/ets2ts_isolated/test_ets2ts_isolated_interface.ets} (99%) create mode 100644 ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_module-expected.txt rename ets2panda/test/{isolated_declgen/infer_function_return_type_with_variable.ets => unit/declgen/ets2ts_isolated/test_ets2ts_isolated_module.ets} (63%) create mode 100644 ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_namespace-expected.txt rename ets2panda/test/{isolated_declgen/isolated_namespace.ets => unit/declgen/ets2ts_isolated/test_ets2ts_isolated_namespace.ets} (100%) rename ets2panda/test/{isolated_declgen/infer_function_return_type_with_literal.ets => unit/declgen/test_ets2ts_isolated_declgen.cpp} (34%) create mode 100644 ets2panda/test/unit/declgen/util.cpp rename ets2panda/test/{isolated_declgen/isolated_class-expected.txt => unit/declgen/util.h} (43%) diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index 42c9d7f055..faf1a25254 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -59,7 +59,6 @@ libes2panda_sources = [ "checker/ETSAnalyzerHelpers.cpp", "checker/ETSAnalyzerUnreachable.cpp", "checker/ETSchecker.cpp", - "checker/IsolatedDeclgenChecker.cpp", "checker/JSchecker.cpp", "checker/TSAnalyzer.cpp", "checker/TSAnalyzerUnreachable.cpp", @@ -1099,6 +1098,7 @@ ark_gen("gen") { # libes2panda does not include bytecode optimizer, because it is used in # libarkruntime, and conflict with JIT setup ensues libes2panda_public_sources = [ + "declgen_ets2ts/isolatedDeclgenChecker.cpp", "declgen_ets2ts/declgenEts2Ts.cpp", "public/${LIB_NAME}.cpp", "util/generateBin.cpp", @@ -1247,9 +1247,9 @@ ark_gen("es2panda_diagnostic_gen") { "util/diagnostic/semantic.yaml", "util/diagnostic/warning.yaml", "util/diagnostic/fatal.yaml", - "util/diagnostic/isolated_declgen.yaml", "declgen_ets2ts/declgen_ets2ts_error.yaml", "declgen_ets2ts/declgen_ets2ts_warning.yaml", + "declgen_ets2ts/isolated_declgen.yaml", "util/diagnostic/arktsconfig_error.yaml", ] template_files = [ "diagnostic.h.erb" ] diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index 695f3a76f9..4e8288dc0a 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -144,8 +144,8 @@ panda_gen( ${DIAGNOSTIC_DIR}/fatal.yaml ${CMAKE_CURRENT_SOURCE_DIR}/declgen_ets2ts/declgen_ets2ts_error.yaml ${CMAKE_CURRENT_SOURCE_DIR}/declgen_ets2ts/declgen_ets2ts_warning.yaml + ${CMAKE_CURRENT_SOURCE_DIR}/declgen_ets2ts/isolated_declgen.yaml ${DIAGNOSTIC_DIR}/arktsconfig_error.yaml - ${DIAGNOSTIC_DIR}/isolated_declgen.yaml TARGET_NAME es2panda_diagnostic_gen TEMPLATES diagnostic.h.erb SOURCE ${DIAGNOSTIC_DIR} @@ -542,7 +542,6 @@ set(ES2PANDA_LIB_SRC checker/TSAnalyzer.cpp checker/TSAnalyzerUnreachable.cpp checker/JSchecker.cpp - checker/IsolatedDeclgenChecker.cpp checker/typeChecker/TypeChecker.cpp checker/ets/aliveAnalyzer.cpp checker/ets/etsWarningAnalyzer.cpp @@ -686,6 +685,13 @@ panda_target_compile_options(es2panda-lib PRIVATE -fexceptions -Werror=shadow ) +if (EN_ISOLATED_DECLGEN) + message(STATUS "Isolated declgen enabled") + panda_target_compile_definitions(es2panda-lib + PRIVATE -DENABLE_ISOLATED_DECLGEN + ) +endif() + panda_target_link_libraries(es2panda-lib PUBLIC arkbase hmicuuc.z PRIVATE arkassembler arkdisassembler arkfile diff --git a/ets2panda/bindings/native/src/bridges.cpp b/ets2panda/bindings/native/src/bridges.cpp index 2757d4b9ef..19790f849e 100644 --- a/ets2panda/bindings/native/src/bridges.cpp +++ b/ets2panda/bindings/native/src/bridges.cpp @@ -37,13 +37,13 @@ KNativePointer impl_CreateContextFromString(KNativePointer configPtr, KStringPtr TS_INTEROP_3(CreateContextFromString, KNativePointer, KNativePointer, KStringPtr, KStringPtr) KInt impl_GenerateTsDeclarationsFromContext(KNativePointer contextPtr, KStringPtr &outputDeclEts, KStringPtr &outputEts, - KBoolean exportAll) + KBoolean exportAll, KBoolean isolated) { auto context = reinterpret_cast(contextPtr); - return static_cast(GetPublicImpl()->GenerateTsDeclarationsFromContext(context, outputDeclEts.data(), - outputEts.data(), exportAll != 0)); + return static_cast(GetPublicImpl()->GenerateTsDeclarationsFromContext( + context, outputDeclEts.data(), outputEts.data(), exportAll != 0, isolated != 0)); } -TS_INTEROP_4(GenerateTsDeclarationsFromContext, KInt, KNativePointer, KStringPtr, KStringPtr, KBoolean) +TS_INTEROP_5(GenerateTsDeclarationsFromContext, KInt, KNativePointer, KStringPtr, KStringPtr, KBoolean, KBoolean) KNativePointer impl_CreateContextFromFile(KNativePointer configPtr, KStringPtr &filenamePtr) { diff --git a/ets2panda/bindings/src/Es2pandaNativeModule.ts b/ets2panda/bindings/src/Es2pandaNativeModule.ts index 210ad83e1c..0c0838479a 100644 --- a/ets2panda/bindings/src/Es2pandaNativeModule.ts +++ b/ets2panda/bindings/src/Es2pandaNativeModule.ts @@ -65,7 +65,8 @@ export class Es2pandaNativeModule { config: KPtr, outputDeclEts: String, outputEts: String, - exportAll: KBoolean + exportAll: KBoolean, + isolated: KBoolean ): KPtr { throw new Error('Not implemented'); } diff --git a/ets2panda/bindings/src/driver_helper.ts b/ets2panda/bindings/src/driver_helper.ts index 29f82f3d01..5b43299469 100644 --- a/ets2panda/bindings/src/driver_helper.ts +++ b/ets2panda/bindings/src/driver_helper.ts @@ -76,9 +76,11 @@ export class DriverHelper { global.destroyCfg(); } - public generateTsDecl(declOutPath: string, etsOutPath: string, exportAll: boolean): void { + public generateTsDecl(declOutPath: string, etsOutPath: string, exportAll: boolean, isolated: boolean): void { let exportAll_: KBoolean = exportAll ? 1 : 0; - global.es2panda._GenerateTsDeclarationsFromContext(this._cfg.peer, declOutPath, etsOutPath, exportAll_); + let isolated_: KBoolean = isolated ? 1 : 0; + global.es2panda._GenerateTsDeclarationsFromContext(this._cfg.peer, declOutPath, etsOutPath, + exportAll_, isolated_); } } diff --git a/ets2panda/compiler/core/compilerImpl.cpp b/ets2panda/compiler/core/compilerImpl.cpp index 7086b2707d..74f75da500 100644 --- a/ets2panda/compiler/core/compilerImpl.cpp +++ b/ets2panda/compiler/core/compilerImpl.cpp @@ -14,7 +14,6 @@ */ #include "compilerImpl.h" -#include #include "es2panda.h" #include "ast_verifier/ASTVerifier.h" @@ -35,10 +34,7 @@ #include "compiler/lowering/phase.h" #include "compiler/lowering/scopesInit/scopesInitPhase.h" #include "compiler/lowering/checkerPhase.h" -#include "compiler/lowering/resolveIdentifiers.h" -#include "compiler/lowering/ets/insertOptionalParametersAnnotation.h" #include "evaluate/scopedDebugInfoPlugin.h" -#include "generated/isa.h" #include "parser/parserImpl.h" #include "parser/JSparser.h" #include "parser/ASparser.h" @@ -112,7 +108,7 @@ static bool CheckOptionsBeforePhase(const util::Options &options, const parser:: } void HandleGenerateDecl(const parser::Program &program, util::DiagnosticEngine &diagnosticEngine, - const std::string &outputPath, bool isIsolatedDeclgen) + const std::string &outputPath) { std::ofstream outFile(outputPath); if (!outFile.is_open()) { @@ -120,13 +116,7 @@ void HandleGenerateDecl(const parser::Program &program, util::DiagnosticEngine & lexer::SourcePosition()); return; } - std::string result; - if (!isIsolatedDeclgen) { - result = program.Ast()->DumpDecl(); - } else { - result = program.Ast()->IsolatedDumpDecl(); - } - + std::string result = program.Ast()->DumpDecl(); result.erase(0, result.find_first_not_of('\n')); outFile << result; @@ -149,47 +139,13 @@ static bool CheckOptionsAfterPhase(const util::Options &options, const parser::P return options.GetExitAfterPhase() == name; } -static bool DoIsolatedDeclgenCheck(const util::Options &options, const std::string &phaseName, - checker::IsolatedDeclgenChecker &isolatedDeclgenChecker, - public_lib::Context &context) -{ - if (!options.IsGenerateDeclEnableIsolated()) { - return true; - } - if (phaseName == compiler::ResolveIdentifiers::NAME) { - isolatedDeclgenChecker.CheckBeforeChecker(); - if (context.diagnosticEngine->IsAnyError()) { - return false; - } - } - - if (phaseName == compiler::CheckerPhase::NAME) { - isolatedDeclgenChecker.CheckAfterChecker(); - if (context.diagnosticEngine->IsAnyError()) { - return false; - } - } - - return true; -} - -static bool CheckIfPhaseToSkip(util::Options &options, const std::string &name) -{ - return options.GetSkipPhases().count(name) > 0 || - (options.IsGenerateDeclEnableIsolated() && name == compiler::InsertOptionalParametersAnnotation::NAME); -} - // CC-OFFNXT(huge_method[C++], G.FUN.01-CPP, G.FUD.05) solid logic static bool RunVerifierAndPhases(public_lib::Context &context, parser::Program &program) { - auto &options = const_cast(*context.config->options); + const auto &options = *context.config->options; const auto verifierEachPhase = options.IsAstVerifierEachPhase(); ast_verifier::ASTVerifier verifier(context, program); - checker::IsolatedDeclgenChecker isolatedDeclgenChecker(*context.diagnosticEngine, program); - if (options.IsGenerateDeclEnableIsolated()) { - options.SetGenerateDeclEnabled(true); - } bool afterCheckerPhase = false; while (auto phase = context.phaseManager->NextPhase()) { @@ -198,28 +154,17 @@ static bool RunVerifierAndPhases(public_lib::Context &context, parser::Program & afterCheckerPhase = true; } - if (CheckIfPhaseToSkip(options, name)) { + if (options.GetSkipPhases().count(name) > 0) { continue; } - if (options.IsGenerateDeclEnableIsolated() && name == "plugins-after-check") { - return false; - } - if (CheckOptionsBeforePhase(options, program, name) || !phase->Apply(&context, &program) || CheckOptionsAfterPhase(options, program, name)) { return false; } - if (!DoIsolatedDeclgenCheck(options, name, isolatedDeclgenChecker, context)) { - return false; - } - - if (!options.IsGenerateDeclEnableIsolated()) { - verifier.IntroduceNewInvariants(phase->Name()); - } - - if (verifierEachPhase || options.HasVerifierPhase(phase->Name())) { + if (verifier.IntroduceNewInvariants(phase->Name()); + verifierEachPhase || options.HasVerifierPhase(phase->Name())) { verifier.Verify(phase->Name()); } @@ -235,7 +180,7 @@ static bool RunVerifierAndPhases(public_lib::Context &context, parser::Program & } else { path = options.GetGenerateDeclPath(); } - HandleGenerateDecl(program, *context.diagnosticEngine, path, options.IsGenerateDeclEnableIsolated()); + HandleGenerateDecl(program, *context.diagnosticEngine, path); } } diff --git a/ets2panda/compiler/core/compilerImpl.h b/ets2panda/compiler/core/compilerImpl.h index 6c669d5e00..02ac0514b2 100644 --- a/ets2panda/compiler/core/compilerImpl.h +++ b/ets2panda/compiler/core/compilerImpl.h @@ -26,7 +26,7 @@ namespace ark::es2panda::compiler { class CompileQueue; void HandleGenerateDecl(const parser::Program &program, util::DiagnosticEngine &diagnosticEngine, - const std::string &outputPath, bool isIsolatedDeclgen); + const std::string &outputPath); class CompilationUnit { public: diff --git a/ets2panda/compiler/lowering/ets/insertOptionalParametersAnnotation.h b/ets2panda/compiler/lowering/ets/insertOptionalParametersAnnotation.h index 1e8a0440a1..780d43d514 100644 --- a/ets2panda/compiler/lowering/ets/insertOptionalParametersAnnotation.h +++ b/ets2panda/compiler/lowering/ets/insertOptionalParametersAnnotation.h @@ -22,10 +22,9 @@ namespace ark::es2panda::compiler { class InsertOptionalParametersAnnotation : public PhaseForDeclarations { public: - static constexpr std::string_view NAME = "InsertOptionalParametersAnnotation"; std::string_view Name() const override { - return NAME; + return "InsertOptionalParametersAnnotation"; } bool PerformForModule(public_lib::Context *ctx, parser::Program *program) override; diff --git a/ets2panda/declgen_ets2ts/BUILD.gn b/ets2panda/declgen_ets2ts/BUILD.gn index 165a35a81f..8de1df605d 100644 --- a/ets2panda/declgen_ets2ts/BUILD.gn +++ b/ets2panda/declgen_ets2ts/BUILD.gn @@ -16,6 +16,7 @@ import("//build/ohos.gni") ohos_executable("declgen_ets2ts") { sources = [ + "isolatedDeclgenChecker.cpp", "declgenEts2Ts.cpp", "main.cpp", ] diff --git a/ets2panda/declgen_ets2ts/CMakeLists.txt b/ets2panda/declgen_ets2ts/CMakeLists.txt index 6d0687fa1d..994c760889 100644 --- a/ets2panda/declgen_ets2ts/CMakeLists.txt +++ b/ets2panda/declgen_ets2ts/CMakeLists.txt @@ -14,6 +14,7 @@ set(DECLGEN_ETS2TS_SRC main.cpp declgenEts2Ts.cpp + isolatedDeclgenChecker.cpp ) set(DECLGEN_ETS2TS_INCLUDE_DIRS diff --git a/ets2panda/declgen_ets2ts/declgenEts2Ts.cpp b/ets2panda/declgen_ets2ts/declgenEts2Ts.cpp index 6dd04a3916..ebdc7c56d6 100644 --- a/ets2panda/declgen_ets2ts/declgenEts2Ts.cpp +++ b/ets2panda/declgen_ets2ts/declgenEts2Ts.cpp @@ -14,8 +14,8 @@ */ #include "declgenEts2Ts.h" -#include +#include "isolatedDeclgenChecker.h" #include "checker/types/ets/etsTupleType.h" #include "generated/diagnostic.h" #include "ir/base/classProperty.h" @@ -700,8 +700,8 @@ void TSDeclGen::ProcessFunctionReturnType(const checker::Signature *sig) } std::string typeStr = sig->ReturnType()->ToString(); - if (declgenOptions_.isIsolatedDeclgen && typeStr.find(ERROR_TYPE) != std::string::npos) { - typeStr = sig->Function()->GetIsolatedDeclgenReturnType(); + if (declgenOptions_.isolated && typeStr.find(ERROR_TYPE) != std::string::npos) { + typeStr = isolatedDeclgenChecker_->Check(const_cast(sig->Function())); OutDts(typeStr); SplitUnionTypes(typeStr); return; @@ -2062,7 +2062,12 @@ bool WriteToFile(const std::string &path, const std::string &content, checker::E bool GenerateTsDeclarations(checker::ETSChecker *checker, const ark::es2panda::parser::Program *program, const DeclgenOptions &declgenOptions) { - TSDeclGen declBuilder(checker, program); + declgen::IsolatedDeclgenChecker isolatedDeclgenChecker(checker->DiagnosticEngine(), *program); + if (declgenOptions.isolated) { + isolatedDeclgenChecker.Check(); + } + + TSDeclGen declBuilder(checker, &isolatedDeclgenChecker, program); declBuilder.SetDeclgenOptions(declgenOptions); if ((declBuilder.GetDeclgenOptions().outputDeclEts.empty() && !declBuilder.GetDeclgenOptions().outputEts.empty()) || diff --git a/ets2panda/declgen_ets2ts/declgenEts2Ts.h b/ets2panda/declgen_ets2ts/declgenEts2Ts.h index fda8c826a1..81f29c2a6b 100644 --- a/ets2panda/declgen_ets2ts/declgenEts2Ts.h +++ b/ets2panda/declgen_ets2ts/declgenEts2Ts.h @@ -22,12 +22,13 @@ #include "libpandabase/utils/arena_containers.h" #include "util/options.h" #include "util/diagnosticEngine.h" +#include "isolatedDeclgenChecker.h" namespace ark::es2panda::declgen_ets2ts { struct DeclgenOptions { bool exportAll = false; - bool isIsolatedDeclgen = false; + bool isolated = false; std::string outputDeclEts; std::string outputEts; }; @@ -38,8 +39,10 @@ bool GenerateTsDeclarations(checker::ETSChecker *checker, const ark::es2panda::p class TSDeclGen { public: - TSDeclGen(checker::ETSChecker *checker, const ark::es2panda::parser::Program *program) + TSDeclGen(checker::ETSChecker *checker, declgen::IsolatedDeclgenChecker *isolatedDeclgenChecker, + const ark::es2panda::parser::Program *program) : checker_(checker), + isolatedDeclgenChecker_(isolatedDeclgenChecker), program_(program), diagnosticEngine_(checker->DiagnosticEngine()), allocator_(SpaceType::SPACE_TYPE_COMPILER, nullptr, true), @@ -95,9 +98,9 @@ private: const checker::Signature *GetFuncSignature(const checker::ETSFunctionType *etsFunctionType, const ir::MethodDefinition *methodDef); - void SplitUnionTypes(std::string &unionTypeString); void GenType(const checker::Type *checkerType); void GenFunctionType(const checker::ETSFunctionType *functionType, const ir::MethodDefinition *methodDef = nullptr); + void SplitUnionTypes(std::string &unionTypeString); void ProcessFunctionReturnType(const checker::Signature *sig); bool ProcessTSQualifiedName(const ir::ETSTypeReference *typeReference); void ProcessETSTypeReferenceType(const ir::ETSTypeReference *typeReference, @@ -289,6 +292,7 @@ private: std::stringstream outputDts_; std::stringstream outputTs_; checker::ETSChecker *checker_ {}; + declgen::IsolatedDeclgenChecker *isolatedDeclgenChecker_ {}; const ark::es2panda::parser::Program *program_ {}; util::DiagnosticEngine &diagnosticEngine_; ArenaAllocator allocator_; diff --git a/ets2panda/checker/IsolatedDeclgenChecker.cpp b/ets2panda/declgen_ets2ts/isolatedDeclgenChecker.cpp similarity index 75% rename from ets2panda/checker/IsolatedDeclgenChecker.cpp rename to ets2panda/declgen_ets2ts/isolatedDeclgenChecker.cpp index ed623f5cb4..052a88c503 100644 --- a/ets2panda/checker/IsolatedDeclgenChecker.cpp +++ b/ets2panda/declgen_ets2ts/isolatedDeclgenChecker.cpp @@ -13,11 +13,13 @@ * limitations under the License. */ -#include "checker/IsolatedDeclgenChecker.h" +#include "isolatedDeclgenChecker.h" + +#include "es2panda.h" #include "clang.h" #include "utils/logger.h" -namespace ark::es2panda::checker { +namespace ark::es2panda::declgen { using AstNodePtr = ir::AstNode *; void IsolatedDeclgenChecker::LogError(const diagnostic::DiagnosticKind &diagnostic, @@ -27,23 +29,28 @@ void IsolatedDeclgenChecker::LogError(const diagnostic::DiagnosticKind &diagnost diagnosticEngine_.LogDiagnostic(diagnostic, diagnosticParams, pos); } +static bool IsUnionTypeWithError(const checker::Type *type) +{ + if (type == nullptr || !type->IsUnionType()) { + return false; + } + + return type->ToString().find(ERROR_TYPE) != std::string::npos; +} + void IsolatedDeclgenChecker::Check(ir::ClassProperty *ast) { if (ast->Parent()->IsAnnotationUsage()) { return; } - if (ast->TypeAnnotation() == nullptr) { - LogError(diagnostic::PROPERTY_MUST_HAVE_EXPLICIT_TYPE_ANNOTATION_WITH_ISOLATED_DECL, {}, ast->Start()); + if (ast->IsPrivate()) { + return; } -} - -void IsolatedDeclgenChecker::Check(ir::ObjectExpression *ast) -{ - for (auto property : ast->Properties()) { - if (property->IsSpreadElement()) { - LogError(diagnostic::OBJECTS_THAT_CONTAIN_SPREAD_ASSIGNMENTS_CANNOT_BE_INFERRED_WITH_ISOLATED_DECL, {}, - property->Start()); - } + if (ast->TypeAnnotation() != nullptr) { + return; + } + if (ast->TsType()->IsTypeError() || IsUnionTypeWithError(ast->TsType())) { + LogError(diagnostic::PROPERTY_MUST_HAVE_EXPLICIT_TYPE_ANNOTATION_WITH_ISOLATED_DECL, {}, ast->Start()); } } @@ -76,9 +83,30 @@ void IsolatedDeclgenChecker::Check(ir::ArrayExpression *ast) } } +static std::string GetETSTypeReferenceName(ir::ETSTypeReference *typeRef) +{ + if (typeRef == nullptr) { + return ""; + } + auto *part = typeRef->Part(); + if (part == nullptr) { + return ""; + } + if (part->Name()->IsIdentifier()) { + return part->Name()->AsIdentifier()->Name().Mutf8(); + } + if (part->Name()->IsTSQualifiedName()) { + return part->Name()->AsTSQualifiedName()->Name().Mutf8(); + } + return ""; +} + void IsolatedDeclgenChecker::Check(ir::ETSParameterExpression *ast) { - if (ast->TypeAnnotation() == nullptr) { + if (ast->TypeAnnotation() != nullptr) { + return; + } + if (ast->TsType()->IsTypeError() || IsUnionTypeWithError(ast->TsType())) { LogError(diagnostic::PARAMETER_MUST_HAVE_EXPLICIT_TYPE_ANNOTATION_WITH_ISOLATED_DECL, {}, ast->Start()); } } @@ -87,57 +115,57 @@ void IsolatedDeclgenChecker::Check(ir::ExportDefaultDeclaration *ast) { auto *decl = ast->Decl(); if (decl == nullptr) { - LogError(diagnostic::DEFAULT_EXPORTS__CANNOT_BE_INFERRED_WITH_ISOLATED_DECL, {}, ast->Start()); + LogError(diagnostic::DEFAULT_EXPORTS_CANNOT_BE_INFERRED_WITH_ISOLATED_DECL, {}, ast->Start()); return; } if (decl->IsClassDeclaration()) { auto *classDecl = decl->AsClassDeclaration(); if (classDecl == nullptr) { - LogError(diagnostic::DEFAULT_EXPORTS__CANNOT_BE_INFERRED_WITH_ISOLATED_DECL, {}, ast->Start()); + LogError(diagnostic::DEFAULT_EXPORTS_CANNOT_BE_INFERRED_WITH_ISOLATED_DECL, {}, ast->Start()); } return; } if (decl->IsTSInterfaceDeclaration()) { auto *interfaceDecl = decl->AsTSInterfaceDeclaration(); if (interfaceDecl == nullptr) { - LogError(diagnostic::DEFAULT_EXPORTS__CANNOT_BE_INFERRED_WITH_ISOLATED_DECL, {}, ast->Start()); + LogError(diagnostic::DEFAULT_EXPORTS_CANNOT_BE_INFERRED_WITH_ISOLATED_DECL, {}, ast->Start()); } return; } if (decl->IsTSEnumDeclaration()) { auto *enumDecl = decl->AsTSEnumDeclaration(); if (enumDecl == nullptr) { - LogError(diagnostic::DEFAULT_EXPORTS__CANNOT_BE_INFERRED_WITH_ISOLATED_DECL, {}, ast->Start()); + LogError(diagnostic::DEFAULT_EXPORTS_CANNOT_BE_INFERRED_WITH_ISOLATED_DECL, {}, ast->Start()); } return; } if (decl->IsFunctionDeclaration()) { auto *funcDecl = decl->AsFunctionDeclaration(); if (funcDecl == nullptr) { - LogError(diagnostic::DEFAULT_EXPORTS__CANNOT_BE_INFERRED_WITH_ISOLATED_DECL, {}, ast->Start()); + LogError(diagnostic::DEFAULT_EXPORTS_CANNOT_BE_INFERRED_WITH_ISOLATED_DECL, {}, ast->Start()); } return; } if (decl->IsClassProperty()) { auto *classProperty = decl->AsClassProperty(); if (classProperty == nullptr) { - LogError(diagnostic::DEFAULT_EXPORTS__CANNOT_BE_INFERRED_WITH_ISOLATED_DECL, {}, ast->Start()); + LogError(diagnostic::DEFAULT_EXPORTS_CANNOT_BE_INFERRED_WITH_ISOLATED_DECL, {}, ast->Start()); } return; } - LogError(diagnostic::DEFAULT_EXPORTS__CANNOT_BE_INFERRED_WITH_ISOLATED_DECL, {}, ast->Start()); + LogError(diagnostic::DEFAULT_EXPORTS_CANNOT_BE_INFERRED_WITH_ISOLATED_DECL, {}, ast->Start()); } -std::string GetLiteralType(const ir::Literal *literal) +static std::string GetLiteralType(const ir::Literal *literal) { if (literal->IsStringLiteral()) { - return "String"; + return "string"; } if (literal->IsNumberLiteral()) { - return "Number"; + return "number"; } if (literal->IsBooleanLiteral()) { - return "Boolean"; + return "boolean"; } return ""; } @@ -170,15 +198,8 @@ std::string IsolatedDeclgenChecker::ProcessIdentifierArgument(ir::Identifier *id } if (decl->IsLetOrConstDecl()) { - return decl->Node() - ->AsClassProperty() - ->TypeAnnotation() - ->AsETSTypeReference() - ->Part() - ->Name() - ->AsIdentifier() - ->Name() - .Mutf8(); + auto *typeAnnotationRef = decl->Node()->AsClassProperty()->TypeAnnotation()->AsETSTypeReference(); + return GetETSTypeReferenceName(typeAnnotationRef); } LogError(diagnostic::FUNCTION_MUST_HAVE_AN_EXPLICIT_RETURN_TYPE_ANNOTATION_WITH_ISOLATED_DECL, {}, returnStatement->Start()); @@ -206,7 +227,7 @@ std::string IsolatedDeclgenChecker::ProcessNewClassInstanceExpressionArgument( returnStatement->Start()); return ""; } - return classType->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Name().Mutf8(); + return GetETSTypeReferenceName(classType->AsETSTypeReference()); } std::string IsolatedDeclgenChecker::InferReturnTypeForArgument(ir::ReturnStatement *returnStatement) @@ -281,9 +302,9 @@ std::string IsolatedDeclgenChecker::Check(ir::ScriptFunction *ast) return returnTypeStr; } -void IsolatedDeclgenChecker::CheckBeforeChecker() +void IsolatedDeclgenChecker::Check() { - program_.Ast()->TransformChildrenRecursively( + const_cast(program_).Ast()->TransformChildrenRecursively( [&](ir::AstNode *ast) -> AstNodePtr { if (ast->IsClassProperty()) { Check(ast->AsClassProperty()); @@ -300,10 +321,6 @@ void IsolatedDeclgenChecker::CheckBeforeChecker() return ast; } - if (ast->IsObjectExpression()) { - Check(ast->AsObjectExpression()); - return ast; - } if (ast->IsExportDefaultDeclaration()) { Check(ast->AsExportDefaultDeclaration()); return ast; @@ -311,31 +328,6 @@ void IsolatedDeclgenChecker::CheckBeforeChecker() return ast; }, - "CheckIsolatedDeclBeforeChecker"); -} - -void IsolatedDeclgenChecker::CheckAfterChecker() -{ - program_.Ast()->TransformChildrenRecursively( - [&](ir::AstNode *ast) -> AstNodePtr { - if (!ast->IsScriptFunction()) { - return ast; - } - - auto *scriptFunction = ast->AsScriptFunction(); - auto *returnType = scriptFunction->Signature()->ReturnType(); - if (returnType == nullptr) { - return ast; - } - std::string returnTypeStr = Check(scriptFunction); - if (returnType->ToString().find(ERROR_TYPE) == std::string::npos) { - scriptFunction->SetIsolatedDeclgenReturnType(returnType->ToString()); - return ast; - } - scriptFunction->SetIsolatedDeclgenReturnType(returnTypeStr); - - return ast; - }, - "CheckIsolatedDeclAfterChecker"); + "CheckIsolatedDecl"); } -} // namespace ark::es2panda::checker \ No newline at end of file +} // namespace ark::es2panda::declgen \ No newline at end of file diff --git a/ets2panda/checker/IsolatedDeclgenChecker.h b/ets2panda/declgen_ets2ts/isolatedDeclgenChecker.h similarity index 90% rename from ets2panda/checker/IsolatedDeclgenChecker.h rename to ets2panda/declgen_ets2ts/isolatedDeclgenChecker.h index eef54b0232..3769b90ea1 100644 --- a/ets2panda/checker/IsolatedDeclgenChecker.h +++ b/ets2panda/declgen_ets2ts/isolatedDeclgenChecker.h @@ -19,10 +19,10 @@ #include "macros.h" #include "checker/checker.h" -namespace ark::es2panda::checker { +namespace ark::es2panda::declgen { class IsolatedDeclgenChecker { public: - explicit IsolatedDeclgenChecker(util::DiagnosticEngine &diagnosticEngine, parser::Program &program) + explicit IsolatedDeclgenChecker(util::DiagnosticEngine &diagnosticEngine, const parser::Program &program) : diagnosticEngine_(diagnosticEngine), program_(program) { } @@ -31,18 +31,16 @@ public: NO_COPY_SEMANTIC(IsolatedDeclgenChecker); NO_MOVE_SEMANTIC(IsolatedDeclgenChecker); - void CheckBeforeChecker(); - void CheckAfterChecker(); + void Check(); + std::string Check(ir::ScriptFunction *ast); + +private: void Check(ir::ClassProperty *ast); - void Check(ir::ObjectExpression *ast); void Check(ir::ArrayExpression *ast); void Check(ir::ETSParameterExpression *ast); void Check(ir::ExportDefaultDeclaration *ast); - std::string Check(ir::ScriptFunction *ast); - -private: std::string InferReturnTypeForArgument(ir::ReturnStatement *returnStatement); std::string ProcessLiteralArgument(ir::Literal *literal, ir::ReturnStatement *returnStatement); @@ -56,8 +54,8 @@ private: private: util::DiagnosticEngine &diagnosticEngine_; - parser::Program &program_; + const parser::Program &program_; }; -} // namespace ark::es2panda::checker +} // namespace ark::es2panda::declgen #endif // ES2PANDA_CHECKER_ISOLATED_DECLGEN_CHECKER_H \ No newline at end of file diff --git a/ets2panda/util/diagnostic/isolated_declgen.yaml b/ets2panda/declgen_ets2ts/isolated_declgen.yaml similarity index 88% rename from ets2panda/util/diagnostic/isolated_declgen.yaml rename to ets2panda/declgen_ets2ts/isolated_declgen.yaml index fb9d9d2c32..bfde0c6897 100644 --- a/ets2panda/util/diagnostic/isolated_declgen.yaml +++ b/ets2panda/declgen_ets2ts/isolated_declgen.yaml @@ -23,26 +23,22 @@ isolated_declgen: id: 3 message: Property must have an explicit type annotation when using isolated declaration. -- name: OBJECTS_THAT_CONTAIN_SPREAD_ASSIGNMENTS_CANNOT_BE_INFERRED_WITH_ISOLATED_DECL - id: 4 - message: Objects that contain spread assignments cannot be inferred with isolated declaration. - - name: ONLY_CONST_ARRAYS_CAN_BE_INFERRED_WITH_ISOLATED_DECL - id: 5 + id: 4 message: Only const arrays can be inferred with isolated declaration. - name: DECLARATION_EMIT_FOR_THIS_PARAMETER_REQUIRES_IMPLICITLY_ADD_UNDEFINED_TO_ITS_TYPE_NOT_ALLOWED_IN_ISOLATED_DECL - id: 6 + id: 5 message: Declaration emit for this parameter requires implicitly adding undefined to its type, which is not allowed in isolated declaration. -- name: DEFAULT_EXPORTS__CANNOT_BE_INFERRED_WITH_ISOLATED_DECL - id: 7 +- name: DEFAULT_EXPORTS_CANNOT_BE_INFERRED_WITH_ISOLATED_DECL + id: 6 message: Cannot use array creation expression with type parameter. - name: FUNCTION_MUST_HAVE_AN_EXPLICIT_RETURN_TYPE_ANNOTATION_WITH_ISOLATED_DECL - id: 8 + id: 7 message: Function must have an explicit return type annotation when using isolated declaration. - name: METHOD_MUST_HAVE_AN_EXPLICIT_RETURN_TYPE_ANNOTATION_WITH_ISOLATED_DECL - id: 9 + id: 8 message: Method must have an explicit return type annotation when using isolated declaration. \ No newline at end of file diff --git a/ets2panda/declgen_ets2ts/main.cpp b/ets2panda/declgen_ets2ts/main.cpp index 385e9f37c8..a13937b367 100644 --- a/ets2panda/declgen_ets2ts/main.cpp +++ b/ets2panda/declgen_ets2ts/main.cpp @@ -13,10 +13,10 @@ * limitations under the License. */ -#include #include "public/es2panda_lib.h" #include "public/public.h" #include "declgenEts2Ts.h" +#include "isolatedDeclgenChecker.h" namespace ark::es2panda::declgen_ets2ts { @@ -26,7 +26,6 @@ static void PrintUsage() std::cerr << " --export-all Treat all top level statements as exported\n"; std::cerr << " --output-dets=[FILE] Path to output .d.ets file\n"; std::cerr << " --output-ets=[FILE] Path to output .ets file\n"; - std::cerr << " --generate-decl:enable-isolated Generate isolated decl\n"; std::cerr << " --help Print this message and exit. Default: false\n"; std::cerr << "Tail arguments:\n"; std::cerr << "input: input file\n"; @@ -68,21 +67,11 @@ static DeclgenOptions ParseOptions(Span args) std::strchr(args[i], '=') != nullptr) { std::string arg = args[i]; options.outputEts = arg.substr(std::strlen("--output-ets=")); - } else if (std::strcmp(args[i], "--generate-decl:enable-isolated") == 0) { - options.isIsolatedDeclgen = true; } } return options; } -static void DestroyContextAndConfig(const es2panda_Impl *impl, es2panda_Context *ctx, es2panda_Config *cfg, - const char **newArgv) -{ - impl->DestroyContext(ctx); - impl->DestroyConfig(cfg); - delete[] newArgv; -} - static int Run(int argc, const char **argv) { Span args(argv, static_cast(argc)); @@ -107,31 +96,16 @@ static int Run(int argc, const char **argv) auto *ctxImpl = reinterpret_cast(ctx); auto *checker = reinterpret_cast(ctxImpl->GetChecker()); - auto *isolatedDeclgenChecker = reinterpret_cast(ctxImpl->isolatedDeclgenChecker); - impl->ProceedToState(ctx, ES2PANDA_STATE_BOUND); - if (declgenOptions.isIsolatedDeclgen) { - isolatedDeclgenChecker->CheckBeforeChecker(); - if (ctxImpl->diagnosticEngine->IsAnyError()) { - DestroyContextAndConfig(impl, ctx, cfg, newArgv); - return 1; - } - } - impl->ProceedToState(ctx, ES2PANDA_STATE_CHECKED); - if (declgenOptions.isIsolatedDeclgen) { - isolatedDeclgenChecker->CheckAfterChecker(); - if (ctxImpl->diagnosticEngine->IsAnyError()) { - DestroyContextAndConfig(impl, ctx, cfg, newArgv); - return 1; - } - } int res = 0; if (!GenerateTsDeclarations(checker, ctxImpl->parserProgram, declgenOptions)) { res = 1; } - DestroyContextAndConfig(impl, ctx, cfg, newArgv); + impl->DestroyContext(ctx); + impl->DestroyConfig(cfg); + delete[] newArgv; return res; } diff --git a/ets2panda/driver/build_system/src/build/base_mode.ts b/ets2panda/driver/build_system/src/build/base_mode.ts index e1d65f97f6..32c7bbf70a 100644 --- a/ets2panda/driver/build_system/src/build/base_mode.ts +++ b/ets2panda/driver/build_system/src/build/base_mode.ts @@ -194,6 +194,7 @@ export abstract class BaseMode { arkts.generateTsDeclarationsFromContext( declEtsOutputPath, etsOutputPath, + false, false ); // Generate 1.0 declaration files & 1.0 glue code this.logger.printInfo('declaration files generated'); diff --git a/ets2panda/driver/build_system/src/build/declgen_worker.ts b/ets2panda/driver/build_system/src/build/declgen_worker.ts index 63968d0d15..dbf67a1147 100644 --- a/ets2panda/driver/build_system/src/build/declgen_worker.ts +++ b/ets2panda/driver/build_system/src/build/declgen_worker.ts @@ -94,6 +94,7 @@ process.on('message', (message: { arkts.generateTsDeclarationsFromContext( declEtsOutputPath, etsOutputPath, + false, false ); // Generate 1.0 declaration files & 1.0 glue code logger.printInfo('declaration files generated'); diff --git a/ets2panda/ir/astNode.cpp b/ets2panda/ir/astNode.cpp index 9661f1c36c..6c9b210ee2 100644 --- a/ets2panda/ir/astNode.cpp +++ b/ets2panda/ir/astNode.cpp @@ -266,13 +266,6 @@ std::string AstNode::DumpDecl() const return dumper.Str(); } -std::string AstNode::IsolatedDumpDecl() const -{ - ir::SrcDumper dumper {this, true, true}; - dumper.Run(); - return dumper.Str(); -} - void AstNode::SetOriginalNode(AstNode *originalNode) noexcept { if (OriginalNode() != originalNode) { diff --git a/ets2panda/ir/astNode.h b/ets2panda/ir/astNode.h index 1fd37c07dd..99b589133f 100644 --- a/ets2panda/ir/astNode.h +++ b/ets2panda/ir/astNode.h @@ -555,7 +555,6 @@ public: std::string DumpJSON() const; std::string DumpEtsSrc() const; std::string DumpDecl() const; - std::string IsolatedDumpDecl() const; virtual void Dump(ir::AstDumper *dumper) const = 0; virtual void Dump(ir::SrcDumper *dumper) const = 0; diff --git a/ets2panda/ir/base/classProperty.cpp b/ets2panda/ir/base/classProperty.cpp index 2bacec57d1..9fb04ee715 100644 --- a/ets2panda/ir/base/classProperty.cpp +++ b/ets2panda/ir/base/classProperty.cpp @@ -14,7 +14,6 @@ */ #include "classProperty.h" -#include #include "checker/ETSchecker.h" #include "checker/TSchecker.h" @@ -199,10 +198,6 @@ void ClassProperty::DumpCheckerTypeForDeclGen(ir::SrcDumper *dumper) const } auto typeStr = TsType()->ToString(); - if (TsType()->IsTypeError() && dumper->IsIsolatedDeclgen() && typeAnnotation_ != nullptr) { - typeStr = typeAnnotation_->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Name().Mutf8(); - } - dumper->Add(": "); dumper->Add(typeStr); diff --git a/ets2panda/ir/base/scriptFunction.cpp b/ets2panda/ir/base/scriptFunction.cpp index 73ef90390f..71fe36ba69 100644 --- a/ets2panda/ir/base/scriptFunction.cpp +++ b/ets2panda/ir/base/scriptFunction.cpp @@ -294,8 +294,7 @@ void ScriptFunction::DumpCheckerTypeForDeclGen(ir::SrcDumper *dumper) const return; } - auto typeStr = dumper->IsIsolatedDeclgen() ? GetIsolatedDeclgenReturnType() : Signature()->ReturnType()->ToString(); - + auto typeStr = Signature()->ReturnType()->ToString(); dumper->Add(": "); dumper->Add(typeStr); @@ -409,8 +408,8 @@ void ScriptFunction::CopyTo(AstNode *other) const otherImpl->preferredReturnType_ = preferredReturnType_; otherImpl->lang_ = lang_; otherImpl->returnStatements_ = returnStatements_; - otherImpl->isolatedDeclGenInferType_ = isolatedDeclGenInferType_; JsDocAllowed>::CopyTo(other); } + } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/base/scriptFunction.h b/ets2panda/ir/base/scriptFunction.h index e5a246ebb6..56ba72e368 100644 --- a/ets2panda/ir/base/scriptFunction.h +++ b/ets2panda/ir/base/scriptFunction.h @@ -344,16 +344,6 @@ public: checker::Type *Check(checker::TSChecker *checker) override; checker::VerifiedType Check(checker::ETSChecker *checker) override; - void SetIsolatedDeclgenReturnType(std::string type) noexcept - { - isolatedDeclGenInferType_ = std::move(type); - } - - [[nodiscard]] std::string GetIsolatedDeclgenReturnType() const noexcept - { - return isolatedDeclGenInferType_; - } - void Accept(ASTVisitorT *v) override { v->Accept(this); @@ -391,7 +381,6 @@ private: checker::Type *preferredReturnType_ {}; es2panda::Language lang_; ArenaVector returnStatements_; - std::string isolatedDeclGenInferType_; }; } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/srcDump.cpp b/ets2panda/ir/srcDump.cpp index da7293ca38..d3b7c1da85 100644 --- a/ets2panda/ir/srcDump.cpp +++ b/ets2panda/ir/srcDump.cpp @@ -31,9 +31,7 @@ SrcDumper::SrcDumper(const ir::AstNode *node) node->Dump(this); } -SrcDumper::SrcDumper(const ir::AstNode *node, bool isDeclgen, bool isIsolatedDeclgen) - : isDeclgen_(isDeclgen), isIsolatedDeclgen_(isIsolatedDeclgen) - +SrcDumper::SrcDumper(const ir::AstNode *node, bool isDeclgen) : isDeclgen_(isDeclgen) { node->Dump(this); } diff --git a/ets2panda/ir/srcDump.h b/ets2panda/ir/srcDump.h index f21bcc31e8..226108b506 100644 --- a/ets2panda/ir/srcDump.h +++ b/ets2panda/ir/srcDump.h @@ -42,7 +42,7 @@ using NodeVariant = class SrcDumper { public: explicit SrcDumper(const ir::AstNode *node); - explicit SrcDumper(const ir::AstNode *node, bool isDeclgen, bool isIsolatedDeclgen = false); + explicit SrcDumper(const ir::AstNode *node, bool isDeclgen); void Add(const std::string &str); void Add(int8_t i); @@ -62,10 +62,6 @@ public: void Endl(size_t num = 1); bool IsDeclgen() const; - bool IsIsolatedDeclgen() const - { - return isIsolatedDeclgen_; - } void DumpVariant(NodeVariant &node); void DumpNode(const std::string &key); @@ -100,7 +96,6 @@ private: std::stringstream ss_; std::string indent_; bool isDeclgen_ = false; - bool isIsolatedDeclgen_ = false; bool isIndirectDepPhase_ = false; std::unordered_map unExportNode_; diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 36001a7946..9321f21511 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -140,11 +140,9 @@ void ETSParser::ParseProgram(ScriptKind kind) if ((GetContext().Status() & ParserStatus::IN_PACKAGE) != 0) { GetContext().Status() &= ~ParserStatus::IN_PACKAGE; } - - if (!GetOptions().IsGenerateDeclEnableIsolated()) { - AddExternalSource(ParseSources(true)); - } - +#ifndef ENABLE_ISOLATED_DECLGEN + AddExternalSource(ParseSources(true)); +#endif GetProgram()->SetAst(script); } diff --git a/ets2panda/public/CMakeLists.txt b/ets2panda/public/CMakeLists.txt index 12227ac6fe..59a10c7855 100644 --- a/ets2panda/public/CMakeLists.txt +++ b/ets2panda/public/CMakeLists.txt @@ -624,6 +624,7 @@ add_custom_target(gen_yamls DEPENDS es2panda_options_gen es2panda_keywords ${ES2 set(ES2PANDA_PUBLIC_SOURCES ${LIB_NAME}.cpp ../declgen_ets2ts/declgenEts2Ts.cpp + ../declgen_ets2ts/isolatedDeclgenChecker.cpp ../util/generateBin.cpp ../util/options.cpp ../util/plugin.cpp diff --git a/ets2panda/public/es2panda_lib.cpp b/ets2panda/public/es2panda_lib.cpp index 14a173532e..31255c13b7 100644 --- a/ets2panda/public/es2panda_lib.cpp +++ b/ets2panda/public/es2panda_lib.cpp @@ -360,7 +360,6 @@ static void InitializeContext(Context *res) res->parser->SetContext(res); res->PushChecker(res->allocator->New(res->allocator, *res->diagnosticEngine, res->allocator)); - res->isolatedDeclgenChecker = new checker::IsolatedDeclgenChecker(*res->diagnosticEngine, *(res->parserProgram)); res->PushAnalyzer(res->allocator->New(res->GetChecker())); res->GetChecker()->SetAnalyzer(res->GetAnalyzer()); @@ -1171,7 +1170,8 @@ extern "C" es2panda_AstNode **AllDeclarationsByNameFromProgram([[maybe_unused]] extern "C" __attribute__((unused)) int GenerateTsDeclarationsFromContext(es2panda_Context *ctx, const char *outputDeclEts, - const char *outputEts, bool exportAll) + const char *outputEts, bool exportAll, + bool isolated) { auto *ctxImpl = reinterpret_cast(ctx); auto *checker = reinterpret_cast(ctxImpl->GetChecker()); @@ -1180,6 +1180,7 @@ extern "C" __attribute__((unused)) int GenerateTsDeclarationsFromContext(es2pand declgenOptions.exportAll = exportAll; declgenOptions.outputDeclEts = outputDeclEts ? outputDeclEts : ""; declgenOptions.outputEts = outputEts ? outputEts : ""; + declgenOptions.isolated = isolated; return ark::es2panda::declgen_ets2ts::GenerateTsDeclarations(checker, ctxImpl->parserProgram, declgenOptions) ? 0 : 1; @@ -1193,7 +1194,7 @@ extern "C" __attribute__((unused)) int GenerateStaticDeclarationsFromContext(es2 if (ctxImpl->state != ES2PANDA_STATE_CHECKED) { return 1; } - compiler::HandleGenerateDecl(*ctxImpl->parserProgram, *ctxImpl->diagnosticEngine, outputPath, false); + compiler::HandleGenerateDecl(*ctxImpl->parserProgram, *ctxImpl->diagnosticEngine, outputPath); return ctxImpl->diagnosticEngine->IsAnyError() ? 1 : 0; } diff --git a/ets2panda/public/es2panda_lib.h b/ets2panda/public/es2panda_lib.h index cf927443b4..0ee2e6932d 100644 --- a/ets2panda/public/es2panda_lib.h +++ b/ets2panda/public/es2panda_lib.h @@ -262,7 +262,7 @@ struct CAPI_EXPORT es2panda_Impl { const char *name, size_t *declsLen); int (*GenerateTsDeclarationsFromContext)(es2panda_Context *context, const char *outputDeclEts, - const char *outputEts, bool exportAll); + const char *outputEts, bool exportAll, bool isolated); void (*InsertETSImportDeclarationAndParse)(es2panda_Context *context, es2panda_Program *program, es2panda_AstNode *importDeclaration); int (*GenerateStaticDeclarationsFromContext)(es2panda_Context *context, const char *outputPath); diff --git a/ets2panda/public/public.h b/ets2panda/public/public.h index 8ae7475ff7..447555838c 100644 --- a/ets2panda/public/public.h +++ b/ets2panda/public/public.h @@ -25,7 +25,6 @@ #include "compiler/core/compileQueue.h" #include "parser/ETSparser.h" #include "checker/ETSchecker.h" -#include "checker/IsolatedDeclgenChecker.h" #include "compiler/core/emitter.h" namespace ark::es2panda::util { @@ -212,7 +211,6 @@ struct Context { parser::Program *parserProgram = nullptr; parser::ParserImpl *parser = nullptr; - compiler::Emitter *emitter = nullptr; pandasm::Program *program = nullptr; util::DiagnosticEngine *diagnosticEngine = nullptr; @@ -226,7 +224,6 @@ struct Context { TransitionMemory *transitionMemory {nullptr}; bool isExternal = false; bool compiledByCapi = false; - checker::IsolatedDeclgenChecker *isolatedDeclgenChecker {nullptr}; // NOLINTEND(misc-non-private-member-variables-in-classes) private: diff --git a/ets2panda/test/isolated_declgen/infer_function_return_type_with_import_symbol-expected.txt b/ets2panda/test/isolated_declgen/infer_function_return_type_with_import_symbol-expected.txt deleted file mode 100644 index 1804ab1e7b..0000000000 --- a/ets2panda/test/isolated_declgen/infer_function_return_type_with_import_symbol-expected.txt +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2025 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. - */ - -import A from "./infer_function_return_type_with_literal.ets"; - -import B from "./infer_function_return_type_with_literal.ets"; - -import C from "./infer_function_return_type_with_literal.ets"; - -export declare let b: A; - -export default declare let d: int; - -export declare function foo(a: int, c: C): A | Array | Array | Array | B | Number | String; \ No newline at end of file diff --git a/ets2panda/test/isolated_declgen/infer_function_return_type_with_literal-expected.txt b/ets2panda/test/isolated_declgen/infer_function_return_type_with_literal-expected.txt deleted file mode 100644 index 0580538547..0000000000 --- a/ets2panda/test/isolated_declgen/infer_function_return_type_with_literal-expected.txt +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright (c) 2025 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. - */ - - export declare function foo(a: int): Int|Boolean|String; \ No newline at end of file diff --git a/ets2panda/test/isolated_declgen/infer_function_return_type_with_variable-expected.txt b/ets2panda/test/isolated_declgen/infer_function_return_type_with_variable-expected.txt deleted file mode 100644 index 6eced86611..0000000000 --- a/ets2panda/test/isolated_declgen/infer_function_return_type_with_variable-expected.txt +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright (c) 2025 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. - */ - - export declare function foo(a: int): String|B|Int|A; \ No newline at end of file diff --git a/ets2panda/test/isolated_declgen/isolated_interface-expected.txt b/ets2panda/test/isolated_declgen/isolated_interface-expected.txt deleted file mode 100644 index 029658ebdd..0000000000 --- a/ets2panda/test/isolated_declgen/isolated_interface-expected.txt +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2025 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. - */ - -export declare interface User { - set id(id: number): void; - - get id(): double; - set name(name: string): void; - - get name(): String; - set age(age: number | undefined): void; - - get age(): Double|undefined; - get apiUrl(): String; - -} - -export declare interface Animal { - set name(name: string): void; - - get name(): String; - makeSound(): void; - -} \ No newline at end of file diff --git a/ets2panda/test/isolated_declgen/isolated_namespace-expected.txt b/ets2panda/test/isolated_declgen/isolated_namespace-expected.txt deleted file mode 100644 index c5d5aa7784..0000000000 --- a/ets2panda/test/isolated_declgen/isolated_namespace-expected.txt +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2025 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. - */ - - export declare namespace MathOperations { - - let PI: double; - - function add(a: number, b: number): double; - - function subtract(a: number, b: number): double; - - -} \ No newline at end of file diff --git a/ets2panda/test/unit/CMakeLists.txt b/ets2panda/test/unit/CMakeLists.txt index 07663a9a29..c84184cf5f 100644 --- a/ets2panda/test/unit/CMakeLists.txt +++ b/ets2panda/test/unit/CMakeLists.txt @@ -16,6 +16,7 @@ if(NOT PANDA_REGRESSION_TESTS) endif() add_subdirectory(cfg) +add_subdirectory(declgen) add_subdirectory(dynamic) add_subdirectory(lowerings) add_subdirectory(public) diff --git a/ets2panda/test/unit/declgen/CMakeLists.txt b/ets2panda/test/unit/declgen/CMakeLists.txt new file mode 100644 index 0000000000..37a9cc4496 --- /dev/null +++ b/ets2panda/test/unit/declgen/CMakeLists.txt @@ -0,0 +1,89 @@ +# Copyright (c) 2025 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. + +if (PANDA_ENABLE_ADDRESS_SANITIZER OR PANDA_ENABLE_THREAD_SANITIZER) + return() +endif() + +set(COMMON_SOURCE_FILES + "util.cpp" +) + +set(DECLGEN_PLUGIN_TESTS + "test_ets2ts_isolated_declgen cpp" +) + +set(ETS2TS_ISOLATED_TESTS + "./ets2ts_isolated/test_ets2ts_isolated_class.ets" + "./ets2ts_isolated/test_ets2ts_isolated_enum.ets" + "./ets2ts_isolated/test_ets2ts_isolated_module.ets" + "./ets2ts_isolated/test_ets2ts_isolated_namespace.ets" + "./ets2ts_isolated/test_ets2ts_isolated_interface.ets" + "./ets2ts_isolated/test_ets2ts_isolated_function_with_optional_parameter.ets" + "./ets2ts_isolated/test_ets2ts_infer_function_return_type_with_import_symbol.ets" +) + +foreach(TEST_DATA IN ITEMS ${DECLGEN_PLUGIN_TESTS}) + string(REPLACE " " ";" TEST_DATA_ELEM "${TEST_DATA}") + list(GET TEST_DATA_ELEM 0 TEST_NAME) + list(GET TEST_DATA_ELEM 1 EXTENSION) + + panda_add_executable(${TEST_NAME} ${TEST_NAME}.${EXTENSION} ${COMMON_SOURCE_FILES} OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + panda_add_sanitizers(TARGET ${TEST_NAME} SANITIZERS ${PANDA_SANITIZERS_LIST}) + + panda_target_include_directories(${TEST_NAME} + PRIVATE ${ES2PANDA_PATH} + PRIVATE ${PANDA_ROOT}/libpandafile + PRIVATE ${PANDA_ROOT}/assembler + PRIVATE ${OUTPUT_DIR} + PUBLIC ${CMAKE_CURRENT_BINARY_DIR} + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + PUBLIC ${CMAKE_SOURCE_DIR}/libpandabase + PUBLIC ${CMAKE_SOURCE_DIR}/runtime + PUBLIC ${CMAKE_BINARY_DIR}/libpandabase + PUBLIC ${CMAKE_BINARY_DIR}/libpandafile/include + ${CMAKE_BINARY_DIR} + ) + panda_target_link_libraries(${TEST_NAME} es2panda-public arkassembler arkbase arkfile) +endforeach() + +add_custom_target(es2panda-declgen-plugin-test) + +set(ETS2TS "ets2ts_isolated") +foreach(TEST_DATA IN ITEMS ${DECLGEN_PLUGIN_TESTS}) + string(REPLACE " " ";" TEST_DATA_ELEM "${TEST_DATA}") + list(GET TEST_DATA_ELEM 0 TEST_NAME) + list(GET TEST_DATA_ELEM 1 EXTENSION) + foreach(TEST_ETS_FILE IN ITEMS ${ETS2TS_ISOLATED_TESTS}) + cmake_path(SET PATH_ITEM "${TEST_ETS_FILE}") + cmake_path(GET PATH_ITEM STEM FILE_NAME) + add_custom_target(es2panda-declgen-plugin-test-compile-${FILE_NAME} + COMMAND ${CMAKE_COMMAND} -E env + LD_LIBRARY_PATH=${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${PANDA_RUN_PREFIX} + ${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME} $ + --extension=ets --ets-unnamed --output="${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}.abc" + "${CMAKE_CURRENT_SOURCE_DIR}/${TEST_ETS_FILE}" > "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}.out" 2>&1 + ) + add_dependencies(es2panda-declgen-plugin-test-compile-${FILE_NAME} es2panda ${TEST_NAME} es2panda-lib) + add_dependencies(es2panda-declgen-plugin-test es2panda-declgen-plugin-test-compile-${FILE_NAME}) + + add_custom_target(es2panda-declgen-plugin-test-expected-${FILE_NAME} + COMMAND ${CMAKE_COMMAND} -E compare_files + "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}.d.ets" "${CMAKE_CURRENT_SOURCE_DIR}/${ETS2TS}/${FILE_NAME}-expected.txt" + ) + add_dependencies(es2panda-declgen-plugin-test-expected-${FILE_NAME} es2panda-declgen-plugin-test-compile-${FILE_NAME} es2panda-lib) + add_dependencies(es2panda-declgen-plugin-test es2panda-declgen-plugin-test-expected-${FILE_NAME}) + endforeach() +endforeach() + +add_dependencies(es2panda_tests es2panda-declgen-plugin-test) \ No newline at end of file diff --git a/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_infer_function_return_type_with_import_symbol-expected.txt b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_infer_function_return_type_with_import_symbol-expected.txt new file mode 100644 index 0000000000..ca2fd1c2e9 --- /dev/null +++ b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_infer_function_return_type_with_import_symbol-expected.txt @@ -0,0 +1,7 @@ +import A from "./test_ets2ts_isolated_enum"; +import B from "./test_ets2ts_isolated_enum"; +import C from "./test_ets2ts_isolated_enum"; +export declare let b: A; +declare let d: number; +export default d; +export declare function foo(a: number, c: C): A | Array | Array | Array | B | number | string; diff --git a/ets2panda/test/isolated_declgen/infer_function_return_type_with_import_symbol.ets b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_infer_function_return_type_with_import_symbol.ets similarity index 84% rename from ets2panda/test/isolated_declgen/infer_function_return_type_with_import_symbol.ets rename to ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_infer_function_return_type_with_import_symbol.ets index 6acccddadf..3948758074 100644 --- a/ets2panda/test/isolated_declgen/infer_function_return_type_with_import_symbol.ets +++ b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_infer_function_return_type_with_import_symbol.ets @@ -13,9 +13,9 @@ * limitations under the License. */ -import A from "./infer_function_return_type_with_literal.ets" -import B from "./infer_function_return_type_with_literal.ets" -import C from "./infer_function_return_type_with_literal.ets" +import A from "./test_ets2ts_isolated_enum.ets" +import B from "./test_ets2ts_isolated_enum.ets" +import C from "./test_ets2ts_isolated_enum.ets" export let b: A = new A @@ -43,8 +43,4 @@ export function foo(a: int, c: C) } return "hello"; -} - - - - +} \ No newline at end of file diff --git a/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_class-expected.txt b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_class-expected.txt new file mode 100644 index 0000000000..4ad14cb500 --- /dev/null +++ b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_class-expected.txt @@ -0,0 +1,18 @@ +export declare interface I0 { + I0Method(a: string): string; +} +export declare interface I1 { + I1Method(a: number): number; +} +export declare class Base { + public get a(): number; + public set a(value: number); + public constructor(a: number); +} +export declare class Derived extends Base implements I0, I1 { + public I0Method(a: string): string; + public I1Method(a: number): number; + public get b(): number; + public set b(value: number); + public constructor(a: number, b: number); +} diff --git a/ets2panda/test/isolated_declgen/isolated_class.ets b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_class.ets similarity index 100% rename from ets2panda/test/isolated_declgen/isolated_class.ets rename to ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_class.ets diff --git a/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_enum-expected.txt b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_enum-expected.txt new file mode 100644 index 0000000000..ae0a088911 --- /dev/null +++ b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_enum-expected.txt @@ -0,0 +1,11 @@ +export declare enum Direction { + Up = 0, + Down = 1, + Left = 2, + Right = 3, +} +export declare enum Message { + Success = "SUCCESS", + Failure = "FAILURE", + Pending = "PENDING", +} diff --git a/ets2panda/test/isolated_declgen/isolated_function_with_optional_parameter-expected.txt b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_enum.ets similarity index 80% rename from ets2panda/test/isolated_declgen/isolated_function_with_optional_parameter-expected.txt rename to ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_enum.ets index 5276a1c1bd..045fe8db94 100644 --- a/ets2panda/test/isolated_declgen/isolated_function_with_optional_parameter-expected.txt +++ b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_enum.ets @@ -12,7 +12,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +export enum Direction { + Up, + Down, + Left, + Right +} -export declare function greet(name: string, age?: number): String; - -export declare function multiply(x: number, gensym%%_1?: number): double; \ No newline at end of file +export enum Message { + Success = "SUCCESS", + Failure = "FAILURE", + Pending = "PENDING" +} \ No newline at end of file diff --git a/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_function_with_optional_parameter-expected.txt b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_function_with_optional_parameter-expected.txt new file mode 100644 index 0000000000..602c65d87e --- /dev/null +++ b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_function_with_optional_parameter-expected.txt @@ -0,0 +1,2 @@ +export declare function greet(name: string, age?: number): string; +export declare function multiply(x: number, y?: number): number; diff --git a/ets2panda/test/isolated_declgen/isolated_function_with_optional_parameter.ets b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_function_with_optional_parameter.ets similarity index 100% rename from ets2panda/test/isolated_declgen/isolated_function_with_optional_parameter.ets rename to ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_function_with_optional_parameter.ets diff --git a/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_interface-expected.txt b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_interface-expected.txt new file mode 100644 index 0000000000..40f1e96753 --- /dev/null +++ b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_interface-expected.txt @@ -0,0 +1,14 @@ +export declare interface User { + get id(): number; + set id(value: number); + get name(): string; + set name(value: string); + get age(): number | undefined; + set age(value: number | undefined); + get apiUrl(): string; +} +export declare interface Animal { + get name(): string; + set name(value: string); + makeSound(): void; +} diff --git a/ets2panda/test/isolated_declgen/isolated_interface.ets b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_interface.ets similarity index 99% rename from ets2panda/test/isolated_declgen/isolated_interface.ets rename to ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_interface.ets index 828c677385..1b27d21ef4 100644 --- a/ets2panda/test/isolated_declgen/isolated_interface.ets +++ b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_interface.ets @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - + export interface User { id: number; name: string; diff --git a/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_module-expected.txt b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_module-expected.txt new file mode 100644 index 0000000000..9091aa582e --- /dev/null +++ b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_module-expected.txt @@ -0,0 +1,6 @@ +import * as np from "./test_ets2ts_isolated_enum"; +import { B, C0 as C } from "./test_ets2ts_isolated_enum"; +export declare let b: np.A; +declare let d: number; +export default d; +export declare function foo(a: number, c: C): Array | Array | Array | B | np.A | number | string; diff --git a/ets2panda/test/isolated_declgen/infer_function_return_type_with_variable.ets b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_module.ets similarity index 63% rename from ets2panda/test/isolated_declgen/infer_function_return_type_with_variable.ets rename to ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_module.ets index 4a19a2de33..cd3bbc6bfa 100644 --- a/ets2panda/test/isolated_declgen/infer_function_return_type_with_variable.ets +++ b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_module.ets @@ -13,20 +13,33 @@ * limitations under the License. */ -class A {} -class B {} +import * as np from "./test_ets2ts_isolated_enum.ets" +import {B, C0 as C} from "./test_ets2ts_isolated_enum.ets" -export function foo(a: int) +export let b: np.A = new np.A + +export default let d: int = 1 + +export function foo(a: int, c: C) { if (a < 0) { return 1; } if (a == 0) { - return new A; + return b; } - if (a > 0) { + if (a == 1) { return new B; } + if (a == 2) { + return ["hello", "arkts"]; + } + if (a == 3) { + return [0, 1, 2]; + } + if (a == 4) { + return [true, false, false, true]; + } return "hello"; } \ No newline at end of file diff --git a/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_namespace-expected.txt b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_namespace-expected.txt new file mode 100644 index 0000000000..d0ac8cfd8a --- /dev/null +++ b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_namespace-expected.txt @@ -0,0 +1,5 @@ +export declare namespace MathOperations { + const PI: number; + function add(a: number, b: number): number; + function subtract(a: number, b: number): number; +} diff --git a/ets2panda/test/isolated_declgen/isolated_namespace.ets b/ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_namespace.ets similarity index 100% rename from ets2panda/test/isolated_declgen/isolated_namespace.ets rename to ets2panda/test/unit/declgen/ets2ts_isolated/test_ets2ts_isolated_namespace.ets diff --git a/ets2panda/test/isolated_declgen/infer_function_return_type_with_literal.ets b/ets2panda/test/unit/declgen/test_ets2ts_isolated_declgen.cpp similarity index 34% rename from ets2panda/test/isolated_declgen/infer_function_return_type_with_literal.ets rename to ets2panda/test/unit/declgen/test_ets2ts_isolated_declgen.cpp index 00375f7d6e..8cb169287b 100644 --- a/ets2panda/test/isolated_declgen/infer_function_return_type_with_literal.ets +++ b/ets2panda/test/unit/declgen/test_ets2ts_isolated_declgen.cpp @@ -12,18 +12,52 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -export function foo(a: int) + +#include +#include +#include + +#include "os/library_loader.h" + +#include "public/es2panda_lib.h" +#include "./util.h" + +// NOLINTBEGIN + +static es2panda_Impl *impl = nullptr; + +int main(int argc, char **argv) { - if (a < 0) { - return 1; + if (argc < MIN_ARGC) { + return INVALID_ARGC_ERROR_CODE; } - if (a == 0) { - return "hello"; + + if (GetImpl() == nullptr) { + return NULLPTR_IMPL_ERROR_CODE; } - if (a > 0) { - return true; + impl = GetImpl(); + std::cout << "LOAD SUCCESS" << std::endl; + + const char **args = const_cast(&(argv[1])); + auto config = impl->CreateConfig(argc - 1, args); + auto context = impl->CreateContextFromFile(config, argv[argc - 1]); + if (context == nullptr) { + std::cerr << "FAILED TO CREATE CONTEXT" << std::endl; + return NULLPTR_CONTEXT_ERROR_CODE; } - + + impl->ProceedToState(context, ES2PANDA_STATE_CHECKED); + CheckForErrors("CHECKED", context); + std::string declName = GetDeclPrefix(argv[argc - 1]) + ".d.ets"; + int result = impl->GenerateTsDeclarationsFromContext(context, declName.c_str(), "dump.ets", false, true); + if (result != 0) { + std::cerr << "FAILED TO GENERATE DECLARATIONS" << std::endl; + return result; + } + + impl->DestroyConfig(config); + return 0; -} \ No newline at end of file +} + +// NOLINTEND diff --git a/ets2panda/test/unit/declgen/util.cpp b/ets2panda/test/unit/declgen/util.cpp new file mode 100644 index 0000000000..ed872305b2 --- /dev/null +++ b/ets2panda/test/unit/declgen/util.cpp @@ -0,0 +1,83 @@ +/** + * Copyright (c) 2025 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 "util.h" +#include +#include +#include +#include +#include +#include +#include "macros.h" + +static es2panda_Impl *g_implPtr = nullptr; + +es2panda_Impl *GetImpl() +{ + if (g_implPtr != nullptr) { + return g_implPtr; + } + + std::string soName = ark::os::library_loader::DYNAMIC_LIBRARY_PREFIX + std::string("es2panda-public") + + ark::os::library_loader::DYNAMIC_LIBRARY_SUFFIX; + auto libraryRes = ark::os::library_loader::Load(soName); + if (!libraryRes.HasValue()) { + std::cout << "Error in load lib" << std::endl; + return nullptr; + } + + auto library = std::move(libraryRes.Value()); + auto getImpl = ark::os::library_loader::ResolveSymbol(library, "es2panda_GetImpl"); + if (!getImpl.HasValue()) { + std::cout << "Error in load func get g_implPtr" << std::endl; + return nullptr; + } + + auto getImplFunc = reinterpret_cast(getImpl.Value()); + if (getImplFunc != nullptr) { + g_implPtr = const_cast(getImplFunc(ES2PANDA_LIB_VERSION)); + return g_implPtr; + } + return nullptr; +} + +void CheckForErrors(const std::string &stateName, es2panda_Context *context) +{ + if (g_implPtr->ContextState(context) == ES2PANDA_STATE_ERROR) { + std::cout << "PROCEED TO " << stateName << " ERROR" << std::endl; + std::cout << g_implPtr->ContextErrorMessage(context) << std::endl; + } else { + std::cout << "PROCEED TO " << stateName << " SUCCESS" << std::endl; + } +} + +std::string GetDeclPrefix(const char *etsSrcName) +{ + if (etsSrcName == nullptr) { + return ""; + } + std::string_view etsSrc(etsSrcName); + auto pos = etsSrc.find_last_of('/'); + if (pos != std::string_view::npos) { + etsSrc = etsSrc.substr(pos + 1); + } + std::cout << "ETS SRC: " << etsSrc << std::endl; + pos = etsSrc.find_last_of('.'); + if (pos != std::string_view::npos) { + etsSrc = etsSrc.substr(0, pos); + } + std::cout << "ETS SRC PREFIX: " << etsSrc << std::endl; + return std::string(etsSrc); +} \ No newline at end of file diff --git a/ets2panda/test/isolated_declgen/isolated_class-expected.txt b/ets2panda/test/unit/declgen/util.h similarity index 43% rename from ets2panda/test/isolated_declgen/isolated_class-expected.txt rename to ets2panda/test/unit/declgen/util.h index 5ee4f26785..d4c678d9ad 100644 --- a/ets2panda/test/isolated_declgen/isolated_class-expected.txt +++ b/ets2panda/test/unit/declgen/util.h @@ -13,30 +13,34 @@ * limitations under the License. */ -export declare interface I0 { - I0Method(a: string): String; +#ifndef ES2PANDA_TEST_UNIT_DECLGEN_PLUGIN_UTIL_H +#define ES2PANDA_TEST_UNIT_DECLGEN_PLUGIN_UTIL_H -} +#include +#include +#include +#include +#include -export declare interface I1 { - I1Method(a: double): double; +#include "os/library_loader.h" -} +#include "public/es2panda_lib.h" -export declare class Base { - public a: double; +constexpr int MIN_ARGC = 3; - public constructor(a: double); +// error code number +constexpr int NULLPTR_IMPL_ERROR_CODE = 2; +constexpr int PROCEED_ERROR_CODE = 3; +constexpr int TEST_ERROR_CODE = 4; +constexpr int INVALID_ARGC_ERROR_CODE = 5; +constexpr int NULLPTR_CONTEXT_ERROR_CODE = 6; -} +es2panda_Impl *GetImpl(); +void CheckForErrors(const std::string &stateName, es2panda_Context *context); -export declare class Derived extends Base implements I0, I1 { - public I0Method(a: string): String; +es2panda_AstNode *GetETSGlobalClass(es2panda_Context *ctx, es2panda_AstNode *rootNode); - public I1Method(a: double): double; +// CC-OFFNXT(G.NAM.01) false positive +std::string GetDeclPrefix(const char *etsSrcName); - public b: double; - - public constructor(a: double, b: double); - -} \ No newline at end of file +#endif \ No newline at end of file diff --git a/ets2panda/test/unit/sizeof_node_test.cpp b/ets2panda/test/unit/sizeof_node_test.cpp index 61589226cd..b5912cb841 100644 --- a/ets2panda/test/unit/sizeof_node_test.cpp +++ b/ets2panda/test/unit/sizeof_node_test.cpp @@ -283,8 +283,7 @@ size_t SizeOfNodeTest::SizeOf() sizeof(node->signature_) + sizeof(node->preferredReturnType_) + Align(sizeof(node->lang_)) + - sizeof(node->returnStatements_) + - sizeof(node->isolatedDeclGenInferType_); + sizeof(node->returnStatements_); // clang-format on } diff --git a/ets2panda/util/diagnostic.cpp b/ets2panda/util/diagnostic.cpp index 40b71f1e63..8104e2ad61 100644 --- a/ets2panda/util/diagnostic.cpp +++ b/ets2panda/util/diagnostic.cpp @@ -166,12 +166,12 @@ const char *DiagnosticTypeToString(DiagnosticType type) return "Declgen ets2ts error"; case DiagnosticType::DECLGEN_ETS2TS_WARNING: return "Declgen ets2ts warning"; + case DiagnosticType::ISOLATED_DECLGEN: + return "Isolated declgen error"; case DiagnosticType::ARKTS_CONFIG_ERROR: return "ArkTS config error"; case DiagnosticType::SUGGESTION: return "SUGGESTION"; - case DiagnosticType::ISOLATED_DECLGEN: - return "Isolated declgen error"; default: ES2PANDA_UNREACHABLE(); } diff --git a/ets2panda/util/diagnostic.h b/ets2panda/util/diagnostic.h index cb4c70a256..40584dac1c 100644 --- a/ets2panda/util/diagnostic.h +++ b/ets2panda/util/diagnostic.h @@ -50,9 +50,9 @@ enum DiagnosticType { PLUGIN_WARNING, DECLGEN_ETS2TS_ERROR, DECLGEN_ETS2TS_WARNING, + ISOLATED_DECLGEN, ARKTS_CONFIG_ERROR, SUGGESTION, - ISOLATED_DECLGEN, COUNT, INVALID = COUNT }; diff --git a/ets2panda/util/diagnosticEngine.cpp b/ets2panda/util/diagnosticEngine.cpp index 1108b9e7f1..9e294a8cf8 100644 --- a/ets2panda/util/diagnosticEngine.cpp +++ b/ets2panda/util/diagnosticEngine.cpp @@ -114,8 +114,8 @@ bool DiagnosticEngine::IsError(DiagnosticType type) const case DiagnosticType::SEMANTIC: case DiagnosticType::PLUGIN_ERROR: case DiagnosticType::DECLGEN_ETS2TS_ERROR: - case DiagnosticType::ARKTS_CONFIG_ERROR: case DiagnosticType::ISOLATED_DECLGEN: + case DiagnosticType::ARKTS_CONFIG_ERROR: return true; case DiagnosticType::WARNING: case DiagnosticType::DECLGEN_ETS2TS_WARNING: diff --git a/ets2panda/util/options.yaml b/ets2panda/util/options.yaml index 2a1894aeb7..22bf3b6f48 100644 --- a/ets2panda/util/options.yaml +++ b/ets2panda/util/options.yaml @@ -182,10 +182,6 @@ options: type: std::string default: "" description: Output path for generated static declaration files - - name: enable-isolated - type: bool - default: false - description: Whether to enable isolated declaration file generation - name: thread type: int diff --git a/ets2panda/varbinder/ETSBinder.cpp b/ets2panda/varbinder/ETSBinder.cpp index f2983e06ca..aa10db8d69 100644 --- a/ets2panda/varbinder/ETSBinder.cpp +++ b/ets2panda/varbinder/ETSBinder.cpp @@ -155,10 +155,7 @@ void ETSBinder::LookupTypeReference(ir::Identifier *ident, bool allowDynamicName return; } - if (!GetContext()->config->options->IsGenerateDeclEnableIsolated()) { - ThrowUnresolvableType(ident->Start(), name); - } - + ThrowUnresolvableType(ident->Start(), name); CreateDummyVariable(this, ident); } @@ -1010,10 +1007,8 @@ varbinder::Variable *ETSBinder::FindStaticBinding(Span r if (result != nullptr) { return result; } - if (!GetContext()->config->options->IsGenerateDeclEnableIsolated()) { - ThrowError(importPath->Start(), diagnostic::DEFAULT_IMPORT_NOT_FOUND); - } + ThrowError(importPath->Start(), diagnostic::DEFAULT_IMPORT_NOT_FOUND); return nullptr; } -- Gitee From aeb0aa77ab4d5d411de430eb31bf67dd9de498af Mon Sep 17 00:00:00 2001 From: leo9001 Date: Wed, 11 Jun 2025 15:41:45 +0800 Subject: [PATCH 024/209] support GetClassHierarchyInfo support GetClassHierarchyInfo Issue:https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICD5N1 Signed-off-by: leo9001 --- ets2panda/bindings/native/src/lsp.cpp | 39 +++- .../bindings/src/Es2pandaNativeModule.ts | 12 +- ets2panda/bindings/src/lspNode.ts | 45 +++- ets2panda/lsp/include/class_hierarchy_info.h | 139 ++++++------ ets2panda/lsp/include/class_hierarchy_item.h | 135 ++++++++++++ ets2panda/lsp/include/internal_api.h | 2 +- ets2panda/lsp/src/class_hierarchy_info.cpp | 169 +++++++++++---- ets2panda/lsp/src/completions.cpp | 14 +- .../unit/lsp/class_hierarchy_info_test.cpp | 199 ++++++++++++++++-- 9 files changed, 588 insertions(+), 166 deletions(-) create mode 100644 ets2panda/lsp/include/class_hierarchy_item.h diff --git a/ets2panda/bindings/native/src/lsp.cpp b/ets2panda/bindings/native/src/lsp.cpp index 286efef597..d23b1e01cd 100644 --- a/ets2panda/bindings/native/src/lsp.cpp +++ b/ets2panda/bindings/native/src/lsp.cpp @@ -28,7 +28,9 @@ namespace { using ark::es2panda::lsp::ClassHierarchy; using ark::es2panda::lsp::ClassHierarchyInfo; +using ark::es2panda::lsp::ClassHierarchyItem; using ark::es2panda::lsp::ClassMethodItem; +using ark::es2panda::lsp::ClassPropertyItem; } // namespace char *GetStringCopy(KStringPtr &ptr) @@ -722,14 +724,14 @@ KNativePointer impl_getClassNameFromClassHierarchyInfo(KNativePointer info) } TS_INTEROP_1(getClassNameFromClassHierarchyInfo, KNativePointer, KNativePointer) -KNativePointer impl_getMethodListFromClassHierarchyInfo(KNativePointer info) +KNativePointer impl_getMethodItemsFromClassHierarchyInfo(KNativePointer info) { auto *infoPtr = reinterpret_cast(info); if (infoPtr == nullptr) { return nullptr; } std::vector ptrs; - for (const auto &element : infoPtr->GetMethodList()) { + for (const auto &element : infoPtr->GetMethodItemList()) { if (element.second == nullptr) { continue; } @@ -737,17 +739,34 @@ KNativePointer impl_getMethodListFromClassHierarchyInfo(KNativePointer info) } return new std::vector(ptrs); } -TS_INTEROP_1(getMethodListFromClassHierarchyInfo, KNativePointer, KNativePointer) +TS_INTEROP_1(getMethodItemsFromClassHierarchyInfo, KNativePointer, KNativePointer) -KNativePointer impl_getDetailFromClassMethodItem(KNativePointer item) +KNativePointer impl_getPropertyItemsFromClassHierarchyInfo(KNativePointer info) { - auto *itemPtr = reinterpret_cast(item); + auto *infoPtr = reinterpret_cast(info); + if (infoPtr == nullptr) { + return nullptr; + } + std::vector ptrs; + for (const auto &element : infoPtr->GetPropertyItemList()) { + if (element.second == nullptr) { + continue; + } + ptrs.push_back(new ClassPropertyItem(*(element.second))); + } + return new std::vector(ptrs); +} +TS_INTEROP_1(getPropertyItemsFromClassHierarchyInfo, KNativePointer, KNativePointer) + +KNativePointer impl_getDetailFromClassHierarchyItem(KNativePointer item) +{ + auto *itemPtr = reinterpret_cast(item); if (itemPtr == nullptr) { return nullptr; } - return new std::string(itemPtr->GetFunctionDetail()); + return new std::string(itemPtr->GetDetail()); } -TS_INTEROP_1(getDetailFromClassMethodItem, KNativePointer, KNativePointer) +TS_INTEROP_1(getDetailFromClassHierarchyItem, KNativePointer, KNativePointer) KInt impl_getSetterStyleFromClassMethodItem(KNativePointer item) { @@ -759,15 +778,15 @@ KInt impl_getSetterStyleFromClassMethodItem(KNativePointer item) } TS_INTEROP_1(getSetterStyleFromClassMethodItem, KInt, KNativePointer) -KInt impl_getAccessModifierStyleFromClassMethodItem(KNativePointer item) +KInt impl_getAccessModifierStyleFromClassHierarchyItem(KNativePointer item) { - auto *itemPtr = reinterpret_cast(item); + auto *itemPtr = reinterpret_cast(item); if (itemPtr == nullptr) { return 0; } return static_cast(itemPtr->GetAccessModifierStyle()); } -TS_INTEROP_1(getAccessModifierStyleFromClassMethodItem, KInt, KNativePointer) +TS_INTEROP_1(getAccessModifierStyleFromClassHierarchyItem, KInt, KNativePointer) KInt impl_getAliasScriptElementKind(KNativePointer context, KInt position) { diff --git a/ets2panda/bindings/src/Es2pandaNativeModule.ts b/ets2panda/bindings/src/Es2pandaNativeModule.ts index 210ad83e1c..c8ac45f8a8 100644 --- a/ets2panda/bindings/src/Es2pandaNativeModule.ts +++ b/ets2panda/bindings/src/Es2pandaNativeModule.ts @@ -205,19 +205,23 @@ export class Es2pandaNativeModule { throw new Error('Not implemented'); } - _getMethodListFromClassHierarchyInfo(ptr: KNativePointer): KPtr { + _getMethodItemsFromClassHierarchyInfo(ptr: KNativePointer): KPtr { throw new Error('Not implemented'); } - _getDetailFromClassMethodItem(ptr: KNativePointer): KPtr { + _getPropertyItemsFromClassHierarchyInfo(ptr: KNativePointer): KPtr { throw new Error('Not implemented'); } - _getSetterStyleFromClassMethodItem(ptr: KNativePointer): KInt { + _getDetailFromClassHierarchyItem(ptr: KNativePointer): KPtr { throw new Error('Not implemented'); } - _getAccessModifierStyleFromClassMethodItem(ptr: KNativePointer): KInt { + _getAccessModifierStyleFromClassHierarchyItem(ptr: KNativePointer): KInt { + throw new Error('Not implemented'); + } + + _getSetterStyleFromClassMethodItem(ptr: KNativePointer): KInt { throw new Error('Not implemented'); } diff --git a/ets2panda/bindings/src/lspNode.ts b/ets2panda/bindings/src/lspNode.ts index 17f846fce2..ebe31ff07c 100644 --- a/ets2panda/bindings/src/lspNode.ts +++ b/ets2panda/bindings/src/lspNode.ts @@ -23,7 +23,7 @@ import { NativePtrDecoder } from './Platform'; enum HierarchyType { OTHERS, INTERFACE, CLASS }; export enum SetterStyle { - METHOD = 0, + NONE = 0, SETTER, GETTER } @@ -36,6 +36,11 @@ export enum AccessModifierStyle { enum ClassRelationKind { UNKNOWN, INTERFACE, CLASS, FIELD, METHOD, PROPERTY }; +export enum ClassDefinitionStyle { + FIELD = 0, + METHOD +} + export abstract class LspNode { readonly peer: KNativePointer; @@ -228,30 +233,50 @@ export class LspSymbolDisplayPart extends LspNode { readonly kind: String; } -export class LspClassMethodItem extends LspNode { - constructor(peer: KNativePointer) { +export class LspClassHierarchyItem extends LspNode { + constructor(peer: KNativePointer, style: ClassDefinitionStyle) { super(peer); - this.functionDetail = unpackString(global.es2panda._getDetailFromClassMethodItem(this.peer)); + this.style = style; + this.detail = unpackString(global.es2panda._getDetailFromClassHierarchyItem(this.peer)); + this.accessModifier = global.es2panda._getAccessModifierStyleFromClassHierarchyItem(this.peer); + } + readonly detail: string; + readonly accessModifier: AccessModifierStyle; + readonly style: ClassDefinitionStyle; +} + +export class LspClassMethodItem extends LspClassHierarchyItem { + constructor(peer: KNativePointer) { + super(peer, ClassDefinitionStyle.METHOD); this.setter = global.es2panda._getSetterStyleFromClassMethodItem(this.peer); - this.accessModifier = global.es2panda._getAccessModifierStyleFromClassMethodItem(this.peer); } - readonly functionDetail: string; readonly setter: SetterStyle; - readonly accessModifier: AccessModifierStyle; +} + +export class LspClassPropertyItem extends LspClassHierarchyItem { + constructor(peer: KNativePointer) { + super(peer, ClassDefinitionStyle.FIELD); + } } export class LspClassHierarchyInfo extends LspNode { constructor(peer: KNativePointer) { super(peer); this.className = unpackString(global.es2panda._getClassNameFromClassHierarchyInfo(this.peer)); - this.items = new NativePtrDecoder() - .decode(global.es2panda._getMethodListFromClassHierarchyInfo(this.peer)) + this.methodItems = new NativePtrDecoder() + .decode(global.es2panda._getMethodItemsFromClassHierarchyInfo(this.peer)) .map((elPeer: KNativePointer) => { return new LspClassMethodItem(elPeer); }); + this.fieldItems = new NativePtrDecoder() + .decode(global.es2panda._getPropertyItemsFromClassHierarchyInfo(this.peer)) + .map((elPeer: KNativePointer) => { + return new LspClassPropertyItem(elPeer); + }); } readonly className: string; - readonly items: LspClassMethodItem[]; + readonly methodItems: LspClassMethodItem[]; + readonly fieldItems: LspClassPropertyItem[]; } export class LspClassHierarchy extends LspNode { diff --git a/ets2panda/lsp/include/class_hierarchy_info.h b/ets2panda/lsp/include/class_hierarchy_info.h index f7730151ed..8ff110fa20 100644 --- a/ets2panda/lsp/include/class_hierarchy_info.h +++ b/ets2panda/lsp/include/class_hierarchy_info.h @@ -17,9 +17,9 @@ #define ES2PANDA_LSP_CLASS_HIERARCHY_INFO_H #include -#include #include #include +#include "class_hierarchy_item.h" #include "public/es2panda_lib.h" namespace ark::es2panda::lsp { @@ -45,59 +45,6 @@ private: std::string kind_; }; -enum class SetterStyle { METHOD = 0, SETTER, GETTER }; - -enum class AccessModifierStyle { PUBLIC = 0, PROTECTED, PRIVATE }; - -class ClassMethodItem { -public: - ClassMethodItem(std::string detail, SetterStyle setter, AccessModifierStyle access) - : detail_(std::move(detail)), setter_(setter), accessModifier_(access) - { - } - - virtual ~ClassMethodItem() = default; - - ClassMethodItem(const ClassMethodItem &other) = default; - ClassMethodItem(ClassMethodItem &&other) = default; - ClassMethodItem &operator=(const ClassMethodItem &other) = default; - ClassMethodItem &operator=(ClassMethodItem &&other) = default; - - void SetFunctionName(const std::string &functionName) - { - if (functionName.empty()) { - return; - } - funcName_ = functionName; - } - - const std::string &GetFunctionName() const - { - return funcName_; - } - - const std::string &GetFunctionDetail() const - { - return detail_; - } - - SetterStyle GetSetterStyle() const - { - return setter_; - } - - AccessModifierStyle GetAccessModifierStyle() const - { - return accessModifier_; - } - -private: - std::string funcName_; - std::string detail_; - SetterStyle setter_; - AccessModifierStyle accessModifier_; -}; - class ClassHierarchyInfo { public: ClassHierarchyInfo() = default; @@ -122,58 +69,98 @@ public: return className_; } - const std::unordered_map> &GetMethodList() const + const std::unordered_map> &GetMethodItemList() const + { + return methodItems_; + } + + const std::unordered_map> &GetPropertyItemList() const + { + return propertyItems_; + } + + bool AddItemToMethodList(const std::shared_ptr &item) { - return methods_; + if (item == nullptr) { + return false; + } + auto detail = item->GetDetail(); + auto result = methodItems_.try_emplace(detail, item); + return result.second; } - bool AddClassMethodItem(const std::shared_ptr &item) + bool AddItemToPropertyList(const std::shared_ptr &item) { - if (item == nullptr || IsItemExist(item)) { + if (item == nullptr) { return false; } - auto funcDetail = item->GetFunctionDetail(); - methods_[funcDetail] = item; - return true; + auto detail = item->GetDetail(); + auto result = propertyItems_.try_emplace(detail, item); + return result.second; } - void DeleteClassMethodItem(const std::shared_ptr &item) + void DeleteTargetItemInMethodList(const std::shared_ptr &item) { if (item == nullptr) { return; } - auto funcDetail = item->GetFunctionDetail(); - methods_.erase(funcDetail); + auto detail = item->GetDetail(); + methodItems_.erase(detail); } - void DeleteAllClassMethodItem() + void DeleteTargetItemInPropertyList(const std::shared_ptr &item) { - methods_.clear(); + if (item == nullptr) { + return; + } + auto detail = item->GetDetail(); + propertyItems_.erase(detail); } - bool IsItemExist(const std::shared_ptr &item) const + void DeleteAllItemsInMethodList() + { + methodItems_.clear(); + } + + void DeleteAllItemsInPropertyList() + { + propertyItems_.clear(); + } + + bool IsItemExistInMethodList(const std::shared_ptr &item) const { if (item == nullptr) { return false; } - auto func = item->GetFunctionDetail(); - auto iter = methods_.find(func); - return iter != methods_.end(); + auto detail = item->GetDetail(); + auto iter = methodItems_.find(detail); + return iter != methodItems_.end(); + } + + bool IsItemExistInPropertyList(const std::shared_ptr &item) const + { + if (item == nullptr) { + return false; + } + auto detail = item->GetDetail(); + auto iter = propertyItems_.find(detail); + return iter != propertyItems_.end(); } private: std::string className_; - std::unordered_map> methods_; + std::unordered_map> methodItems_; + std::unordered_map> propertyItems_; }; using ClassHierarchy = std::vector; /** - * Retrieve the list of undefined virtual functions in the parent class. + * Retrieve the list of undefined virtual functions and properties in the parent class. * * such as ets: * class Animal { - * private body_: string = ''; + * public body_: string = ''; * * public action(): void { * console.log("need Animal action"); @@ -192,9 +179,9 @@ using ClassHierarchy = std::vector; * console.log("need Bird Drink"); * } * } - * - * when clicking 'Bird'. - * ClassHierarchy is [ { "Animal", { detail: sleep(), SetterStyle: METHOD, AccessModifierStyle: PUBLIC } } ]. + * when clicking 'Bird'. ClassHierarchy is : + * [ { "Animal", { detail: body_: string, ClassDefinitionStyle FIELD, AccessModifierStyle: PUBLIC } }, + * { "Animal", { detail: sleep(): void, ClassDefinitionStyle: METHOD, AccessModifierStyle: PUBLIC } } ]. */ ClassHierarchy GetClassHierarchyInfoImpl(es2panda_Context *context, size_t position); } // namespace ark::es2panda::lsp diff --git a/ets2panda/lsp/include/class_hierarchy_item.h b/ets2panda/lsp/include/class_hierarchy_item.h new file mode 100644 index 0000000000..a2d6789aa7 --- /dev/null +++ b/ets2panda/lsp/include/class_hierarchy_item.h @@ -0,0 +1,135 @@ +/** + * Copyright (c) 2025 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_LSP_CLASS_HIERARCHY_ITEM_H +#define ES2PANDA_LSP_CLASS_HIERARCHY_ITEM_H + +#include + +namespace ark::es2panda::lsp { +enum class SetterStyle { NONE = 0, SETTER, GETTER }; + +enum class AccessModifierStyle { PUBLIC = 0, PROTECTED, PRIVATE }; + +enum class ClassDefinitionStyle { FIELD = 0, METHOD }; + +class ClassHierarchyItem { +public: + ClassHierarchyItem(AccessModifierStyle access, std::string detail) + : accessModifier_(access), detail_(std::move(detail)) + { + } + + virtual ~ClassHierarchyItem() = default; + + ClassHierarchyItem(const ClassHierarchyItem &other) = default; + ClassHierarchyItem(ClassHierarchyItem &&other) = default; + ClassHierarchyItem &operator=(const ClassHierarchyItem &other) = default; + ClassHierarchyItem &operator=(ClassHierarchyItem &&other) = default; + + virtual ClassDefinitionStyle GetClassDefinitionStyle() const = 0; + + AccessModifierStyle GetAccessModifierStyle() const + { + return accessModifier_; + } + + const std::string &GetDetail() const + { + return detail_; + } + +private: + AccessModifierStyle accessModifier_; + std::string detail_; +}; + +class ClassPropertyItem : public ClassHierarchyItem { +public: + ClassPropertyItem(AccessModifierStyle access, std::string detail) : ClassHierarchyItem(access, std::move(detail)) {} + + ~ClassPropertyItem() override = default; + + ClassPropertyItem(const ClassPropertyItem &other) = default; + ClassPropertyItem(ClassPropertyItem &&other) = default; + ClassPropertyItem &operator=(const ClassPropertyItem &other) = default; + ClassPropertyItem &operator=(ClassPropertyItem &&other) = default; + + ClassDefinitionStyle GetClassDefinitionStyle() const override + { + return ClassDefinitionStyle::FIELD; + } + + void SetVariableName(const std::string &variableName) + { + if (variableName.empty()) { + return; + } + variableName_ = variableName; + } + + const std::string &GetVariableName() const + { + return variableName_; + } + +private: + std::string variableName_; +}; + +class ClassMethodItem : public ClassHierarchyItem { +public: + ClassMethodItem(AccessModifierStyle access, std::string detail, SetterStyle setter) + : ClassHierarchyItem(access, std::move(detail)), setter_(setter) + { + } + + ~ClassMethodItem() override = default; + + ClassMethodItem(const ClassMethodItem &other) = default; + ClassMethodItem(ClassMethodItem &&other) = default; + ClassMethodItem &operator=(const ClassMethodItem &other) = default; + ClassMethodItem &operator=(ClassMethodItem &&other) = default; + + ClassDefinitionStyle GetClassDefinitionStyle() const override + { + return ClassDefinitionStyle::METHOD; + } + + void SetFunctionName(const std::string &functionName) + { + if (functionName.empty()) { + return; + } + funcName_ = functionName; + } + + const std::string &GetFunctionName() const + { + return funcName_; + } + + SetterStyle GetSetterStyle() const + { + return setter_; + } + +private: + std::string funcName_; + SetterStyle setter_; +}; +} // namespace ark::es2panda::lsp + +#endif diff --git a/ets2panda/lsp/include/internal_api.h b/ets2panda/lsp/include/internal_api.h index 9d1f8ff9b6..428dbbf806 100644 --- a/ets2panda/lsp/include/internal_api.h +++ b/ets2panda/lsp/include/internal_api.h @@ -93,7 +93,7 @@ std::vector GetCodeFixesAtPositionImpl(es2panda_Context *cont CodeFixOptions &codeFixOptions); CombinedCodeActionsInfo GetCombinedCodeFixImpl(es2panda_Context *context, const std::string &fixId, CodeFixOptions &codeFixOptions); - +ir::Identifier *GetIdentFromNewClassExprPart(const ir::Expression *value); } // namespace ark::es2panda::lsp #endif \ No newline at end of file diff --git a/ets2panda/lsp/src/class_hierarchy_info.cpp b/ets2panda/lsp/src/class_hierarchy_info.cpp index 6534cd30d9..94aa7c9c7a 100644 --- a/ets2panda/lsp/src/class_hierarchy_info.cpp +++ b/ets2panda/lsp/src/class_hierarchy_info.cpp @@ -17,6 +17,7 @@ #include "internal_api.h" #include "public/public.h" #include "compiler/lowering/util.h" +#include "quick_info.h" namespace ark::es2panda::lsp { std::string GetNameFromIdentifierNode(const ir::AstNode *node) @@ -24,7 +25,7 @@ std::string GetNameFromIdentifierNode(const ir::AstNode *node) if (node == nullptr || !node->IsIdentifier()) { return ""; } - return std::string(node->AsIdentifier()->Name()); + return node->AsIdentifier()->ToString(); } // Currently only considering enum scenarios. @@ -77,9 +78,17 @@ std::string SpliceFunctionDetailStr(const std::string &functionName, const std:: return result; } +std::string SplicePropertyDetailStr(const std::string &name, const std::string &type) +{ + if (name.empty() || type.empty()) { + return ""; + } + return name + ": " + type; +} + std::string GetFunctionNameFromScriptFunction(const ir::ScriptFunction *function) { - if (function == nullptr) { + if (function == nullptr || function->Id() == nullptr) { return ""; } return function->Id()->ToString(); @@ -92,21 +101,23 @@ std::vector GetParamListFromScriptFunction(const ir::ScriptF return params; } auto nodeParams = function->Params(); - for (const auto &nodeParam : nodeParams) { + for (const auto *it : nodeParams) { + if (it == nullptr || !it->IsETSParameterExpression()) { + continue; + } std::string paramName; std::string paramKind; - if (!nodeParam->IsETSParameterExpression()) { + auto nodeParam = it->AsETSParameterExpression(); + if (nodeParam->IsRestParameter()) { + paramName = nodeParam->RestParameter()->ToString(); + } else { + paramName = GetNameFromIdentifierNode(nodeParam->Ident()); + } + if (paramName == INVALID_EXPRESSION || nodeParam->TypeAnnotation() == nullptr) { continue; } - paramName = std::string(nodeParam->AsETSParameterExpression()->Name()); - nodeParam->AsETSParameterExpression()->FindChild([¶mKind](ir::AstNode *childNode) { - if (childNode->IsETSTypeReference()) { - paramKind = childNode->AsETSTypeReference()->Part()->Name()->ToString(); - } - return false; - }); - FunctionParamStyle tmp(paramName, paramKind); - params.emplace_back(std::move(tmp)); + paramKind = GetNameForTypeNode(nodeParam->TypeAnnotation()); + params.emplace_back(FunctionParamStyle(std::move(paramName), std::move(paramKind))); } return params; } @@ -116,20 +127,17 @@ std::string GetReturnTypeFromScriptFunction(const ir::ScriptFunction *function) if (function == nullptr) { return ""; } - auto nodeReturn = function->ReturnTypeAnnotation(); - if (nodeReturn == nullptr || !nodeReturn->IsETSTypeReference()) { + auto returnNode = function->ReturnTypeAnnotation(); + if (returnNode == nullptr) { return ""; } - auto ident = nodeReturn->AsETSTypeReference()->Part()->Name(); - if (ident == nullptr || !ident->IsIdentifier()) { - return ""; - } - return std::string(ident->AsIdentifier()->Name()); + auto returnType = GetNameForTypeNode(returnNode); + return returnType; } SetterStyle CreateSetterStyle(ir::MethodDefinitionKind kind) { - SetterStyle setter = SetterStyle::METHOD; + SetterStyle setter = SetterStyle::NONE; switch (kind) { case ir::MethodDefinitionKind::GET: case ir::MethodDefinitionKind::EXTENSION_GET: @@ -151,17 +159,31 @@ std::shared_ptr CreateClassMethodItem(const ir::MethodDefinitio if (methodDefinition == nullptr || funcName.empty() || detail.empty()) { return nullptr; } - auto setter = CreateSetterStyle(methodDefinition->Kind()); AccessModifierStyle access = AccessModifierStyle::PUBLIC; if (methodDefinition->IsProtected()) { access = AccessModifierStyle::PROTECTED; } - auto item = std::make_shared(std::move(detail), setter, access); + auto item = std::make_shared(access, std::move(detail), setter); item->SetFunctionName(funcName); return item; } +std::shared_ptr CreateClassPropertyItem(const ir::ClassProperty *property, + const std::string &propertyName, std::string detail) +{ + if (property == nullptr || propertyName.empty() || detail.empty()) { + return nullptr; + } + AccessModifierStyle access = AccessModifierStyle::PUBLIC; + if (property->IsProtected()) { + access = AccessModifierStyle::PROTECTED; + } + auto item = std::make_shared(access, std::move(detail)); + item->SetVariableName(propertyName); + return item; +} + std::shared_ptr ParseFunctionStyleWithCreateItem(const ir::MethodDefinition *methodDefinition, bool isCurrentToken) { @@ -184,6 +206,48 @@ std::shared_ptr ParseFunctionStyleWithCreateItem(const ir::Meth return CreateClassMethodItem(methodDefinition, functionName, functionDetail); } +ir::Identifier *GetIdentFromNewClassExprPart(const ir::Expression *value) +{ + if (value == nullptr || !value->IsETSNewClassInstanceExpression()) { + return nullptr; + } + auto typeRef = value->AsETSNewClassInstanceExpression()->GetTypeRef(); + if (typeRef == nullptr || !typeRef->IsETSTypeReference()) { + return nullptr; + } + auto part = typeRef->AsETSTypeReference()->Part(); + if (part == nullptr) { + return nullptr; + } + return part->GetIdent(); +} + +std::shared_ptr ParsePropertyStyleWithCreateItem(const ir::ClassProperty *property, + bool isCurrentToken) +{ + if (property == nullptr) { + return nullptr; + } + if ((isCurrentToken && property->IsStatic()) || + (!isCurrentToken && (property->IsPrivate() || property->IsStatic()))) { + return nullptr; + } + std::string propertyName = GetNameFromIdentifierNode(property->Key()); + std::string type; + if (property->TypeAnnotation() == nullptr) { + auto value = property->Value(); + auto ident = GetIdentFromNewClassExprPart(value); + type = GetNameFromIdentifierNode(ident); + } else { + type = GetNameForTypeNode(property->TypeAnnotation()); + } + if (propertyName == INVALID_EXPRESSION || type == INVALID_EXPRESSION) { + return nullptr; + } + auto detail = SplicePropertyDetailStr(propertyName, type); + return CreateClassPropertyItem(property, propertyName, detail); +} + ClassHierarchyInfo CreateClassHierarchyInfoFromBody(const ir::ClassDefinition *classDefinition, const std::string &className, bool isCurrentToken) { @@ -194,23 +258,28 @@ ClassHierarchyInfo CreateClassHierarchyInfoFromBody(const ir::ClassDefinition *c result.SetClassName(className); auto bodyNodes = classDefinition->Body(); for (const auto &node : bodyNodes) { - if (node == nullptr || !node->IsMethodDefinition()) { - continue; - } - auto methodDefinition = node->AsMethodDefinition(); - if (methodDefinition == nullptr) { + if (node == nullptr) { continue; } - auto item = ParseFunctionStyleWithCreateItem(methodDefinition, isCurrentToken); - if (item != nullptr) { - result.AddClassMethodItem(item); - } - auto overLoads = methodDefinition->Overloads(); - for (const auto *overLoadMethodDefinition : overLoads) { - auto overLoadItem = ParseFunctionStyleWithCreateItem(overLoadMethodDefinition, isCurrentToken); - if (overLoadItem != nullptr) { - result.AddClassMethodItem(overLoadItem); + if (node->IsMethodDefinition()) { + auto methodDefinition = node->AsMethodDefinition(); + if (methodDefinition == nullptr) { + continue; + } + auto item = ParseFunctionStyleWithCreateItem(methodDefinition, isCurrentToken); + result.AddItemToMethodList(item); + auto overLoads = methodDefinition->Overloads(); + for (const auto *overLoadMethodDefinition : overLoads) { + auto overLoadItem = ParseFunctionStyleWithCreateItem(overLoadMethodDefinition, isCurrentToken); + result.AddItemToMethodList(overLoadItem); + } + } else if (node->IsClassProperty()) { + auto property = node->AsClassProperty(); + if (property == nullptr) { + continue; } + auto item = ParsePropertyStyleWithCreateItem(property, isCurrentToken); + result.AddItemToPropertyList(item); } } return result; @@ -230,13 +299,29 @@ ir::AstNode *GetSuperClassNode(const ir::ClassDefinition *classDefinition) void ComputeClassHierarchyInfo(const ClassHierarchyInfo &deriveInfo, ClassHierarchyInfo &superInfo) { - auto deriveMethods = deriveInfo.GetMethodList(); + auto deriveMethods = deriveInfo.GetMethodItemList(); for (const auto &method : deriveMethods) { - superInfo.DeleteClassMethodItem(method.second); + superInfo.DeleteTargetItemInMethodList(method.second); + } + auto deriveProperties = deriveInfo.GetPropertyItemList(); + for (const auto &property : deriveProperties) { + superInfo.DeleteTargetItemInPropertyList(property.second); + } +} + +void FillBaseClassHierarchyInfo(const ClassHierarchyInfo &extraInfo, ClassHierarchyInfo &baseInfo) +{ + auto extraMethods = extraInfo.GetMethodItemList(); + for (const auto &method : extraMethods) { + baseInfo.AddItemToMethodList(method.second); + } + auto extraProperties = extraInfo.GetPropertyItemList(); + for (const auto &property : extraProperties) { + baseInfo.AddItemToPropertyList(property.second); } } -void ProcessClassHierarchy(const ir::AstNode *token, const ClassHierarchyInfo &baseInfo, ClassHierarchy &result) +void ProcessClassHierarchy(const ir::AstNode *token, ClassHierarchyInfo &baseInfo, ClassHierarchy &result) { if (token == nullptr || !token->IsIdentifier()) { return; @@ -250,8 +335,10 @@ void ProcessClassHierarchy(const ir::AstNode *token, const ClassHierarchyInfo &b if (!className.empty()) { // Calculate the difference between the obtained parent class info and the current clicked node class info. ComputeClassHierarchyInfo(baseInfo, info); - if (info.GetClassName() == className && !info.GetMethodList().empty()) { + if (info.GetClassName() == className && + (!info.GetMethodItemList().empty() || !info.GetPropertyItemList().empty())) { result.emplace_back(info); + FillBaseClassHierarchyInfo(info, baseInfo); } } auto superClass = GetSuperClassNode(classDefinition); diff --git a/ets2panda/lsp/src/completions.cpp b/ets2panda/lsp/src/completions.cpp index cc8bda9324..8b1961ff2f 100644 --- a/ets2panda/lsp/src/completions.cpp +++ b/ets2panda/lsp/src/completions.cpp @@ -303,17 +303,9 @@ ir::AstNode *GetClassDefinitionFromClassProperty(ir::AstNode *node) return nullptr; } auto value = node->AsClassProperty()->Value(); - if (value != nullptr && value->IsETSNewClassInstanceExpression() && - value->AsETSNewClassInstanceExpression()->GetTypeRef() != nullptr && - value->AsETSNewClassInstanceExpression()->GetTypeRef()->IsETSTypeReference()) { - auto typeReferencePart = value->AsETSNewClassInstanceExpression()->GetTypeRef()->AsETSTypeReference()->Part(); - if (typeReferencePart == nullptr) { - return nullptr; - } - auto id = typeReferencePart->Name(); - if (id != nullptr && id->IsIdentifier()) { - return compiler::DeclarationFromIdentifier(id->AsIdentifier()); - } + auto ident = GetIdentFromNewClassExprPart(value); + if (ident != nullptr) { + return compiler::DeclarationFromIdentifier(ident); } auto type = node->AsClassProperty()->TypeAnnotation(); if (type != nullptr && type->IsETSTypeReference()) { diff --git a/ets2panda/test/unit/lsp/class_hierarchy_info_test.cpp b/ets2panda/test/unit/lsp/class_hierarchy_info_test.cpp index 6d2466a99b..231e38ae56 100644 --- a/ets2panda/test/unit/lsp/class_hierarchy_info_test.cpp +++ b/ets2panda/test/unit/lsp/class_hierarchy_info_test.cpp @@ -22,9 +22,9 @@ using ark::es2panda::lsp::Initializer; namespace { -class LspScriptElementKindTests : public LSPAPITests {}; +class LspGetClassHierarchyInfoTests : public LSPAPITests {}; -TEST_F(LSPAPITests, GetClassHierarchyInfo_1) +TEST_F(LspGetClassHierarchyInfoTests, GetClassHierarchyInfo_1) { LSPAPI const *lspApi = GetImpl(); ASSERT_TRUE(lspApi != nullptr); @@ -56,21 +56,21 @@ private privateMethod(): void { ASSERT_EQ(classHierarchy.size(), 1); ASSERT_EQ(classHierarchy[0].GetClassName(), "Parent"); - auto methods = classHierarchy[0].GetMethodList(); - auto it = methods.find("publicMethod()"); + auto methods = classHierarchy[0].GetMethodItemList(); + auto it = methods.find("publicMethod(): void"); ASSERT_TRUE(it != methods.end()); ASSERT_TRUE(it->second != nullptr); - ASSERT_EQ(it->second->GetSetterStyle(), ark::es2panda::lsp::SetterStyle::METHOD); + ASSERT_EQ(it->second->GetSetterStyle(), ark::es2panda::lsp::SetterStyle::NONE); ASSERT_EQ(it->second->GetAccessModifierStyle(), ark::es2panda::lsp::AccessModifierStyle::PUBLIC); it = methods.find("action(fileName: string, position: number): number"); ASSERT_TRUE(it != methods.end()); ASSERT_TRUE(it->second != nullptr); - ASSERT_EQ(it->second->GetSetterStyle(), ark::es2panda::lsp::SetterStyle::METHOD); + ASSERT_EQ(it->second->GetSetterStyle(), ark::es2panda::lsp::SetterStyle::NONE); ASSERT_EQ(it->second->GetAccessModifierStyle(), ark::es2panda::lsp::AccessModifierStyle::PROTECTED); initializer.DestroyContext(context); } -TEST_F(LSPAPITests, GetClassHierarchyInfo_2) +TEST_F(LspGetClassHierarchyInfoTests, GetClassHierarchyInfo_2) { LSPAPI const *lspApi = GetImpl(); ASSERT_TRUE(lspApi != nullptr); @@ -110,16 +110,16 @@ class Magpie extends Bird { ASSERT_EQ(classHierarchy.size(), 1); ASSERT_EQ(classHierarchy[0].GetClassName(), "Animal"); - auto methods = classHierarchy[0].GetMethodList(); - auto it = methods.find("sleep()"); + auto methods = classHierarchy[0].GetMethodItemList(); + auto it = methods.find("sleep(): void"); ASSERT_TRUE(it != methods.end()); ASSERT_TRUE(it->second != nullptr); - ASSERT_EQ(it->second->GetSetterStyle(), ark::es2panda::lsp::SetterStyle::METHOD); + ASSERT_EQ(it->second->GetSetterStyle(), ark::es2panda::lsp::SetterStyle::NONE); ASSERT_EQ(it->second->GetAccessModifierStyle(), ark::es2panda::lsp::AccessModifierStyle::PROTECTED); initializer.DestroyContext(context); } -TEST_F(LSPAPITests, GetClassHierarchyInfo_3) +TEST_F(LspGetClassHierarchyInfoTests, GetClassHierarchyInfo_3) { LSPAPI const *lspApi = GetImpl(); ASSERT_TRUE(lspApi != nullptr); @@ -143,7 +143,7 @@ TEST_F(LSPAPITests, GetClassHierarchyInfo_3) initializer.DestroyContext(context); } -TEST_F(LSPAPITests, GetClassHierarchyInfo_4) +TEST_F(LspGetClassHierarchyInfoTests, GetClassHierarchyInfo_4) { LSPAPI const *lspApi = GetImpl(); ASSERT_TRUE(lspApi != nullptr); @@ -177,7 +177,7 @@ TEST_F(LSPAPITests, GetClassHierarchyInfo_4) ASSERT_EQ(classHierarchy.size(), 1); ASSERT_EQ(classHierarchy[0].GetClassName(), "ii"); - auto methods = classHierarchy[0].GetMethodList(); + auto methods = classHierarchy[0].GetMethodItemList(); auto it = methods.find("Body(): string"); ASSERT_TRUE(it != methods.end()); ASSERT_TRUE(it->second != nullptr); @@ -190,4 +190,177 @@ TEST_F(LSPAPITests, GetClassHierarchyInfo_4) ASSERT_EQ(it->second->GetAccessModifierStyle(), ark::es2panda::lsp::AccessModifierStyle::PUBLIC); initializer.DestroyContext(context); } + +TEST_F(LspGetClassHierarchyInfoTests, GetClassHierarchyInfo_5) +{ + LSPAPI const *lspApi = GetImpl(); + ASSERT_TRUE(lspApi != nullptr); + const std::string text = R"(class C { + func1(): void {} + func2(): string { + return "1"; + } + func3(): number { + return 1; + } + func4(): boolean { + return false; + } + func5(): Array { + return [1, 2]; + } +} + +class B extends C { + method1(): void {} + method2(parameter1: string, callBack: () => void): void {} +} + +class A extends B {/*1*/};)"; + + auto pos = text.find("/*1*/"); + ASSERT_NE(pos, std::string::npos); + Initializer initializer = Initializer(); + auto context = initializer.CreateContext("class_hierarchy_info_5.ets", ES2PANDA_STATE_CHECKED, text.c_str()); + auto classHierarchy = lspApi->getClassHierarchyInfo(context, pos); + size_t expectInfoListSize = 2; + ASSERT_EQ(classHierarchy.size(), expectInfoListSize); + ASSERT_EQ(classHierarchy[0].GetClassName(), "B"); + ASSERT_EQ(classHierarchy[1].GetClassName(), "C"); + auto classBItems = classHierarchy[0].GetMethodItemList(); + ASSERT_TRUE(classBItems.find("method1(): void") != classBItems.end()); + ASSERT_TRUE(classBItems.find("method2(parameter1: string, callBack: (() => void)): void") != classBItems.end()); + auto classCItems = classHierarchy[1].GetMethodItemList(); + ASSERT_TRUE(classCItems.find("func1(): void") != classCItems.end()); + ASSERT_TRUE(classCItems.find("func2(): string") != classCItems.end()); + ASSERT_TRUE(classCItems.find("func3(): number") != classCItems.end()); + ASSERT_TRUE(classCItems.find("func4(): boolean") != classCItems.end()); + ASSERT_TRUE(classCItems.find("func5(): Array") != classCItems.end()); + initializer.DestroyContext(context); +} + +TEST_F(LspGetClassHierarchyInfoTests, GetClassHierarchyInfo_6) +{ + LSPAPI const *lspApi = GetImpl(); + ASSERT_TRUE(lspApi != nullptr); + const std::string text = R"(type parameter = number; + +class B { + public method1(parameter1: number): parameter { + return 1; + } + method2(parameter1: number): number { + return parameter1 as number; + } + async method3(parameter1: string): Promise { + return '1'; + } +} + +class A extends B {/*1*/};)"; + + auto pos = text.find("/*1*/"); + ASSERT_NE(pos, std::string::npos); + Initializer initializer = Initializer(); + auto context = initializer.CreateContext("class_hierarchy_info_6.ets", ES2PANDA_STATE_CHECKED, text.c_str()); + auto classHierarchy = lspApi->getClassHierarchyInfo(context, pos); + ASSERT_FALSE(classHierarchy.empty()); + ASSERT_EQ(classHierarchy[0].GetClassName(), "B"); + auto classBItems = classHierarchy[0].GetMethodItemList(); + ASSERT_TRUE(classBItems.find("method1(parameter1: number): parameter") != classBItems.end()); + ASSERT_TRUE(classBItems.find("method2(parameter1: number): number") != classBItems.end()); + ASSERT_TRUE(classBItems.find("method3(parameter1: string): Promise") != classBItems.end()); + initializer.DestroyContext(context); +} + +TEST_F(LspGetClassHierarchyInfoTests, GetClassHierarchyInfo_7) +{ + LSPAPI const *lspApi = GetImpl(); + ASSERT_TRUE(lspApi != nullptr); + const std::string text = R"(class C { + func1(): void {} + + func2(): boolean { + return false; + } + + func3(): Array { + return [1, 2]; + } +}; + +class B extends C { + method1() {} + func2(): boolean { + return false; + } +} + +class A extends B { + method1() {} + func3(): Array { + return [1, 2]; + }/*1*/ +})"; + + auto pos = text.find("/*1*/"); + ASSERT_NE(pos, std::string::npos); + Initializer initializer = Initializer(); + auto context = initializer.CreateContext("class_hierarchy_info_7.ets", ES2PANDA_STATE_CHECKED, text.c_str()); + auto classHierarchy = lspApi->getClassHierarchyInfo(context, pos); + size_t expectInfoListSize = 2; + ASSERT_EQ(classHierarchy.size(), expectInfoListSize); + ASSERT_EQ(classHierarchy[0].GetClassName(), "B"); + ASSERT_EQ(classHierarchy[1].GetClassName(), "C"); + auto classBItems = classHierarchy[0].GetMethodItemList(); + ASSERT_EQ(classBItems.size(), 1); + ASSERT_TRUE(classBItems.find("func2(): boolean") != classBItems.end()); + auto classCItems = classHierarchy[1].GetMethodItemList(); + ASSERT_EQ(classCItems.size(), 1); + ASSERT_TRUE(classCItems.find("func1(): void") != classCItems.end()); + initializer.DestroyContext(context); +} + +TEST_F(LspGetClassHierarchyInfoTests, GetClassHierarchyInfo_8) +{ + LSPAPI const *lspApi = GetImpl(); + ASSERT_TRUE(lspApi != nullptr); + const std::string text = R"(class Parent { + public property1: number = 1; + protected property2: string = '1'; + private property3: boolean = true; + readonly property4: number = 1; + static property5: number = 1; +} + +class Son extends Parent { + property1: number = 2; + ChildExtraProperty1: number = 2; + ChildExtraProperty2: number = 2; +} + +class GrandSon extends Son {/*1*/ + public property2: string = '2'; + ChildExtraProperty1: number = 3; +})"; + + auto pos = text.find("/*1*/"); + ASSERT_NE(pos, std::string::npos); + Initializer initializer = Initializer(); + auto context = initializer.CreateContext("class_hierarchy_info_8.ets", ES2PANDA_STATE_CHECKED, text.c_str()); + auto classHierarchy = lspApi->getClassHierarchyInfo(context, pos); + size_t expectInfoListSize = 2; + ASSERT_EQ(classHierarchy.size(), expectInfoListSize); + ASSERT_EQ(classHierarchy[0].GetClassName(), "Son"); + ASSERT_EQ(classHierarchy[1].GetClassName(), "Parent"); + auto sonItems = classHierarchy[0].GetPropertyItemList(); + size_t expectPropertyListSize = 2; + ASSERT_EQ(sonItems.size(), expectPropertyListSize); + ASSERT_TRUE(sonItems.find("property1: number") != sonItems.end()); + ASSERT_TRUE(sonItems.find("ChildExtraProperty2: number") != sonItems.end()); + auto parentItems = classHierarchy[1].GetPropertyItemList(); + ASSERT_EQ(parentItems.size(), 1); + ASSERT_TRUE(parentItems.find("property4: number") != parentItems.end()); + initializer.DestroyContext(context); +} } // namespace -- Gitee From 2be8ac88545c14ea3f13e5ec2bf290a9ee07d0bd Mon Sep 17 00:00:00 2001 From: xudan16 Date: Wed, 11 Jun 2025 16:19:24 +0800 Subject: [PATCH 025/209] fix bug of custom-builder rule Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICED88 Signed-off-by: xudan16 --- .../src/checker/migration/CustomBuilderCheck.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/ets2panda/linter/homecheck/src/checker/migration/CustomBuilderCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/CustomBuilderCheck.ts index b8dcb06db7..8aa70c4807 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/CustomBuilderCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/CustomBuilderCheck.ts @@ -149,15 +149,18 @@ export class CustomBuilderCheck implements BaseChecker { } private isPassToCustomBuilder(stmt: Stmt, locals: Set): Local | undefined { + let res: Local | undefined = undefined; if (stmt instanceof ArkAssignStmt) { - if (!this.isCustomBuilderTy(stmt.getLeftOp().getType())) { - return undefined; - } - const rightOp = stmt.getRightOp(); - if (rightOp instanceof Local && locals.has(rightOp)) { - return rightOp; + if (this.isCustomBuilderTy(stmt.getLeftOp().getType())) { + const rightOp = stmt.getRightOp(); + if (rightOp instanceof Local && locals.has(rightOp)) { + res = rightOp; + } } } + if (res !== undefined) { + return res; + } const invokeExpr = stmt.getInvokeExpr(); if (invokeExpr) { const paramTys = invokeExpr.getMethodSignature().getMethodSubSignature().getParameterTypes(); -- Gitee From 3b2d793f53ff705c13fda8b81c3b1551c7dafaec Mon Sep 17 00:00:00 2001 From: Okolnov Evgeniy Date: Mon, 2 Jun 2025 22:46:08 +0300 Subject: [PATCH 026/209] Fix missing report on invalid properties Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICBZBZ Test scenarios: new tests added to the linter Signed-off-by: Okolnov Evgeniy --- ets2panda/linter/src/lib/LinterRunner.ts | 5 +- ets2panda/linter/src/lib/TypeScriptLinter.ts | 3 - ets2panda/linter/src/lib/utils/TsUtils.ts | 8 +- .../test/main/literals_as_prop_names.ets | 20 +- .../literals_as_prop_names.ets.arkts2.json | 158 ++++++- .../literals_as_prop_names.ets.autofix.json | 248 ++++++++++- .../test/main/literals_as_prop_names.ets.json | 30 ++ .../literals_as_prop_names.ets.migrate.ets | 20 +- .../literals_as_prop_names.ets.migrate.json | 90 ++++ .../test/main/object_literals_properties.ets | 8 +- ...object_literals_properties.ets.arkts2.json | 188 ++++++++- ...bject_literals_properties.ets.autofix.json | 397 +++++++++++++++++- .../main/object_literals_properties.ets.json | 10 - ...object_literals_properties.ets.migrate.ets | 43 +- ...bject_literals_properties.ets.migrate.json | 144 +++---- 15 files changed, 1214 insertions(+), 158 deletions(-) diff --git a/ets2panda/linter/src/lib/LinterRunner.ts b/ets2panda/linter/src/lib/LinterRunner.ts index 83d5c4ba59..9cf5cd2f09 100644 --- a/ets2panda/linter/src/lib/LinterRunner.ts +++ b/ets2panda/linter/src/lib/LinterRunner.ts @@ -43,7 +43,10 @@ import { ProjectStatistics } from './statistics/ProjectStatistics'; import type { BaseTypeScriptLinter } from './BaseTypeScriptLinter'; function prepareInputFilesList(cmdOptions: CommandLineOptions): string[] { - let inputFiles = cmdOptions.inputFiles; + let inputFiles = cmdOptions.inputFiles.map((x) => { + return path.normalize(x); + }); + if (!cmdOptions.parsedConfigFile) { return inputFiles; } diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index ca016e788d..005e998117 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -617,9 +617,6 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } for (const prop of invalidProps) { - if (ts.isShorthandPropertyAssignment(prop) && !TsUtils.isAnyType(this.tsTypeChecker.getTypeAtLocation(prop))) { - continue; - } const autofix = ts.isShorthandPropertyAssignment(prop) ? this.autofixer?.fixShorthandPropertyAssignment(prop) : objLiteralAutofix; diff --git a/ets2panda/linter/src/lib/utils/TsUtils.ts b/ets2panda/linter/src/lib/utils/TsUtils.ts index 5ed15ab452..3a0f7b32eb 100644 --- a/ets2panda/linter/src/lib/utils/TsUtils.ts +++ b/ets2panda/linter/src/lib/utils/TsUtils.ts @@ -2174,8 +2174,10 @@ export class TsUtils { return true; } } - // We allow computed property names if expression is string literal or string Enum member - return ts.isStringLiteralLike(expr) || this.isEnumStringLiteral(computedProperty.expression); + // In ArkTS 1.0, the computed property names are allowed if expression is string literal or string Enum member. + return ( + !this.options.arkts2 && (ts.isStringLiteralLike(expr) || this.isEnumStringLiteral(computedProperty.expression)) + ); } skipPropertyInferredTypeCheck( @@ -3733,7 +3735,7 @@ export class TsUtils { if (sourceFile.fileName.endsWith(EXTNAME_D_ETS)) { return true; } - return !!this.options.inputFiles?.includes(sourceFile.fileName); + return !!this.options.inputFiles?.includes(path.normalize(sourceFile.fileName)); } static removeOrReplaceQuotes(str: string, isReplace: boolean): string { diff --git a/ets2panda/linter/test/main/literals_as_prop_names.ets b/ets2panda/linter/test/main/literals_as_prop_names.ets index c994718102..114339394c 100755 --- a/ets2panda/linter/test/main/literals_as_prop_names.ets +++ b/ets2panda/linter/test/main/literals_as_prop_names.ets @@ -128,11 +128,23 @@ class A{ let a:A = { "age": 30} -class B{ +class B { public 'age': number = 1 // error in arkts2 } let obj11: Record = { -['value']: 1, // 误扫 -'value2': 1 // ok -} \ No newline at end of file + ['value']: 1, // Error in arkts 2.0 + 'value2': 1 // ok +} + +class CompPropClass { + ['CompProp'] = 1; // Error in arkts 2.0 + [2] = 'CompProp2'; // Error in arkts 2.0 + [LiteralAsPropertyNameEnum.One] = 3; // Error in arkts 2.0 +} + +let compPropObj = { + ['CompProp']: 1, // Error in arkts 2.0 + [2]: 'CompProp2', // Error in arkts 2.0 + [LiteralAsPropertyNameEnum.One]: 3 // Error in arkts 2.0 +}; \ No newline at end of file diff --git a/ets2panda/linter/test/main/literals_as_prop_names.ets.arkts2.json b/ets2panda/linter/test/main/literals_as_prop_names.ets.arkts2.json index 79102a9b70..f6df27e1d6 100755 --- a/ets2panda/linter/test/main/literals_as_prop_names.ets.arkts2.json +++ b/ets2panda/linter/test/main/literals_as_prop_names.ets.arkts2.json @@ -494,11 +494,31 @@ "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" }, + { + "line": 135, + "column": 37, + "endLine": 135, + "endColumn": 38, + "problem": "ObjectLiteralNoContextType", + "suggest": "", + "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", + "severity": "ERROR" + }, { "line": 136, - "column": 12, + "column": 3, "endLine": 136, - "endColumn": 13, + "endColumn": 12, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 136, + "column": 14, + "endLine": 136, + "endColumn": 15, "problem": "NumericSemantics", "suggest": "", "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", @@ -506,9 +526,139 @@ }, { "line": 137, - "column": 11, + "column": 13, "endLine": 137, - "endColumn": 12, + "endColumn": 14, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 141, + "column": 3, + "endLine": 141, + "endColumn": 15, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 141, + "column": 18, + "endLine": 141, + "endColumn": 19, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 142, + "column": 3, + "endLine": 142, + "endColumn": 6, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 142, + "column": 4, + "endLine": 142, + "endColumn": 5, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 143, + "column": 3, + "endLine": 143, + "endColumn": 34, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 143, + "column": 37, + "endLine": 143, + "endColumn": 38, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 146, + "column": 19, + "endLine": 146, + "endColumn": 20, + "problem": "ObjectLiteralNoContextType", + "suggest": "", + "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", + "severity": "ERROR" + }, + { + "line": 147, + "column": 3, + "endLine": 147, + "endColumn": 15, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 147, + "column": 17, + "endLine": 147, + "endColumn": 18, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 148, + "column": 3, + "endLine": 148, + "endColumn": 6, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 148, + "column": 4, + "endLine": 148, + "endColumn": 5, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 149, + "column": 3, + "endLine": 149, + "endColumn": 34, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 149, + "column": 36, + "endLine": 149, + "endColumn": 37, "problem": "NumericSemantics", "suggest": "", "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", diff --git a/ets2panda/linter/test/main/literals_as_prop_names.ets.autofix.json b/ets2panda/linter/test/main/literals_as_prop_names.ets.autofix.json index 82e0ac288a..d66cfd8c7c 100644 --- a/ets2panda/linter/test/main/literals_as_prop_names.ets.autofix.json +++ b/ets2panda/linter/test/main/literals_as_prop_names.ets.autofix.json @@ -1035,8 +1035,8 @@ "autofix": [ { "replacementText": "age", - "start": 2465, - "end": 2470, + "start": 2466, + "end": 2471, "line": 132, "column": 10, "endLine": 132, @@ -1055,8 +1055,8 @@ "problem": "NumericSemantics", "autofix": [ { - "start": 2481, - "end": 2482, + "start": 2482, + "end": 2483, "replacementText": "1.0", "line": 132, "column": 26, @@ -1068,21 +1068,41 @@ "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" }, + { + "line": 135, + "column": 37, + "endLine": 135, + "endColumn": 38, + "problem": "ObjectLiteralNoContextType", + "suggest": "", + "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", + "severity": "ERROR" + }, { "line": 136, - "column": 12, + "column": 3, "endLine": 136, - "endColumn": 13, + "endColumn": 12, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 136, + "column": 14, + "endLine": 136, + "endColumn": 15, "problem": "NumericSemantics", "autofix": [ { - "start": 2554, - "end": 2555, + "start": 2557, + "end": 2558, "replacementText": "1.0", "line": 136, - "column": 12, + "column": 14, "endLine": 136, - "endColumn": 13 + "endColumn": 15 } ], "suggest": "", @@ -1091,19 +1111,215 @@ }, { "line": 137, - "column": 11, + "column": 13, "endLine": 137, - "endColumn": 12, + "endColumn": 14, "problem": "NumericSemantics", "autofix": [ { - "start": 2573, - "end": 2574, + "start": 2594, + "end": 2595, "replacementText": "1.0", "line": 137, - "column": 11, + "column": 13, "endLine": 137, - "endColumn": 12 + "endColumn": 14 + } + ], + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 141, + "column": 3, + "endLine": 141, + "endColumn": 15, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 141, + "column": 18, + "endLine": 141, + "endColumn": 19, + "problem": "NumericSemantics", + "autofix": [ + { + "start": 2644, + "end": 2645, + "replacementText": "1.0", + "line": 141, + "column": 18, + "endLine": 141, + "endColumn": 19 + } + ], + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 142, + "column": 3, + "endLine": 142, + "endColumn": 6, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 142, + "column": 4, + "endLine": 142, + "endColumn": 5, + "problem": "NumericSemantics", + "autofix": [ + { + "start": 2672, + "end": 2673, + "replacementText": "2.0", + "line": 142, + "column": 4, + "endLine": 142, + "endColumn": 5 + } + ], + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 143, + "column": 3, + "endLine": 143, + "endColumn": 34, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 143, + "column": 37, + "endLine": 143, + "endColumn": 38, + "problem": "NumericSemantics", + "autofix": [ + { + "start": 2748, + "end": 2749, + "replacementText": "3.0", + "line": 143, + "column": 37, + "endLine": 143, + "endColumn": 38 + } + ], + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 146, + "column": 19, + "endLine": 146, + "endColumn": 20, + "problem": "ObjectLiteralNoContextType", + "suggest": "", + "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", + "severity": "ERROR" + }, + { + "line": 147, + "column": 3, + "endLine": 147, + "endColumn": 15, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 147, + "column": 17, + "endLine": 147, + "endColumn": 18, + "problem": "NumericSemantics", + "autofix": [ + { + "start": 2812, + "end": 2813, + "replacementText": "1.0", + "line": 147, + "column": 17, + "endLine": 147, + "endColumn": 18 + } + ], + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 148, + "column": 3, + "endLine": 148, + "endColumn": 6, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 148, + "column": 4, + "endLine": 148, + "endColumn": 5, + "problem": "NumericSemantics", + "autofix": [ + { + "start": 2840, + "end": 2841, + "replacementText": "2.0", + "line": 148, + "column": 4, + "endLine": 148, + "endColumn": 5 + } + ], + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 149, + "column": 3, + "endLine": 149, + "endColumn": 34, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 149, + "column": 36, + "endLine": 149, + "endColumn": 37, + "problem": "NumericSemantics", + "autofix": [ + { + "start": 2914, + "end": 2915, + "replacementText": "3.0", + "line": 149, + "column": 36, + "endLine": 149, + "endColumn": 37 } ], "suggest": "", diff --git a/ets2panda/linter/test/main/literals_as_prop_names.ets.json b/ets2panda/linter/test/main/literals_as_prop_names.ets.json index 7e721f74f1..dfce9f6d57 100644 --- a/ets2panda/linter/test/main/literals_as_prop_names.ets.json +++ b/ets2panda/linter/test/main/literals_as_prop_names.ets.json @@ -144,6 +144,36 @@ "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", "severity": "ERROR" }, + { + "line": 142, + "column": 3, + "endLine": 142, + "endColumn": 6, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 146, + "column": 19, + "endLine": 146, + "endColumn": 20, + "problem": "ObjectLiteralNoContextType", + "suggest": "", + "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", + "severity": "ERROR" + }, + { + "line": 148, + "column": 3, + "endLine": 148, + "endColumn": 6, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, { "line": 42, "column": 11, diff --git a/ets2panda/linter/test/main/literals_as_prop_names.ets.migrate.ets b/ets2panda/linter/test/main/literals_as_prop_names.ets.migrate.ets index 54ed22aed8..5211df075e 100644 --- a/ets2panda/linter/test/main/literals_as_prop_names.ets.migrate.ets +++ b/ets2panda/linter/test/main/literals_as_prop_names.ets.migrate.ets @@ -134,11 +134,23 @@ class A{ let a:A = { age: 30.0} -class B{ +class B { public age: number = 1.0 // error in arkts2 } let obj11: Record = { -['value']: 1.0, // 误扫 -'value2': 1.0 // ok -} \ No newline at end of file + ['value']: 1.0, // Error in arkts 2.0 + 'value2': 1.0 // ok +} + +class CompPropClass { + ['CompProp'] = 1.0; // Error in arkts 2.0 + [2.0] = 'CompProp2'; // Error in arkts 2.0 + [LiteralAsPropertyNameEnum.One] = 3.0; // Error in arkts 2.0 +} + +let compPropObj = { + ['CompProp']: 1.0, // Error in arkts 2.0 + [2.0]: 'CompProp2', // Error in arkts 2.0 + [LiteralAsPropertyNameEnum.One]: 3.0 // Error in arkts 2.0 +}; \ No newline at end of file diff --git a/ets2panda/linter/test/main/literals_as_prop_names.ets.migrate.json b/ets2panda/linter/test/main/literals_as_prop_names.ets.migrate.json index 97c0791cc5..adafc797dd 100644 --- a/ets2panda/linter/test/main/literals_as_prop_names.ets.migrate.json +++ b/ets2panda/linter/test/main/literals_as_prop_names.ets.migrate.json @@ -104,6 +104,96 @@ "rule": "Enum cannot get member name by member value (arkts-unsupport-prop-name-from-value)", "severity": "ERROR" }, + { + "line": 141, + "column": 37, + "endLine": 141, + "endColumn": 38, + "problem": "ObjectLiteralNoContextType", + "suggest": "", + "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", + "severity": "ERROR" + }, + { + "line": 142, + "column": 3, + "endLine": 142, + "endColumn": 12, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 147, + "column": 3, + "endLine": 147, + "endColumn": 15, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 148, + "column": 3, + "endLine": 148, + "endColumn": 8, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 149, + "column": 3, + "endLine": 149, + "endColumn": 34, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 152, + "column": 19, + "endLine": 152, + "endColumn": 20, + "problem": "ObjectLiteralNoContextType", + "suggest": "", + "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", + "severity": "ERROR" + }, + { + "line": 153, + "column": 3, + "endLine": 153, + "endColumn": 15, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 154, + "column": 3, + "endLine": 154, + "endColumn": 8, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 155, + "column": 3, + "endLine": 155, + "endColumn": 34, + "problem": "ComputedPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, { "line": 28, "column": 11, diff --git a/ets2panda/linter/test/main/object_literals_properties.ets b/ets2panda/linter/test/main/object_literals_properties.ets index d5265f7493..f603b4bcfe 100644 --- a/ets2panda/linter/test/main/object_literals_properties.ets +++ b/ets2panda/linter/test/main/object_literals_properties.ets @@ -244,15 +244,15 @@ let b3: Derived3 = { // Fixable m() { console.log(2); } }; -interface A { +interface I4 { map: Map; } let map:Map = new Map(); -let a:A = {map}; +let i4: I4 = {map}; -class C { +class C6 { map1: Map = new Map(); } let map1:Map = new Map(); -let c:C = {map1}; \ No newline at end of file +let c6: C6 = {map1}; \ No newline at end of file diff --git a/ets2panda/linter/test/main/object_literals_properties.ets.arkts2.json b/ets2panda/linter/test/main/object_literals_properties.ets.arkts2.json index ac48689e30..ed1d4e6f86 100644 --- a/ets2panda/linter/test/main/object_literals_properties.ets.arkts2.json +++ b/ets2panda/linter/test/main/object_literals_properties.ets.arkts2.json @@ -124,6 +124,36 @@ "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", "severity": "ERROR" }, + { + "line": 34, + "column": 3, + "endLine": 34, + "endColumn": 4, + "problem": "ObjectLiteralProperty", + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 35, + "column": 3, + "endLine": 35, + "endColumn": 4, + "problem": "ObjectLiteralProperty", + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 36, + "column": 3, + "endLine": 36, + "endColumn": 4, + "problem": "ObjectLiteralProperty", + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, { "line": 39, "column": 14, @@ -164,6 +194,26 @@ "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", "severity": "ERROR" }, + { + "line": 47, + "column": 3, + "endLine": 47, + "endColumn": 4, + "problem": "ObjectLiteralProperty", + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 48, + "column": 3, + "endLine": 48, + "endColumn": 4, + "problem": "ObjectLiteralProperty", + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, { "line": 50, "column": 3, @@ -334,6 +384,36 @@ "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", "severity": "ERROR" }, + { + "line": 69, + "column": 3, + "endLine": 69, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 70, + "column": 3, + "endLine": 70, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 71, + "column": 3, + "endLine": 71, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, { "line": 72, "column": 3, @@ -554,6 +634,36 @@ "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", "severity": "ERROR" }, + { + "line": 110, + "column": 3, + "endLine": 110, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 111, + "column": 3, + "endLine": 111, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 112, + "column": 3, + "endLine": 112, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, { "line": 113, "column": 3, @@ -584,6 +694,36 @@ "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", "severity": "ERROR" }, + { + "line": 117, + "column": 3, + "endLine": 117, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 118, + "column": 3, + "endLine": 118, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 119, + "column": 3, + "endLine": 119, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, { "line": 120, "column": 3, @@ -694,6 +834,36 @@ "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", "severity": "ERROR" }, + { + "line": 134, + "column": 3, + "endLine": 134, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 135, + "column": 3, + "endLine": 135, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 136, + "column": 3, + "endLine": 136, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, { "line": 137, "column": 3, @@ -1104,14 +1274,24 @@ "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" }, + { + "line": 251, + "column": 15, + "endLine": 251, + "endColumn": 18, + "problem": "ObjectLiteralProperty", + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, { "line": 258, - "column": 11, + "column": 15, "endLine": 258, - "endColumn": 12, - "problem": "ObjectLiteralNoContextType", + "endColumn": 19, + "problem": "ObjectLiteralProperty", "suggest": "", - "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", "severity": "ERROR" }, { diff --git a/ets2panda/linter/test/main/object_literals_properties.ets.autofix.json b/ets2panda/linter/test/main/object_literals_properties.ets.autofix.json index 706c09bb34..43d944717d 100644 --- a/ets2panda/linter/test/main/object_literals_properties.ets.autofix.json +++ b/ets2panda/linter/test/main/object_literals_properties.ets.autofix.json @@ -228,6 +228,69 @@ "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", "severity": "ERROR" }, + { + "line": 34, + "column": 3, + "endLine": 34, + "endColumn": 4, + "problem": "ObjectLiteralProperty", + "autofix": [ + { + "start": 922, + "end": 923, + "replacementText": "x: x", + "line": 34, + "column": 3, + "endLine": 34, + "endColumn": 4 + } + ], + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 35, + "column": 3, + "endLine": 35, + "endColumn": 4, + "problem": "ObjectLiteralProperty", + "autofix": [ + { + "start": 945, + "end": 946, + "replacementText": "y: y", + "line": 35, + "column": 3, + "endLine": 35, + "endColumn": 4 + } + ], + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 36, + "column": 3, + "endLine": 36, + "endColumn": 4, + "problem": "ObjectLiteralProperty", + "autofix": [ + { + "start": 968, + "end": 969, + "replacementText": "z: z", + "line": 36, + "column": 3, + "endLine": 36, + "endColumn": 4 + } + ], + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, { "line": 39, "column": 14, @@ -288,6 +351,48 @@ "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", "severity": "ERROR" }, + { + "line": 47, + "column": 3, + "endLine": 47, + "endColumn": 4, + "problem": "ObjectLiteralProperty", + "autofix": [ + { + "start": 1112, + "end": 1113, + "replacementText": "x: x", + "line": 47, + "column": 3, + "endLine": 47, + "endColumn": 4 + } + ], + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 48, + "column": 3, + "endLine": 48, + "endColumn": 4, + "problem": "ObjectLiteralProperty", + "autofix": [ + { + "start": 1126, + "end": 1127, + "replacementText": "y: y", + "line": 48, + "column": 3, + "endLine": 48, + "endColumn": 4 + } + ], + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, { "line": 50, "column": 3, @@ -601,6 +706,69 @@ "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", "severity": "ERROR" }, + { + "line": 69, + "column": 3, + "endLine": 69, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "autofix": [ + { + "start": 1425, + "end": 1427, + "replacementText": "x2: x2", + "line": 69, + "column": 3, + "endLine": 69, + "endColumn": 5 + } + ], + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 70, + "column": 3, + "endLine": 70, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "autofix": [ + { + "start": 1449, + "end": 1451, + "replacementText": "y2: y2", + "line": 70, + "column": 3, + "endLine": 70, + "endColumn": 5 + } + ], + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 71, + "column": 3, + "endLine": 71, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "autofix": [ + { + "start": 1473, + "end": 1475, + "replacementText": "z2: z2", + "line": 71, + "column": 3, + "endLine": 71, + "endColumn": 5 + } + ], + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, { "line": 72, "column": 3, @@ -1013,6 +1181,69 @@ "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", "severity": "ERROR" }, + { + "line": 110, + "column": 3, + "endLine": 110, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "autofix": [ + { + "start": 1926, + "end": 1928, + "replacementText": "x2: x2", + "line": 110, + "column": 3, + "endLine": 110, + "endColumn": 5 + } + ], + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 111, + "column": 3, + "endLine": 111, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "autofix": [ + { + "start": 1943, + "end": 1945, + "replacementText": "y2: y2", + "line": 111, + "column": 3, + "endLine": 111, + "endColumn": 5 + } + ], + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 112, + "column": 3, + "endLine": 112, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "autofix": [ + { + "start": 1960, + "end": 1962, + "replacementText": "z2: z2", + "line": 112, + "column": 3, + "endLine": 112, + "endColumn": 5 + } + ], + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, { "line": 113, "column": 3, @@ -1074,6 +1305,69 @@ "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", "severity": "ERROR" }, + { + "line": 117, + "column": 3, + "endLine": 117, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "autofix": [ + { + "start": 2034, + "end": 2036, + "replacementText": "x2: x2", + "line": 117, + "column": 3, + "endLine": 117, + "endColumn": 5 + } + ], + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 118, + "column": 3, + "endLine": 118, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "autofix": [ + { + "start": 2051, + "end": 2053, + "replacementText": "y2: y2", + "line": 118, + "column": 3, + "endLine": 118, + "endColumn": 5 + } + ], + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 119, + "column": 3, + "endLine": 119, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "autofix": [ + { + "start": 2068, + "end": 2070, + "replacementText": "z2: z2", + "line": 119, + "column": 3, + "endLine": 119, + "endColumn": 5 + } + ], + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, { "line": 120, "column": 3, @@ -1261,6 +1555,69 @@ "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", "severity": "ERROR" }, + { + "line": 134, + "column": 3, + "endLine": 134, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "autofix": [ + { + "start": 2289, + "end": 2291, + "replacementText": "x2: x2", + "line": 134, + "column": 3, + "endLine": 134, + "endColumn": 5 + } + ], + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 135, + "column": 3, + "endLine": 135, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "autofix": [ + { + "start": 2306, + "end": 2308, + "replacementText": "y2: y2", + "line": 135, + "column": 3, + "endLine": 135, + "endColumn": 5 + } + ], + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, + { + "line": 136, + "column": 3, + "endLine": 136, + "endColumn": 5, + "problem": "ObjectLiteralProperty", + "autofix": [ + { + "start": 2323, + "end": 2325, + "replacementText": "z2: z2", + "line": 136, + "column": 3, + "endLine": 136, + "endColumn": 5 + } + ], + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, { "line": 137, "column": 3, @@ -1909,14 +2266,46 @@ "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" }, + { + "line": 251, + "column": 15, + "endLine": 251, + "endColumn": 18, + "problem": "ObjectLiteralProperty", + "autofix": [ + { + "start": 4619, + "end": 4622, + "replacementText": "map: map", + "line": 251, + "column": 15, + "endLine": 251, + "endColumn": 18 + } + ], + "suggest": "", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", + "severity": "ERROR" + }, { "line": 258, - "column": 11, + "column": 15, "endLine": 258, - "endColumn": 12, - "problem": "ObjectLiteralNoContextType", + "endColumn": 19, + "problem": "ObjectLiteralProperty", + "autofix": [ + { + "start": 4766, + "end": 4770, + "replacementText": "map1: map1", + "line": 258, + "column": 15, + "endLine": 258, + "endColumn": 19 + } + ], "suggest": "", - "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", + "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", "severity": "ERROR" }, { diff --git a/ets2panda/linter/test/main/object_literals_properties.ets.json b/ets2panda/linter/test/main/object_literals_properties.ets.json index 8548318c10..c8d9bf18dc 100644 --- a/ets2panda/linter/test/main/object_literals_properties.ets.json +++ b/ets2panda/linter/test/main/object_literals_properties.ets.json @@ -294,16 +294,6 @@ "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", "severity": "ERROR" }, - { - "line": 258, - "column": 11, - "endLine": 258, - "endColumn": 12, - "problem": "ObjectLiteralNoContextType", - "suggest": "", - "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", - "severity": "ERROR" - }, { "line": 187, "column": 3, diff --git a/ets2panda/linter/test/main/object_literals_properties.ets.migrate.ets b/ets2panda/linter/test/main/object_literals_properties.ets.migrate.ets index eb3a50b921..a47d79115e 100644 --- a/ets2panda/linter/test/main/object_literals_properties.ets.migrate.ets +++ b/ets2panda/linter/test/main/object_literals_properties.ets.migrate.ets @@ -36,10 +36,15 @@ let setMethod = new GeneratedObjectLiteralClass_3(); let x: number = 1.0, y = '2', z = true; -let shorthand = { - x, // Error, fixable - y, // Error, fixable - z // Error, fixable +interface GeneratedObjectLiteralInterface_1 { + x: number; + y: string; + z: boolean; +} +let shorthand: GeneratedObjectLiteralInterface_1 = { + x: x, // Error, fixable + y: y, // Error, fixable + z: z // Error, fixable }; let spread = { @@ -92,9 +97,9 @@ let x2: number = 1.0, y2: number = 2.0, z2: number = 3.0; let mixedBad = { // Not fixable a: 1.0, b: 2.0, - x2, // Error, fixable - y2, // Error, fixable - z2, // Error, fixable + x2: x2, // Error, fixable + y2: y2, // Error, fixable + z2: z2, // Error, fixable m() {}, ...shorthand // Error, not fixable } @@ -142,7 +147,7 @@ class GeneratedObjectLiteralClass_8 extends C2 { x2: number; y2: number; z2: number; - constructor(init: GeneratedObjectLiteralInitInterface_8) { + constructor(init: GeneratedObjectLiteralInitInterface_1) { super(); this.x2 = init.x2; this.y2 = init.y2; @@ -151,7 +156,7 @@ class GeneratedObjectLiteralClass_8 extends C2 { m() { console.log(1.0); } // Fixable } -interface GeneratedObjectLiteralInitInterface_8 { +interface GeneratedObjectLiteralInitInterface_1 { x2: number; y2: number; z2: number; @@ -164,9 +169,9 @@ let c2: C2 = new GeneratedObjectLiteralClass_8({ }); let c22: C2 = { - x2, // Fixable - y2, // Fixable - z2, // Fixable + x2: x2, // Fixable + y2: y2, // Fixable + z2: z2, // Fixable m() { console.log(1.0); }, // Not fixable, object has spread property ...shorthand // Not fixable }; @@ -181,9 +186,9 @@ class C3 { constructor(a: number) {} } let c3: C3 = { - x2, // Fixable - y2, // Fixable - z2, // Fixable + x2: x2, // Fixable + y2: y2, // Fixable + z2: z2, // Fixable m() { console.log(1.0); } // Not fixable, class type has constructor with parameters }; @@ -301,15 +306,15 @@ class GeneratedObjectLiteralClass_10 extends Derived3 { let b3: Derived3 = new GeneratedObjectLiteralClass_10(); -interface A { +interface I4 { map: Map; } let map:Map = new Map(); -let a:A = {map}; +let i4: I4 = {map: map}; -class C { +class C6 { map1: Map = new Map(); } let map1:Map = new Map(); -let c:C = {map1}; \ No newline at end of file +let c6: C6 = {map1: map1}; \ No newline at end of file diff --git a/ets2panda/linter/test/main/object_literals_properties.ets.migrate.json b/ets2panda/linter/test/main/object_literals_properties.ets.migrate.json index 972e1c73e2..f7f4541321 100644 --- a/ets2panda/linter/test/main/object_literals_properties.ets.migrate.json +++ b/ets2panda/linter/test/main/object_literals_properties.ets.migrate.json @@ -15,19 +15,9 @@ ], "result": [ { - "line": 39, - "column": 17, - "endLine": 39, - "endColumn": 18, - "problem": "ObjectLiteralNoContextType", - "suggest": "", - "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", - "severity": "ERROR" - }, - { - "line": 45, + "line": 50, "column": 14, - "endLine": 45, + "endLine": 50, "endColumn": 15, "problem": "ObjectLiteralNoContextType", "suggest": "", @@ -35,9 +25,9 @@ "severity": "ERROR" }, { - "line": 46, + "line": 51, "column": 3, - "endLine": 46, + "endLine": 51, "endColumn": 15, "problem": "ObjectLiteralProperty", "suggest": "", @@ -45,9 +35,9 @@ "severity": "ERROR" }, { - "line": 46, + "line": 51, "column": 3, - "endLine": 46, + "endLine": 51, "endColumn": 15, "problem": "SpreadOperator", "suggest": "", @@ -55,9 +45,9 @@ "severity": "ERROR" }, { - "line": 92, + "line": 97, "column": 16, - "endLine": 92, + "endLine": 97, "endColumn": 17, "problem": "ObjectLiteralNoContextType", "suggest": "", @@ -65,9 +55,9 @@ "severity": "ERROR" }, { - "line": 98, + "line": 103, "column": 3, - "endLine": 98, + "endLine": 103, "endColumn": 9, "problem": "ObjectLiteralProperty", "suggest": "", @@ -75,9 +65,9 @@ "severity": "ERROR" }, { - "line": 99, + "line": 104, "column": 3, - "endLine": 99, + "endLine": 104, "endColumn": 15, "problem": "ObjectLiteralProperty", "suggest": "", @@ -85,9 +75,9 @@ "severity": "ERROR" }, { - "line": 99, + "line": 104, "column": 3, - "endLine": 99, + "endLine": 104, "endColumn": 15, "problem": "SpreadOperator", "suggest": "", @@ -95,9 +85,9 @@ "severity": "ERROR" }, { - "line": 166, + "line": 171, "column": 15, - "endLine": 166, + "endLine": 171, "endColumn": 16, "problem": "ObjectLiteralNoContextType", "suggest": "", @@ -105,9 +95,9 @@ "severity": "ERROR" }, { - "line": 170, + "line": 175, "column": 3, - "endLine": 170, + "endLine": 175, "endColumn": 28, "problem": "ObjectLiteralProperty", "suggest": "", @@ -115,9 +105,9 @@ "severity": "ERROR" }, { - "line": 171, + "line": 176, "column": 3, - "endLine": 171, + "endLine": 176, "endColumn": 15, "problem": "ObjectLiteralProperty", "suggest": "", @@ -125,9 +115,9 @@ "severity": "ERROR" }, { - "line": 171, + "line": 176, "column": 3, - "endLine": 171, + "endLine": 176, "endColumn": 15, "problem": "SpreadOperator", "suggest": "", @@ -135,9 +125,9 @@ "severity": "ERROR" }, { - "line": 183, + "line": 188, "column": 14, - "endLine": 183, + "endLine": 188, "endColumn": 15, "problem": "ObjectLiteralNoContextType", "suggest": "", @@ -145,9 +135,9 @@ "severity": "ERROR" }, { - "line": 187, + "line": 192, "column": 3, - "endLine": 187, + "endLine": 192, "endColumn": 28, "problem": "ObjectLiteralProperty", "suggest": "", @@ -155,9 +145,9 @@ "severity": "ERROR" }, { - "line": 192, + "line": 197, "column": 25, - "endLine": 192, + "endLine": 197, "endColumn": 26, "problem": "ObjectLiteralNoContextType", "suggest": "", @@ -165,9 +155,9 @@ "severity": "ERROR" }, { - "line": 193, + "line": 198, "column": 5, - "endLine": 195, + "endLine": 200, "endColumn": 6, "problem": "ObjectLiteralProperty", "suggest": "", @@ -175,9 +165,9 @@ "severity": "ERROR" }, { - "line": 198, + "line": 203, "column": 29, - "endLine": 198, + "endLine": 203, "endColumn": 30, "problem": "ObjectLiteralNoContextType", "suggest": "", @@ -185,9 +175,9 @@ "severity": "ERROR" }, { - "line": 199, + "line": 204, "column": 5, - "endLine": 201, + "endLine": 206, "endColumn": 6, "problem": "ObjectLiteralProperty", "suggest": "", @@ -195,9 +185,9 @@ "severity": "ERROR" }, { - "line": 209, + "line": 214, "column": 26, - "endLine": 209, + "endLine": 214, "endColumn": 27, "problem": "ObjectLiteralNoContextType", "suggest": "", @@ -205,9 +195,9 @@ "severity": "ERROR" }, { - "line": 210, + "line": 215, "column": 5, - "endLine": 212, + "endLine": 217, "endColumn": 6, "problem": "ObjectLiteralProperty", "suggest": "", @@ -215,9 +205,9 @@ "severity": "ERROR" }, { - "line": 214, + "line": 219, "column": 27, - "endLine": 214, + "endLine": 219, "endColumn": 28, "problem": "ObjectLiteralNoContextType", "suggest": "", @@ -225,9 +215,9 @@ "severity": "ERROR" }, { - "line": 215, + "line": 220, "column": 5, - "endLine": 217, + "endLine": 222, "endColumn": 6, "problem": "ObjectLiteralProperty", "suggest": "", @@ -235,9 +225,9 @@ "severity": "ERROR" }, { - "line": 221, + "line": 226, "column": 27, - "endLine": 221, + "endLine": 226, "endColumn": 28, "problem": "ObjectLiteralNoContextType", "suggest": "", @@ -245,9 +235,9 @@ "severity": "ERROR" }, { - "line": 222, + "line": 227, "column": 5, - "endLine": 224, + "endLine": 229, "endColumn": 6, "problem": "ObjectLiteralProperty", "suggest": "", @@ -255,9 +245,9 @@ "severity": "ERROR" }, { - "line": 233, + "line": 238, "column": 14, - "endLine": 233, + "endLine": 238, "endColumn": 15, "problem": "ObjectLiteralNoContextType", "suggest": "", @@ -265,9 +255,9 @@ "severity": "ERROR" }, { - "line": 244, + "line": 249, "column": 3, - "endLine": 244, + "endLine": 249, "endColumn": 9, "problem": "ObjectLiteralProperty", "suggest": "", @@ -275,9 +265,9 @@ "severity": "ERROR" }, { - "line": 251, + "line": 256, "column": 14, - "endLine": 251, + "endLine": 256, "endColumn": 15, "problem": "ObjectLiteralNoContextType", "suggest": "", @@ -285,9 +275,9 @@ "severity": "ERROR" }, { - "line": 262, + "line": 267, "column": 3, - "endLine": 262, + "endLine": 267, "endColumn": 9, "problem": "ObjectLiteralProperty", "suggest": "", @@ -295,9 +285,9 @@ "severity": "ERROR" }, { - "line": 281, + "line": 286, "column": 16, - "endLine": 281, + "endLine": 286, "endColumn": 29, "problem": "MissingSuperCall", "suggest": "", @@ -305,9 +295,9 @@ "severity": "ERROR" }, { - "line": 284, + "line": 289, "column": 20, - "endLine": 284, + "endLine": 289, "endColumn": 21, "problem": "ObjectLiteralNoContextType", "suggest": "", @@ -315,9 +305,9 @@ "severity": "ERROR" }, { - "line": 285, + "line": 290, "column": 3, - "endLine": 285, + "endLine": 290, "endColumn": 28, "problem": "ObjectLiteralProperty", "suggest": "", @@ -325,19 +315,9 @@ "severity": "ERROR" }, { - "line": 315, - "column": 11, - "endLine": 315, - "endColumn": 12, - "problem": "ObjectLiteralNoContextType", - "suggest": "", - "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", - "severity": "ERROR" - }, - { - "line": 240, + "line": 245, "column": 3, - "endLine": 240, + "endLine": 245, "endColumn": 4, "problem": "StrictDiagnostic", "suggest": "Property 'b' has no initializer and is not definitely assigned in the constructor.", -- Gitee From b99a2fab802a8cba5c3b8db72103299ea2c71355 Mon Sep 17 00:00:00 2001 From: xudan16 Date: Wed, 11 Jun 2025 16:00:53 +0800 Subject: [PATCH 027/209] arkts-no-ts-like-as add class field check Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICE9CY Signed-off-by: xudan16 --- .../src/checker/migration/NoTSLikeAsCheck.ts | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/ets2panda/linter/homecheck/src/checker/migration/NoTSLikeAsCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/NoTSLikeAsCheck.ts index 7375978f11..3e6f594aa1 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/NoTSLikeAsCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/NoTSLikeAsCheck.ts @@ -42,6 +42,8 @@ import { UnaryOperator, ArkNormalBinopExpr, NormalBinaryOperator, + AbstractFieldRef, + ClassSignature, } from 'arkanalyzer/lib'; import Logger, { LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger'; import { BaseChecker, BaseMetaData } from '../BaseChecker'; @@ -368,6 +370,11 @@ export class NoTSLikeAsCheck implements BaseChecker { if (this.isWithInterfaceAnnotation(currentStmt, scene)) { return currentStmt; } + + const fieldDeclareStmt = this.isCastOpFieldWithInterfaceType(currentStmt, scene); + if (fieldDeclareStmt) { + return fieldDeclareStmt; + } const gv = this.checkIfCastOpIsGlobalVar(currentStmt); if (gv) { const globalDefs = globalVarMap.get(gv.getName()); @@ -418,6 +425,34 @@ export class NoTSLikeAsCheck implements BaseChecker { return null; } + private isCastOpFieldWithInterfaceType(stmt: Stmt, scene: Scene): Stmt | undefined { + const obj = this.getCastOp(stmt); + if (obj === null || !(obj instanceof Local)) { + return undefined; + } + const declaringStmt = obj.getDeclaringStmt(); + if (declaringStmt === null || !(declaringStmt instanceof ArkAssignStmt)) { + return undefined; + } + const rightOp = declaringStmt.getRightOp(); + if (!(rightOp instanceof AbstractFieldRef)) { + return undefined; + } + const fieldDeclaring = rightOp.getFieldSignature().getDeclaringSignature(); + if (fieldDeclaring instanceof ClassSignature) { + const field = scene.getClass(fieldDeclaring)?.getField(rightOp.getFieldSignature()); + if (!field) { + return undefined; + } + const fieldInitializer = field.getInitializer(); + const lastStmt = fieldInitializer[fieldInitializer.length - 1]; + if (this.isWithInterfaceAnnotation(lastStmt, scene)) { + return lastStmt; + } + } + return undefined; + } + private checkIfCastOpIsGlobalVar(stmt: Stmt): Local | undefined { const obj = this.getCastOp(stmt); if (obj instanceof Local && !obj.getDeclaringStmt()) { -- Gitee From fd4ec4369341547ee050e11818a910562ec933b0 Mon Sep 17 00:00:00 2001 From: zengyuan Date: Wed, 11 Jun 2025 17:01:27 +0800 Subject: [PATCH 028/209] Fix the bug that generates redundant comments Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICEE3M Signed-off-by: zengyuan Change-Id: I1b59b310d365afdad0f65502bfd3d7332420a36f --- .../linter/src/lib/autofixes/Autofixer.ts | 4 +- ets2panda/linter/test/main/comment_test.ets | 23 ++++ .../test/main/comment_test.ets.args.json | 21 +++ .../test/main/comment_test.ets.arkts2.json | 68 ++++++++++ .../test/main/comment_test.ets.autofix.json | 123 ++++++++++++++++++ .../linter/test/main/comment_test.ets.json | 17 +++ .../test/main/comment_test.ets.migrate.ets | 23 ++++ .../test/main/comment_test.ets.migrate.json | 17 +++ 8 files changed, 294 insertions(+), 2 deletions(-) create mode 100644 ets2panda/linter/test/main/comment_test.ets create mode 100644 ets2panda/linter/test/main/comment_test.ets.args.json create mode 100644 ets2panda/linter/test/main/comment_test.ets.arkts2.json create mode 100644 ets2panda/linter/test/main/comment_test.ets.autofix.json create mode 100644 ets2panda/linter/test/main/comment_test.ets.json create mode 100644 ets2panda/linter/test/main/comment_test.ets.migrate.ets create mode 100644 ets2panda/linter/test/main/comment_test.ets.migrate.json diff --git a/ets2panda/linter/src/lib/autofixes/Autofixer.ts b/ets2panda/linter/src/lib/autofixes/Autofixer.ts index eb940bc3ab..67ce638be6 100644 --- a/ets2panda/linter/src/lib/autofixes/Autofixer.ts +++ b/ets2panda/linter/src/lib/autofixes/Autofixer.ts @@ -3332,7 +3332,7 @@ export class Autofixer { node.initializer ); - const replacementText = this.printer.printNode(ts.EmitHint.Unspecified, newProperty, node.getSourceFile()); + const replacementText = this.nonCommentPrinter.printNode(ts.EmitHint.Unspecified, newProperty, node.getSourceFile()); return [ { @@ -3457,7 +3457,7 @@ export class Autofixer { initializer ); - const text = this.printer.printNode(ts.EmitHint.Unspecified, newPropDecl, node.getSourceFile()); + const text = this.nonCommentPrinter.printNode(ts.EmitHint.Unspecified, newPropDecl, node.getSourceFile()); return [{ start: node.getStart(), end: node.getEnd(), replacementText: text }]; } diff --git a/ets2panda/linter/test/main/comment_test.ets b/ets2panda/linter/test/main/comment_test.ets new file mode 100644 index 0000000000..3731be6780 --- /dev/null +++ b/ets2panda/linter/test/main/comment_test.ets @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 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 TestClass { + /** + * This is a comment. + */ + property = 123; // This is a comment. + // This is a comment. + arr = [1, 0]; // This is a comment. +} diff --git a/ets2panda/linter/test/main/comment_test.ets.args.json b/ets2panda/linter/test/main/comment_test.ets.args.json new file mode 100644 index 0000000000..ef3938e967 --- /dev/null +++ b/ets2panda/linter/test/main/comment_test.ets.args.json @@ -0,0 +1,21 @@ +{ + "copyright": [ + "Copyright (c) 2025 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." + ], + "mode": { + "arkts2": "", + "autofix": "--arkts-2", + "migrate": "--arkts-2" + } +} \ No newline at end of file diff --git a/ets2panda/linter/test/main/comment_test.ets.arkts2.json b/ets2panda/linter/test/main/comment_test.ets.arkts2.json new file mode 100644 index 0000000000..76f0d20523 --- /dev/null +++ b/ets2panda/linter/test/main/comment_test.ets.arkts2.json @@ -0,0 +1,68 @@ +{ + "copyright": [ + "Copyright (c) 2025 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." + ], + "result": [ + { + "line": 20, + "column": 5, + "endLine": 20, + "endColumn": 20, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 20, + "column": 16, + "endLine": 20, + "endColumn": 19, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 22, + "column": 5, + "endLine": 22, + "endColumn": 18, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 22, + "column": 12, + "endLine": 22, + "endColumn": 13, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 22, + "column": 15, + "endLine": 22, + "endColumn": 16, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + } + ] +} diff --git a/ets2panda/linter/test/main/comment_test.ets.autofix.json b/ets2panda/linter/test/main/comment_test.ets.autofix.json new file mode 100644 index 0000000000..e1951adff8 --- /dev/null +++ b/ets2panda/linter/test/main/comment_test.ets.autofix.json @@ -0,0 +1,123 @@ +{ + "copyright": [ + "Copyright (c) 2025 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." + ], + "result": [ + { + "line": 20, + "column": 5, + "endLine": 20, + "endColumn": 20, + "problem": "NumericSemantics", + "autofix": [ + { + "start": 669, + "end": 684, + "replacementText": "property: number = 123;", + "line": 20, + "column": 5, + "endLine": 20, + "endColumn": 20 + } + ], + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 20, + "column": 16, + "endLine": 20, + "endColumn": 19, + "problem": "NumericSemantics", + "autofix": [ + { + "start": 680, + "end": 683, + "replacementText": "123.0", + "line": 20, + "column": 16, + "endLine": 20, + "endColumn": 19 + } + ], + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 22, + "column": 5, + "endLine": 22, + "endColumn": 18, + "problem": "NumericSemantics", + "autofix": [ + { + "start": 737, + "end": 750, + "replacementText": "arr: number[] = [1, 0];", + "line": 22, + "column": 5, + "endLine": 22, + "endColumn": 18 + } + ], + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 22, + "column": 12, + "endLine": 22, + "endColumn": 13, + "problem": "NumericSemantics", + "autofix": [ + { + "start": 744, + "end": 745, + "replacementText": "1.0", + "line": 22, + "column": 12, + "endLine": 22, + "endColumn": 13 + } + ], + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 22, + "column": 15, + "endLine": 22, + "endColumn": 16, + "problem": "NumericSemantics", + "autofix": [ + { + "start": 747, + "end": 748, + "replacementText": "0.0", + "line": 22, + "column": 15, + "endLine": 22, + "endColumn": 16 + } + ], + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + } + ] +} \ No newline at end of file diff --git a/ets2panda/linter/test/main/comment_test.ets.json b/ets2panda/linter/test/main/comment_test.ets.json new file mode 100644 index 0000000000..ca88f857e9 --- /dev/null +++ b/ets2panda/linter/test/main/comment_test.ets.json @@ -0,0 +1,17 @@ +{ + "copyright": [ + "Copyright (c) 2025 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." + ], + "result": [] +} \ No newline at end of file diff --git a/ets2panda/linter/test/main/comment_test.ets.migrate.ets b/ets2panda/linter/test/main/comment_test.ets.migrate.ets new file mode 100644 index 0000000000..2131000bfa --- /dev/null +++ b/ets2panda/linter/test/main/comment_test.ets.migrate.ets @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 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 TestClass { + /** + * This is a comment. + */ + property: number = 123.0; // This is a comment. + // This is a comment. + arr: number[] = [1.0, 0.0]; // This is a comment. +} diff --git a/ets2panda/linter/test/main/comment_test.ets.migrate.json b/ets2panda/linter/test/main/comment_test.ets.migrate.json new file mode 100644 index 0000000000..ca88f857e9 --- /dev/null +++ b/ets2panda/linter/test/main/comment_test.ets.migrate.json @@ -0,0 +1,17 @@ +{ + "copyright": [ + "Copyright (c) 2025 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." + ], + "result": [] +} \ No newline at end of file -- Gitee From b2151fbc896945c068715ba8ccc62db29b640363 Mon Sep 17 00:00:00 2001 From: fcc Date: Tue, 10 Jun 2025 15:43:56 +0800 Subject: [PATCH 029/209] fix unicode whitespace in lexer Fix Unicode whitespace in lexer. Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICE0R4 Signed-off-by: fcc --- ets2panda/lexer/lexer.cpp | 15 ++++++++++-- ets2panda/lexer/token/letters.h | 24 ++++++++++++------- .../test/runtime/ets/unicode_whitespace.ets | 17 +++++++++++++ 3 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 ets2panda/test/runtime/ets/unicode_whitespace.ets diff --git a/ets2panda/lexer/lexer.cpp b/ets2panda/lexer/lexer.cpp index 3868b42336..5cbf89f97c 100644 --- a/ets2panda/lexer/lexer.cpp +++ b/ets2panda/lexer/lexer.cpp @@ -1340,17 +1340,27 @@ bool Lexer::SkipWhiteSpacesHelperDefault(const char32_t &cp) size_t cpSize {}; - switch (Iterator().PeekCp(&cpSize)) { + char32_t ch = Iterator().PeekCp(&cpSize); + switch (ch) { case LEX_CHAR_LS: case LEX_CHAR_PS: pos_.nextTokenLine_++; [[fallthrough]]; case LEX_CHAR_NBSP: case LEX_CHAR_ZWNBSP: + case LEX_CHAR_OGHAM: + case LEX_CHAR_NARROW_NO_BREAK_SP: + case LEX_CHAR_MATHEMATICAL_SP: + case LEX_CHAR_IDEOGRAPHIC_SP: Iterator().Forward(cpSize); return true; default: - return false; + if (ch >= LEX_CHAR_ENQUAD && ch <= LEX_CHAR_ZERO_WIDTH_SP) { + Iterator().Forward(cpSize); + return true; + } else { + return false; + } } } @@ -1376,6 +1386,7 @@ void Lexer::SkipWhiteSpaces() case LEX_CHAR_FF: case LEX_CHAR_SP: case LEX_CHAR_TAB: + case LEX_CHAR_NEXT_LINE: Iterator().Forward(1); continue; case LEX_CHAR_SLASH: diff --git a/ets2panda/lexer/token/letters.h b/ets2panda/lexer/token/letters.h index 222aa6ca68..e33d21b114 100644 --- a/ets2panda/lexer/token/letters.h +++ b/ets2panda/lexer/token/letters.h @@ -82,14 +82,22 @@ inline constexpr char32_t LEX_CHAR_UPPERCASE_X = 0x58; /* X */ inline constexpr char32_t LEX_CHAR_UPPERCASE_Y = 0x59; /* Y */ inline constexpr char32_t LEX_CHAR_UPPERCASE_Z = 0x5A; /* Y */ -inline constexpr char32_t LEX_CHAR_BS = 0x08; /* backspace */ -inline constexpr char32_t LEX_CHAR_TAB = 0x09; /* character tabulation */ -inline constexpr char32_t LEX_CHAR_VT = 0x0B; /* liner tabulation */ -inline constexpr char32_t LEX_CHAR_FF = 0x0C; /* form feed */ -inline constexpr char32_t LEX_CHAR_SP = 0x20; /* space */ -inline constexpr char32_t LEX_CHAR_NBSP = 0xA0; /* no-break space */ -inline constexpr char32_t LEX_CHAR_ZWNBSP = 0xFEFF; /* zero width no-break space */ -inline constexpr char32_t LEX_CHAR_MVS = 0x180e; /* MONGOLIAN VOWEL SEPARATOR (U+180E) */ +inline constexpr char32_t LEX_CHAR_BS = 0x08; /* backspace */ +inline constexpr char32_t LEX_CHAR_TAB = 0x09; /* character tabulation */ +inline constexpr char32_t LEX_CHAR_VT = 0x0B; /* liner tabulation */ +inline constexpr char32_t LEX_CHAR_FF = 0x0C; /* form feed */ +inline constexpr char32_t LEX_CHAR_SP = 0x20; /* space */ +inline constexpr char32_t LEX_CHAR_NBSP = 0xA0; /* no-break space */ +inline constexpr char32_t LEX_CHAR_ZWNBSP = 0xFEFF; /* zero width no-break space */ +inline constexpr char32_t LEX_CHAR_MVS = 0x180e; /* MONGOLIAN VOWEL SEPARATOR (U+180E) */ +inline constexpr char32_t LEX_CHAR_NEXT_LINE = 0x85; /* next line */ +inline constexpr char32_t LEX_CHAR_OGHAM = 0x1680; /* ogham */ +inline constexpr char32_t LEX_CHAR_ENQUAD = 0X2000; +inline constexpr char32_t LEX_CHAR_ZERO_WIDTH_SP = 0x200B; +inline constexpr char32_t LEX_CHAR_NARROW_NO_BREAK_SP = 0x202F; +inline constexpr char32_t LEX_CHAR_MATHEMATICAL_SP = 0x205F; +inline constexpr char32_t LEX_CHAR_IDEOGRAPHIC_SP = 0x3000; + inline constexpr char32_t LEX_CHAR_DOUBLE_QUOTE = 0x22; /* " */ inline constexpr char32_t LEX_CHAR_DOLLAR_SIGN = 0x24; /* $ */ inline constexpr char32_t LEX_CHAR_SINGLE_QUOTE = 0x27; /* ' */ diff --git a/ets2panda/test/runtime/ets/unicode_whitespace.ets b/ets2panda/test/runtime/ets/unicode_whitespace.ets new file mode 100644 index 0000000000..dc0042c7b9 --- /dev/null +++ b/ets2panda/test/runtime/ets/unicode_whitespace.ets @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 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. + */ + +// this function intentionally contains unicode whitespace +function main() { assertTrue(true) } -- Gitee From 4011b6f280dab4b83ee99d78be7e07a7832e8c61 Mon Sep 17 00:00:00 2001 From: groshevmaksim Date: Mon, 2 Jun 2025 16:31:48 +0300 Subject: [PATCH 030/209] Remove JSValue-based front-end types Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICCBO1 Tests: ninja all tests Signed-off-by: groshevmaksim Change-Id: I14a13f57dbe165fb7fe9354a36e89fef37ef8d28 Change-Id: If52946c70a02d4e1782f7e28d352e0a493eca16f --- ets2panda/BUILD.gn | 7 - ets2panda/CMakeLists.txt | 3 - ets2panda/REVIEWERS | 2 - ets2panda/checker/ETSAnalyzer.cpp | 58 +- ets2panda/checker/ETSAnalyzerHelpers.cpp | 2 +- ets2panda/checker/ETSchecker.cpp | 7 - ets2panda/checker/ETSchecker.h | 14 - ets2panda/checker/ets/arithmetic.cpp | 37 +- ets2panda/checker/ets/dynamic.cpp | 481 ----------------- ets2panda/checker/ets/dynamic/dynamicCall.cpp | 80 --- ets2panda/checker/ets/dynamic/dynamicCall.h | 60 --- ets2panda/checker/ets/function.cpp | 9 +- ets2panda/checker/ets/helpers.cpp | 7 +- ets2panda/checker/ets/object.cpp | 11 - ets2panda/checker/ets/typeCheckingHelpers.cpp | 12 - ets2panda/checker/ets/typeCreation.cpp | 43 -- ets2panda/checker/ets/validateHelpers.cpp | 2 +- .../types/ets/etsDynamicFunctionType.h | 54 -- .../checker/types/ets/etsDynamicType.cpp | 119 ----- ets2panda/checker/types/ets/etsDynamicType.h | 73 --- .../checker/types/ets/etsFunctionType.cpp | 10 - ets2panda/checker/types/ets/etsObjectType.cpp | 34 -- ets2panda/checker/types/ets/types.h | 1 - ets2panda/checker/types/type.h | 36 -- ets2panda/checker/types/typeRelation.cpp | 8 - ets2panda/compiler/base/lreference.cpp | 19 +- ets2panda/compiler/core/ETSCompiler.cpp | 122 +---- ets2panda/compiler/core/ETSCompiler.h | 1 - ets2panda/compiler/core/ETSGen.cpp | 502 ------------------ ets2panda/compiler/core/ETSGen.h | 19 - ets2panda/compiler/core/ETSemitter.cpp | 5 - .../lowering/ets/asyncMethodLowering.cpp | 2 +- .../lowering/ets/dynamicImportLowering.cpp | 28 - .../lowering/ets/dynamicImportLowering.h | 35 -- .../compiler/lowering/ets/lambdaLowering.cpp | 3 - .../lowering/ets/objectIndexAccess.cpp | 9 +- .../lowering/ets/restArgsLowering.cpp | 2 +- .../compiler/lowering/ets/unboxLowering.cpp | 52 +- ets2panda/compiler/lowering/phase.cpp | 3 - ets2panda/ir/expressions/memberExpression.cpp | 7 - ets2panda/public/CMakeLists.txt | 4 - ets2panda/public/README.md | 2 - ets2panda/public/es2panda_lib.rb | 2 - .../compiler/ets/esobject_with_string_key.ets | 18 - .../ets/esobject_with_string_key_1.ets | 19 - .../dynamic_import_interop_neg.ets | 18 - .../ets/test_jsvalue_set_property_1.ets | 23 - .../ets/test_jsvalue_set_property_2.ets | 21 - .../test-lists/parser/parser-js-ignored.txt | 22 +- .../test-lists/recheck/recheck-ignored.txt | 1 - .../test/tsconfig/test-decl/CMakeLists.txt | 6 +- ets2panda/test/unit/dynamic/CMakeLists.txt | 3 +- .../test/unit/dynamic/dynamic_call_test.cpp | 2 - ..._verifier_identifier_has_variable_test.cpp | 3 +- ets2panda/varbinder/ETSBinder.cpp | 121 +---- ets2panda/varbinder/ETSBinder.h | 24 +- 56 files changed, 78 insertions(+), 2190 deletions(-) delete mode 100644 ets2panda/checker/ets/dynamic/dynamicCall.cpp delete mode 100644 ets2panda/checker/ets/dynamic/dynamicCall.h delete mode 100644 ets2panda/checker/types/ets/etsDynamicFunctionType.h delete mode 100644 ets2panda/checker/types/ets/etsDynamicType.cpp delete mode 100644 ets2panda/checker/types/ets/etsDynamicType.h delete mode 100644 ets2panda/compiler/lowering/ets/dynamicImportLowering.cpp delete mode 100644 ets2panda/compiler/lowering/ets/dynamicImportLowering.h delete mode 100644 ets2panda/test/ast/compiler/ets/esobject_with_string_key.ets delete mode 100644 ets2panda/test/ast/compiler/ets/esobject_with_string_key_1.ets delete mode 100644 ets2panda/test/ast/compiler/ets/import_tests/dynamic_import_interop_neg.ets delete mode 100644 ets2panda/test/ast/parser/ets/test_jsvalue_set_property_1.ets delete mode 100644 ets2panda/test/ast/parser/ets/test_jsvalue_set_property_2.ets diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index 42c9d7f055..2e31993bf1 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -74,7 +74,6 @@ libes2panda_sources = [ "checker/ets/castingContext.cpp", "checker/ets/conversion.cpp", "checker/ets/dynamic.cpp", - "checker/ets/dynamic/dynamicCall.cpp", "checker/ets/etsWarningAnalyzer.cpp", "checker/ets/function.cpp", "checker/ets/helpers.cpp", @@ -103,7 +102,6 @@ libes2panda_sources = [ "checker/types/ets/etsAsyncFuncReturnType.cpp", "checker/types/ets/etsBigIntType.cpp", "checker/types/ets/etsBooleanType.cpp", - "checker/types/ets/etsDynamicType.cpp", "checker/types/ets/etsEnumType.cpp", "checker/types/ets/etsExtensionFuncHelperType.cpp", "checker/types/ets/etsFunctionType.cpp", @@ -213,7 +211,6 @@ libes2panda_sources = [ "compiler/lowering/ets/declareOverloadLowering.cpp", "compiler/lowering/ets/defaultParametersInConstructorLowering.cpp", "compiler/lowering/ets/defaultParametersLowering.cpp", - "compiler/lowering/ets/dynamicImportLowering.cpp", "compiler/lowering/ets/enumLowering.cpp", "compiler/lowering/ets/enumPostCheckLowering.cpp", "compiler/lowering/ets/enumPropertiesInAnnotationsLowering.cpp", @@ -542,7 +539,6 @@ HEADERS_TO_BE_PARSED = [ "checker/types/ts/nonPrimitiveType.h", "ir/ts/tsTypeParameterInstantiation.h", "ir/module/importDeclaration.h", - "checker/types/ets/etsDynamicType.h", "ir/statements/doWhileStatement.h", "ir/expressions/literals/bigIntLiteral.h", "ir/expressions/assignmentExpression.h", @@ -630,7 +626,6 @@ HEADERS_TO_BE_PARSED = [ "ir/ts/tsParenthesizedType.h", "ir/ts/tsModuleDeclaration.h", "ir/ets/etsPackageDeclaration.h", - "checker/types/ets/etsDynamicFunctionType.h", "ir/expressions/literals/regExpLiteral.h", "ir/ets/etsNewArrayInstanceExpression.h", "checker/types/ets/etsVoidType.h", @@ -803,7 +798,6 @@ ES2PANDA_API_GENERATED = [ "$LIBGEN_DIR/gen/headers/ir/expressions/objectExpression.yaml", "$LIBGEN_DIR/gen/headers/ir/module/importSpecifier.yaml", "$LIBGEN_DIR/gen/headers/ir/expressions/conditionalExpression.yaml", - "$LIBGEN_DIR/gen/headers/checker/types/ets/etsDynamicFunctionType.yaml", "$LIBGEN_DIR/gen/headers/ir/expressions/callExpression.yaml", "$LIBGEN_DIR/gen/headers/ir/expressions/literals/bigIntLiteral.yaml", "$LIBGEN_DIR/gen/headers/ir/base/classElement.yaml", @@ -927,7 +921,6 @@ ES2PANDA_API_GENERATED = [ "$LIBGEN_DIR/gen/headers/ir/expressions/blockExpression.yaml", "$LIBGEN_DIR/gen/headers/ir/ts/tsTypeLiteral.yaml", "$LIBGEN_DIR/gen/headers/ir/ts/tsTypeParameter.yaml", - "$LIBGEN_DIR/gen/headers/checker/types/ets/etsDynamicType.yaml", "$LIBGEN_DIR/gen/headers/checker/types/ets/charType.yaml", "$LIBGEN_DIR/gen/headers/ir/ts/tsBooleanKeyword.yaml", "$LIBGEN_DIR/gen/headers/ir/base/spreadElement.yaml", diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index 695f3a76f9..cdc7ad2904 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -285,7 +285,6 @@ set(ES2PANDA_LIB_SRC compiler/lowering/ets/declareOverloadLowering.cpp compiler/lowering/ets/defaultParametersInConstructorLowering.cpp compiler/lowering/ets/defaultParametersLowering.cpp - compiler/lowering/ets/dynamicImportLowering.cpp compiler/lowering/ets/exportAnonymousConst.cpp compiler/lowering/ets/lateInitialization.cpp compiler/lowering/ets/lambdaLowering.cpp @@ -553,7 +552,6 @@ set(ES2PANDA_LIB_SRC checker/ets/castingContext.cpp checker/ets/conversion.cpp checker/ets/dynamic.cpp - checker/ets/dynamic/dynamicCall.cpp checker/ets/function.cpp checker/ets/validateHelpers.cpp checker/ets/typeCheckingHelpers.cpp @@ -587,7 +585,6 @@ set(ES2PANDA_LIB_SRC checker/types/ets/etsAnyType.cpp checker/types/ets/etsArrayType.cpp checker/types/ets/etsBooleanType.cpp - checker/types/ets/etsDynamicType.cpp checker/types/ets/etsEnumType.cpp checker/types/ets/etsExtensionFuncHelperType.cpp checker/types/ets/etsFunctionType.cpp diff --git a/ets2panda/REVIEWERS b/ets2panda/REVIEWERS index 8d77d32339..6835ef0e17 100644 --- a/ets2panda/REVIEWERS +++ b/ets2panda/REVIEWERS @@ -47,7 +47,6 @@ /ets2panda/util/diagnostic* @chernykhsergey ^igelhaus ^Prof1983 /ets2panda/util/importPathManager* @dreamdoomwalker ^trubachevilya ^igelhaus ^Prof1983 /test/workload/ignored*.txt @shirunova_viktoria @kuchkovairina @gavin1012_hw @zhuheng27 -/ets2panda/checker/ets/dynamic.cpp @akmaevaleksey ^vpukhov ^igelhaus ^Prof1983 /ets2panda/checker/ets/function.cpp ^vpukhov @gogabr ^igelhaus ^Prof1983 /ets2panda/checker/ets/helpers.cpp @zelentsovdmitry ^igelhaus ^Prof1983 /ets2panda/checker/ets/object.cpp @zelentsovdmitry ^vpukhov ^igelhaus ^Prof1983 @@ -61,7 +60,6 @@ /ets2panda/test/test-lists/parser @chernykhsergey ^igelhaus ^Prof1983 /ets2panda/test/unit/lsp ^igelhaus ^Prof1983 @dreamdoomwalker @Ascnbio ^muhammet-fevzi-bayiroglu @utkugursel /ets2panda/checker/types/ets/Nullish.* ^vpukhov @gogabr ^igelhaus ^Prof1983 -/ets2panda/checker/types/ets/etsDynamicType.* ^vpukhov @gogabr ^igelhaus ^Prof1983 /ets2panda/checker/types/ets/etsFunctionType.* ^vpukhov @gogabr ^igelhaus ^Prof1983 /ets2panda/checker/types/ets/etsTypeParameter.* ^vpukhov @gogabr ^igelhaus ^Prof1983 /ets2panda/checker/types/ets/etsUnionType.* @akmaevaleksey ^vpukhov @gogabr ^igelhaus ^Prof1983 diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 43ab9c71bf..3aa4109c2e 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -514,29 +514,17 @@ checker::Type *ETSAnalyzer::Check(ir::ETSNewClassInstanceExpression *expr) const auto *calleeObj = calleeType->AsETSObjectType(); expr->SetTsType(calleeObj); - if (calleeType->IsETSDynamicType() && !calleeType->AsETSDynamicType()->HasDecl()) { - auto lang = calleeType->AsETSDynamicType()->Language(); - expr->SetSignature(checker->ResolveDynamicCallExpression(expr->GetTypeRef(), expr->GetArguments(), lang, true)); - } else { - auto *signature = checker->ResolveConstructExpression(calleeObj, expr->GetArguments(), expr->Start()); + auto *signature = checker->ResolveConstructExpression(calleeObj, expr->GetArguments(), expr->Start()); - if (signature == nullptr) { - return checker->InvalidateType(expr); - } + if (signature == nullptr) { + return checker->InvalidateType(expr); + } - checker->CheckObjectLiteralArguments(signature, expr->GetArguments()); + checker->CheckObjectLiteralArguments(signature, expr->GetArguments()); - checker->ValidateSignatureAccessibility(calleeObj, signature, expr->Start()); + checker->ValidateSignatureAccessibility(calleeObj, signature, expr->Start()); - if (calleeType->IsETSDynamicType()) { - ES2PANDA_ASSERT(signature->Function()->IsDynamic()); - auto lang = calleeType->AsETSDynamicType()->Language(); - expr->SetSignature( - checker->ResolveDynamicCallExpression(expr->GetTypeRef(), signature->Params(), lang, true)); - } else { - expr->SetSignature(signature); - } - } + expr->SetSignature(signature); return expr->TsType(); } @@ -1406,13 +1394,7 @@ Type *ETSAnalyzer::GetReturnType(ir::CallExpression *expr, Type *calleeType) con checker->ValidateSignatureAccessibility(calleeObj, signature, expr->Start()); } - if (calleeType->IsETSMethodType() && signature->Function()->IsDynamic()) { - ES2PANDA_ASSERT(signature->Function()->IsDynamic()); - auto lang = signature->Function()->Language(); - expr->SetSignature(checker->ResolveDynamicCallExpression(expr->Callee(), signature->Params(), lang, false)); - } else { - expr->SetSignature(signature); - } + expr->SetSignature(signature); // #22951: this type should not be encoded as a signature flag if (signature->HasSignatureFlag(SignatureFlags::THIS_RETURN_TYPE)) { @@ -1469,16 +1451,7 @@ static checker::SavedCheckerContext ReconstructOwnerClassContext(ETSChecker *che checker::Type *ETSAnalyzer::GetCallExpressionReturnType(ir::CallExpression *expr, checker::Type *calleeType) const { ETSChecker *checker = GetETSChecker(); - checker::Type *returnType = nullptr; - if (UNLIKELY(calleeType->IsETSDynamicType() && !calleeType->AsETSDynamicType()->HasDecl())) { - // Trailing lambda for js function call is not supported, check the correctness of `foo() {}` - checker->EnsureValidCurlyBrace(expr); - auto lang = calleeType->AsETSDynamicType()->Language(); - expr->SetSignature(checker->ResolveDynamicCallExpression(expr->Callee(), expr->Arguments(), lang, false)); - returnType = expr->Signature()->ReturnType(); - } else { - returnType = GetReturnType(expr, calleeType); - } + checker::Type *returnType = GetReturnType(expr, calleeType); if (returnType->IsTypeError()) { return checker->GlobalTypeError(); @@ -2277,16 +2250,11 @@ checker::Type *ETSAnalyzer::Check(ir::ObjectExpression *expr) const return expr->TsType(); } - if (!expr->PreferredType()->IsETSUnionType() && !expr->PreferredType()->IsETSDynamicType() && - !ValidatePreferredType(checker, expr)) { + if (!expr->PreferredType()->IsETSUnionType() && !ValidatePreferredType(checker, expr)) { expr->SetTsType(checker->GlobalTypeError()); return expr->TsType(); } - if (expr->PreferredType()->IsETSDynamicType() && !expr->PreferredType()->AsETSDynamicType()->HasDecl()) { - return CheckDynamic(expr); - } - checker::ETSObjectType *objType = ResolveObjectTypeFromPreferredType(checker, expr); if (objType == nullptr) { @@ -3545,12 +3513,6 @@ checker::Type *ETSAnalyzer::Check(ir::TSAsExpression *expr) const {sourceType, targetType}, checker::CastingContext::ConstructorData {expr->Expr(), sourceType, targetType, expr->Expr()->Start()}); - if (sourceType->IsETSDynamicType() && targetType->IsLambdaObject()) { - // NOTE: itrubachev. change targetType to created lambdaobject type. - // Now targetType is not changed, only construct signature is added to it - checker->BuildLambdaObjectClass(targetType->AsETSObjectType(), - expr->TypeAnnotation()->AsETSFunctionType()->ReturnType()); - } expr->isUncheckedCast_ = ctx.UncheckedCast(); // Make sure the array type symbol gets created for the assembler to be able to emit checkcast. diff --git a/ets2panda/checker/ETSAnalyzerHelpers.cpp b/ets2panda/checker/ETSAnalyzerHelpers.cpp index cec0d02e2d..2a5443ae23 100644 --- a/ets2panda/checker/ETSAnalyzerHelpers.cpp +++ b/ets2panda/checker/ETSAnalyzerHelpers.cpp @@ -244,7 +244,7 @@ void ComposeAsyncImplFuncReturnType(ETSChecker *checker, ir::ScriptFunction *scr auto *objectId = checker->ProgramAllocNode(compiler::Signatures::BUILTIN_OBJECT_CLASS, checker->ProgramAllocator()); - checker->VarBinder()->AsETSBinder()->LookupTypeReference(objectId, false); + checker->VarBinder()->AsETSBinder()->LookupTypeReference(objectId); auto *returnType = checker->ProgramAllocNode( checker->ProgramAllocNode(objectId, nullptr, nullptr, checker->ProgramAllocator()), checker->ProgramAllocator()); diff --git a/ets2panda/checker/ETSchecker.cpp b/ets2panda/checker/ETSchecker.cpp index f345e2e86b..ce5dd58750 100644 --- a/ets2panda/checker/ETSchecker.cpp +++ b/ets2panda/checker/ETSchecker.cpp @@ -318,13 +318,6 @@ bool ETSChecker::StartChecker(varbinder::VarBinder *varbinder, const util::Optio auto *etsBinder = varbinder->AsETSBinder(); InitializeBuiltins(etsBinder); - for (auto &entry : etsBinder->DynamicImportVars()) { - auto &data = entry.second; - if (data.import->IsPureDynamic()) { - data.variable->SetTsType(GlobalBuiltinDynamicType(data.import->Language())); - } - } - bool isEvalMode = (debugInfoPlugin_ != nullptr); if (UNLIKELY(isEvalMode)) { // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 97ae5b8f2b..7de58a472e 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -329,9 +329,6 @@ public: bool isRecursive = false); ETSFunctionType *CreateETSArrowType(Signature *signature); ETSFunctionType *CreateETSMethodType(util::StringView name, ArenaVector &&signatures); - ETSFunctionType *CreateETSDynamicArrowType(Signature *signature, Language lang); - ETSFunctionType *CreateETSDynamicMethodType(util::StringView name, ArenaVector &&signatures, - Language lang); ETSExtensionFuncHelperType *CreateETSExtensionFuncHelperType(ETSFunctionType *classMethodType, ETSFunctionType *extensionFunctionType); void AddThisReturnTypeFlagForInterfaceInvoke(ETSObjectType *interface); @@ -341,7 +338,6 @@ public: std::tuple CreateBuiltinArraySignatureInfo(const ETSArrayType *arrayType, size_t dim); Signature *CreateBuiltinArraySignature(const ETSArrayType *arrayType, size_t dim); - std::tuple CheckForDynamicLang(ir::AstNode *declNode, util::StringView assemblerName); ETSObjectType *CreatePromiseOf(Type *type); Signature *CreateSignature(SignatureInfo *info, Type *returnType, ir::ScriptFunction *func); @@ -783,15 +779,6 @@ public: static Type *TryToInstantiate(Type *type, ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes); - // Dynamic interop - template - Signature *ResolveDynamicCallExpression(ir::Expression *callee, const ArenaVector &arguments, Language lang, - bool isConstruct); - ir::ClassProperty *CreateStaticReadonlyField(const char *name); - void BuildClassBodyFromDynamicImports(const ArenaVector &dynamicImports, - ArenaVector *classBody); - void BuildDynamicImportClass(); - void BuildLambdaObjectClass(ETSObjectType *functionalInterface, ir::TypeNode *retTypeAnnotation); // Trailing lambda void EnsureValidCurlyBrace(ir::CallExpression *callExpr); @@ -1007,7 +994,6 @@ private: ir::MethodDefinition *CreateLambdaObjectClassInvokeMethod(Signature *invokeSignature, ir::TypeNode *retTypeAnnotation); - void ClassInitializerFromImport(ir::ETSImportDeclaration *import, ArenaVector *statements); void EmitDynamicModuleClassInitCall(); DynamicCallIntrinsicsMap *DynamicCallIntrinsics(bool isConstruct) { diff --git a/ets2panda/checker/ets/arithmetic.cpp b/ets2panda/checker/ets/arithmetic.cpp index 3f7cdeda3d..8eebfe0d38 100644 --- a/ets2panda/checker/ets/arithmetic.cpp +++ b/ets2panda/checker/ets/arithmetic.cpp @@ -655,36 +655,10 @@ std::tuple ETSChecker::CheckBinaryOperatorStrictEqual(ir::Expres } tsType = GlobalETSBooleanType(); - if (rightType->IsETSDynamicType() && leftType->IsETSDynamicType()) { - return {tsType, GlobalBuiltinJSValueType()}; - } return {tsType, GlobalETSObjectType()}; } -static Type *CheckOperatorEqualDynamic(ETSChecker *checker, BinaryArithmOperands const &ops) -{ - auto left = ops.expr->Left(); - auto right = ops.expr->Right(); - // canonicalize - auto *const dynExp = left->TsType()->IsETSDynamicType() ? left : right; - auto *const otherExp = dynExp == left ? right : left; - - if (otherExp->TsType()->IsETSDynamicType()) { - return checker->GlobalBuiltinJSValueType(); - } - if (dynExp->TsType()->AsETSDynamicType()->IsConvertible(otherExp->TsType())) { - // NOTE: vpukhov. boxing flags are not set in dynamic values - return otherExp->TsType(); - } - if (otherExp->TsType()->IsETSReferenceType()) { - // have to prevent casting dyn_exp via ApplyCast without nullish flag - return checker->GlobalETSAnyType(); - } - checker->LogError(diagnostic::BINOP_DYN_UNIMPLEMENTED, {}, ops.expr->Start()); - return checker->GlobalETSAnyType(); -} - static Type *HandelReferenceBinaryEquality(ETSChecker *checker, BinaryArithmOperands const &ops) { [[maybe_unused]] auto const [expr, typeL, typeR, reducedL, reducedR] = ops; @@ -722,10 +696,6 @@ static Type *CheckBinaryOperatorEqual(ETSChecker *checker, BinaryArithmOperands return checker->GlobalTypeError(); } - if (typeL->IsETSDynamicType() || typeR->IsETSDynamicType()) { - return CheckOperatorEqualDynamic(checker, ops); - } - if (reducedL->IsETSBooleanType() && reducedR->IsETSBooleanType()) { if (reducedL->IsConstantType() && reducedR->IsConstantType()) { return checker->GetGlobalTypesHolder()->GlobalETSBooleanBuiltinType(); @@ -819,12 +789,7 @@ std::tuple ETSChecker::CheckBinaryOperatorInstanceOf(lexer::Sour return {GlobalETSBooleanBuiltinType(), leftType}; } - if (rightType->IsETSDynamicType() && !rightType->AsETSDynamicType()->HasDecl()) { - LogError(diagnostic::INSTANCEOF_NOT_TYPE, {}, pos); - return {GlobalETSBooleanBuiltinType(), leftType}; - } - - checker::Type *opType = rightType->IsETSDynamicType() ? GlobalBuiltinJSValueType() : GlobalETSObjectType(); + checker::Type *opType = GlobalETSObjectType(); RemoveStatus(checker::CheckerStatus::IN_INSTANCEOF_CONTEXT); return {GlobalETSBooleanBuiltinType(), opType}; diff --git a/ets2panda/checker/ets/dynamic.cpp b/ets2panda/checker/ets/dynamic.cpp index f5d2544345..e5530fc812 100644 --- a/ets2panda/checker/ets/dynamic.cpp +++ b/ets2panda/checker/ets/dynamic.cpp @@ -20,8 +20,6 @@ #include "varbinder/declaration.h" #include "varbinder/varbinder.h" #include "varbinder/ETSBinder.h" -#include "checker/types/ets/etsDynamicFunctionType.h" -#include "checker/ets/dynamic/dynamicCall.h" #include "compiler/lowering/scopesInit/scopesInitPhase.h" #include "ir/base/classProperty.h" #include "ir/base/classStaticBlock.h" @@ -94,147 +92,6 @@ ir::ETSParameterExpression *ETSChecker::AddParam(util::StringView name, ir::Type return ProgramAllocNode(paramIdent, false, ProgramAllocator()); } -template -ir::MethodDefinition *ETSChecker::CreateDynamicCallIntrinsic(ir::Expression *callee, const ArenaVector &arguments, - Language lang) -{ - ArenaVector params(ProgramAllocator()->Adapter()); - - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto dynamicTypeNode = ProgramAllocNode(GlobalBuiltinDynamicType(lang), ProgramAllocator()); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto intTypeNode = ProgramAllocNode(ir::PrimitiveType::INT, ProgramAllocator()); - - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *objParam = AddParam("obj", dynamicTypeNode); - params.push_back(objParam); - - ir::ETSParameterExpression *param2; - if (!DynamicCall::IsByValue(VarBinder()->AsETSBinder(), callee)) { - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - param2 = AddParam("qname_start", intTypeNode); - params.push_back(param2); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - param2 = AddParam("qname_len", intTypeNode->Clone(ProgramAllocator(), nullptr)); - } else { - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - param2 = AddParam("this", dynamicTypeNode->Clone(ProgramAllocator(), nullptr)); - } - - params.push_back(param2); - - for (size_t i = 0; i < arguments.size(); i++) { - util::UString paramName("p" + std::to_string(i), ProgramAllocator()); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto paramType = arguments[i]->TsType()->IsLambdaObject() - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ? dynamicTypeNode->Clone(ProgramAllocator(), nullptr) - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - : ProgramAllocNode(arguments[i]->TsType(), ProgramAllocator()); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - params.emplace_back(AddParam(paramName.View(), paramType)); - } - - auto funcSignature = - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ir::FunctionSignature(nullptr, std::move(params), dynamicTypeNode->Clone(ProgramAllocator(), nullptr)); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *func = ProgramAllocNode( - ProgramAllocator(), - ir::ScriptFunction::ScriptFunctionData {nullptr, std::move(funcSignature), ir::ScriptFunctionFlags::METHOD, - ir::ModifierFlags::NONE}); - - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *name = ProgramAllocNode(compiler::Signatures::STATIC_INVOKE_METHOD, ProgramAllocator()); - func->SetIdent(name); - - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *funcExpr = ProgramAllocNode(func); - - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *method = ProgramAllocNode( - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ir::MethodDefinitionKind::METHOD, func->Id()->Clone(ProgramAllocator(), nullptr), funcExpr, - ir::ModifierFlags::PUBLIC | ir::ModifierFlags::NATIVE | ir::ModifierFlags::STATIC, ProgramAllocator(), false); - return method; -} - -static void ToString(ETSChecker *checker, const ArenaVector &arguments, std::stringstream &ss) -{ - for (auto *arg : arguments) { - auto type = arg->Check(checker); - ss << "-"; - type->ToString(ss); - } -} - -static void ToString([[maybe_unused]] ETSChecker *checker, const ArenaVector &arguments, - std::stringstream &ss) -{ - for (auto *arg : arguments) { - auto *type = arg->TsType(); - ss << "-"; - type->ToString(ss); - } -} - -template -Signature *ETSChecker::ResolveDynamicCallExpression(ir::Expression *callee, const ArenaVector &arguments, - Language lang, bool isConstruct) -{ - auto &dynamicIntrinsics = *DynamicCallIntrinsics(isConstruct); - - auto mapIt = dynamicIntrinsics.find(lang); - if (mapIt == dynamicIntrinsics.cend()) { - std::tie(mapIt, std::ignore) = dynamicIntrinsics.emplace(lang, ProgramAllocator()->Adapter()); - } - - auto &map = mapIt->second; - - std::stringstream ss; - ss << "dyncall"; - if (DynamicCall::IsByValue(VarBinder()->AsETSBinder(), callee)) { - ss << "-byvalue"; - } else { - const auto callNames = DynamicCall::ResolveCall(VarBinder()->AsETSBinder(), callee); - DynamicCallNames(isConstruct)->try_emplace(callNames.name, 0); - } - - ToString(this, arguments, ss); - - auto key = ss.str(); - auto it = map.find(util::StringView(key)); - if (it == map.end()) { - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto klass = GetDynamicClass(lang, isConstruct); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *method = CreateDynamicCallIntrinsic(callee, arguments, lang); - auto props = ArenaVector(ProgramAllocator()->Adapter()); - props.emplace_back(method); - klass->Definition()->AddProperties(std::move(props)); - - { - auto prevClass = VarBinder()->AsETSBinder()->GetGlobalRecordTable()->ClassDefinition(); - VarBinder()->AsETSBinder()->GetGlobalRecordTable()->SetClassDefinition(klass->Definition()); - ProcessScopesNode(this, method); - ProcessCheckerNode(this, method); - VarBinder()->AsETSBinder()->GetGlobalRecordTable()->SetClassDefinition(prevClass); - } - method->Function()->Signature()->SetReturnType(GlobalBuiltinDynamicType(lang)); - - map.emplace(util::UString(key, ProgramAllocator()).View(), method->Function()); - return method->Function()->Signature(); - } - - return it->second->Signature(); -} - -template Signature *ETSChecker::ResolveDynamicCallExpression( - ir::Expression *callee, const ArenaVector &arguments, Language lang, bool isConstruct); - -template Signature *ETSChecker::ResolveDynamicCallExpression( - ir::Expression *callee, const ArenaVector &arguments, Language lang, bool isConstruct); - std::pair ETSChecker::CreateStaticScriptFunction( ClassInitializerBuilder const &builder) { @@ -325,33 +182,6 @@ ir::MethodDefinition *ETSChecker::CreateClassInstanceInitializer(const ClassInit return ctor; } -ir::ClassStaticBlock *ETSChecker::CreateDynamicCallClassInitializer(Language lang, bool isConstruct) -{ - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - return CreateClassStaticInitializer( - [this, lang, isConstruct](ArenaVector *statements, - [[maybe_unused]] ArenaVector *params) { - auto [builtin_class_name, builtin_method_name] = - util::Helpers::SplitSignature(isConstruct ? compiler::Signatures::Dynamic::InitNewClassBuiltin(lang) - : compiler::Signatures::Dynamic::InitCallClassBuiltin(lang)); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *classId = ProgramAllocNode(builtin_class_name, ProgramAllocator()); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *methodId = ProgramAllocNode(builtin_method_name, ProgramAllocator()); - auto *callee = - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ProgramAllocNode(classId, methodId, ir::MemberExpressionKind::PROPERTY_ACCESS, - false, false); - - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *initCall = ProgramAllocNode( - callee, ArenaVector(ProgramAllocator()->Adapter()), nullptr, false); - - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - statements->push_back(ProgramAllocNode(initCall)); - }); -} - ir::ClassDeclaration *ETSChecker::BuildClass(util::StringView name, const ClassBuilder &builder) { // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) @@ -385,94 +215,6 @@ ir::ClassDeclaration *ETSChecker::BuildClass(util::StringView name, const ClassB return classDecl; } -ir::ClassProperty *ETSChecker::CreateStaticReadonlyField(const char *name) -{ - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *fieldIdent = ProgramAllocNode(name, ProgramAllocator()); - auto flags = ir::ModifierFlags::STATIC | ir::ModifierFlags::PRIVATE | ir::ModifierFlags::READONLY; - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *field = ProgramAllocNode( - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - fieldIdent, nullptr, ProgramAllocNode(ir::PrimitiveType::INT, ProgramAllocator()), flags, - ProgramAllocator(), false); - return field; -} - -ir::ClassDeclaration *ETSChecker::GetDynamicClass(Language lang, bool isConstruct) -{ - auto &klasses = dynamicClasses_[static_cast(isConstruct)]; - if (klasses.count(lang) != 0U) { - return klasses[lang]; - } - auto className = - isConstruct ? compiler::Signatures::Dynamic::NewClass(lang) : compiler::Signatures::Dynamic::CallClass(lang); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto klass = BuildClass(className, [this, lang, isConstruct](ArenaVector *classBody) { - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - classBody->push_back(CreateStaticReadonlyField("qname_start_from")); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - classBody->push_back(CreateDynamicCallClassInitializer(lang, isConstruct)); - }); - klasses.emplace(lang, klass); - return klass; -} - -void ETSChecker::ClassInitializerFromImport(ir::ETSImportDeclaration *import, ArenaVector *statements) -{ - auto builtin = compiler::Signatures::Dynamic::LoadModuleBuiltin(import->Language()); - auto [builtin_class_name, builtin_method_name] = util::Helpers::SplitSignature(builtin); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *classId = ProgramAllocNode(builtin_class_name, ProgramAllocator()); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *methodId = ProgramAllocNode(builtin_method_name, ProgramAllocator()); - auto *callee = - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ProgramAllocNode(classId, methodId, ir::MemberExpressionKind::PROPERTY_ACCESS, false, - false); - - // NOTE: #23698. Make 'ohmUrl' mandatory in 'dynamicPaths'. - util::StringView ohmUrl = util::UString(import->OhmUrl(), ProgramAllocator()).View(); - if (ohmUrl.Empty()) { - ohmUrl = import->ResolvedSource(); - if (ark::os::file::File::IsRegularFile(ohmUrl.Mutf8())) { - ohmUrl = util::UString(ark::os::RemoveExtension(ohmUrl.Mutf8()), ProgramAllocator()).View(); - } - } - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ArenaVector callParams({ProgramAllocNode(ohmUrl)}, - ProgramAllocator()->Adapter()); - - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *loadCall = ProgramAllocNode(callee, std::move(callParams), nullptr, false); - auto *moduleClassId = - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ProgramAllocNode(compiler::Signatures::DYNAMIC_MODULE_CLASS, ProgramAllocator()); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *fieldId = ProgramAllocNode(import->AssemblerName(), ProgramAllocator()); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *property = ProgramAllocNode(moduleClassId, fieldId, - ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); - - auto *initializer = - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ProgramAllocNode(property, loadCall, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - statements->push_back(ProgramAllocNode(initializer)); -} - -ir::ClassStaticBlock *ETSChecker::CreateDynamicModuleClassInitializer( - const std::vector &imports) -{ - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - return CreateClassStaticInitializer([this, imports](ArenaVector *statements, - [[maybe_unused]] ArenaVector *params) { - for (auto *import : imports) { - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ClassInitializerFromImport(import, statements); - } - }); -} - ir::MethodDefinition *ETSChecker::CreateClassMethod(const std::string_view name, ir::ScriptFunctionFlags funcFlags, ir::ModifierFlags modifierFlags, const MethodBuilder &builder) { @@ -510,227 +252,4 @@ ir::MethodDefinition *ETSChecker::CreateClassMethod(const std::string_view name, return method; } -ir::MethodDefinition *ETSChecker::CreateDynamicModuleClassInitMethod() -{ - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - return CreateClassMethod(compiler::Signatures::DYNAMIC_MODULE_CLASS_INIT, ir::ScriptFunctionFlags::METHOD, - ir::ModifierFlags::PUBLIC | ir::ModifierFlags::STATIC, - [this]([[maybe_unused]] ArenaVector *statements, - [[maybe_unused]] ArenaVector *params, - Type **returnType) { *returnType = GlobalVoidType(); }); -} - -ir::MethodDefinition *ETSChecker::CreateLambdaObjectClassInvokeMethod(Signature *invokeSignature, - ir::TypeNode *retTypeAnnotation) -{ - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - return CreateClassMethod( - compiler::Signatures::LAMBDA_OBJECT_INVOKE, ir::ScriptFunctionFlags::METHOD, ir::ModifierFlags::PUBLIC, - [this, invokeSignature, retTypeAnnotation](ArenaVector *statements, - ArenaVector *params, Type **returnType) { - util::UString thisParamName(std::string("this"), ProgramAllocator()); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ir::ETSParameterExpression *thisParam = AddParam(thisParamName.View(), nullptr); - params->push_back(thisParam); - - ArenaVector callParams(ProgramAllocator()->Adapter()); - for (auto *invokeParam : invokeSignature->Params()) { - auto paramName = - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - util::UString(std::string("p") + std::to_string(callParams.size()), ProgramAllocator()).View(); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *param = AddParam(paramName, - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ProgramAllocNode(invokeParam->TsType(), ProgramAllocator())); - params->push_back(param); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - callParams.push_back(param->Clone(ProgramAllocator(), nullptr)); - } - - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *properyId = ProgramAllocNode("jsvalue_lambda", ProgramAllocator()); - auto *callee = - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ProgramAllocNode(thisParam->Clone(ProgramAllocator(), nullptr), properyId, - ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *callLambda = ProgramAllocNode(callee, std::move(callParams), nullptr, false); - - auto *castToRetTypeExpr = - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ProgramAllocNode(callLambda, retTypeAnnotation->Clone(ProgramAllocator(), nullptr), - false); - castToRetTypeExpr->SetTsType(invokeSignature->ReturnType()); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *retStatement = ProgramAllocNode(castToRetTypeExpr); - statements->push_back(retStatement); - - *returnType = invokeSignature->ReturnType(); - }); -} - -void ETSChecker::EmitDynamicModuleClassInitCall() -{ - auto *globalClass = VarBinder()->Program()->GlobalClass(); - auto &body = globalClass->Body(); - auto it = std::find_if(body.begin(), body.end(), [](ir::AstNode *node) { return node->IsClassStaticBlock(); }); - - ES2PANDA_ASSERT(it != body.end()); - - auto *staticBlock = (*it)->AsClassStaticBlock(); - auto *cctorBody = staticBlock->Function()->Body()->AsBlockStatement(); - - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *classId = ProgramAllocNode(compiler::Signatures::DYNAMIC_MODULE_CLASS, ProgramAllocator()); - auto *methodId = - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ProgramAllocNode(compiler::Signatures::DYNAMIC_MODULE_CLASS_INIT, ProgramAllocator()); - auto *callee = - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ProgramAllocNode(classId, methodId, ir::MemberExpressionKind::PROPERTY_ACCESS, false, - false); - - ArenaVector callParams(ProgramAllocator()->Adapter()); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *initCall = ProgramAllocNode(callee, std::move(callParams), nullptr, false); - - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *const node = ProgramAllocNode(initCall); - node->SetParent(cctorBody); - cctorBody->AddStatement(node); - - ProcessScopesNode(this, node); - ProcessCheckerNode(this, node); -} - -void ETSChecker::BuildClassBodyFromDynamicImports(const ArenaVector &dynamicImports, - ArenaVector *classBody) -{ - std::unordered_set fields; - std::vector imports; - - for (auto *import : dynamicImports) { - auto source = import->Source()->Str(); - if (fields.find(source) != fields.cend()) { - continue; - } - - auto assemblyName = std::string(source); - std::replace_if( - assemblyName.begin(), assemblyName.end(), [](char c) { return std::isalnum(c) == 0; }, '_'); - assemblyName.append(std::to_string(fields.size())); - - import->SetAssemblerName(util::UString(assemblyName, ProgramAllocator()).View()); - fields.insert(import->AssemblerName()); - imports.push_back(import); - - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *fieldIdent = ProgramAllocNode(import->AssemblerName(), ProgramAllocator()); - auto flags = ir::ModifierFlags::STATIC | ir::ModifierFlags::PUBLIC | ir::ModifierFlags::READONLY; - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *field = ProgramAllocNode( - fieldIdent, nullptr, - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ProgramAllocNode(GlobalBuiltinDynamicType(import->Language()), ProgramAllocator()), - flags, ProgramAllocator(), false); - - classBody->push_back(field); - } - - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - classBody->push_back(CreateDynamicModuleClassInitializer(imports)); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - classBody->push_back(CreateDynamicModuleClassInitMethod()); -} - -void ETSChecker::BuildDynamicImportClass() -{ - const auto &dynamicImports = VarBinder()->AsETSBinder()->DynamicImports(); - if (dynamicImports.empty()) { - return; - } - - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - BuildClass(compiler::Signatures::DYNAMIC_MODULE_CLASS, - [this, dynamicImports](ArenaVector *classBody) { - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - BuildClassBodyFromDynamicImports(dynamicImports, classBody); - }); - - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - EmitDynamicModuleClassInitCall(); -} - -ir::MethodDefinition *ETSChecker::CreateLambdaObjectClassInitializer(ETSObjectType *functionalInterface) -{ - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - return CreateClassInstanceInitializer( - [this](ArenaVector *statements, ArenaVector *params) { - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ir::ETSParameterExpression *thisParam = AddParam(varbinder::VarBinder::MANDATORY_PARAM_THIS, nullptr); - params->push_back(thisParam); - - util::UString jsvalueParamName(std::string("jsvalue_param"), ProgramAllocator()); - ir::ETSParameterExpression *jsvalueParam = - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - AddParam(jsvalueParamName.View(), - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ProgramAllocNode(GlobalBuiltinJSValueType(), ProgramAllocator())); - params->push_back(jsvalueParam); - auto *moduleClassId = - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ProgramAllocNode(varbinder::VarBinder::MANDATORY_PARAM_THIS, ProgramAllocator()); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *fieldId = ProgramAllocNode("jsvalue_lambda", ProgramAllocator()); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *property = ProgramAllocNode( - moduleClassId, fieldId, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *initializer = ProgramAllocNode( - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - property, jsvalueParam->Clone(ProgramAllocator(), nullptr), lexer::TokenType::PUNCTUATOR_SUBSTITUTION); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - statements->push_back(ProgramAllocNode(initializer)); - }, - functionalInterface); -} - -void ETSChecker::BuildLambdaObjectClass(ETSObjectType *functionalInterface, ir::TypeNode *retTypeAnnotation) -{ - auto *invokeMethod = functionalInterface->GetOwnProperty( - compiler::Signatures::STATIC_INVOKE_METHOD); - auto *invokeSignature = invokeMethod->TsType()->AsETSFunctionType()->CallSignatures()[0]; - - std::stringstream ss; - ss << compiler::Signatures::LAMBDA_OBJECT; - ToString(this, invokeSignature->Params(), ss); - auto syntheticLambdaObjName = ss.str(); - if (dynamicLambdaSignatureCache_.count(syntheticLambdaObjName) != 0) { - functionalInterface->AddConstructSignature(dynamicLambdaSignatureCache_[syntheticLambdaObjName]); - return; - } - - auto buildBody = [this, invokeSignature, retTypeAnnotation, - functionalInterface](ArenaVector *classBody) { - auto assemblyName = "jsvalue_lambda"; - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *fieldIdent = ProgramAllocNode(assemblyName, ProgramAllocator()); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *field = ProgramAllocNode( - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - fieldIdent, nullptr, ProgramAllocNode(GlobalBuiltinJSValueType(), ProgramAllocator()), - ir::ModifierFlags::PRIVATE, ProgramAllocator(), false); - classBody->push_back(field); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - classBody->push_back(CreateLambdaObjectClassInitializer(functionalInterface)); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - classBody->push_back(CreateLambdaObjectClassInvokeMethod(invokeSignature, retTypeAnnotation)); - }; - - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - BuildClass(util::StringView(syntheticLambdaObjName), buildBody); - - dynamicLambdaSignatureCache_[syntheticLambdaObjName] = functionalInterface->ConstructSignatures()[0]; -} - } // namespace ark::es2panda::checker diff --git a/ets2panda/checker/ets/dynamic/dynamicCall.cpp b/ets2panda/checker/ets/dynamic/dynamicCall.cpp deleted file mode 100644 index a80dd1fd2d..0000000000 --- a/ets2panda/checker/ets/dynamic/dynamicCall.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2021-2025 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 "checker/ets/dynamic/dynamicCall.h" - -#include "ir/ets/etsImportDeclaration.h" -#include "ir/ets/etsTypeReference.h" -#include "ir/ets/etsTypeReferencePart.h" -#include "ir/module/importSpecifier.h" -#include "ir/ts/tsQualifiedName.h" -#include "ir/expressions/memberExpression.h" - -namespace ark::es2panda::checker { - -DynamicCall::Result DynamicCall::ResolveCall(const varbinder::ETSBinder *varbinder, const ir::Expression *callee) -{ - auto calleeName = NameHolder(varbinder->Allocator()->Adapter()); - - if (callee->IsETSTypeReference()) { - // new A.B.C() => call js.new(A, ".B.C") - callee = callee->AsETSTypeReference()->Part()->Name(); - while (callee->IsTSQualifiedName()) { - auto *qname = callee->AsTSQualifiedName(); - callee = qname->Left(); - calleeName.emplace_back(qname->Right()->AsIdentifier()->Name()); - } - ES2PANDA_ASSERT(callee->IsIdentifier()); - } else if (callee->IsMemberExpression()) { - const auto memberExpr = callee->AsMemberExpression(); - callee = SqueezeExpr(memberExpr, calleeName); - } - if (callee->IsIdentifier()) { - // kinda optimization in case: - // `import X from Y` to use (load Y, call "X"), instead of (load Y, load X, call) - const auto var = callee->AsIdentifier()->Variable(); - const auto *data = varbinder->DynamicImportDataForVar(var); - if (data != nullptr && data->specifier != nullptr && data->specifier->IsImportSpecifier()) { - calleeName.emplace_back(data->specifier->AsImportSpecifier()->Imported()->Name()); - std::reverse(calleeName.begin(), calleeName.end()); - return {data->import, calleeName}; - } - } - std::reverse(calleeName.begin(), calleeName.end()); - return {callee, calleeName}; -} - -DynamicCall::Result DynamicCall::SqueezeExpr(ArenaAllocator *allocator, const ir::MemberExpression *expr) -{ - NameHolder name(allocator->Adapter()); - auto obj = SqueezeExpr(expr, name); - std::reverse(name.begin(), name.end()); - return {obj, name}; -} - -const ir::Expression *DynamicCall::SqueezeExpr(const ir::MemberExpression *memberExpr, NameHolder &name) -{ - if (!memberExpr->Object()->TsType()->IsETSDynamicType() || memberExpr->IsComputed()) { - return memberExpr; - } - ES2PANDA_ASSERT(memberExpr->Property()->IsIdentifier()); - name.emplace_back(memberExpr->Property()->AsIdentifier()->Name()); - if (memberExpr->Object()->IsMemberExpression()) { - return SqueezeExpr(memberExpr->Object()->AsMemberExpression(), name); - } - return memberExpr->Object(); -} - -} // namespace ark::es2panda::checker diff --git a/ets2panda/checker/ets/dynamic/dynamicCall.h b/ets2panda/checker/ets/dynamic/dynamicCall.h deleted file mode 100644 index b4de6cfd0a..0000000000 --- a/ets2panda/checker/ets/dynamic/dynamicCall.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2021 - 2024 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 ARK_DYNAMICCALLINFO_H -#define ARK_DYNAMICCALLINFO_H - -#include - -#include "varbinder/ETSBinder.h" -#include "ir/expression.h" - -namespace ark::es2panda::checker { - -class DynamicCall { - using NameHolder = ArenaVector; - -public: - struct Result { - const ir::AstNode *obj; - const NameHolder name; // NOLINT(readability-identifier-naming) - }; - - /** - * Resolve callee - * @param varbinder - * @param callee expression used to call method - * @return callee and name from which should be used to produce call - */ - static Result ResolveCall(const varbinder::ETSBinder *varbinder, const ir::Expression *callee); - static bool IsByValue(const varbinder::ETSBinder *varbinder, const ir::Expression *callee) - { - return ResolveCall(varbinder, callee).name.empty(); - } - - /** - * Example: A[0].C.D => return: A[0], name: ".C.D" - * @param expr member expression - * @param name to store result - * @return object with remaining member expression - */ - static Result SqueezeExpr(ArenaAllocator *allocator, const ir::MemberExpression *expr); - -private: - static const ir::Expression *SqueezeExpr(const ir::MemberExpression *expr, NameHolder &name); -}; - -} // namespace ark::es2panda::checker -#endif // ARK_DYNAMICCALLINFO_H diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index 40338b0c4a..ea80a961c3 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -1686,13 +1686,8 @@ checker::ETSFunctionType *ETSChecker::BuildMethodType(ir::ScriptFunction *func) { ES2PANDA_ASSERT(!func->IsArrow()); auto *nameVar = func->Id()->Variable(); - ETSFunctionType *funcType; - if (func->IsDynamic()) { - funcType = CreateETSDynamicMethodType(nameVar->Name(), {{func->Signature()}, ProgramAllocator()->Adapter()}, - func->Language()); - } else { - funcType = CreateETSMethodType(nameVar->Name(), {{func->Signature()}, ProgramAllocator()->Adapter()}); - } + ETSFunctionType *funcType = + CreateETSMethodType(nameVar->Name(), {{func->Signature()}, ProgramAllocator()->Adapter()}); funcType->SetVariable(nameVar); return funcType; } diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 13f3575f66..553abd66e2 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -652,7 +652,7 @@ static bool SetPreferredTypeForExpression(ETSChecker *checker, ir::Identifier *i checker->SetArrayPreferredTypeForNestedMemberExpressions(init->AsMemberExpression(), annotationType); } - if (init->IsArrayExpression() && (annotationType != nullptr) && !annotationType->IsETSDynamicType()) { + if (init->IsArrayExpression() && (annotationType != nullptr)) { if (annotationType->IsETSTupleType() && !checker->IsArrayExprSizeValidForTuple(init->AsArrayExpression(), annotationType->AsETSTupleType())) { return false; @@ -1756,11 +1756,6 @@ Type *ETSChecker::GetReferencedTypeBase(ir::Expression *name) return name->SetTsType(GlobalTypeError()); } - auto *importData = VarBinder()->AsETSBinder()->DynamicImportDataForVar(var); - if (importData != nullptr && importData->import->IsPureDynamic()) { - return name->SetTsType(GlobalBuiltinDynamicType(importData->import->Language())); - } - return name->SetTsType(ResolveReferencedType(var->AsLocalVariable(), name)); } diff --git a/ets2panda/checker/ets/object.cpp b/ets2panda/checker/ets/object.cpp index 4760ea0ca1..ce34a1924a 100644 --- a/ets2panda/checker/ets/object.cpp +++ b/ets2panda/checker/ets/object.cpp @@ -16,7 +16,6 @@ #include #include "checker/ETSchecker.h" #include "checker/ets/typeRelationContext.h" -#include "checker/types/ets/etsDynamicType.h" #include "checker/types/ets/etsObjectType.h" #include "checker/types/ets/etsTupleType.h" #include "checker/types/ets/etsPartialTypeParameter.h" @@ -2177,13 +2176,6 @@ std::vector ETSChecker::ResolveMemberReference(const ir::Member { std::vector resolveRes {}; - if (target->IsETSDynamicType() && !target->AsETSDynamicType()->HasDecl()) { - auto propName = memberExpr->Property()->AsIdentifier()->Name(); - varbinder::LocalVariable *propVar = target->AsETSDynamicType()->GetPropertyDynamic(propName, this); - resolveRes.emplace_back(ProgramAllocator()->New(propVar, ResolvedKind::PROPERTY)); - return resolveRes; - } - if (target->GetDeclNode() != nullptr && target->GetDeclNode()->IsClassDefinition() && !target->GetDeclNode()->AsClassDefinition()->IsClassDefinitionChecked()) { // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) @@ -2258,9 +2250,6 @@ void ETSChecker::CheckValidInheritance(ETSObjectType *classType, ir::ClassDefini if (classType->SuperType() == nullptr) { return; } - if (classType->SuperType()->IsETSDynamicType()) { - LogError(diagnostic::EXTEND_DYNAMIC, {classDef->Ident()->Name()}, classDef->Start()); - } const auto &allProps = classType->GetAllProperties(); diff --git a/ets2panda/checker/ets/typeCheckingHelpers.cpp b/ets2panda/checker/ets/typeCheckingHelpers.cpp index 39970f37d6..dbb75b798a 100644 --- a/ets2panda/checker/ets/typeCheckingHelpers.cpp +++ b/ets2panda/checker/ets/typeCheckingHelpers.cpp @@ -563,14 +563,6 @@ Type *ETSChecker::GetTypeOfVariable(varbinder::Variable *const var) return var->TsType(); } - // NOTE: kbaladurin. forbid usage of imported entities as types without declarations - if (VarBinder()->AsETSBinder()->IsDynamicModuleVariable(var)) { - auto *importData = VarBinder()->AsETSBinder()->DynamicImportDataForVar(var); - if (importData->import->IsPureDynamic()) { - return GlobalBuiltinDynamicType(importData->import->Language()); - } - } - checker::SavedCheckerContext savedContext(this, CheckerStatus::NO_OPTS); checker::ScopeContext scopeCtx(this, var->GetScope()); IterateInVariableContext(var); @@ -1308,10 +1300,6 @@ void ETSChecker::CheckBoxedSourceTypeAssignable(TypeRelation *relation, Type *so return; } ES2PANDA_ASSERT(target != nullptr); - // Do not box primitive in case of cast to dynamic types - if (target->IsETSDynamicType()) { - return; - } relation->IsAssignableTo(boxedSourceType, target); if (!relation->IsTrue()) { auto unboxedTargetType = MaybeUnboxInRelation(target); diff --git a/ets2panda/checker/ets/typeCreation.cpp b/ets2panda/checker/ets/typeCreation.cpp index fd835f0b7a..1c8c6c9a98 100644 --- a/ets2panda/checker/ets/typeCreation.cpp +++ b/ets2panda/checker/ets/typeCreation.cpp @@ -17,7 +17,6 @@ #include "checker/types/ets/etsAsyncFuncReturnType.h" #include "checker/types/ets/etsEnumType.h" -#include "checker/types/ets/etsDynamicFunctionType.h" #include "checker/types/ets/etsResizableArrayType.h" #include "checker/types/globalTypesHolder.h" #include "checker/types/type.h" @@ -158,17 +157,6 @@ ETSFunctionType *ETSChecker::CreateETSMethodType(util::StringView name, ArenaVec return ProgramAllocator()->New(this, name, std::move(signatures)); } -ETSFunctionType *ETSChecker::CreateETSDynamicArrowType(Signature *signature, Language lang) -{ - return ProgramAllocator()->New(this, signature, lang); -} - -ETSFunctionType *ETSChecker::CreateETSDynamicMethodType(util::StringView name, ArenaVector &&signatures, - Language lang) -{ - return ProgramAllocator()->New(this, name, std::move(signatures), lang); -} - static SignatureFlags ConvertToSignatureFlags(ir::ModifierFlags inModifiers, ir::ScriptFunctionFlags inFunctionFlags) { SignatureFlags outFlags = SignatureFlags::NO_OPTS; @@ -341,31 +329,6 @@ ETSObjectType *ETSChecker::CreateETSObjectTypeOrBuiltin(ir::AstNode *declNode, E return InitializeGlobalBuiltinObjectType(this, globalId.value(), declNode, flags); } -std::tuple ETSChecker::CheckForDynamicLang(ir::AstNode *declNode, util::StringView assemblerName) -{ - Language lang(Language::Id::ETS); - bool hasDecl = false; - - if (declNode->IsClassDefinition()) { - auto *clsDef = declNode->AsClassDefinition(); - lang = clsDef->Language(); - hasDecl = clsDef->IsDeclare(); - } - - if (declNode->IsTSInterfaceDeclaration()) { - auto *ifaceDecl = declNode->AsTSInterfaceDeclaration(); - lang = ifaceDecl->Language(); - hasDecl = ifaceDecl->IsDeclare(); - } - - auto res = compiler::Signatures::Dynamic::LanguageFromType(assemblerName.Utf8()); - if (res) { - lang = *res; - } - - return std::make_tuple(lang, hasDecl); -} - ETSObjectType *ETSChecker::CreateETSObjectType(ir::AstNode *declNode, ETSObjectFlags flags) { auto const [name, internalName] = GetObjectTypeDeclNames(declNode); @@ -383,12 +346,6 @@ ETSObjectType *ETSChecker::CreateETSObjectType(ir::AstNode *declNode, ETSObjectF return ProgramAllocator()->New(ProgramAllocator(), name, std::make_tuple(declNode, flags, Relation())); } - - if (auto [lang, hasDecl] = CheckForDynamicLang(declNode, internalName); lang.IsDynamic()) { - return ProgramAllocator()->New(ProgramAllocator(), std::make_tuple(name, internalName, lang), - std::make_tuple(declNode, flags, Relation()), hasDecl); - } - return ProgramAllocator()->New(ProgramAllocator(), name, internalName, std::make_tuple(declNode, flags, Relation())); } diff --git a/ets2panda/checker/ets/validateHelpers.cpp b/ets2panda/checker/ets/validateHelpers.cpp index 8d28ba8fd7..96d8ceedff 100644 --- a/ets2panda/checker/ets/validateHelpers.cpp +++ b/ets2panda/checker/ets/validateHelpers.cpp @@ -68,7 +68,7 @@ void ETSChecker::ValidateCallExpressionIdentifier(ir::Identifier *const ident, T ident->Variable()->Declaration()->Node()->IsImportNamespaceSpecifier()) { std::ignore = TypeError(ident->Variable(), diagnostic::NAMESPACE_CALL, {ident->ToString()}, ident->Start()); } - if (type->IsETSFunctionType() || type->IsETSDynamicType()) { + if (type->IsETSFunctionType()) { return; } // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) diff --git a/ets2panda/checker/types/ets/etsDynamicFunctionType.h b/ets2panda/checker/types/ets/etsDynamicFunctionType.h deleted file mode 100644 index 77a3c5731b..0000000000 --- a/ets2panda/checker/types/ets/etsDynamicFunctionType.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2024-2025 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_TYPES_ETS_DYNAMIC_FUNCTION_TYPE_H -#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_DYNAMIC_FUNCTION_TYPE_H - -#include "checker/types/ets/etsFunctionType.h" -#include "checker/ETSchecker.h" - -namespace ark::es2panda::checker { - -class ETSDynamicFunctionType : public ETSFunctionType { -public: - explicit ETSDynamicFunctionType(ETSChecker *checker, util::StringView name, ArenaVector &&signatures, - Language lang) - : ETSFunctionType(checker, name, std::move(signatures)), lang_(lang) - { - AddTypeFlag(TypeFlag::ETS_DYNAMIC_FUNCTION_TYPE); - } - - explicit ETSDynamicFunctionType(ETSChecker *checker, Signature *signature, Language lang) - : ETSFunctionType(checker, signature), lang_(lang) - { - AddTypeFlag(TypeFlag::ETS_DYNAMIC_FUNCTION_TYPE); - } - - ETSDynamicFunctionType() = delete; - ~ETSDynamicFunctionType() override = default; - NO_COPY_SEMANTIC(ETSDynamicFunctionType); - NO_MOVE_SEMANTIC(ETSDynamicFunctionType); - - es2panda::Language Language() const - { - return lang_; - } - -private: - es2panda::Language lang_; -}; -} // namespace ark::es2panda::checker - -#endif /* ES2PANDA_COMPILER_CHECKER_TYPES_ETS_DYNAMIC_FUNCTION_TYPE_H */ diff --git a/ets2panda/checker/types/ets/etsDynamicType.cpp b/ets2panda/checker/types/ets/etsDynamicType.cpp deleted file mode 100644 index cd6be095d6..0000000000 --- a/ets2panda/checker/types/ets/etsDynamicType.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2021-2025 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 "etsDynamicType.h" -#include "checker/ETSchecker.h" -#include "checker/ets/conversion.h" -#include "checker/types/ets/etsDynamicFunctionType.h" - -namespace ark::es2panda::checker { - -varbinder::LocalVariable *ETSDynamicType::GetPropertyDynamic(const util::StringView &name, - const ETSChecker *checker) const -{ - auto it = propertiesCache_.find(name); - if (it != propertiesCache_.end()) { - return it->second; - } - - varbinder::LocalVariable *var = varbinder::Scope::CreateVar( - Allocator(), name, varbinder::VariableFlags::BUILTIN_TYPE, nullptr); - var->SetTsType(checker->GlobalBuiltinDynamicType(lang_)); - propertiesCache_.emplace(name, var); - - return var; -} - -void ETSDynamicType::AssignmentTarget(TypeRelation *relation, Type *source) -{ - if (hasDecl_) { - return ETSObjectType::AssignmentTarget(relation, source); - } - - if (relation->ApplyBoxing() && !relation->IsTrue() && IsConvertible(source)) { - relation->Result(true); - return; - } - - if (source->IsETSDynamicType()) { - relation->Result(true); - } -} - -bool ETSDynamicType::AssignmentSource(TypeRelation *relation, Type *target) -{ - if (hasDecl_) { - return ETSObjectType::AssignmentSource(relation, target); - } - - if (relation->ApplyUnboxing() && IsConvertible(target)) { - relation->Result(true); - return true; - } - - if (target->IsETSDynamicType()) { - relation->Result(true); - } - return relation->IsTrue(); -} - -void ETSDynamicType::Cast(TypeRelation *relation, Type *target) -{ - if (hasDecl_) { - return ETSObjectType::Cast(relation, target); - } - - if (relation->InCastingContext() || IsConvertible(target)) { - relation->Result(true); - return; - } - - conversion::Forbidden(relation); -} - -void ETSDynamicType::CastTarget(TypeRelation *relation, Type *source) -{ - if (hasDecl_) { - ETSObjectType::CastTarget(relation, source); - return; - } - - if (relation->InCastingContext() || IsConvertible(source)) { - relation->Result(true); - return; - } - - conversion::Forbidden(relation); -} - -bool ETSDynamicType::IsConvertible(Type const *target) -{ - return target->IsETSDynamicType() || target->IsETSObjectType() || target->IsETSArrayType() || - target->IsETSTupleType() || target->IsETSFunctionType() || - target->HasTypeFlag(checker::TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC | checker::TypeFlag::ETS_BOOLEAN); -} - -ETSFunctionType *ETSDynamicType::CreateMethodTypeForProp(util::StringView name) const -{ - auto checker = GetRelation()->GetChecker()->AsETSChecker(); - return checker->CreateETSDynamicMethodType(name, {{}, Allocator()->Adapter()}, lang_); -} - -void ETSDynamicType::ToAssemblerType(std::stringstream &ss) const -{ - ss << compiler::Signatures::Dynamic::Type(lang_); -} - -} // namespace ark::es2panda::checker diff --git a/ets2panda/checker/types/ets/etsDynamicType.h b/ets2panda/checker/types/ets/etsDynamicType.h deleted file mode 100644 index 47b99e3102..0000000000 --- a/ets2panda/checker/types/ets/etsDynamicType.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2021-2025 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_TYPES_ETS_DYNAMIC_TYPE_H -#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_DYNAMIC_TYPE_H - -#include "checker/types/ets/etsObjectType.h" - -namespace ark::es2panda::checker { -class ETSDynamicType : public ETSObjectType { - static constexpr auto NAME = 0; - static constexpr auto ASSEMBLER_NAME = 1; - static constexpr auto LANGUAGE = 2; - static constexpr auto DECL_NODE = 0; - static constexpr auto FLAGS = 1; - static constexpr auto RELATION = 2; - -public: - explicit ETSDynamicType(ThreadSafeArenaAllocator *allocator, - std::tuple label, - std::tuple info, bool hasDecl) - : ETSObjectType(allocator, std::get(label), std::get(label), - std::make_tuple(std::get(info), std::get(info) | ETSObjectFlags::DYNAMIC, - std::get(info))), - propertiesCache_ {allocator->Adapter()}, - lang_(std::get(label)), - hasDecl_(hasDecl) - { - AddTypeFlag(TypeFlag::ETS_DYNAMIC_TYPE); - } - - varbinder::LocalVariable *GetPropertyDynamic(const util::StringView &name, const ETSChecker *checker) const; - void AssignmentTarget(TypeRelation *relation, Type *source) override; - bool AssignmentSource(TypeRelation *relation, Type *target) override; - void Cast(TypeRelation *relation, Type *target) override; - void CastTarget(TypeRelation *relation, Type *source) override; - - es2panda::Language Language() const - { - return lang_; - } - - bool HasDecl() const - { - return hasDecl_; - } - - ETSFunctionType *CreateMethodTypeForProp(util::StringView name) const override; - - void ToAssemblerType(std::stringstream &ss) const override; - - static bool IsConvertible(Type const *target); - -private: - mutable PropertyMap propertiesCache_; - es2panda::Language lang_; - bool hasDecl_; -}; -} // namespace ark::es2panda::checker - -#endif diff --git a/ets2panda/checker/types/ets/etsFunctionType.cpp b/ets2panda/checker/types/ets/etsFunctionType.cpp index 5a9a176d9c..d6b776d64c 100644 --- a/ets2panda/checker/types/ets/etsFunctionType.cpp +++ b/ets2panda/checker/types/ets/etsFunctionType.cpp @@ -263,16 +263,6 @@ bool ETSFunctionType::AssignmentSource(TypeRelation *relation, Type *target) { AssertNoMethodsInFunctionRelation(this, target); - // this should be defined by the dynamic type itself - if (target->IsETSDynamicType()) { - ES2PANDA_ASSERT(relation->GetNode() != nullptr); - if (relation->GetNode()->IsArrowFunctionExpression()) { - ES2PANDA_ASSERT(callSignatures_.size() == 1 && ArrowSignature()->HasSignatureFlag(SignatureFlags::CALL)); - return relation->Result(true); - } - return relation->Result(false); - } - return relation->IsSupertypeOf(target, this); } diff --git a/ets2panda/checker/types/ets/etsObjectType.cpp b/ets2panda/checker/types/ets/etsObjectType.cpp index c86dbcd510..f4626cb22a 100644 --- a/ets2panda/checker/types/ets/etsObjectType.cpp +++ b/ets2panda/checker/types/ets/etsObjectType.cpp @@ -553,9 +553,6 @@ bool ETSObjectType::AssignmentSource(TypeRelation *const relation, [[maybe_unuse bool ETSObjectType::IsBoxedPrimitive() const { - if (this->IsETSDynamicType()) { - return false; - } if (this->IsETSEnumType()) { return false; } @@ -1137,31 +1134,6 @@ static std::pair GetObjectTypeDeclNames(ir:: return {node->AsAnnotationDeclaration()->GetBaseName()->Name(), node->AsAnnotationDeclaration()->InternalName()}; } -static std::tuple CheckForDynamicLang(ir::AstNode *declNode, util::StringView assemblerName) -{ - Language lang(Language::Id::ETS); - bool hasDecl = false; - - if (declNode->IsClassDefinition()) { - auto *clsDef = declNode->AsClassDefinition(); - lang = clsDef->Language(); - hasDecl = clsDef->IsDeclare(); - } - - if (declNode->IsTSInterfaceDeclaration()) { - auto *ifaceDecl = declNode->AsTSInterfaceDeclaration(); - lang = ifaceDecl->Language(); - hasDecl = ifaceDecl->IsDeclare(); - } - - auto res = compiler::Signatures::Dynamic::LanguageFromType(assemblerName.Utf8()); - if (res) { - lang = *res; - } - - return std::make_tuple(lang, hasDecl); -} - ETSObjectType *ETSObjectType::CreateETSObjectType(ir::AstNode *declNode, ETSObjectFlags flags) { auto const [name, internalName] = GetObjectTypeDeclNames(declNode); @@ -1173,12 +1145,6 @@ ETSObjectType *ETSObjectType::CreateETSObjectType(ir::AstNode *declNode, ETSObje ES2PANDA_ASSERT(declNode->AsClassDefinition()->IsStringEnumTransformed()); return Allocator()->New(Allocator(), name, internalName, declNode, GetRelation()); } - - if (auto [lang, hasDecl] = CheckForDynamicLang(declNode, internalName); lang.IsDynamic()) { - return Allocator()->New(Allocator(), std::make_tuple(name, internalName, lang), - std::make_tuple(declNode, flags, GetRelation()), hasDecl); - } - if (internalName == compiler::Signatures::BUILTIN_ARRAY) { return Allocator()->New(Allocator(), name, std::make_tuple(declNode, flags, GetRelation())); diff --git a/ets2panda/checker/types/ets/types.h b/ets2panda/checker/types/ets/types.h index ce05b8b154..e82a8fa0a5 100644 --- a/ets2panda/checker/types/ets/types.h +++ b/ets2panda/checker/types/ets/types.h @@ -32,7 +32,6 @@ #include "etsBigIntType.h" #include "etsObjectType.h" #include "etsTypeAliasType.h" -#include "etsDynamicType.h" #include "etsArrayType.h" #include "wildcardType.h" #include "etsTypeParameter.h" diff --git a/ets2panda/checker/types/type.h b/ets2panda/checker/types/type.h index c3d06181de..d3f83e9d37 100644 --- a/ets2panda/checker/types/type.h +++ b/ets2panda/checker/types/type.h @@ -29,10 +29,8 @@ class Variable; namespace ark::es2panda::checker { class ObjectDescriptor; class GlobalTypesHolder; -class ETSDynamicType; class ETSAsyncFuncReturnType; class ETSChecker; -class ETSDynamicFunctionType; class ETSTypeParameter; class ETSEnumType; @@ -143,25 +141,8 @@ public: return reinterpret_cast(this); } - [[nodiscard]] bool IsETSDynamicType() const noexcept - { - return IsETSObjectType() && HasTypeFlag(TypeFlag::ETS_DYNAMIC_FLAG); - } - [[nodiscard]] bool IsBuiltinNumeric() const noexcept; - ETSDynamicType *AsETSDynamicType() - { - ES2PANDA_ASSERT(IsETSDynamicType()); - return reinterpret_cast(this); - } - - const ETSDynamicType *AsETSDynamicType() const - { - ES2PANDA_ASSERT(IsETSDynamicType()); - return reinterpret_cast(this); - } - ETSAsyncFuncReturnType *AsETSAsyncFuncReturnType() { ES2PANDA_ASSERT(IsETSAsyncFuncReturnType()); @@ -174,23 +155,6 @@ public: return reinterpret_cast(this); } - bool IsETSDynamicFunctionType() const - { - return TypeFlags() == TypeFlag::ETS_DYNAMIC_FUNCTION_TYPE; - } - - ETSDynamicFunctionType *AsETSDynamicFunctionType() - { - ES2PANDA_ASSERT(IsETSDynamicFunctionType()); - return reinterpret_cast(this); - } - - const ETSDynamicFunctionType *AsETSDynamicFunctionType() const - { - ES2PANDA_ASSERT(IsETSDynamicFunctionType()); - return reinterpret_cast(this); - } - bool IsConstantType() const { return HasTypeFlag(checker::TypeFlag::CONSTANT); diff --git a/ets2panda/checker/types/typeRelation.cpp b/ets2panda/checker/types/typeRelation.cpp index 80a8ad001a..5ebe65a859 100644 --- a/ets2panda/checker/types/typeRelation.cpp +++ b/ets2panda/checker/types/typeRelation.cpp @@ -154,14 +154,6 @@ bool TypeRelation::IsAssignableTo(Type *source, Type *target) bool TypeRelation::IsComparableTo(Type *source, Type *target) { result_ = CacheLookup(source, target, checker_->ComparableResults(), RelationType::COMPARABLE); - - // NOTE: vpukhov. reimplement dynamic comparison and remove this check - if (source->IsETSDynamicType() || target->IsETSDynamicType()) { - if (!(source->IsETSDynamicType() && target->IsETSDynamicType())) { - return false; - } - } - if (result_ == RelationResult::CACHE_MISS) { if (IsAssignableTo(source, target)) { return true; diff --git a/ets2panda/compiler/base/lreference.cpp b/ets2panda/compiler/base/lreference.cpp index 9f9a3c45c0..96572db071 100644 --- a/ets2panda/compiler/base/lreference.cpp +++ b/ets2panda/compiler/base/lreference.cpp @@ -183,8 +183,7 @@ ETSLReference::ETSLReference(CodeGen *cg, const ir::AstNode *node, ReferenceKind const auto *memberExpr = Node()->AsMemberExpression(); staticObjRef_ = memberExpr->Object()->TsType(); - if (!memberExpr->IsComputed() && etsg_->Checker()->IsVariableStatic(memberExpr->PropVar()) && - !staticObjRef_->IsETSDynamicType()) { + if (!memberExpr->IsComputed() && etsg_->Checker()->IsVariableStatic(memberExpr->PropVar())) { return; } @@ -281,11 +280,6 @@ void ETSLReference::SetValueComputed(const ir::MemberExpression *memberExpr) con { const auto *const objectType = memberExpr->Object()->TsType(); - if (objectType->IsETSDynamicType()) { - etsg_->StoreElementDynamic(Node(), baseReg_, propReg_); - return; - } - if (objectType->IsETSTupleType()) { ES2PANDA_ASSERT(memberExpr->GetTupleIndexValue().has_value()); @@ -350,22 +344,13 @@ void ETSLReference::SetValue() const if (memberExpr->PropVar()->HasFlag(varbinder::VariableFlags::STATIC)) { const util::StringView fullName = etsg_->FormClassPropReference(staticObjRef_->AsETSObjectType(), propName); - if (staticObjRef_->IsETSDynamicType()) { - etsg_->StorePropertyDynamic(Node(), memberExprTsType, baseReg_, propName); - } else { - etsg_->StoreStaticProperty(Node(), memberExprTsType, fullName); - } + etsg_->StoreStaticProperty(Node(), memberExprTsType, fullName); return; } auto const *objectType = memberExpr->Object()->TsType(); - if (objectType->IsETSDynamicType()) { - etsg_->StorePropertyDynamic(Node(), memberExprTsType, baseReg_, propName); - return; - } - if (objectType->IsETSUnionType()) { etsg_->StorePropertyByName(Node(), baseReg_, checker::ETSChecker::FormNamedAccessMetadata(memberExpr->PropVar())); diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index bae951abe4..09d7df240a 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -16,12 +16,10 @@ #include "ETSCompiler.h" #include "compiler/base/catchTable.h" -#include "checker/ets/dynamic/dynamicCall.h" #include "compiler/base/condition.h" #include "compiler/base/lreference.h" #include "compiler/core/switchBuilder.h" #include "checker/ETSchecker.h" -#include "checker/types/ets/etsDynamicFunctionType.h" #include "checker/types/ets/etsTupleType.h" #include "ETSGen-inl.h" @@ -151,41 +149,6 @@ void ETSCompiler::Compile(const ir::ETSNewArrayInstanceExpression *expr) const ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType())); } -static std::pair LoadDynamicName(compiler::ETSGen *etsg, const ir::AstNode *node, - const ArenaVector &dynName, bool isConstructor) -{ - auto *checker = const_cast(etsg->Checker()->AsETSChecker()); - auto *callNames = checker->DynamicCallNames(isConstructor); - - auto qnameStart = etsg->AllocReg(); - auto qnameLen = etsg->AllocReg(); - - TargetTypeContext ttctx(etsg, nullptr); // without this ints will be cast to JSValue - etsg->LoadAccumulatorInt(node, callNames->at(dynName)); - etsg->StoreAccumulator(node, qnameStart); - etsg->LoadAccumulatorInt(node, dynName.size()); - etsg->StoreAccumulator(node, qnameLen); - return {qnameStart, qnameLen}; -} - -static void CreateDynamicObject(const ir::AstNode *node, compiler::ETSGen *etsg, const ir::Expression *typeRef, - checker::Signature *signature, const ArenaVector &arguments) -{ - auto objReg = etsg->AllocReg(); - - auto callInfo = checker::DynamicCall::ResolveCall(etsg->VarBinder(), typeRef); - if (callInfo.obj->IsETSImportDeclaration()) { - etsg->LoadAccumulatorDynamicModule(node, callInfo.obj->AsETSImportDeclaration()); - } else { - callInfo.obj->Compile(etsg); - } - - etsg->StoreAccumulator(node, objReg); - - auto [qnameStart, qnameLen] = LoadDynamicName(etsg, node, callInfo.name, true); - etsg->CallDynamic(ETSGen::CallDynamicData {node, objReg, qnameStart}, qnameLen, signature, arguments); -} - static void ConvertRestArguments(checker::ETSChecker *const checker, const ir::ETSNewClassInstanceExpression *expr) { if (expr->GetSignature()->RestVar() != nullptr && (expr->GetSignature()->RestVar()->TsType()->IsETSArrayType() || @@ -279,14 +242,8 @@ static void GetSizeInForOf(compiler::ETSGen *etsg, checker::Type const *const ex void ETSCompiler::Compile(const ir::ETSNewClassInstanceExpression *expr) const { ETSGen *etsg = GetETSGen(); - if (expr->TsType()->IsETSDynamicType()) { - compiler::RegScope rs(etsg); - auto *name = expr->GetTypeRef(); - CreateDynamicObject(expr, etsg, name, expr->signature_, expr->GetArguments()); - } else { - ConvertRestArguments(const_cast(etsg->Checker()->AsETSChecker()), expr); - etsg->InitObject(expr, expr->signature_, expr->GetArguments()); - } + ConvertRestArguments(const_cast(etsg->Checker()->AsETSChecker()), expr); + etsg->InitObject(expr, expr->signature_, expr->GetArguments()); etsg->SetAccumulatorType(expr->TsType()); } @@ -529,15 +486,8 @@ static void CompileInstanceof(compiler::ETSGen *etsg, const ir::BinaryExpression expr->Left()->Compile(etsg); etsg->ApplyConversionAndStoreAccumulator(expr->Left(), lhs, expr->OperationType()); - if (expr->Left()->TsType()->IsETSDynamicType() || expr->Right()->TsType()->IsETSDynamicType()) { - auto rhs = etsg->AllocReg(); - expr->Right()->Compile(etsg); - etsg->StoreAccumulator(expr, rhs); - etsg->IsInstanceDynamic(expr, lhs, rhs); - } else { - auto target = expr->Right()->TsType(); - etsg->IsInstance(expr, lhs, target); - } + auto target = expr->Right()->TsType(); + etsg->IsInstance(expr, lhs, target); ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType())); } @@ -696,38 +646,6 @@ void ETSCompiler::Compile(const ir::BlockExpression *expr) const expr->Scope()->SetParent(oldParent); } -void ETSCompiler::CompileDynamic(const ir::CallExpression *expr, compiler::VReg &calleeReg) const -{ - ETSGen *etsg = GetETSGen(); - auto callInfo = checker::DynamicCall::ResolveCall(etsg->VarBinder(), expr->Callee()); - if (callInfo.obj->IsETSImportDeclaration()) { - etsg->LoadAccumulatorDynamicModule(expr, callInfo.obj->AsETSImportDeclaration()); - } else { - callInfo.obj->Compile(etsg); - } - etsg->StoreAccumulator(expr, calleeReg); - - if (!callInfo.name.empty()) { - auto [qnameStart, qnameLen] = LoadDynamicName(etsg, expr, callInfo.name, false); - etsg->CallDynamic(ETSGen::CallDynamicData {expr, calleeReg, qnameStart}, qnameLen, expr->Signature(), - expr->Arguments()); - } else { - compiler::VReg dynParam2 = etsg->AllocReg(); - - auto lang = expr->Callee()->TsType()->IsETSDynamicFunctionType() - ? expr->Callee()->TsType()->AsETSDynamicFunctionType()->Language() - : expr->Callee()->TsType()->AsETSDynamicType()->Language(); - etsg->LoadUndefinedDynamic(expr, lang); - etsg->StoreAccumulator(expr, dynParam2); - etsg->CallDynamic(ETSGen::CallDynamicData {expr, calleeReg, dynParam2}, expr->Signature(), expr->Arguments()); - } - etsg->SetAccumulatorType(expr->Signature()->ReturnType()); - - if (etsg->GetAccumulatorType() != expr->TsType()) { - etsg->ApplyConversion(expr, expr->TsType()); - } -} - bool IsCastCallName(util::StringView name) { return name == Signatures::BYTE_CAST || name == Signatures::SHORT_CAST || name == Signatures::INT_CAST || @@ -795,9 +713,7 @@ void ETSCompiler::Compile(const ir::CallExpression *expr) const ConvertRestArguments(const_cast(etsg->Checker()->AsETSChecker()), expr, signature); - if (callee->TsType()->HasTypeFlag(checker::TypeFlag::ETS_DYNAMIC_FLAG)) { - CompileDynamic(expr, calleeReg); - } else if (callee->IsIdentifier()) { + if (callee->IsIdentifier()) { if (!isStatic) { etsg->LoadThis(expr); etsg->StoreAccumulator(expr, calleeReg); @@ -869,17 +785,6 @@ void ETSCompiler::Compile(const ir::Identifier *expr) const etsg->SetAccumulatorType(smartType); } -static void LoadETSDynamicTypeFromMemberExpr(compiler::ETSGen *etsg, const ir::MemberExpression *expr, - compiler::VReg objReg) -{ - if (etsg->Checker()->AsETSChecker()->Relation()->IsSupertypeOf(etsg->Checker()->GlobalBuiltinETSStringType(), - expr->Property()->TsType())) { - etsg->LoadPropertyDynamic(expr, expr->TsType(), objReg, expr->Property()); - } else { - etsg->LoadElementDynamic(expr, objReg); - } -} - bool ETSCompiler::CompileComputed(compiler::ETSGen *etsg, const ir::MemberExpression *expr) { if (!expr->IsComputed()) { @@ -905,8 +810,6 @@ bool ETSCompiler::CompileComputed(compiler::ETSGen *etsg, const ir::MemberExpres auto indexValue = *expr->GetTupleIndexValue(); auto *tupleElementType = objectType->AsETSTupleType()->GetTypeAtIndex(indexValue); etsg->LoadTupleElement(expr, objReg, tupleElementType, indexValue); - } else if (objectType->IsETSDynamicType()) { - LoadETSDynamicTypeFromMemberExpr(etsg, expr, objReg); } else { ES2PANDA_ASSERT(objectType->IsETSArrayType()); etsg->LoadArrayElement(expr, objReg); @@ -956,8 +859,6 @@ void ETSCompiler::Compile(const ir::MemberExpression *expr) const } else { etsg->CallVirtual(expr, variableType->AsETSFunctionType()->FindGetter(), objReg); } - } else if (objectType->IsETSDynamicType()) { - etsg->LoadPropertyDynamic(expr, expr->TsType(), objReg, propName); } else if (objectType->IsETSUnionType()) { etsg->LoadPropertyByName(expr, objReg, checker::ETSChecker::FormNamedAccessMetadata(expr->PropVar())); } else { @@ -1018,9 +919,6 @@ void ETSCompiler::Compile(const ir::ObjectExpression *expr) const compiler::RegScope rs {etsg}; compiler::VReg objReg = etsg->AllocReg(); - // NOTE: object expressions of dynamic type are not handled in objectLiteralLowering phase - ES2PANDA_ASSERT(expr->TsType()->IsETSDynamicType()); - auto *signatureInfo = etsg->Allocator()->New(etsg->Allocator()); auto *createObjSig = etsg->Allocator()->New(signatureInfo, nullptr, nullptr); createObjSig->SetInternalName(compiler::Signatures::BUILTIN_JSRUNTIME_CREATE_OBJECT); @@ -1048,11 +946,7 @@ void ETSCompiler::Compile(const ir::ObjectExpression *expr) const value->Compile(etsg); etsg->ApplyConversion(value, key->TsType()); - if (expr->TsType()->IsETSDynamicType()) { - etsg->StorePropertyDynamic(expr, value->TsType(), objReg, pname); - } else { - etsg->StoreProperty(expr, key->TsType(), objReg, pname); - } + etsg->StoreProperty(expr, key->TsType(), objReg, pname); } etsg->LoadAccumulator(expr, objReg); @@ -1662,10 +1556,6 @@ void ETSCompiler::CompileCast(const ir::TSAsExpression *expr, checker::Type cons etsg->CastToReftype(expr, targetType, expr->isUncheckedCast_); break; } - case checker::TypeFlag::ETS_DYNAMIC_TYPE: { - etsg->CastToDynamic(expr, targetType->AsETSDynamicType()); - break; - } // NOTE(gogabr): will be needed once we forbid as conversion /* // CC-OFFNXT(redundant_code[C++]) tmp code diff --git a/ets2panda/compiler/core/ETSCompiler.h b/ets2panda/compiler/core/ETSCompiler.h index 42f81ca50a..d09df63fd6 100644 --- a/ets2panda/compiler/core/ETSCompiler.h +++ b/ets2panda/compiler/core/ETSCompiler.h @@ -35,7 +35,6 @@ public: private: void GetDynamicNameParts(const ir::CallExpression *expr, ArenaVector &parts) const; - void CompileDynamic(const ir::CallExpression *expr, compiler::VReg &calleeReg) const; void CompileCastPrimitives(const ir::Expression *expr, checker::Type const *targetType) const; void CompileCast(const ir::TSAsExpression *expr, checker::Type const *targetType) const; void EmitCall(const ir::CallExpression *expr, compiler::VReg &calleeReg, checker::Signature *signature) const; diff --git a/ets2panda/compiler/core/ETSGen.cpp b/ets2panda/compiler/core/ETSGen.cpp index fde13df423..149c12d4d5 100644 --- a/ets2panda/compiler/core/ETSGen.cpp +++ b/ets2panda/compiler/core/ETSGen.cpp @@ -234,71 +234,8 @@ void ETSGen::LoadAccumulatorPoison(const ir::AstNode *node, const checker::Type SetAccumulatorType(type); } -util::StringView ETSGen::FormDynamicModulePropReference(const varbinder::Variable *var) -{ - ES2PANDA_ASSERT(VarBinder()->IsDynamicModuleVariable(var) || VarBinder()->IsDynamicNamespaceVariable(var)); - - auto *data = VarBinder()->DynamicImportDataForVar(var); - ES2PANDA_ASSERT(data != nullptr); - - auto *import = data->import; - - return FormDynamicModulePropReference(import); -} - -void ETSGen::LoadAccumulatorDynamicModule(const ir::AstNode *node, const ir::ETSImportDeclaration *import) -{ - ES2PANDA_ASSERT(import->Language().IsDynamic()); - LoadStaticProperty(node, Checker()->GlobalBuiltinDynamicType(import->Language()), - FormDynamicModulePropReference(import)); -} - -util::StringView ETSGen::FormDynamicModulePropReference(const ir::ETSImportDeclaration *import) -{ - std::stringstream ss; - ss << VarBinder()->Program()->ModulePrefix(); - ss << compiler::Signatures::DYNAMIC_MODULE_CLASS; - ss << '.'; - ss << import->AssemblerName(); - return util::UString(ss.str(), Allocator()).View(); -} - -void ETSGen::LoadDynamicModuleVariable(const ir::AstNode *node, varbinder::Variable const *const var) -{ - RegScope rs(this); - - auto *data = VarBinder()->DynamicImportDataForVar(var); - auto *import = data->import; - - LoadStaticProperty(node, var->TsType(), FormDynamicModulePropReference(var)); - - auto objReg = AllocReg(); - StoreAccumulator(node, objReg); - - auto *id = data->specifier->AsImportSpecifier()->Imported(); - auto lang = import->Language(); - LoadPropertyDynamic(node, Checker()->GlobalBuiltinDynamicType(lang), objReg, id->Name()); - - ApplyConversion(node); -} - -void ETSGen::LoadDynamicNamespaceVariable(const ir::AstNode *node, varbinder::Variable const *const var) -{ - LoadStaticProperty(node, var->TsType(), FormDynamicModulePropReference(var)); -} - void ETSGen::LoadVar(const ir::Identifier *node, varbinder::Variable const *const var) { - if (VarBinder()->IsDynamicModuleVariable(var)) { - LoadDynamicModuleVariable(node, var); - return; - } - - if (VarBinder()->IsDynamicNamespaceVariable(var)) { - LoadDynamicNamespaceVariable(node, var); - return; - } - auto *local = var->AsLocalVariable(); switch (ETSLReference::ResolveReferenceKind(var)) { @@ -488,139 +425,6 @@ void ETSGen::LoadPropertyByName([[maybe_unused]] const ir::AstNode *const node, #endif // PANDA_WITH_ETS } -void ETSGen::StorePropertyDynamic(const ir::AstNode *node, const checker::Type *propType, VReg objReg, - const util::StringView &propName) -{ - auto const lang = GetVRegType(objReg)->AsETSDynamicType()->Language(); - std::string_view methodName {}; - if (propType->IsETSBooleanType()) { - methodName = Signatures::Dynamic::SetPropertyBooleanBuiltin(lang); - } else if (propType->IsByteType()) { - methodName = Signatures::Dynamic::SetPropertyByteBuiltin(lang); - } else if (propType->IsCharType()) { - methodName = Signatures::Dynamic::SetPropertyCharBuiltin(lang); - } else if (propType->IsShortType()) { - methodName = Signatures::Dynamic::SetPropertyShortBuiltin(lang); - } else if (propType->IsIntType()) { - methodName = Signatures::Dynamic::SetPropertyIntBuiltin(lang); - } else if (propType->IsLongType()) { - methodName = Signatures::Dynamic::SetPropertyLongBuiltin(lang); - } else if (propType->IsFloatType()) { - methodName = Signatures::Dynamic::SetPropertyFloatBuiltin(lang); - } else if (propType->IsDoubleType()) { - methodName = Signatures::Dynamic::SetPropertyDoubleBuiltin(lang); - } else if (propType->IsETSStringType()) { - methodName = Signatures::Dynamic::SetPropertyStringBuiltin(lang); - } else if (propType->IsETSObjectType() || propType->IsETSTypeParameter()) { - methodName = Signatures::Dynamic::SetPropertyDynamicBuiltin(lang); - // NOTE: vpukhov. add non-dynamic builtin - if (!propType->IsETSDynamicType()) { - CastToDynamic(node, Checker()->GlobalBuiltinDynamicType(lang)->AsETSDynamicType()); - } - } else { - ASSERT_PRINT(false, "Unsupported property type"); - } - - RegScope rs(this); - VReg propValueReg = AllocReg(); - VReg propNameReg = AllocReg(); - - StoreAccumulator(node, propValueReg); - - // Load property name - LoadAccumulatorString(node, propName); - StoreAccumulator(node, propNameReg); - - // Set property by name - Ra().Emit(node, methodName, objReg, propNameReg, propValueReg, dummyReg_); - SetAccumulatorType(Checker()->GlobalBuiltinJSValueType()); -} - -void ETSGen::LoadPropertyDynamic(const ir::AstNode *node, const checker::Type *propType, VReg objReg, - std::variant property) -{ - auto const lang = GetVRegType(objReg)->AsETSDynamicType()->Language(); - auto *type = propType; - std::string_view methodName {}; - if (propType->IsETSBooleanType()) { - methodName = Signatures::Dynamic::GetPropertyBooleanBuiltin(lang); - } else if (propType->IsByteType()) { - methodName = Signatures::Dynamic::GetPropertyByteBuiltin(lang); - } else if (propType->IsCharType()) { - methodName = Signatures::Dynamic::GetPropertyCharBuiltin(lang); - } else if (propType->IsShortType()) { - methodName = Signatures::Dynamic::GetPropertyShortBuiltin(lang); - } else if (propType->IsIntType()) { - methodName = Signatures::Dynamic::GetPropertyIntBuiltin(lang); - } else if (propType->IsLongType()) { - methodName = Signatures::Dynamic::GetPropertyLongBuiltin(lang); - } else if (propType->IsFloatType()) { - methodName = Signatures::Dynamic::GetPropertyFloatBuiltin(lang); - } else if (propType->IsDoubleType()) { - methodName = Signatures::Dynamic::GetPropertyDoubleBuiltin(lang); - } else if (propType->IsETSStringType()) { - methodName = Signatures::Dynamic::GetPropertyStringBuiltin(lang); - } else if (propType->IsETSObjectType() || propType->IsETSTypeParameter()) { - methodName = Signatures::Dynamic::GetPropertyDynamicBuiltin(lang); - type = Checker()->GlobalBuiltinDynamicType(lang); - } else { - ASSERT_PRINT(false, "Unsupported property type"); - } - - RegScope rs(this); - - VReg propNameObject; - - if (node->IsMemberExpression() && node->AsMemberExpression()->IsComputed()) { - (std::get(property))->Compile(this); - } else { - // Load property name - LoadAccumulatorString(node, std::get(property)); - } - - propNameObject = AllocReg(); - StoreAccumulator(node, propNameObject); - - // Get property - Ra().Emit(node, methodName, objReg, propNameObject); - - SetAccumulatorType(type); - - if (propType != type && !propType->IsETSDynamicType()) { - CastDynamicToObject(node, propType); - } -} - -void ETSGen::StoreElementDynamic(const ir::AstNode *node, VReg objectReg, VReg index) -{ - auto const lang = GetVRegType(objectReg)->AsETSDynamicType()->Language(); - std::string_view methodName = Signatures::Dynamic::SetElementDynamicBuiltin(lang); - - RegScope rs(this); - - VReg valueReg = AllocReg(); - StoreAccumulator(node, valueReg); - - // Set property by index - Ra().Emit(node, methodName, objectReg, index, valueReg, dummyReg_); - SetAccumulatorType(Checker()->GlobalVoidType()); -} - -void ETSGen::LoadElementDynamic(const ir::AstNode *node, VReg objectReg) -{ - auto const lang = GetVRegType(objectReg)->AsETSDynamicType()->Language(); - std::string_view methodName = Signatures::Dynamic::GetElementDynamicBuiltin(lang); - - RegScope rs(this); - - VReg indexReg = AllocReg(); - StoreAccumulator(node, indexReg); - - // Get property by index - Ra().Emit(node, methodName, objectReg, indexReg); - SetAccumulatorType(Checker()->GlobalBuiltinDynamicType(lang)); -} - void ETSGen::CallRangeFillUndefined(const ir::AstNode *const node, checker::Signature *const signature, const VReg thisReg) { @@ -725,83 +529,10 @@ static bool IsNullUnsafeObjectType(checker::Type const *type) return type->IsETSObjectType() && type->AsETSObjectType()->IsGlobalETSObjectType(); } -void ETSGen::IsInstanceDynamic(const ir::BinaryExpression *const node, const VReg srcReg, - [[maybe_unused]] const VReg tgtReg) -{ - ES2PANDA_ASSERT(node->OperatorType() == lexer::TokenType::KEYW_INSTANCEOF); - const checker::Type *lhsType = node->Left()->TsType(); - const checker::Type *rhsType = node->Right()->TsType(); - ES2PANDA_ASSERT(rhsType->IsETSDynamicType() || lhsType->IsETSDynamicType()); - - const RegScope rs(this); - if (rhsType->IsETSDynamicType()) { - ES2PANDA_ASSERT(node->Right()->TsType()->AsETSDynamicType()->HasDecl()); - if (lhsType->IsETSDynamicType()) { - VReg dynTypeReg = MoveAccToReg(node); - // Semantics: - // let dyn_val: JSValue = ... - // dyn_value instanceof DynamicDecl - // Bytecode: - // call runtime intrinsic_dynamic - CallExact(node, Signatures::BUILTIN_JSRUNTIME_INSTANCE_OF_DYNAMIC, srcReg, dynTypeReg); - } else if (lhsType == Checker()->GlobalETSObjectType()) { - // Semantics: - // let obj: Object = ... - // obj instanceof DynamicDecl - // Bytecode: - // if isinstance : - // checkcast - // return call runtime intrinsic_dynamic - // return false - Label *ifFalse = AllocLabel(); - Language lang = rhsType->AsETSDynamicType()->Language(); - VReg dynTypeReg = MoveAccToReg(node); - LoadAccumulator(node, srcReg); - EmitIsInstance(node, Checker()->GlobalBuiltinDynamicType(lang)->AssemblerName()); - BranchIfFalse(node, ifFalse); - LoadAccumulator(node, srcReg); - EmitCheckCast(node, Checker()->GlobalBuiltinDynamicType(lang)->AssemblerName()); - CallExact(node, Signatures::BUILTIN_JSRUNTIME_INSTANCE_OF_DYNAMIC, srcReg, dynTypeReg); - SetLabel(node, ifFalse); - } else { - // Semantics: - // let obj: EtsType = ... - // obj instanceof DynamicDecl - // Bytecode: - // False - Sa().Emit(node, 0); - } - } else { - if (lhsType->IsETSDynamicType()) { - if (rhsType == Checker()->GlobalETSObjectType()) { - // Semantics: - // let dyn_val: JSValue = ... - // dyn_val instanceof Object - // Bytecode: - // True - Sa().Emit(node, 1); - } else { - // Semantics: - // let dyn_val: JSValue = ... - // dyn_val instanceof EtsType - // Bytecode: - // lda.type + call runtime instrinsic_static - Sa().Emit(node, rhsType->AsETSObjectType()->AssemblerName()); - VReg typeReg = MoveAccToReg(node); - CallExact(node, Signatures::BUILTIN_JSRUNTIME_INSTANCE_OF_STATIC, srcReg, typeReg); - } - } else { - ES2PANDA_UNREACHABLE(); - } - } - SetAccumulatorType(Checker()->GlobalETSBooleanType()); -} - // Implemented on top of the runtime type system, do not relax checks, do not introduce new types void ETSGen::TestIsInstanceConstituent(const ir::AstNode *const node, std::tuple