From 194cceecd1beb321287d657b859ee051dfbeb91b Mon Sep 17 00:00:00 2001 From: HuSenlin Date: Wed, 25 Jun 2025 21:55:34 +0800 Subject: [PATCH 01/16] Auto fix add configure rule Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICHU2N Signed-off-by: HuSenlin --- ets2panda/linter/src/cli/CommandLineParser.ts | 37 ++++++++++ ets2panda/linter/src/lib/LinterOptions.ts | 2 + ets2panda/linter/src/lib/LinterRunner.ts | 67 ++++++++++++++++--- 3 files changed, 97 insertions(+), 9 deletions(-) diff --git a/ets2panda/linter/src/cli/CommandLineParser.ts b/ets2panda/linter/src/cli/CommandLineParser.ts index 42e2cf404b..5664b7368e 100644 --- a/ets2panda/linter/src/cli/CommandLineParser.ts +++ b/ets2panda/linter/src/cli/CommandLineParser.ts @@ -192,6 +192,8 @@ function formCommandLineOptions(parsedCmd: ParsedCommand): CommandLineOptions { if (options.useRtLogic !== undefined) { opts.linterOptions.useRtLogic = options.useRtLogic; } + processRuleConfig(opts, options); + processAutofixRuleConfig(opts, options); formIdeInteractive(opts, options); formSdkOptions(opts, options); formMigrateOptions(opts, options); @@ -199,6 +201,39 @@ function formCommandLineOptions(parsedCmd: ParsedCommand): CommandLineOptions { return opts; } +function processRuleConfig(commandLineOptions: CommandLineOptions, options: OptionValues): void { + if (options.ruleConfig !== undefined) { + const stats = fs.statSync(path.normalize(options.ruleConfig)); + if (!stats.isFile()) { + console.error(`The file at ${options.ruleConfig} path does not exist!`); + } else { + const configuredRulesMap = getRulesFromConfig(options.ruleConfig); + const arkTSRulesMap = extractRuleTags(cookBookTag); + commandLineOptions.linterOptions.ruleConfigTags = getConfiguredRuleTags(arkTSRulesMap, configuredRulesMap); + } + } +} + + +function processAutofixRuleConfig(commandLineOptions: CommandLineOptions, options: OptionValues): void { + const autofixConfigureRulePath = getAutofixConfigureRulePath(options); + if (autofixConfigureRulePath.length > 0) { + const configuredRulesMap = getRulesFromConfig(autofixConfigureRulePath); + const arkTSRulesMap = extractRuleTags(cookBookTag); + commandLineOptions.linterOptions.autofixRuleConfigTags = getConfiguredRuleTags(arkTSRulesMap, configuredRulesMap); + } +} + +function getAutofixConfigureRulePath(options: OptionValues) : string { + if (!options.ruleConfig && options.autofixRuleConfig) { + const autofixRuleConfigPath = options.autofixRuleConfig + const stats = fs.statSync(path.normalize(autofixRuleConfigPath)); + return stats.isFile() ? autofixRuleConfigPath : ""; + } else { + return ""; + } +} + function createCommand(): Command { const program = new Command(); program. @@ -235,6 +270,8 @@ function createCommand(): Command { option('-o, --output-file-path ', 'path to store all log and result files'). option('--verbose', 'set log level to see debug messages'). option('--enable-interop', 'scan whole project to report 1.1 import 1.2'). + option('--rule-config ', 'Path to the rule configuration file'). + option('--autofix-rule-config ', 'Path to the auofix rule configuration file'). addOption(new Option('--warnings-as-errors', 'treat warnings as errors').hideHelp(true)). addOption(new Option('--no-check-ts-as-source', 'check TS files as third-party libary').hideHelp(true)). addOption(new Option('--no-use-rt-logic', 'run linter with SDK logic').hideHelp(true)). diff --git a/ets2panda/linter/src/lib/LinterOptions.ts b/ets2panda/linter/src/lib/LinterOptions.ts index 11c2183d5c..88a6031780 100644 --- a/ets2panda/linter/src/lib/LinterOptions.ts +++ b/ets2panda/linter/src/lib/LinterOptions.ts @@ -47,4 +47,6 @@ export interface LinterOptions { checkTsAndJs?: boolean; inputFiles?: string[]; onlySyntax?: boolean; + ruleConfigTags?: Set; + autofixRuleConfigTags?: Set; } diff --git a/ets2panda/linter/src/lib/LinterRunner.ts b/ets2panda/linter/src/lib/LinterRunner.ts index ea35b6ea9e..0c1eca18fe 100644 --- a/ets2panda/linter/src/lib/LinterRunner.ts +++ b/ets2panda/linter/src/lib/LinterRunner.ts @@ -16,6 +16,9 @@ import * as fs from 'node:fs'; import * as path from 'node:path'; import * as ts from 'typescript'; +import { processSyncErr } from '../lib/utils/functions/ProcessWrite'; +import * as qEd from './autofixes/QuasiEditor'; +import type { BaseTypeScriptLinter } from './BaseTypeScriptLinter'; import type { CommandLineOptions } from './CommandLineOptions'; import { InteropTypescriptLinter } from './InteropTypescriptLinter'; import type { LinterConfig } from './LinterConfig'; @@ -23,25 +26,22 @@ import type { LinterOptions } from './LinterOptions'; import type { LintRunResult } from './LintRunResult'; import { Logger } from './Logger'; import type { ProblemInfo } from './ProblemInfo'; -import { TypeScriptLinter } from './TypeScriptLinter'; +import { ProjectStatistics } from './statistics/ProjectStatistics'; +import type { createProgramCallback } from './ts-compiler/Compiler'; +import { compileLintOptions } from './ts-compiler/Compiler'; import { getTscDiagnostics } from './ts-diagnostics/GetTscDiagnostics'; import { transformTscDiagnostics } from './ts-diagnostics/TransformTscDiagnostics'; +import { TypeScriptLinter } from './TypeScriptLinter'; import { ARKTS_IGNORE_DIRS_NO_OH_MODULES, ARKTS_IGNORE_DIRS_OH_MODULES, ARKTS_IGNORE_FILES } from './utils/consts/ArktsIgnorePaths'; +import { EXTNAME_JS, EXTNAME_TS } from './utils/consts/ExtensionName'; import { USE_STATIC } from './utils/consts/InteropAPI'; -import { EXTNAME_TS, EXTNAME_JS } from './utils/consts/ExtensionName'; +import { LibraryTypeCallDiagnosticChecker } from './utils/functions/LibraryTypeCallDiagnosticChecker'; import { mergeArrayMaps } from './utils/functions/MergeArrayMaps'; import { clearPathHelperCache, pathContainsDirectory } from './utils/functions/PathHelper'; -import { LibraryTypeCallDiagnosticChecker } from './utils/functions/LibraryTypeCallDiagnosticChecker'; -import type { createProgramCallback } from './ts-compiler/Compiler'; -import { compileLintOptions } from './ts-compiler/Compiler'; -import * as qEd from './autofixes/QuasiEditor'; -import { ProjectStatistics } from './statistics/ProjectStatistics'; -import type { BaseTypeScriptLinter } from './BaseTypeScriptLinter'; -import { processSyncErr } from '../lib/utils/functions/ProcessWrite'; function prepareInputFilesList(cmdOptions: CommandLineOptions): string[] { let inputFiles = cmdOptions.inputFiles.map((x) => { @@ -164,6 +164,10 @@ function migrate( let lintResult: LintRunResult = initialLintResult; const problemsInfosBeforeMigrate = lintResult.problemsInfos; + // According the configration file to filter linter rule + const noNeedToBeFixedProblemsInfos = new Map(); + filterLinterProblems(cmdOptions, lintResult, noNeedToBeFixedProblemsInfos); + for (let pass = 0; pass < (cmdOptions.linterOptions.migrationMaxPass ?? qEd.DEFAULT_MAX_AUTOFIX_PASSES); pass++) { const appliedFix = fix(linterConfig, lintResult, updatedSourceTexts, hcResults); hcResults = undefined; @@ -188,6 +192,10 @@ function migrate( fs.writeFileSync(writeFileName, newText); }); + if (cmdOptions.linterOptions.autofixRuleConfigTags) { + addNoFixedProblems(lintResult.problemsInfos, noNeedToBeFixedProblemsInfos); + } + if (cmdOptions.linterOptions.ideInteractive) { lintResult.problemsInfos = problemsInfosBeforeMigrate; } @@ -195,6 +203,47 @@ function migrate( return lintResult; } +function addNoFixedProblems( + problemsInfos: Map, + noNeedToBeFixedProblemsInfos: Map +) : void { + for (const [filePath, problems] of problemsInfos) { + const noFixProblems = noNeedToBeFixedProblemsInfos.get(filePath) || []; + if (noFixProblems.length > 0) { + problems.push(...noFixProblems); + } + } +} + +function filterLinterProblems( + cmdOptions: CommandLineOptions, + lintResult: LintRunResult, + noNeedToBeFixedProblemsInfos: Map +): void { + const autofixRuleConfigTags = cmdOptions.linterOptions.autofixRuleConfigTags; + + if (!autofixRuleConfigTags || !lintResult.problemsInfos) { + return; + } + const stringArray: string[] = [...autofixRuleConfigTags].map(String); + console.log(`The autofixRuleConfigTags is: ${JSON.stringify(stringArray, null, 2)}`); + + const needToBeFixedProblemsInfos = new Map(); + for (const [filePath, problems] of lintResult.problemsInfos) { + const needToFix: ProblemInfo[] = []; + const noNeedToFix: ProblemInfo[] = []; + + for (const problem of problems) { + (autofixRuleConfigTags.has(problem.ruleTag) ? needToFix : noNeedToFix).push(problem); + } + + needToBeFixedProblemsInfos.set(filePath, needToFix); + noNeedToBeFixedProblemsInfos.set(filePath, noNeedToFix); + } + + lintResult.problemsInfos = needToBeFixedProblemsInfos; +} + function hasUseStaticDirective(srcFile: ts.SourceFile): boolean { if (!srcFile?.statements.length) { return false; -- Gitee From 42ac2762e8f3590f109723015c5c380e148beb0a Mon Sep 17 00:00:00 2001 From: ohhusenlin Date: Fri, 20 Jun 2025 17:10:12 +0800 Subject: [PATCH 02/16] Add detailed statistics report Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICGQPK Signed-off-by: ohhusenlin --- ets2panda/linter/src/cli/CommandLineParser.ts | 11 +- ets2panda/linter/src/cli/LinterCLI.ts | 146 +++++++---- ets2panda/linter/src/lib/LintRunResult.ts | 2 + ets2panda/linter/src/lib/LinterOptions.ts | 1 + ets2panda/linter/src/lib/LinterRunner.ts | 13 +- .../src/lib/statistics/scan/CountFile.ts | 216 ++++++++++++++++ .../src/lib/statistics/scan/CountNapiFile.ts | 151 ++++++++++++ .../statistics/scan/FloderScanResultInfo.ts | 25 ++ .../statistics/scan/NapiFileStatisticInfo.ts | 22 ++ .../lib/statistics/scan/ProblemNumbersInfo.ts | 22 ++ .../scan/ProblemStatisticsCommonFunction.ts | 232 ++++++++++++++++++ .../statistics/scan/ProblemStatisticsInfo.ts | 24 ++ .../statistics/scan/RuleDetailedErrorInfo.ts | 20 ++ .../statistics/scan/ScanTaskRelatedInfo.ts | 31 +++ .../scan/StatisticsReportInPutInfo.ts | 27 ++ .../src/lib/statistics/scan/TimeRecorder.ts | 54 ++++ .../src/lib/statistics/scan/WorkLoadInfo.ts | 59 +++++ .../src/lib/utils/consts/MapKeyConst.ts | 28 +++ .../lib/utils/consts/WorkloadRelatedConst.ts | 20 ++ ets2panda/linter/src/testRunner/LintTest.ts | 14 +- 20 files changed, 1061 insertions(+), 57 deletions(-) create mode 100644 ets2panda/linter/src/lib/statistics/scan/CountFile.ts create mode 100644 ets2panda/linter/src/lib/statistics/scan/CountNapiFile.ts create mode 100644 ets2panda/linter/src/lib/statistics/scan/FloderScanResultInfo.ts create mode 100644 ets2panda/linter/src/lib/statistics/scan/NapiFileStatisticInfo.ts create mode 100644 ets2panda/linter/src/lib/statistics/scan/ProblemNumbersInfo.ts create mode 100644 ets2panda/linter/src/lib/statistics/scan/ProblemStatisticsCommonFunction.ts create mode 100644 ets2panda/linter/src/lib/statistics/scan/ProblemStatisticsInfo.ts create mode 100644 ets2panda/linter/src/lib/statistics/scan/RuleDetailedErrorInfo.ts create mode 100644 ets2panda/linter/src/lib/statistics/scan/ScanTaskRelatedInfo.ts create mode 100644 ets2panda/linter/src/lib/statistics/scan/StatisticsReportInPutInfo.ts create mode 100644 ets2panda/linter/src/lib/statistics/scan/TimeRecorder.ts create mode 100644 ets2panda/linter/src/lib/statistics/scan/WorkLoadInfo.ts create mode 100644 ets2panda/linter/src/lib/utils/consts/MapKeyConst.ts create mode 100644 ets2panda/linter/src/lib/utils/consts/WorkloadRelatedConst.ts diff --git a/ets2panda/linter/src/cli/CommandLineParser.ts b/ets2panda/linter/src/cli/CommandLineParser.ts index 5664b7368e..2dd88d03d3 100644 --- a/ets2panda/linter/src/cli/CommandLineParser.ts +++ b/ets2panda/linter/src/cli/CommandLineParser.ts @@ -13,15 +13,15 @@ * limitations under the License. */ -import { Logger } from '../lib/Logger'; -import { logTscDiagnostic } from '../lib/utils/functions/LogTscDiagnostic'; -import type { CommandLineOptions } from '../lib/CommandLineOptions'; -import { ARKTS_IGNORE_DIRS_OH_MODULES } from '../lib/utils/consts/ArktsIgnorePaths'; import type { OptionValues } from 'commander'; import { Command, Option } from 'commander'; -import * as ts from 'typescript'; import * as fs from 'node:fs'; import * as path from 'node:path'; +import * as ts from 'typescript'; +import type { CommandLineOptions } from '../lib/CommandLineOptions'; +import { Logger } from '../lib/Logger'; +import { ARKTS_IGNORE_DIRS_OH_MODULES } from '../lib/utils/consts/ArktsIgnorePaths'; +import { logTscDiagnostic } from '../lib/utils/functions/LogTscDiagnostic'; const TS_EXT = '.ts'; const TSX_EXT = '.tsx'; @@ -179,6 +179,7 @@ function formCommandLineOptions(parsedCmd: ParsedCommand): CommandLineOptions { } if (options.projectFolder) { doProjectFolderArg(options.projectFolder, opts); + opts.linterOptions.projectFolderList = options.projectFolder; } if (options.project) { doProjectArg(options.project, opts); diff --git a/ets2panda/linter/src/cli/LinterCLI.ts b/ets2panda/linter/src/cli/LinterCLI.ts index 438c56756c..17edbb9b4b 100644 --- a/ets2panda/linter/src/cli/LinterCLI.ts +++ b/ets2panda/linter/src/cli/LinterCLI.ts @@ -13,20 +13,24 @@ * limitations under the License. */ +import { MigrationTool } from 'homecheck'; import * as fs from 'node:fs'; import * as os from 'node:os'; import * as path from 'node:path'; import * as readline from 'node:readline'; import type { CommandLineOptions } from '../lib/CommandLineOptions'; +import { getHomeCheckConfigInfo, transferIssues2ProblemInfo } from '../lib/HomeCheck'; import { lint } from '../lib/LinterRunner'; import { Logger } from '../lib/Logger'; import type { ProblemInfo } from '../lib/ProblemInfo'; -import { parseCommandLine } from './CommandLineParser'; -import { compileLintOptions, getEtsLoaderPath } from '../lib/ts-compiler/Compiler'; +import * as statistic from '../lib/statistics/scan/ProblemStatisticsCommonFunction'; +import type { ScanTaskRelatedInfo } from '../lib/statistics/scan/ScanTaskRelatedInfo'; +import { StatisticsReportInPutInfo } from '../lib/statistics/scan/StatisticsReportInPutInfo'; +import { TimeRecorder } from '../lib/statistics/scan/TimeRecorder'; import { logStatistics } from '../lib/statistics/StatisticsLogger'; -import { MigrationTool } from 'homecheck'; -import { getHomeCheckConfigInfo, transferIssues2ProblemInfo } from '../lib/HomeCheck'; +import { compileLintOptions, getEtsLoaderPath } from '../lib/ts-compiler/Compiler'; import { processSyncErr, processSyncOut } from '../lib/utils/functions/ProcessWrite'; +import { parseCommandLine } from './CommandLineParser'; export function run(): void { const commandLineArgs = process.argv.slice(2); @@ -43,7 +47,7 @@ export function run(): void { runIdeInteractiveMode(cmdOptions); } else { const compileOptions = compileLintOptions(cmdOptions); - const result = lint(compileOptions); + const result = lint(compileOptions, new TimeRecorder()); logStatistics(result.projectStats); process.exit(result.hasErrors ? 1 : 0); } @@ -52,36 +56,28 @@ export function run(): void { async function runIdeInteractiveMode(cmdOptions: CommandLineOptions): Promise { cmdOptions.followSdkSettings = true; cmdOptions.disableStrictDiagnostics = true; + const timeRecorder = new TimeRecorder(); + const scanTaskRelatedInfo = {} as ScanTaskRelatedInfo; const compileOptions = compileLintOptions(cmdOptions); - let homeCheckResult = new Map(); - const mergedProblems = new Map(); - - if (cmdOptions.linterOptions.arkts2 && cmdOptions.homecheck) { - const { ruleConfigInfo, projectConfigInfo } = getHomeCheckConfigInfo(cmdOptions); - let migrationTool: MigrationTool | null = new MigrationTool(ruleConfigInfo, projectConfigInfo); - await migrationTool.buildCheckEntry(); - const result = await migrationTool.start(); - migrationTool = null; - - homeCheckResult = transferIssues2ProblemInfo(result); - for (const [filePath, problems] of homeCheckResult) { - if (!mergedProblems.has(filePath)) { - mergedProblems.set(filePath, []); - } - mergedProblems.get(filePath)!.push(...problems); - } - } - - if (!cmdOptions.skipLinter) { - const result = lint(compileOptions, getEtsLoaderPath(compileOptions), homeCheckResult); - for (const [filePath, problems] of result.problemsInfos) { - mergeLintProblems(filePath, problems, mergedProblems, cmdOptions); - } + scanTaskRelatedInfo.cmdOptions = cmdOptions; + scanTaskRelatedInfo.timeRecorder = timeRecorder; + scanTaskRelatedInfo.compileOptions = compileOptions; + await executeScanTask(scanTaskRelatedInfo); + + const statisticsReportInPutInfo = scanTaskRelatedInfo.statisticsReportInPutInfo; + statisticsReportInPutInfo.statisticsReportName = 'scan-problems-statistics.json'; + statisticsReportInPutInfo.totalProblemNumbers = getTotalProblemNumbers(scanTaskRelatedInfo.mergedProblems); + statisticsReportInPutInfo.cmdOptions = cmdOptions; + statisticsReportInPutInfo.timeRecorder = timeRecorder; + + if (!cmdOptions.linterOptions.migratorMode && statisticsReportInPutInfo.cmdOptions.linterOptions.projectFolderList) { + await statistic.generateScanProbelemStatisticsReport(statisticsReportInPutInfo); } + const mergedProblems = scanTaskRelatedInfo.mergedProblems; const reportData = Object.fromEntries(mergedProblems); - await generateReportFile(reportData, cmdOptions.outputFilePath); - + const reportName: string = 'scan-report.json'; + await statistic.generateReportFile(reportName, reportData, cmdOptions.outputFilePath); for (const [filePath, problems] of mergedProblems) { const reportLine = JSON.stringify({ filePath, problems }) + '\n'; await processSyncOut(reportLine); @@ -90,6 +86,79 @@ async function runIdeInteractiveMode(cmdOptions: CommandLineOptions): Promise): number { + let totalProblemNumbers: number = 0; + for (const problems of mergedProblems.values()) { + totalProblemNumbers += problems.length; + } + return totalProblemNumbers; +} + +async function executeScanTask(scanTaskRelatedInfo: ScanTaskRelatedInfo): Promise { + const cmdOptions = scanTaskRelatedInfo.cmdOptions; + scanTaskRelatedInfo.statisticsReportInPutInfo = new StatisticsReportInPutInfo(); + scanTaskRelatedInfo.statisticsReportInPutInfo.ruleToNumbersMap = new Map(); + scanTaskRelatedInfo.statisticsReportInPutInfo.ruleToAutoFixedNumbersMap = new Map(); + scanTaskRelatedInfo.mergedProblems = new Map(); + if (cmdOptions.linterOptions.arkts2 && cmdOptions.homecheck) { + await executeHomeCheckTask(scanTaskRelatedInfo); + } + + if (!cmdOptions.skipLinter) { + executeLintTask(scanTaskRelatedInfo); + } +} + +async function executeHomeCheckTask(scanTaskRelatedInfo: ScanTaskRelatedInfo): Promise { + const cmdOptions = scanTaskRelatedInfo.cmdOptions; + const { ruleConfigInfo, projectConfigInfo } = getHomeCheckConfigInfo(cmdOptions); + let migrationTool: MigrationTool | null = new MigrationTool(ruleConfigInfo, projectConfigInfo); + await migrationTool.buildCheckEntry(); + scanTaskRelatedInfo.timeRecorder.startScan(); + scanTaskRelatedInfo.timeRecorder.setHomeCheckCountStatus(true); + const result = await migrationTool.start(); + migrationTool = null; + scanTaskRelatedInfo.homeCheckResult = transferIssues2ProblemInfo(result); + for (const [filePath, problems] of scanTaskRelatedInfo.homeCheckResult) { + if (!scanTaskRelatedInfo.mergedProblems.has(filePath)) { + scanTaskRelatedInfo.mergedProblems.set(filePath, []); + } + statistic.accumulateRuleNumbers( + problems, + scanTaskRelatedInfo.statisticsReportInPutInfo.ruleToNumbersMap, + scanTaskRelatedInfo.statisticsReportInPutInfo.ruleToAutoFixedNumbersMap + ); + scanTaskRelatedInfo.statisticsReportInPutInfo.arkOnePointOneProblemNumbers += + statistic.getArktsOnePointOneProlemNumbers(problems); + scanTaskRelatedInfo.mergedProblems.get(filePath)!.push(...problems); + } +} + +function executeLintTask(scanTaskRelatedInfo: ScanTaskRelatedInfo): void { + const cmdOptions = scanTaskRelatedInfo.cmdOptions; + const compileOptions = scanTaskRelatedInfo.compileOptions; + const homeCheckResult = scanTaskRelatedInfo.homeCheckResult; + if (!scanTaskRelatedInfo.timeRecorder.getHomeCheckCountStatus()) { + scanTaskRelatedInfo.timeRecorder.startScan(); + } + const result = lint( + compileOptions, + scanTaskRelatedInfo.timeRecorder, + getEtsLoaderPath(compileOptions), + homeCheckResult + ); + for (const [filePath, problems] of result.problemsInfos) { + statistic.accumulateRuleNumbers( + problems, + scanTaskRelatedInfo.statisticsReportInPutInfo.ruleToNumbersMap, + scanTaskRelatedInfo.statisticsReportInPutInfo.ruleToAutoFixedNumbersMap + ); + scanTaskRelatedInfo.statisticsReportInPutInfo.arkOnePointOneProblemNumbers += + statistic.getArktsOnePointOneProlemNumbers(problems); + mergeLintProblems(filePath, problems, scanTaskRelatedInfo.mergedProblems, cmdOptions); + } +} + function mergeLintProblems( filePath: string, problems: ProblemInfo[], @@ -123,19 +192,6 @@ function mergeLintProblems( } } -async function generateReportFile(reportData, reportPath?: string): Promise { - let reportFilePath = path.join('scan-report.json'); - if (reportPath !== undefined) { - reportFilePath = path.join(path.normalize(reportPath), 'scan-report.json'); - } - try { - await fs.promises.mkdir(path.dirname(reportFilePath), { recursive: true }); - await fs.promises.writeFile(reportFilePath, JSON.stringify(reportData, null, 2)); - } catch (error) { - console.error('Error generating report file:', error); - } -} - function getTempFileName(): string { return path.join(os.tmpdir(), Math.floor(Math.random() * 10000000).toString() + '_linter_tmp_file.ts'); } @@ -178,7 +234,7 @@ function runIdeModeDeprecated(cmdOptions: CommandLineOptions): void { cmdOptions.parsedConfigFile.fileNames.push(tmpFileName); } const compileOptions = compileLintOptions(cmdOptions); - const result = lint(compileOptions); + const result = lint(compileOptions, new TimeRecorder()); const problems = Array.from(result.problemsInfos.values()); if (problems.length === 1) { showJSONMessage(problems); diff --git a/ets2panda/linter/src/lib/LintRunResult.ts b/ets2panda/linter/src/lib/LintRunResult.ts index 3397a3941a..9c1519d077 100644 --- a/ets2panda/linter/src/lib/LintRunResult.ts +++ b/ets2panda/linter/src/lib/LintRunResult.ts @@ -15,9 +15,11 @@ import type { ProblemInfo } from './ProblemInfo'; import type { ProjectStatistics } from './statistics/ProjectStatistics'; +import type { TimeRecorder } from './statistics/scan/TimeRecorder'; export interface LintRunResult { hasErrors: boolean; problemsInfos: Map; projectStats: ProjectStatistics; + timeRecorder?: TimeRecorder; } diff --git a/ets2panda/linter/src/lib/LinterOptions.ts b/ets2panda/linter/src/lib/LinterOptions.ts index 88a6031780..9c75ad3c98 100644 --- a/ets2panda/linter/src/lib/LinterOptions.ts +++ b/ets2panda/linter/src/lib/LinterOptions.ts @@ -44,6 +44,7 @@ export interface LinterOptions { noMigrationBackupFile?: boolean; migrationReport?: boolean; wholeProjectPath?: string; + projectFolderList?: string[]; checkTsAndJs?: boolean; inputFiles?: string[]; onlySyntax?: boolean; diff --git a/ets2panda/linter/src/lib/LinterRunner.ts b/ets2panda/linter/src/lib/LinterRunner.ts index 0c1eca18fe..dd5d2cc790 100644 --- a/ets2panda/linter/src/lib/LinterRunner.ts +++ b/ets2panda/linter/src/lib/LinterRunner.ts @@ -27,6 +27,8 @@ import type { LintRunResult } from './LintRunResult'; import { Logger } from './Logger'; import type { ProblemInfo } from './ProblemInfo'; import { ProjectStatistics } from './statistics/ProjectStatistics'; +import { generateMigrationStatisicsReport } from './statistics/scan/ProblemStatisticsCommonFunction'; +import type { TimeRecorder } from './statistics/scan/TimeRecorder'; import type { createProgramCallback } from './ts-compiler/Compiler'; import { compileLintOptions } from './ts-compiler/Compiler'; import { getTscDiagnostics } from './ts-diagnostics/GetTscDiagnostics'; @@ -77,6 +79,7 @@ function prepareInputFilesList(cmdOptions: CommandLineOptions): string[] { export function lint( config: LinterConfig, + timeRecorder: TimeRecorder, etsLoaderPath?: string, hcResults?: Map ): LintRunResult { @@ -84,7 +87,10 @@ export function lint( config.cmdOptions.linterOptions.etsLoaderPath = etsLoaderPath; } const lintResult = lintImpl(config); - return config.cmdOptions.linterOptions.migratorMode ? migrate(config, lintResult, hcResults) : lintResult; + timeRecorder.endScan(); + return config.cmdOptions.linterOptions.migratorMode ? + migrate(config, lintResult, timeRecorder, hcResults) : + lintResult; } function lintImpl(config: LinterConfig): LintRunResult { @@ -156,8 +162,10 @@ function lintFiles( function migrate( initialConfig: LinterConfig, initialLintResult: LintRunResult, + timeRecorder: TimeRecorder, hcResults?: Map ): LintRunResult { + timeRecorder.startMigration(); let linterConfig = initialConfig; const { cmdOptions } = initialConfig; const updatedSourceTexts: Map = new Map(); @@ -192,6 +200,9 @@ function migrate( fs.writeFileSync(writeFileName, newText); }); + timeRecorder.endMigration(); + generateMigrationStatisicsReport(lintResult, timeRecorder, cmdOptions.outputFilePath); + if (cmdOptions.linterOptions.autofixRuleConfigTags) { addNoFixedProblems(lintResult.problemsInfos, noNeedToBeFixedProblemsInfos); } diff --git a/ets2panda/linter/src/lib/statistics/scan/CountFile.ts b/ets2panda/linter/src/lib/statistics/scan/CountFile.ts new file mode 100644 index 0000000000..04f0166f35 --- /dev/null +++ b/ets2panda/linter/src/lib/statistics/scan/CountFile.ts @@ -0,0 +1,216 @@ +/* + * 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 fs from 'fs'; +import path from 'path'; +import { promisify } from 'util'; + +// Define file type extensions +const FILE_TYPES: { [key: string]: string[] } = { + 'C/C++': ['.c', '.h', '.cpp', '.hpp'], + JavaScript: ['.js'], + TypeScript: ['.ts'], + JSON: ['.json', '.json5'], + XML: ['.xml'], + ArkTS: ['.ets'], + 'ArkTS Test': ['.test.ets'] +}; + +// Comment regex patterns by file type +const COMMENT_REGEX1: { [key: string]: RegExp } = { + 'C/C++': /\/\/.*/g, + JavaScript: /\/\/.*/g, + TypeScript: /\/\/.*/g, + ArkTS: /\/\/.*/g, + 'ArkTS Test': /\/\/.*/g, + XML: //g +}; + +const COMMENT_REGEX2: { [key: string]: RegExp } = { + 'C/C++': /\/\*.*?\*\//gs, + JavaScript: /\/\*.*?\*\//gs, + TypeScript: /\/\*.*?\*\//gs, + ArkTS: /\/\*.*?\*\//gs, + 'ArkTS Test': /\/\*.*?\*\//gs +}; + +/** + * Remove comments from file content + */ +function removeComments(content: string, fileType: string): string { + if (COMMENT_REGEX1[fileType]) { + content = content.replace(COMMENT_REGEX1[fileType], ''); + } + if (COMMENT_REGEX2[fileType]) { + content = content.replace(COMMENT_REGEX2[fileType], ''); + } + return content; +} + +/** + * Count valid lines of code (excluding comments and empty lines) + */ +async function countLines(filePath: string, fileType: string): Promise { + try { + const content = await promisify(fs.readFile)(filePath, 'utf-8'); + const cleanedContent = removeComments(content, fileType); + const lines = cleanedContent.split('\n'); + + // Filter out empty lines + const validLines = lines.filter((line) => { + return line.trim(); + }); + return validLines.length; + } catch (error) { + console.error(`Error reading ${filePath}: ${error}`); + return 0; + } +} + +/** + * Merge multiple result objects + */ +function mergeAllResults(results: { [key: string]: { fileCount: number; lineCount: number } }[]): { + [key: string]: { fileCount: number; lineCount: number }; +} { + const combined: { [key: string]: { fileCount: number; lineCount: number } } = {}; + + for (const result of results) { + for (const [type, counts] of Object.entries(result)) { + if (!combined[type]) { + combined[type] = { fileCount: 0, lineCount: 0 }; + } + combined[type].fileCount += counts.fileCount; + combined[type].lineCount += counts.lineCount; + } + } + + return combined; +} + +/** + * Process directory entries recursively + */ +async function walkDir(dir: string): Promise<{ [key: string]: { fileCount: number; lineCount: number } }> { + try { + const entries = await promisify(fs.readdir)(dir, { withFileTypes: true }); + const fileResults = await processFiles(dir, entries); + const dirResults = await processDirs(dir, entries); + return mergeAllResults([fileResults, dirResults]); + } catch (error) { + console.error(`Error reading ${dir}: ${error}`); + return {}; + } +} + +/** + * Process files in a directory + */ +async function processFiles( + dir: string, + entries: fs.Dirent[] +): Promise<{ [key: string]: { fileCount: number; lineCount: number } }> { + const fileResults = await Promise.all( + entries. + filter((entry) => { + return entry.isFile(); + }). + map(async(entry) => { + return processFileEntry(dir, entry); + }) + ); + return mergeAllResults(fileResults); +} + +/** + * Process a single file entry + */ +async function processFileEntry( + dir: string, + entry: fs.Dirent +): Promise<{ [key: string]: { fileCount: number; lineCount: number } }> { + const fullPath = path.join(dir, entry.name); + + for (const fileType in FILE_TYPES) { + const extensions = FILE_TYPES[fileType]; + const ext = path.extname(entry.name); + + if (extensions.includes(ext)) { + const lines = await countLines(fullPath, fileType); + return { + [fileType]: { + fileCount: 1, + lineCount: lines + } + }; + } + } + + return {}; +} + +/** + * Process subdirectories recursively + */ +async function processDirs( + dir: string, + entries: fs.Dirent[] +): Promise<{ [key: string]: { fileCount: number; lineCount: number } }> { + const dirEntries = entries.filter((entry) => { + return entry.isDirectory(); + }); + const dirResults = await Promise.all( + dirEntries.map((entry) => { + return walkDir(path.join(dir, entry.name)); + }) + ); + return mergeAllResults(dirResults); +} + +/** + * Analyze directory and count files/lines by type + */ +async function analyzeDirectory( + directory: string +): Promise<{ [key: string]: { fileCount: number; lineCount: number } }> { + // Initialize results + const results: { [key: string]: { fileCount: number; lineCount: number } } = {}; + for (const fileType in FILE_TYPES) { + results[fileType] = { fileCount: 0, lineCount: 0 }; + } + + const finalResults = await walkDir(directory); + Object.assign(results, finalResults); + return results; +} + +/** + * Main export function + */ +export async function countFiles( + directory: string +): Promise<{ [key: string]: { fileCount: number; lineCount: number } }> { + try { + const stats = await promisify(fs.stat)(directory); + if (stats.isDirectory()) { + return await analyzeDirectory(directory); + } + console.error('The directory is invalid!'); + return {}; + } catch (error) { + console.error('Read directory failed', error); + return {}; + } +} diff --git a/ets2panda/linter/src/lib/statistics/scan/CountNapiFile.ts b/ets2panda/linter/src/lib/statistics/scan/CountNapiFile.ts new file mode 100644 index 0000000000..93e31a0aa5 --- /dev/null +++ b/ets2panda/linter/src/lib/statistics/scan/CountNapiFile.ts @@ -0,0 +1,151 @@ +/* + * 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 fs from 'fs'; +import * as path from 'path'; +import type { NapiFileStatisticInfo } from './NapiFileStatisticInfo'; + +const EXTENSIONS = ['.c', '.cpp', '.cc', '.cxx', '.h', '.hpp', '.hh', '.hxx']; + +const SINGLE_LINE_COMMENT_REGEX = /\/\/.*/g; +const MULTI_LINE_COMMENT_REGEX = /\/\*[\s\S]*?\*\//g; + +const DEFAULT_STATISTICS: NapiFileStatisticInfo = { + totalFiles: 0, + totalLines: 0, + napiFiles: 0, + napiLines: 0, + napiFileLines: 0 +}; + +function removeComments(content: string): string { + return content.replace(MULTI_LINE_COMMENT_REGEX, '').replace(SINGLE_LINE_COMMENT_REGEX, ''); +} + +async function countLines(filePath: string): Promise { + try { + const content = await fs.promises.readFile(filePath, 'utf-8'); + const contentWithoutComments = removeComments(content); + const validLines = contentWithoutComments.split('\n').filter((line) => { + return line.trim(); + }); + return validLines.length; + } catch (e) { + console.error(`Error reading ${filePath}: ${e}`); + return 0; + } +} + +async function countNapiLines(filePath: string): Promise { + try { + const content = await fs.promises.readFile(filePath, 'utf-8'); + const lines = content.split('\n'); + const napiLines = new Set(); + + for (const line of lines) { + if (line.toLowerCase().includes('napi')) { + napiLines.add(line); + } + } + + return napiLines.size; + } catch (e) { + console.error(`Error reading ${filePath}: ${e}`); + return 0; + } +} + +async function analyzeDirectoryAsync(directory: string): Promise { + const dirQueue: string[] = [directory]; + const allResults: NapiFileStatisticInfo[] = []; + + while (dirQueue.length > 0) { + const currentDir = dirQueue.shift()!; + const entries = await fs.promises.readdir(currentDir, { withFileTypes: true }); + const fileResults = await Promise.all( + entries. + map((entry) => { + const fullPath = path.join(currentDir, entry.name); + if (entry.isDirectory()) { + dirQueue.push(fullPath); + return null; + } else if (isTargetFile(entry.name)) { + return processFile(fullPath); + } + return null; + }). + filter(Boolean) as Promise[] + ); + allResults.push(...fileResults); + } + + return allResults.reduce( + (acc, cur) => { + acc.totalFiles += cur.totalFiles; + acc.totalLines += cur.totalLines; + if (cur.napiFiles > 0) { + acc.napiFiles += cur.napiFiles; + acc.napiLines += cur.napiLines; + acc.napiFileLines += cur.napiFileLines; + } + return acc; + }, + { ...DEFAULT_STATISTICS } + ); +} + +async function processFile(filePath: string): Promise { + const result: NapiFileStatisticInfo = { + totalFiles: 1, + totalLines: 0, + napiFiles: 0, + napiLines: 0, + napiFileLines: 0 + }; + + try { + const [lines, napiCount] = await Promise.all([countLines(filePath), countNapiLines(filePath)]); + + result.totalLines = lines; + if (napiCount > 0) { + result.napiFiles = 1; + result.napiLines = napiCount; + result.napiFileLines = lines; + } + } catch (e) { + console.error(`Error processing ${filePath}: ${e}`); + } + return result; +} + +function isTargetFile(filename: string): boolean { + return EXTENSIONS.some((ext) => { + return filename.endsWith(ext); + }); +} + +export async function countNapiFiles(directory: string): Promise { + try { + const stat = await fs.promises.stat(directory); + if (!stat.isDirectory()) { + console.log('The provided path is not a directory!'); + return DEFAULT_STATISTICS; + } + return await analyzeDirectoryAsync(directory); + } catch (e) { + console.error(`Error accessing directory ${directory}: ${e}`); + return DEFAULT_STATISTICS; + } +} diff --git a/ets2panda/linter/src/lib/statistics/scan/FloderScanResultInfo.ts b/ets2panda/linter/src/lib/statistics/scan/FloderScanResultInfo.ts new file mode 100644 index 0000000000..447813a2d2 --- /dev/null +++ b/ets2panda/linter/src/lib/statistics/scan/FloderScanResultInfo.ts @@ -0,0 +1,25 @@ +/* + * 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 interface FloderScanResultInfo { + normalizedPath: string; + arkTSCodeLines: number; + cAndCPPCodeLines: number; + napiCodeLines: number; + jsCodeLines: number; + tsCodeLines: number; + jsonCodeLines: number; + xmlCodeLines: number; +} diff --git a/ets2panda/linter/src/lib/statistics/scan/NapiFileStatisticInfo.ts b/ets2panda/linter/src/lib/statistics/scan/NapiFileStatisticInfo.ts new file mode 100644 index 0000000000..20b3243802 --- /dev/null +++ b/ets2panda/linter/src/lib/statistics/scan/NapiFileStatisticInfo.ts @@ -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. + */ + +export interface NapiFileStatisticInfo { + totalFiles: number; + totalLines: number; + napiFiles: number; + napiLines: number; + napiFileLines: number; +} diff --git a/ets2panda/linter/src/lib/statistics/scan/ProblemNumbersInfo.ts b/ets2panda/linter/src/lib/statistics/scan/ProblemNumbersInfo.ts new file mode 100644 index 0000000000..d969313546 --- /dev/null +++ b/ets2panda/linter/src/lib/statistics/scan/ProblemNumbersInfo.ts @@ -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. + */ + +export interface ProblemNumbersInfo { + totalProblemNumbers: number; + arkOnePointOneProblemNumbers: number; + arkOnePointTWOProblemNumbers: number; + canBeAutoFixedproblemNumbers: number; + needToManualFixproblemNumbers: number; +} diff --git a/ets2panda/linter/src/lib/statistics/scan/ProblemStatisticsCommonFunction.ts b/ets2panda/linter/src/lib/statistics/scan/ProblemStatisticsCommonFunction.ts new file mode 100644 index 0000000000..cdf625ab5f --- /dev/null +++ b/ets2panda/linter/src/lib/statistics/scan/ProblemStatisticsCommonFunction.ts @@ -0,0 +1,232 @@ +/* + * 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 fs from 'node:fs'; +import * as path from 'node:path'; +import type { LintRunResult } from '../../LintRunResult'; +import type { ProblemInfo } from '../../ProblemInfo'; +import * as mk from '../../utils/consts/MapKeyConst'; +import { countFiles } from './CountFile'; +import { countNapiFiles } from './CountNapiFile'; +import type { ProblemNumbersInfo } from './ProblemNumbersInfo'; +import type { ProblemStatisticsInfo } from './ProblemStatisticsInfo'; +import type { RuleDetailedErrorInfo } from './RuleDetailedErrorInfo'; +import type { StatisticsReportInPutInfo } from './StatisticsReportInPutInfo'; +import type { TimeRecorder } from './TimeRecorder'; +import { WorkLoadInfo } from './WorkLoadInfo'; + +export function getProblemStatisticsInfo( + problemNumbers: ProblemNumbersInfo, + ruleToNumbersMap: Map, + ruleToAutoFixedNumbersMap: Map, + timeRecorder: TimeRecorder, + WorkLoadInfo?: WorkLoadInfo +): ProblemStatisticsInfo { + const problemNumberMap: Map = new Map(); + problemNumberMap.set(mk.TOTAL_PROBLEMS, problemNumbers.totalProblemNumbers); + problemNumberMap.set(mk.ONE_POINT_ONE_PROBLEMS, problemNumbers.arkOnePointOneProblemNumbers); + problemNumberMap.set(mk.ONE_POINT_TWO_PROBLEMS, problemNumbers.arkOnePointTWOProblemNumbers); + problemNumberMap.set(mk.CAN_BE_AUTO_FIXED_PROBLEMS_NUMBERS, problemNumbers.canBeAutoFixedproblemNumbers); + problemNumberMap.set(mk.NEED_TO_NAMUAL_FIX_PROBLEM_NUMBERS, problemNumbers.needToManualFixproblemNumbers); + + const scanTime = timeRecorder.getScanTime(); + const migrationTime = timeRecorder.getMigrationTime(); + const usedTimeMap: Map = new Map(); + usedTimeMap.set(mk.SCAN_TIME, scanTime); + usedTimeMap.set(mk.MIGRATION_TIME, migrationTime); + + const detailRuleProblemsMap: Map = new Map(); + ruleToNumbersMap.forEach((value, key) => { + const ruleDetailedErrorInfo: RuleDetailedErrorInfo = { + rule: key, + problemNumbers: value, + canBeAutoFixedMumbers: ruleToAutoFixedNumbersMap.get(key) ?? 0 + }; + detailRuleProblemsMap.set(key, ruleDetailedErrorInfo); + }); + + const problemStatisticsInfo: ProblemStatisticsInfo = { + problems: Object.fromEntries(problemNumberMap), + usedTime: Object.fromEntries(usedTimeMap), + WorkLoadInfo: WorkLoadInfo, + eachRuleProblemsDetail: Array.from(detailRuleProblemsMap.values()) + }; + return problemStatisticsInfo; +} + +export function getArktsOnePointOneProlemNumbers(problems: ProblemInfo[]): number { + let problemNumbersForATSOnePointOne: number = 0; + const signForOne: string = 's2d'; + problems.forEach((problem) => { + if (problem.rule !== undefined) { + if (problem.rule.includes(signForOne)) { + problemNumbersForATSOnePointOne = problemNumbersForATSOnePointOne + 1; + } + } + }); + return problemNumbersForATSOnePointOne; +} + +export function accumulateRuleNumbers( + problems: ProblemInfo[], + ruleToNumbersMap: Map, + ruleToAutoFixedNumbersMap: Map +): void { + problems.forEach((problem) => { + if (problem.rule !== undefined) { + if (problem.autofix) { + const currentNumber = ruleToAutoFixedNumbersMap.get(problem.rule) || 0; + ruleToAutoFixedNumbersMap.set(problem.rule, currentNumber + 1); + } + const currentNumber = ruleToNumbersMap.get(problem.rule) || 0; + ruleToNumbersMap.set(problem.rule, currentNumber + 1); + } + }); +} + +export async function generateReportFile(reportName: string, reportData, reportPath?: string): Promise { + let reportFilePath = path.join(reportName); + if (reportPath !== undefined) { + reportFilePath = path.join(path.normalize(reportPath), reportName); + } + try { + await fs.promises.mkdir(path.dirname(reportFilePath), { recursive: true }); + await fs.promises.writeFile(reportFilePath, JSON.stringify(reportData, null, 2)); + } catch (error) { + console.error('Error generating report file:', error); + } +} + +export function generateReportFileSync(reportName: string, reportData: any, reportPath?: string): void { + let reportFilePath = reportName; + if (reportPath !== undefined) { + reportFilePath = path.join(path.normalize(reportPath), reportName); + } + try { + fs.mkdirSync(path.dirname(reportFilePath), { recursive: true }); + fs.writeFileSync(reportFilePath, JSON.stringify(reportData, null, 2)); + } catch (error) { + console.error('Error generating report file:', error); + } +} + +export function getMapValueSum(map: Map): number { + let result = 0; + for (const value of map.values()) { + result += value; + } + return result; +} + +export async function generateScanProbelemStatisticsReport( + statisticsReportInPutInfo: StatisticsReportInPutInfo +): Promise { + const canBeAutoFixedproblemNumbers = getMapValueSum(statisticsReportInPutInfo.ruleToAutoFixedNumbersMap); + const problemNumbers: ProblemNumbersInfo = { + totalProblemNumbers: statisticsReportInPutInfo.totalProblemNumbers, + arkOnePointOneProblemNumbers: statisticsReportInPutInfo.arkOnePointOneProblemNumbers, + arkOnePointTWOProblemNumbers: + statisticsReportInPutInfo.totalProblemNumbers - statisticsReportInPutInfo.arkOnePointOneProblemNumbers, + canBeAutoFixedproblemNumbers: canBeAutoFixedproblemNumbers, + needToManualFixproblemNumbers: statisticsReportInPutInfo.totalProblemNumbers - canBeAutoFixedproblemNumbers + }; + const projectFolderList = statisticsReportInPutInfo.cmdOptions.linterOptions.projectFolderList!; + const WorkLoadInfo = await getWorkLoadInfo(projectFolderList); + const statisticsReportData = getProblemStatisticsInfo( + problemNumbers, + statisticsReportInPutInfo.ruleToNumbersMap, + statisticsReportInPutInfo.ruleToAutoFixedNumbersMap, + statisticsReportInPutInfo.timeRecorder, + WorkLoadInfo + ); + await generateReportFile( + statisticsReportInPutInfo.statisticsReportName, + statisticsReportData, + statisticsReportInPutInfo.cmdOptions.outputFilePath + ); +} + +export function generateMigrationStatisicsReport( + lintResult: LintRunResult, + timeRecorder: TimeRecorder, + outputFilePath?: string +): void { + const ruleToNumbersMap: Map = new Map(); + const ruleToAutoFixedNumbersMap: Map = new Map(); + let arkOnePointOneProblemNumbers: number = 0; + + const problemsInfoAfterAutofixed = lintResult.problemsInfos; + for (const problems of problemsInfoAfterAutofixed.values()) { + accumulateRuleNumbers(problems, ruleToNumbersMap, ruleToAutoFixedNumbersMap); + arkOnePointOneProblemNumbers = arkOnePointOneProblemNumbers + getArktsOnePointOneProlemNumbers(problems); + } + + let totalProblemNumbers: number = 0; + for (const problems of problemsInfoAfterAutofixed.values()) { + totalProblemNumbers += problems.length; + } + + const canBeAutoFixedproblemNumbers = getMapValueSum(ruleToAutoFixedNumbersMap); + + const problemNumbers: ProblemNumbersInfo = { + totalProblemNumbers: totalProblemNumbers, + arkOnePointOneProblemNumbers: arkOnePointOneProblemNumbers, + arkOnePointTWOProblemNumbers: totalProblemNumbers - arkOnePointOneProblemNumbers, + canBeAutoFixedproblemNumbers: canBeAutoFixedproblemNumbers, + needToManualFixproblemNumbers: totalProblemNumbers - canBeAutoFixedproblemNumbers + }; + + const statisticsReportData = getProblemStatisticsInfo( + problemNumbers, + ruleToNumbersMap, + ruleToAutoFixedNumbersMap, + timeRecorder + ); + const statisticsReportName: string = 'migration-results-statistics.json'; + generateReportFileSync(statisticsReportName, statisticsReportData, outputFilePath); +} + +export async function getWorkLoadInfo(projectPathList: string[]): Promise { + const workloadInfo = new WorkLoadInfo(); + const projectResults = await Promise.all( + projectPathList.map(async(projectPath) => { + const normalizedPath = path.normalize(projectPath); + const [countFilesResults, countNapiFileResults] = await Promise.all([ + countFiles(normalizedPath), + countNapiFiles(normalizedPath) + ]); + + const getLines = (lang: keyof typeof countFilesResults): number => { + return countFilesResults[lang]?.lineCount || 0; + }; + + return { + normalizedPath, + arkTSCodeLines: getLines('ArkTS') + getLines('ArkTS Test'), + cAndCPPCodeLines: getLines('C/C++'), + napiCodeLines: countNapiFileResults.napiLines, + jsCodeLines: getLines('JavaScript'), + tsCodeLines: getLines('TypeScript'), + jsonCodeLines: getLines('JSON'), + xmlCodeLines: getLines('XML') + }; + }) + ); + + projectResults.forEach((result) => { + workloadInfo.addFloderResult(result); + }); + return workloadInfo; +} diff --git a/ets2panda/linter/src/lib/statistics/scan/ProblemStatisticsInfo.ts b/ets2panda/linter/src/lib/statistics/scan/ProblemStatisticsInfo.ts new file mode 100644 index 0000000000..8bbef29b16 --- /dev/null +++ b/ets2panda/linter/src/lib/statistics/scan/ProblemStatisticsInfo.ts @@ -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. + */ + +import type { RuleDetailedErrorInfo } from './RuleDetailedErrorInfo'; +import type { WorkLoadInfo } from './WorkLoadInfo'; + +export interface ProblemStatisticsInfo { + problems: { [k: string]: number }; + usedTime: { [k: string]: string }; + eachRuleProblemsDetail: RuleDetailedErrorInfo[]; + WorkLoadInfo?: WorkLoadInfo; +} diff --git a/ets2panda/linter/src/lib/statistics/scan/RuleDetailedErrorInfo.ts b/ets2panda/linter/src/lib/statistics/scan/RuleDetailedErrorInfo.ts new file mode 100644 index 0000000000..b4c56ee615 --- /dev/null +++ b/ets2panda/linter/src/lib/statistics/scan/RuleDetailedErrorInfo.ts @@ -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. + */ + +export interface RuleDetailedErrorInfo { + rule: string; + problemNumbers: number; + canBeAutoFixedMumbers: number; +} diff --git a/ets2panda/linter/src/lib/statistics/scan/ScanTaskRelatedInfo.ts b/ets2panda/linter/src/lib/statistics/scan/ScanTaskRelatedInfo.ts new file mode 100644 index 0000000000..6cc3f6dafd --- /dev/null +++ b/ets2panda/linter/src/lib/statistics/scan/ScanTaskRelatedInfo.ts @@ -0,0 +1,31 @@ +/* + * 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 type { CommandLineOptions } from '../../CommandLineOptions'; +import type { LinterConfig } from '../../LinterConfig'; +import type { ProblemInfo } from '../../ProblemInfo'; +import type { StatisticsReportInPutInfo } from './StatisticsReportInPutInfo'; +import type { TimeRecorder } from './TimeRecorder'; + +export interface ScanTaskRelatedInfo { + cmdOptions: CommandLineOptions; + timeRecorder: TimeRecorder; + statisticsReportInPutInfo: StatisticsReportInPutInfo; + mergedProblems: Map; + homeCheckResult: Map; + totalProblemNumbers: number; + statisticsReportName: number; + compileOptions: LinterConfig; +} diff --git a/ets2panda/linter/src/lib/statistics/scan/StatisticsReportInPutInfo.ts b/ets2panda/linter/src/lib/statistics/scan/StatisticsReportInPutInfo.ts new file mode 100644 index 0000000000..377f0843ff --- /dev/null +++ b/ets2panda/linter/src/lib/statistics/scan/StatisticsReportInPutInfo.ts @@ -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. + */ + +import type { CommandLineOptions } from '../../CommandLineOptions'; +import type { TimeRecorder } from './TimeRecorder'; + +export class StatisticsReportInPutInfo { + totalProblemNumbers: number = 0; + arkOnePointOneProblemNumbers: number = 0; + ruleToNumbersMap: Map = {} as Map; + ruleToAutoFixedNumbersMap: Map = {} as Map; + cmdOptions: CommandLineOptions = {} as CommandLineOptions; + timeRecorder: TimeRecorder = {} as TimeRecorder; + statisticsReportName: string = ''; +} diff --git a/ets2panda/linter/src/lib/statistics/scan/TimeRecorder.ts b/ets2panda/linter/src/lib/statistics/scan/TimeRecorder.ts new file mode 100644 index 0000000000..5f21944a81 --- /dev/null +++ b/ets2panda/linter/src/lib/statistics/scan/TimeRecorder.ts @@ -0,0 +1,54 @@ +/* + * 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 class TimeRecorder { + private lintStart = BigInt(0); + private lintEnd = BigInt(0); + private migrationStart = BigInt(0); + private migrationEnd = BigInt(0); + private isHomeCheckCount: boolean = false; + + setHomeCheckCountStatus(isHomeCheckCount: boolean): void { + this.isHomeCheckCount = isHomeCheckCount; + } + + getHomeCheckCountStatus(): boolean { + return this.isHomeCheckCount; + } + + startScan(): void { + this.lintStart = process.hrtime.bigint(); + } + + endScan(): void { + this.lintEnd = process.hrtime.bigint(); + } + + startMigration(): void { + this.migrationStart = process.hrtime.bigint(); + } + + endMigration(): void { + this.migrationEnd = process.hrtime.bigint(); + } + + getScanTime(): string { + return `${(Number(this.lintEnd - this.lintStart) / 1000000000).toFixed(2)} s`; + } + + getMigrationTime(): string { + return `${(Number(this.migrationEnd - this.migrationStart) / 1000000000).toFixed(2)} s`; + } +} diff --git a/ets2panda/linter/src/lib/statistics/scan/WorkLoadInfo.ts b/ets2panda/linter/src/lib/statistics/scan/WorkLoadInfo.ts new file mode 100644 index 0000000000..59135b1db2 --- /dev/null +++ b/ets2panda/linter/src/lib/statistics/scan/WorkLoadInfo.ts @@ -0,0 +1,59 @@ +/* + * 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 { + AVERAGE_LINE_FOR_REPAIRE_RULE_COEFFICIENT, + NPAI_REPAIRE_WORKLOADA_COEFFICIEN, + TEST_DEBUG_WORKLOAD_COEFFICIENT +} from '../../utils/consts/WorkloadRelatedConst'; +import type { FloderScanResultInfo } from './FloderScanResultInfo'; +import type { ProblemNumbersInfo } from './ProblemNumbersInfo'; + +export class WorkLoadInfo { + scanFilePathList: string[] = []; + totalArkTSCodeLines = 0; + totalCAndCPPCodeLines = 0; + totalNapiCodeLines = 0; + totalJsCodeLines = 0; + totalTsCodeLines = 0; + totalJsonCodeLines = 0; + totalXmlCodeLines = 0; + + addFloderResult(result: FloderScanResultInfo): void { + this.scanFilePathList.push(result.normalizedPath); + this.totalArkTSCodeLines += result.arkTSCodeLines; + this.totalCAndCPPCodeLines += result.cAndCPPCodeLines; + this.totalNapiCodeLines += result.napiCodeLines; + this.totalJsCodeLines += result.jsCodeLines; + this.totalTsCodeLines += result.tsCodeLines; + this.totalJsonCodeLines += result.jsonCodeLines; + this.totalXmlCodeLines += result.xmlCodeLines; + } + + calculateFixRate(problemNumbers: ProblemNumbersInfo): string { + const totalLines = this.totalArkTSCodeLines + this.totalCAndCPPCodeLines; + if (totalLines <= 0) { + return '0.00%'; + } + + const problemCount = problemNumbers.needToManualFixproblemNumbers; + const ratio = + (problemCount * AVERAGE_LINE_FOR_REPAIRE_RULE_COEFFICIENT * TEST_DEBUG_WORKLOAD_COEFFICIENT + + this.totalNapiCodeLines * NPAI_REPAIRE_WORKLOADA_COEFFICIEN) / + totalLines; + + return `${(ratio * 100).toFixed(2)}%`; + } +} diff --git a/ets2panda/linter/src/lib/utils/consts/MapKeyConst.ts b/ets2panda/linter/src/lib/utils/consts/MapKeyConst.ts new file mode 100644 index 0000000000..e5689d3f2a --- /dev/null +++ b/ets2panda/linter/src/lib/utils/consts/MapKeyConst.ts @@ -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. + */ + +export const TOTAL_PROBLEMS = 'totalProblems'; + +export const ONE_POINT_ONE_PROBLEMS = 'arts1.1_Problems'; + +export const ONE_POINT_TWO_PROBLEMS = 'arts1.2_Problems'; + +export const CAN_BE_AUTO_FIXED_PROBLEMS_NUMBERS = 'canBeAutoFixedproblemNumbers'; + +export const NEED_TO_NAMUAL_FIX_PROBLEM_NUMBERS = 'needToManualFixproblemNumbers'; + +export const SCAN_TIME = 'scanTime'; + +export const MIGRATION_TIME = 'migrationTime'; diff --git a/ets2panda/linter/src/lib/utils/consts/WorkloadRelatedConst.ts b/ets2panda/linter/src/lib/utils/consts/WorkloadRelatedConst.ts new file mode 100644 index 0000000000..c0c5efc0cc --- /dev/null +++ b/ets2panda/linter/src/lib/utils/consts/WorkloadRelatedConst.ts @@ -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. + */ + +export const AVERAGE_LINE_FOR_REPAIRE_RULE_COEFFICIENT = 3; + +export const TEST_DEBUG_WORKLOAD_COEFFICIENT = 1.2; + +export const NPAI_REPAIRE_WORKLOADA_COEFFICIEN = 0.2; \ No newline at end of file diff --git a/ets2panda/linter/src/testRunner/LintTest.ts b/ets2panda/linter/src/testRunner/LintTest.ts index 02db53dd49..8661ed7c74 100644 --- a/ets2panda/linter/src/testRunner/LintTest.ts +++ b/ets2panda/linter/src/testRunner/LintTest.ts @@ -15,20 +15,21 @@ import * as fs from 'node:fs'; import * as path from 'node:path'; +import type { Autofix } from '../lib/autofixes/Autofixer'; import type { CommandLineOptions } from '../lib/CommandLineOptions'; import type { LinterConfig } from '../lib/LinterConfig'; import { lint } from '../lib/LinterRunner'; +import type { LintRunResult } from '../lib/LintRunResult'; import { Logger } from '../lib/Logger'; +import { TimeRecorder } from '../lib/statistics/scan/TimeRecorder'; import { compileLintOptions } from '../lib/ts-compiler/Compiler'; +import { DIFF_EXT, RESULTS_DIR, TAB } from './Consts'; +import type { CreateLintTestOptions } from './TestFactory'; import type { TestModeProperties } from './TestMode'; import { TestMode } from './TestMode'; -import { transformProblemInfos } from './TestUtil'; import type { TestProblemInfo, TestResult } from './TestResult'; import { validateTestResult } from './TestResult'; -import type { LintRunResult } from '../lib/LintRunResult'; -import { DIFF_EXT, RESULTS_DIR, TAB } from './Consts'; -import type { Autofix } from '../lib/autofixes/Autofixer'; -import type { CreateLintTestOptions } from './TestFactory'; +import { transformProblemInfos } from './TestUtil'; export class LintTest { readonly testDir: string; @@ -47,7 +48,8 @@ export class LintTest { Logger.info(`Running test ${this.testFile} (${TestMode[this.testModeProps.mode]} mode)`); const linterConfig = this.compile(); - const linterResult = lint(linterConfig); + const timeRecorder = new TimeRecorder(); + const linterResult = lint(linterConfig, timeRecorder); return this.validate(linterResult); } -- Gitee From 114673b5708db521a42d413644893204a552df13 Mon Sep 17 00:00:00 2001 From: ohhusenlin Date: Sat, 21 Jun 2025 20:39:53 +0800 Subject: [PATCH 03/16] ArkTS rule can be configed by user Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICGV8G Signed-off-by: ohhusenlin --- ets2panda/linter/src/cli/CommandLineParser.ts | 3 + .../linter/src/lib/BaseTypeScriptLinter.ts | 52 ++++++++------ .../linter/src/lib/CommandLineOptions.ts | 1 + .../src/lib/utils/consts/ArkTS2Rules.ts | 14 +++- .../utils/functions/ConfiguredRulesProcess.ts | 68 +++++++++++++++++++ .../src/lib/utils/functions/CookBookUtils.ts | 35 ++++++++++ 6 files changed, 152 insertions(+), 21 deletions(-) create mode 100644 ets2panda/linter/src/lib/utils/functions/ConfiguredRulesProcess.ts create mode 100644 ets2panda/linter/src/lib/utils/functions/CookBookUtils.ts diff --git a/ets2panda/linter/src/cli/CommandLineParser.ts b/ets2panda/linter/src/cli/CommandLineParser.ts index 2dd88d03d3..f0bad7f69f 100644 --- a/ets2panda/linter/src/cli/CommandLineParser.ts +++ b/ets2panda/linter/src/cli/CommandLineParser.ts @@ -19,8 +19,11 @@ import * as fs from 'node:fs'; import * as path from 'node:path'; import * as ts from 'typescript'; import type { CommandLineOptions } from '../lib/CommandLineOptions'; +import { cookBookTag } from '../lib/CookBookMsg'; import { Logger } from '../lib/Logger'; import { ARKTS_IGNORE_DIRS_OH_MODULES } from '../lib/utils/consts/ArktsIgnorePaths'; +import { getConfiguredRuleTags, getRulesFromConfig } from '../lib/utils/functions/ConfiguredRulesProcess'; +import { extractRuleTags } from '../lib/utils/functions/CookBookUtils'; import { logTscDiagnostic } from '../lib/utils/functions/LogTscDiagnostic'; const TS_EXT = '.ts'; diff --git a/ets2panda/linter/src/lib/BaseTypeScriptLinter.ts b/ets2panda/linter/src/lib/BaseTypeScriptLinter.ts index b756543ab9..cb711335e4 100644 --- a/ets2panda/linter/src/lib/BaseTypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/BaseTypeScriptLinter.ts @@ -76,13 +76,31 @@ export abstract class BaseTypeScriptLinter { autofix?: Autofix[], errorMsg?: string ): void { + const badNodeInfo = this.getbadNodeInfo(node, faultId, autofix, errorMsg); + + if (this.shouldSkipRule(badNodeInfo)) { + return; + } + + this.problemsInfos.push(badNodeInfo); + this.updateFileStats(faultId, badNodeInfo.line); + // problems with autofixes might be collected separately + if (this.options.reportAutofixCb && badNodeInfo.autofix) { + this.options.reportAutofixCb(badNodeInfo); + } + } + + private getbadNodeInfo( + node: ts.Node | ts.CommentRange, + faultId: number, + autofix?: Autofix[], + errorMsg?: string + ): ProblemInfo { const [startOffset, endOffset] = TsUtils.getHighlightRange(node, faultId); const startPos = this.sourceFile.getLineAndCharacterOfPosition(startOffset); const endPos = this.sourceFile.getLineAndCharacterOfPosition(endOffset); - const faultDescr = faultDesc[faultId]; const faultType = TypeScriptLinterConfig.tsSyntaxKindNames[node.kind]; - const cookBookMsgNum = faultsAttrs[faultId] ? faultsAttrs[faultId].cookBookRef : 0; const cookBookTg = errorMsg ? errorMsg : cookBookTag[cookBookMsgNum]; const severity = faultsAttrs[faultId]?.severity ?? ProblemSeverity.ERROR; @@ -107,17 +125,7 @@ export abstract class BaseTypeScriptLinter { autofix: autofix, autofixTitle: isMsgNumValid && autofix !== undefined ? cookBookRefToFixTitle.get(cookBookMsgNum) : undefined }; - - if (this.options?.ideInteractive && this.isSkipedRecordProblems(badNodeInfo)) { - return; - } - - this.problemsInfos.push(badNodeInfo); - this.updateFileStats(faultId, badNodeInfo.line); - // problems with autofixes might be collected separately - if (this.options.reportAutofixCb && badNodeInfo.autofix) { - this.options.reportAutofixCb(badNodeInfo); - } + return badNodeInfo; } private static processAutofix( @@ -128,17 +136,21 @@ export abstract class BaseTypeScriptLinter { return autofix ? BaseTypeScriptLinter.addLineColumnInfoInAutofix(autofix, startPos, endPos) : autofix; } - private isSkipedRecordProblems(badNodeInfo: ProblemInfo): boolean { - if (this.options.onlySyntax) { - if (onlyArkts2SyntaxRules.has(badNodeInfo.ruleTag)) { + private shouldSkipRule(badNodeInfo: ProblemInfo): boolean { + const ruleConfigTags = this.options.ruleConfigTags; + if (ruleConfigTags && !ruleConfigTags.has(badNodeInfo.ruleTag)) { + return true; + } + if (this.options?.ideInteractive) { + if (this.options.onlySyntax) { + if (onlyArkts2SyntaxRules.has(badNodeInfo.ruleTag)) { return false; } - } else { - if (this.options.arkts2 - && arkts2Rules.includes(badNodeInfo.ruleTag)) { + } else if (this.options.arkts2 && arkts2Rules.includes(badNodeInfo.ruleTag)) { return false; } + return true; } - return true; + return false; } } diff --git a/ets2panda/linter/src/lib/CommandLineOptions.ts b/ets2panda/linter/src/lib/CommandLineOptions.ts index d793e62044..d1fffdfd15 100644 --- a/ets2panda/linter/src/lib/CommandLineOptions.ts +++ b/ets2panda/linter/src/lib/CommandLineOptions.ts @@ -33,4 +33,5 @@ export interface CommandLineOptions { outputFilePath?: string; verbose?: boolean; scanWholeProjectInHomecheck?: boolean; + ruleConfig?: string; } diff --git a/ets2panda/linter/src/lib/utils/consts/ArkTS2Rules.ts b/ets2panda/linter/src/lib/utils/consts/ArkTS2Rules.ts index ea727f914a..e78c1006f1 100644 --- a/ets2panda/linter/src/lib/utils/consts/ArkTS2Rules.ts +++ b/ets2panda/linter/src/lib/utils/consts/ArkTS2Rules.ts @@ -192,5 +192,17 @@ export const onlyArkts2SyntaxRules: Map = new Map([ [255, 'arkts-no-extends-expression'], [300, 'arkts-no-ts-like-function-call'], [301, 'arkts-ohmurl-full-path'], - [304, 'arkts-no-duplicate-function-name'] + [304, 'arkts-no-duplicate-function-name'], + [319, 'arkts-method-inherit-rule'], + [325, 'arkts-default-args-behind-required-args'], + [329, 'arkts-unsupport-prop-name-from-value'], + [370, 'arkts-no-sparse-array'], + [371, 'arkts-no-enum-prop-as-type'], + [372, 'arkts-no-ts-like-smart-type'], + [373, 'arkts-array-type-immutable'], + [374, 'arkts-primitive-type-normalization'], + [375, 'arkts-no-ts-like-catch-type'], + [376, 'arkts-numeric-bigint-compare'], + [377, 'arkts-only-support-decimal-bigint-literal'], + [378, 'arkts-unsupport-operator'] ]); diff --git a/ets2panda/linter/src/lib/utils/functions/ConfiguredRulesProcess.ts b/ets2panda/linter/src/lib/utils/functions/ConfiguredRulesProcess.ts new file mode 100644 index 0000000000..99e6c5da6f --- /dev/null +++ b/ets2panda/linter/src/lib/utils/functions/ConfiguredRulesProcess.ts @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2023-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. + */ +import * as fs from 'node:fs'; +import * as path from 'node:path'; + +export function getConfiguredRuleTags( + arkTSRulesMap: Map, + configuredRulesMap: Map +): Set { + const mergedRulesMap: string[] = Array.from(configuredRulesMap.values()).flat(); + const configuredRuleTags = new Set(); + const mergedRulesSet = new Set(mergedRulesMap); + arkTSRulesMap.forEach((key, value) => { + if (mergedRulesSet.has(key)) { + configuredRuleTags.add(value); + } + }); + return configuredRuleTags; +} + +export function getRulesFromConfig(configRulePath: string): Map { + try { + const normalizedPath = path.normalize(configRulePath); + const data = fs.readFileSync(normalizedPath, 'utf-8'); + const jsonData = JSON.parse(data); + const dataMap = new Map(); + for (const [key, value] of Object.entries(jsonData)) { + dataMap.set(key, value); + } + return convertToStringArrayMap(dataMap); + } catch (error) { + if (error instanceof SyntaxError) { + throw new Error(`JSON parsing failed: ${error.message}`); + } + return new Map(); + } +} + +function convertToStringArrayMap(inputMap: Map): Map { + const resultMap: Map = new Map(); + for (const [key, value] of inputMap) { + if (isStringArray(value)) { + resultMap.set(key, value); + } + } + return resultMap; +} + +function isStringArray(value: any): value is string[] { + return ( + Array.isArray(value) && + value.every((item) => { + return typeof item === 'string'; + }) + ); +} diff --git a/ets2panda/linter/src/lib/utils/functions/CookBookUtils.ts b/ets2panda/linter/src/lib/utils/functions/CookBookUtils.ts new file mode 100644 index 0000000000..0f2bec5ade --- /dev/null +++ b/ets2panda/linter/src/lib/utils/functions/CookBookUtils.ts @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022-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. + */ + +export function extractRuleTags(tags: string[]): Map { + const resultMap = new Map(); + + for (let i = 0; i < tags.length; i++) { + const tag = tags[i]; + + if (!tag?.trim()) { + continue; + } + + const regex = /\(([^)]+)\)/; + const match = tag.match(regex); + + if (match?.[1]?.trim()) { + resultMap.set(i, match[1]); + } + } + + return resultMap; +} -- Gitee From 820cf4696c0f1222dc85ea33d02ab098cea606b4 Mon Sep 17 00:00:00 2001 From: HuSenlin Date: Wed, 25 Jun 2025 10:48:49 +0800 Subject: [PATCH 04/16] Add default configure rule to the package Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICHRB0 Signed-off-by: HuSenlin --- ets2panda/linter/configure-rule.json | 248 ++++++++++++++++++ ets2panda/linter/package.json | 2 +- ets2panda/linter/src/cli/CommandLineParser.ts | 37 ++- .../linter/src/lib/BaseTypeScriptLinter.ts | 25 +- .../src/lib/utils/functions/CookBookUtils.ts | 3 +- 5 files changed, 282 insertions(+), 33 deletions(-) create mode 100644 ets2panda/linter/configure-rule.json diff --git a/ets2panda/linter/configure-rule.json b/ets2panda/linter/configure-rule.json new file mode 100644 index 0000000000..68fb3449e3 --- /dev/null +++ b/ets2panda/linter/configure-rule.json @@ -0,0 +1,248 @@ +{ + "ArkTS": [ + "arkts-identifiers-as-prop-names", + "arkts-no-symbol", + "arkts-no-private-identifiers", + "arkts-unique-names", + "arkts-no-var", + "arkts-no-any-unknown", + "arkts-no-call-signatures", + "arkts-no-ctor-signatures-type", + "arkts-no-multiple-static-blocks", + "arkts-no-indexed-signatures", + "arkts-no-intersection-types", + "arkts-no-typing-with-this", + "arkts-no-conditional-types", + "arkts-no-ctor-prop-decls", + "arkts-no-ctor-signatures-iface", + "arkts-no-aliases-by-index", + "arkts-no-props-by-index", + "arkts-no-structural-typing", + "arkts-no-inferred-generic-params", + "arkts-no-regexp-literals", + "arkts-no-untyped-obj-literals", + "arkts-no-obj-literals-as-types", + "arkts-no-noninferrable-arr-literals", + "arkts-no-func-expressions", + "arkts-no-class-literals", + "arkts-implements-only-iface", + "arkts-no-method-reassignment", + "arkts-as-casts", + "arkts-no-jsx", + "arkts-no-polymorphic-unops", + "arkts-no-delete", + "arkts-no-type-query", + "arkts-instanceof-ref-types", + "arkts-no-in", + "arkts-no-destruct-assignment", + "arkts-no-comma-outside-loops", + "arkts-no-destruct-decls", + "arkts-no-types-in-catch", + "arkts-no-for-in", + "arkts-no-mapped-types", + "arkts-no-with", + "arkts-limited-throw", + "arkts-no-implicit-return-types", + "arkts-no-destruct-params", + "arkts-no-nested-funcs", + "arkts-no-standalone-this", + "arkts-no-generators", + "arkts-no-is", + "arkts-no-spread", + "arkts-no-extend-same-prop", + "arkts-no-decl-merging", + "arkts-extends-only-class", + "arkts-no-ctor-signatures-funcs", + "arkts-no-enum-mixed-types", + "arkts-no-enum-merging", + "arkts-no-ns-as-obj", + "arkts-no-ns-statements", + "arkts-no-require", + "arkts-no-export-assignment", + "arkts-no-ambient-decls", + "arkts-no-module-wildcards", + "arkts-no-umd", + "arkts-no-new-target", + "arkts-no-definite-assignment", + "arkts-no-prototype-assignment", + "arkts-no-globalthis", + "arkts-no-utility-types", + "arkts-no-func-props", + "arkts-no-func-bind", + "arkts-no-as-const", + "arkts-no-import-assertions", + "arkts-strict-typing", + "arkts-strict-typing-required", + "arkts-no-ts-deps", + "arkts-no-classes-as-obj", + "arkts-no-misplaced-imports", + "arkts-limited-esobj", + "arkts-no-func-apply-call", + "arkts-sendable-class-inheritance", + "arkts-sendable-prop-types", + "arkts-sendable-definite-assignment", + "arkts-sendable-generic-types", + "arkts-sendable-imported-variables", + "arkts-sendable-class-decorator", + "arkts-sendable-obj-init", + "arkts-sendable-computed-prop-name", + "arkts-sendable-as-expr", + "arkts-no-side-effects-imports", + "arkts-shared-module-exports", + "arkts-shared-module-no-wildcard-export", + "arkts-no-ts-import-ets", + "arkts-no-ts-sendable-type-inheritance", + "arkts-no-dts-sendable-type-export", + "arkts-no-ts-re-export-ets", + "arkts-no-namespace-import-in-ts-import-ets", + "artkts-no-side-effect-import-in-ts-import-ets", + "arkts-sendable-explicit-field-type", + "arkts-sendable-function-imported-variables", + "arkts-sendable-function-decorator", + "arkts-sendable-typealias-decorator", + "arkts-sendable-typeAlias-declaration", + "arkts-sendable-function-assignment", + "arkts-sendable-function-overload-decorator", + "arkts-sendable-function-property", + "arkts-sendable-function-as-expr", + "arkts-sendable-decorator-limited", + "arkts-sendable-beta-compatible", + "arkts-obj-literal-props", + "arkts-optional-methods", + "arkts-import-types", + "arkts-no-dynamic-ctor-call", + "arkts-math-pow-standard-diff", + "arkts-numeric-semantic", + "arkts-incompatible-function-types", + "arkts-limited-void-type", + "arkts-no-void-operator", + "arkts-no-ts-overload", + "arkts-limited-literal-types", + "arkts-no-exponent-op", + "arkts-no-debugger", + "arkts-no-arguments-obj", + "arkts-no-tagged-templates", + "arkts-array-index-expr-type", + "arkts-switch-expr", + "arkts-case-expr", + "arkts-array-index-negative", + "arkts-class-lazy-import", + "arkts-obj-no-constructor", + "arkts-runtime-array-check", + "arkts-no-side-effect-import", + "arkts-no-lazy-import", + "arkts-no-dynamic-import", + "arkts-no-ts-decorators", + "arkts-common-union-member-access", + "arkts-no-method-overriding-field", + "arkts-no-tuples-arrays", + "arkts-class-static-initialization", + "arkts-invalid-identifier", + "arkts-no-extends-expression", + "arkts-no-ts-like-function-call", + "arkts-no-sparse-array", + "arkts-no-enum-prop-as-type", + "arkts-no-ts-like-smart-type", + "arkts-array-type-immutable", + "arkts-primitive-type-normalization", + "arkts-no-ts-like-catch-type", + "arkts-numeric-bigint-compare", + "arkts-only-support-decimal-bigint-literal", + "arkts-unsupport-operator", + "arkts-default-args-behind-required-args", + "arkts-enum-no-props-by-index", + "arkts-method-inherit-rule", + "arkts-limited-stdlib-no-setCloneList", + "arkts-limited-stdlib-no-setTransferList", + "arkts-limited-stdlib", + "arkts-subclass-must-call-super-constructor-with-args", + "arkts-no-duplicate-function-name" + ], + "interop": [ + "arkts-interop-js2s-inherit-js-class", + "arkts-interop-js2s-traverse-js-instance", + "arkts-interop-js2s-js-call-static-function", + "arkts-interop-js2s-condition-judgment", + "arkts-interop-js2s-js-expand-static-instance", + "arkts-interop-js2s-js-exception", + "arkts-interop-d2s-static-object-on-dynamic-instance", + "arkts-interop-d2s-static-reflect-on-dynamic-instance", + "arkts-interop-ts2s-static-access-ts-type", + "arkts-interop-ts2s-ts-exception", + "arkts-interop-js2s-export-js", + "arkts-interop-d2s-export-entity", + "arkts-interop-s2d-object-literal", + "arkts-interop-d2s-object-literal-no-ambiguity", + "arkts-interop-d2s-object-literal-no-args-constructor", + "arkts-interop-js2s-import-js", + "arkts-interop-js2s-call-js-func", + "arkts-interop-js2s-access-js-prop", + "arkts-interop-js2s-convert-js-type", + "arkts-interop-js2s-typeof-js-type", + "arkts-interop-js2s-unary-op", + "arkts-interop-js2s-binary-op", + "arkts-interop-js2s-compare-js-data", + "arkts-interop-js2s-equality-judgment", + "arkts-interop-js2s-access-js-index", + "arkts-interop-js2s-await-js-promise", + "arkts-interop-js2s-create-js-instance", + "arkts-interop-js2s-call-js-method", + "arkts-interop-js2s-instanceof-js-type", + "arkts-interop-js2s-self-addtion-reduction" + ], + "ArkUI": [ + "arkui-no-!!-bidirectional-data-binding", + "arkui-no-$$-bidirectional-data-binding", + "arkui-link-decorator-passing", + "arkui-no-extend-decorator", + "arkui-no-styles-decorator", + "arkui-animatableextend-use-receiver", + "arkui-data-observation", + "arkui-modular-interface", + "arkui-entry-annotation-parameters", + "arkui-no-makeobserved-function", + "arkui-provide-annotation-parameters", + "arkui-custom-layout-need-add-decorator", + "arkui-no-prop-decorator", + "arkui-no-storageprop-decorator", + "arkui-no-localstorageprop-decorator", + "arkui-no-prop-function", + "arkui-no-setandprop-function", + "arkui-prop-need-call-method-for-deep-copy", + "arkui-no-localbuilder-decorator", + "arkui-statestyles-block-need-arrow-func" + ], + "builtin": [ + "arkts-builtin-thisArgs", + "arkts-builtin-symbol-iterator", + "arkts-builtin-no-property-descriptor", + "arkts-builtin-cotr", + "arkts-builtin-object-getOwnPropertyNames" + ], + "OHMURL": [ + "arkts-ohmurl-full-path" + ], + "sdk": [ + "sdk-limited-void-type", + "sdk-optional-methods", + "sdk-no-sendable-prop-types", + "sdk-ctor-signatures-iface", + "sdk-no-props-by-index", + "sdk-constructor-funcs", + "sdk-no-literal-as-property-name", + "sdk-no-decl-with-duplicate-name", + "sdk-type-query" + ], + "concurrent": [ + "arkts-limited-stdlib-no-sendable-decorator", + "arkts-limited-stdlib-no-concurrent-decorator", + "arkts-no-need-stdlib-worker", + "arkts-limited-stdlib-no-use-shared", + "arkts-limited-stdlib-no-use-concurrent", + "arkts-no-need-stdlib-sendable-containers", + "arkts-no-need-stdlib-ason", + "arkts-no-need-stdlib-sharedArrayBuffer", + "arkts-limited-stdlib-no-support-isConcurrent", + "arkts-limited-stdlib-no-import-concurrency" + ] +} \ No newline at end of file diff --git a/ets2panda/linter/package.json b/ets2panda/linter/package.json index 1dcc5f8e14..349629e7fc 100644 --- a/ets2panda/linter/package.json +++ b/ets2panda/linter/package.json @@ -4,7 +4,7 @@ "main": "dist/tslinter.js", "bin": "bin/tslinter.js", "files": [ - "dist/*" + "dist/*","configure-rule.json" ], "private": true, "license": "Apache-2.0", diff --git a/ets2panda/linter/src/cli/CommandLineParser.ts b/ets2panda/linter/src/cli/CommandLineParser.ts index f0bad7f69f..b039c332d4 100644 --- a/ets2panda/linter/src/cli/CommandLineParser.ts +++ b/ets2panda/linter/src/cli/CommandLineParser.ts @@ -206,15 +206,25 @@ function formCommandLineOptions(parsedCmd: ParsedCommand): CommandLineOptions { } function processRuleConfig(commandLineOptions: CommandLineOptions, options: OptionValues): void { - if (options.ruleConfig !== undefined) { - const stats = fs.statSync(path.normalize(options.ruleConfig)); - if (!stats.isFile()) { - console.error(`The file at ${options.ruleConfig} path does not exist!`); + const configureRulePath = getConfigureRulePath(options); + const configuredRulesMap = getRulesFromConfig(configureRulePath); + const arkTSRulesMap = extractRuleTags(cookBookTag); + commandLineOptions.linterOptions.ruleConfigTags = getConfiguredRuleTags(arkTSRulesMap, configuredRulesMap); +} + +function getConfigureRulePath(options: OptionValues) : string { + const defaultConfigureRule = path.join('configure-rule.json'); + if (options.ruleConfig !== undefined) { + const stats = fs.statSync(path.normalize(options.ruleConfig)); + if (!stats.isFile()) { + console.error(`The file at ${options.ruleConfig} path does not exist! + And will use the default configure rule: ${defaultConfigureRule}`); + return defaultConfigureRule; + } else { + return options.ruleConfig; + } } else { - const configuredRulesMap = getRulesFromConfig(options.ruleConfig); - const arkTSRulesMap = extractRuleTags(cookBookTag); - commandLineOptions.linterOptions.ruleConfigTags = getConfiguredRuleTags(arkTSRulesMap, configuredRulesMap); - } + return defaultConfigureRule; } } @@ -238,6 +248,7 @@ function getAutofixConfigureRulePath(options: OptionValues) : string { } } + function createCommand(): Command { const program = new Command(); program. @@ -320,11 +331,11 @@ function processResponseFiles(parsedCmd: ParsedCommand): void { const rspFiles = parsedCmd.args.responseFiles; for (const rspFile of rspFiles) { try { - const rspArgs = fs. - readFileSync(rspFile). - toString(). - split('\n'). - filter((e) => { + const rspArgs = fs + .readFileSync(rspFile) + .toString() + .split('\n') + .filter((e) => { return e.trimEnd(); }); const cmdArgs = ['dummy', 'dummy']; diff --git a/ets2panda/linter/src/lib/BaseTypeScriptLinter.ts b/ets2panda/linter/src/lib/BaseTypeScriptLinter.ts index cb711335e4..fbfd9b71a1 100644 --- a/ets2panda/linter/src/lib/BaseTypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/BaseTypeScriptLinter.ts @@ -14,19 +14,18 @@ */ import type * as ts from 'typescript'; -import type { LinterOptions } from './LinterOptions'; -import type { ProblemInfo } from './ProblemInfo'; import type { Autofix } from './autofixes/Autofixer'; -import { FileStatistics } from './statistics/FileStatistics'; -import { TsUtils } from './utils/TsUtils'; import { cookBookRefToFixTitle } from './autofixes/AutofixTitles'; -import { faultDesc } from './FaultDesc'; -import { TypeScriptLinterConfig } from './TypeScriptLinterConfig'; -import { faultsAttrs } from './FaultAttrs'; import { cookBookTag } from './CookBookMsg'; +import { faultsAttrs } from './FaultAttrs'; +import { faultDesc } from './FaultDesc'; +import type { LinterOptions } from './LinterOptions'; +import type { ProblemInfo } from './ProblemInfo'; import { FaultID } from './Problems'; import { ProblemSeverity } from './ProblemSeverity'; -import { arkts2Rules, onlyArkts2SyntaxRules } from './utils/consts/ArkTS2Rules'; +import { FileStatistics } from './statistics/FileStatistics'; +import { TypeScriptLinterConfig } from './TypeScriptLinterConfig'; +import { TsUtils } from './utils/TsUtils'; export abstract class BaseTypeScriptLinter { problemsInfos: ProblemInfo[] = []; @@ -141,16 +140,6 @@ export abstract class BaseTypeScriptLinter { if (ruleConfigTags && !ruleConfigTags.has(badNodeInfo.ruleTag)) { return true; } - if (this.options?.ideInteractive) { - if (this.options.onlySyntax) { - if (onlyArkts2SyntaxRules.has(badNodeInfo.ruleTag)) { - return false; - } - } else if (this.options.arkts2 && arkts2Rules.includes(badNodeInfo.ruleTag)) { - return false; - } - return true; - } return false; } } diff --git a/ets2panda/linter/src/lib/utils/functions/CookBookUtils.ts b/ets2panda/linter/src/lib/utils/functions/CookBookUtils.ts index 0f2bec5ade..b9a9c7e15d 100644 --- a/ets2panda/linter/src/lib/utils/functions/CookBookUtils.ts +++ b/ets2panda/linter/src/lib/utils/functions/CookBookUtils.ts @@ -23,7 +23,8 @@ export function extractRuleTags(tags: string[]): Map { continue; } - const regex = /\(([^)]+)\)/; + // Match content of the last () + const regex = /.*\(([^)]+)\)[^(]*$/; const match = tag.match(regex); if (match?.[1]?.trim()) { -- Gitee From 91011849eaf35f84f0cc4443dea439844f2b399c Mon Sep 17 00:00:00 2001 From: xudan16 Date: Tue, 24 Jun 2025 10:44:35 +0800 Subject: [PATCH 05/16] homecheck update and bug fix Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICHBM2 Signed-off-by: xudan16 --- .../InteropDeprecatedBuiltInAPICheck.ts | 72 ++++++++++++------- .../InteropDynamicObjectLiteralsCheck.ts | 66 ++++++++--------- .../src/checker/migration/NoTSLikeAsCheck.ts | 2 +- .../checker/migration/ObjectLiteralCheck.ts | 23 +++--- .../homecheck/src/utils/common/CheckEntry.ts | 8 ++- 5 files changed, 93 insertions(+), 78 deletions(-) diff --git a/ets2panda/linter/homecheck/src/checker/migration/InteropDeprecatedBuiltInAPICheck.ts b/ets2panda/linter/homecheck/src/checker/migration/InteropDeprecatedBuiltInAPICheck.ts index fad6267bde..02b2b9170d 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/InteropDeprecatedBuiltInAPICheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/InteropDeprecatedBuiltInAPICheck.ts @@ -59,7 +59,7 @@ import { WarnInfo } from '../../utils/common/Utils'; import { ArkClass } from 'arkanalyzer/lib/core/model/ArkClass'; import { Language } from 'arkanalyzer/lib/core/model/ArkFile'; import { MethodParameter } from 'arkanalyzer/lib/core/model/builder/ArkMethodBuilder'; -import { AbstractFieldRef } from 'arkanalyzer'; +import { AbstractFieldRef, ArkReturnStmt } from 'arkanalyzer'; const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'DeprecatedBuiltInAPICheck'); const gMetaData: BaseMetaData = { @@ -427,7 +427,7 @@ export class InteropDeprecatedBuiltInAPICheck implements BaseChecker { let checkAll = { value: true }; let visited: Set = new Set(); if (this.checkFromStmt(checkStmt, globalVarMap, checkAll, visited)) { - this.addIssueReport(stmt, targetLocal); + this.addIssueReport(stmt, targetLocal, checkAll.value); } } } @@ -654,6 +654,10 @@ export class InteropDeprecatedBuiltInAPICheck implements BaseChecker { if (api.name !== callApiName) { continue; } + // 对于for...of的语句,ArkAnalyzer会为其生成Symbol.iterator的调用语句,此处从源码中查找关键字以区分是源码中有还是自动生成的 + if (api.name === 'Symbol.iterator' && !stmt.getOriginalText()?.includes('Symbol.iterator')) { + continue; + } if (api.isStatic) { continue; } @@ -662,7 +666,7 @@ export class InteropDeprecatedBuiltInAPICheck implements BaseChecker { } // Array concat API ArkAnalyzer当前无法很好处理...items形式的入参,此处作为特例处理 - if (api.name === 'concat') { + if (api.name === 'concat' && api.base === APIBaseCategory.Array) { return this.isMatchArrayConcatAPI(args); } @@ -670,18 +674,7 @@ export class InteropDeprecatedBuiltInAPICheck implements BaseChecker { if (apiParams === undefined) { return true; } - let allParamTypeMatch = true; - if (apiParams.length !== callApiParams.length) { - allParamTypeMatch = false; - } else { - for (let i = 0; i < apiParams.length; i++) { - if (!this.isTypeMatch(apiParams[i], callApiParams[i].getType())) { - allParamTypeMatch = false; - break; - } - } - } - + let allParamTypeMatch = this.compareParamTypes(apiParams, callApiParams); if (allParamTypeMatch) { // 形参匹配的情况下,进一步比较传入的实参,因为当前废弃接口大多数为去掉any类型的第二个可选参数 // TODO:这里需要考虑如何做的更通用 @@ -733,7 +726,10 @@ export class InteropDeprecatedBuiltInAPICheck implements BaseChecker { if (apiMatch === null || callApiMatch === null) { return false; } - return apiMatch[0] === callApiMatch[0]; + // 移除字符串中的类型的文件签名、类签名、泛型等信息后进行比较 + let apiParamsStr = apiMatch[0].replace(/@[^:]+:/, '').replace(/<[^>]+>/, ''); + let callApiParamsStr = callApiMatch[0].replace(/@[^:]+:/, '').replace(/<[^>]+>/, ''); + return apiParamsStr === callApiParamsStr; } else if (callApiType instanceof ClassType && apiType instanceof ClassType) { // 若类型为FunctionType,仅需匹配class name,因为apiTypeStr类型推导后有可能为@%unk/%unk: ArrayLike,而callApiTypeStr有明确的declaring file return callApiType.getClassSignature().getClassName() === apiType.getClassSignature().getClassName(); @@ -763,7 +759,7 @@ export class InteropDeprecatedBuiltInAPICheck implements BaseChecker { private checkFromStmt(stmt: Stmt, globalVarMap: Map, checkAll: { value: boolean }, visited: Set, depth: number = 0): boolean { if (depth > CALL_DEPTH_LIMIT) { checkAll.value = false; - return false; + return true; } const node = this.dvfg.getOrNewDVFGNode(stmt); let worklist: DVFGNode[] = [node]; @@ -775,10 +771,11 @@ export class InteropDeprecatedBuiltInAPICheck implements BaseChecker { } visited.add(currentStmt); - if (this.isLeftOpDefinedInStaticArkTS(currentStmt)) { + if (this.isLeftOpOrReturnOpDefinedInStaticArkTS(currentStmt)) { return true; } + // 当前语句的右值是全局变量,查找全局变量的定义语句 const gv = this.isRightOpGlobalVar(currentStmt); if (gv) { const globalDefs = globalVarMap.get(gv.getName()); @@ -794,6 +791,7 @@ export class InteropDeprecatedBuiltInAPICheck implements BaseChecker { continue; } + // 当前语句的右值是函数返回值,查找调用函数的所有return语句 const callsite = this.cg.getCallSiteByStmt(currentStmt); for (const cs of callsite) { const declaringMtd = this.cg.getArkMethodByFuncID(cs.calleeFuncID); @@ -812,6 +810,8 @@ export class InteropDeprecatedBuiltInAPICheck implements BaseChecker { } } } + + // 当前语句的右值是函数参数赋值语句,查找所有调用处的入参情况 const paramRef = this.isFromParameter(currentStmt); if (paramRef) { const paramIdx = paramRef.getIndex(); @@ -826,6 +826,7 @@ export class InteropDeprecatedBuiltInAPICheck implements BaseChecker { } } + // 当前语句的右值是属性赋值语句,查找该属性的初始化语句 if (currentStmt instanceof ArkAssignStmt && currentStmt.getRightOp() instanceof AbstractFieldRef) { const fieldSignature = (currentStmt.getRightOp() as AbstractFieldRef).getFieldSignature(); const classSignature = fieldSignature.getDeclaringSignature(); @@ -836,6 +837,19 @@ export class InteropDeprecatedBuiltInAPICheck implements BaseChecker { } } } + + // 当前语句是return语句,查找return操作数的相关语句 + if (currentStmt instanceof ArkReturnStmt) { + const returnOp = currentStmt.getOp(); + if (returnOp instanceof Local) { + let checkStmt = + this.getLastAssignStmt(returnOp, stmt) ?? + this.checkTargetLocalAsGlobal(currentStmt.getCfg().getDeclaringMethod(), stmt, returnOp, globalVarMap); + if (checkStmt !== null) { + worklist.push(this.dvfg.getOrNewDVFGNode(checkStmt)); + } + } + } current.getIncomingEdge().forEach(e => worklist.push(e.getSrcNode() as DVFGNode)); } return false; @@ -882,15 +896,20 @@ export class InteropDeprecatedBuiltInAPICheck implements BaseChecker { } // 判断语句是否为赋值语句,且左值的定义来自于ArkTS1.2 - private isLeftOpDefinedInStaticArkTS(stmt: Stmt): boolean { - if (!(stmt instanceof ArkAssignStmt)) { + private isLeftOpOrReturnOpDefinedInStaticArkTS(stmt: Stmt): boolean { + if (!(stmt instanceof ArkAssignStmt) && !(stmt instanceof ArkReturnStmt)) { return false; } - const leftOp = stmt.getLeftOp(); - if (!(leftOp instanceof Local)) { + let operand: Value; + if (stmt instanceof ArkAssignStmt) { + operand = stmt.getLeftOp(); + } else { + operand = stmt.getOp(); + } + if (!(operand instanceof Local)) { return false; } - return this.isLocalDefinedInStaticArkTS(leftOp); + return this.isLocalDefinedInStaticArkTS(operand); } private isFromParameter(stmt: Stmt): ArkParameterRef | undefined { @@ -927,11 +946,14 @@ export class InteropDeprecatedBuiltInAPICheck implements BaseChecker { }); } - private addIssueReport(stmt: Stmt, operand: Value): void { + private addIssueReport(stmt: Stmt, operand: Value, checkAll: boolean = true): void { const severity = this.rule.alert ?? this.metaData.severity; const warnInfo = this.getLineAndColumn(stmt, operand); const problem = 'builtin-api'; - const desc = `Builtin API is not support in ArkTS1.2 (${this.rule.ruleId.replace('@migration/', '')})`; + let desc = `Builtin API is not support in ArkTS1.2 (${this.rule.ruleId.replace('@migration/', '')})`; + if (!checkAll) { + desc = `Can not check when function call chain depth exceeds ${CALL_DEPTH_LIMIT}, please check it manually (${this.rule.ruleId.replace('@migration/', '')})`; + } let defects = new Defects( warnInfo.line, diff --git a/ets2panda/linter/homecheck/src/checker/migration/InteropDynamicObjectLiteralsCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/InteropDynamicObjectLiteralsCheck.ts index 3b59046d94..9d93f7f9c6 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/InteropDynamicObjectLiteralsCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/InteropDynamicObjectLiteralsCheck.ts @@ -110,12 +110,11 @@ export class InteropObjectLiteralCheck implements BaseChecker { this.visited.add(target); } - let result: Stmt[] = []; let checkAll = { value: true }; let visited: Set = new Set(); - this.checkFromStmt(stmt, scene, result, checkAll, visited); + // 对于待检查的instanceof语句,其检查对象存在用字面量赋值的情况,需要判断对象声明时的类型注解的来源,满足interop场景时需在此处告警 - if (result.length > 0) { + if (this.checkFromStmt(stmt, scene, checkAll, visited)) { const opType = rightOp.getOp().getType(); if (!(opType instanceof ClassType)) { continue; @@ -124,27 +123,17 @@ export class InteropObjectLiteralCheck implements BaseChecker { if (opTypeClass === null || opTypeClass.getCategory() === ClassCategory.OBJECT) { continue; } - if ( - opTypeClass.getLanguage() === Language.TYPESCRIPT || - opTypeClass.getLanguage() === Language.ARKTS1_1 - ) { - this.addIssueReport(stmt, rightOp, result, opTypeClass.getLanguage()); + if (opTypeClass.getLanguage() === Language.TYPESCRIPT || opTypeClass.getLanguage() === Language.ARKTS1_1) { + this.addIssueReport(stmt, rightOp, opTypeClass.getLanguage(), checkAll.value); } } } } - private checkFromStmt( - stmt: Stmt, - scene: Scene, - res: Stmt[], - checkAll: { value: boolean }, - visited: Set, - depth: number = 0 - ): void { + private checkFromStmt(stmt: Stmt, scene: Scene, checkAll: { value: boolean }, visited: Set, depth: number = 0): boolean { if (depth > CALL_DEPTH_LIMIT) { checkAll.value = false; - return; + return true; } const node = this.dvfg.getOrNewDVFGNode(stmt); let worklist: DVFGNode[] = [node]; @@ -156,36 +145,42 @@ export class InteropObjectLiteralCheck implements BaseChecker { } visited.add(currentStmt); if (this.isObjectLiteral(currentStmt, scene)) { - res.push(currentStmt); - continue; + return true; } const callsite = this.cg.getCallSiteByStmt(currentStmt); - callsite.forEach(cs => { + for (const cs of callsite) { const declaringMtd = this.cg.getArkMethodByFuncID(cs.calleeFuncID); if (!declaringMtd || !declaringMtd.getCfg()) { - return; + return false; } if (!this.visited.has(declaringMtd)) { this.dvfgBuilder.buildForSingleMethod(declaringMtd); this.visited.add(declaringMtd); } - declaringMtd - .getReturnStmt() - .forEach(r => this.checkFromStmt(r, scene, res, checkAll, visited, depth + 1)); - }); + const returnStmts = declaringMtd.getReturnStmt(); + for (const stmt of returnStmts) { + const res = this.checkFromStmt(stmt, scene, checkAll, visited, depth + 1); + if (res) { + return true; + } + } + } 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); - this.collectArgDefs(paramIdx, callsites).forEach(d => - this.checkFromStmt(d, scene, res, checkAll, visited, depth + 1) - ); + const argDefs = this.collectArgDefs(paramIdx, callsites); + for (const def of argDefs) { + const res = this.checkFromStmt(def, scene, checkAll, visited, depth + 1); + if (res) { + return true; + } + } } current.getIncomingEdge().forEach(e => worklist.push(e.getSrcNode() as DVFGNode)); } + return false; } private processCallsites(callsites: Stmt[]): void { @@ -235,7 +230,7 @@ export class InteropObjectLiteralCheck implements BaseChecker { }); } - private addIssueReport(stmt: Stmt, operand: Value, result: Stmt[], targetLanguage: Language): void { + private addIssueReport(stmt: Stmt, operand: Value, targetLanguage: Language, checkAll: boolean = true): void { const interopRuleId = this.getInteropRule(targetLanguage); if (interopRuleId === null) { return; @@ -244,10 +239,11 @@ export class InteropObjectLiteralCheck implements BaseChecker { const warnInfo = getLineAndColumn(stmt, operand); let targetLan = getLanguageStr(targetLanguage); - const resPos: number[] = []; - result.forEach(stmt => resPos.push(stmt.getOriginPositionInfo().getLineNo())); const problem = 'Interop'; - const desc = `instanceof including object literal with class type from ${targetLan} (${interopRuleId})`; + let desc = `instanceof including object literal with class type from ${targetLan} (${interopRuleId})`; + if (!checkAll) { + desc = `Can not check when function call chain depth exceeds ${CALL_DEPTH_LIMIT}, please check it manually (${interopRuleId})`; + } let defects = new Defects( warnInfo.line, warnInfo.startCol, diff --git a/ets2panda/linter/homecheck/src/checker/migration/NoTSLikeAsCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/NoTSLikeAsCheck.ts index 3e6f594aa1..2cd9eab61a 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/NoTSLikeAsCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/NoTSLikeAsCheck.ts @@ -575,7 +575,7 @@ export class NoTSLikeAsCheck implements BaseChecker { let desc = `(${this.rule.ruleId.replace('@migration/', '')})`; if (relatedStmt === undefined) { - desc = `Can not find all assignments of the value in type assertion, please check it manually ` + desc; + desc = `Can not check when function call chain depth exceeds ${CALL_DEPTH_LIMIT}, please check it manually ` + desc; } else { const sinkFile = stmt.getCfg().getDeclaringMethod().getDeclaringArkFile(); const relatedFile = relatedStmt.getCfg().getDeclaringMethod().getDeclaringArkFile(); diff --git a/ets2panda/linter/homecheck/src/checker/migration/ObjectLiteralCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/ObjectLiteralCheck.ts index f6b47c98c9..f0c756eeed 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/ObjectLiteralCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/ObjectLiteralCheck.ts @@ -46,7 +46,6 @@ const gMetaData: BaseMetaData = { ruleDocPath: '', description: 'Object literal shall generate instance of a specific class', }; -const INSTANCE_OF_DESC = 'The `instanceof` may work on an object literal, which now generates an instance of a specific class'; export class ObjectLiteralCheck implements BaseChecker { readonly metaData: BaseMetaData = gMetaData; @@ -102,7 +101,7 @@ export class ObjectLiteralCheck implements BaseChecker { this.checkFromStmt(stmt, scene, result, topLevelVarMap, checkAll, visited); result.forEach(s => this.addIssueReport(s, (s as ArkAssignStmt).getRightOp())); if (!checkAll.value) { - this.addIssueReport(stmt, rightOp, false); + this.addIssueReport(stmt, rightOp, checkAll.value); } } } @@ -203,20 +202,14 @@ export class ObjectLiteralCheck implements BaseChecker { DVFGHelper.buildSingleDVFG(declaringMtd, scene); this.visited.add(declaringMtd); } - declaringMtd - .getReturnStmt() - .forEach(r => this.checkFromStmt(r, scene, res, topLevelVarMap, checkAll, visited, depth + 1)); + declaringMtd.getReturnStmt().forEach(r => this.checkFromStmt(r, scene, res, topLevelVarMap, checkAll, visited, depth + 1)); }); 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, scene); - this.collectArgDefs(paramIdx, callsites, scene).forEach(d => - this.checkFromStmt(d, scene, res, topLevelVarMap, checkAll, visited, depth + 1) - ); + this.collectArgDefs(paramIdx, callsites, scene).forEach(d => this.checkFromStmt(d, scene, res, topLevelVarMap, checkAll, visited, depth + 1)); } current.getIncomingEdge().forEach(e => worklist.push(e.getSrcNode() as DVFGNode)); } @@ -361,12 +354,14 @@ export class ObjectLiteralCheck implements BaseChecker { }); } - private addIssueReport(stmt: Stmt, operand: Value, isPrecise: boolean = true): void { + private addIssueReport(stmt: Stmt, operand: Value, checkAll: boolean = true): void { const severity = this.rule.alert ?? this.metaData.severity; const warnInfo = this.getLineAndColumn(stmt, operand); const problem = 'ObjectLiteral'; - const metaDesc = isPrecise ? this.metaData.description : INSTANCE_OF_DESC; - const desc = `${metaDesc} (${this.rule.ruleId.replace('@migration/', '')})`; + let desc = `${this.metaData.description} (${this.rule.ruleId.replace('@migration/', '')})`; + if (!checkAll) { + desc = `Can not check when function call chain depth exceeds ${CALL_DEPTH_LIMIT}, please check it manually (${this.rule.ruleId.replace('@migration/', '')})`; + } let defects = new Defects( warnInfo.line, warnInfo.startCol, diff --git a/ets2panda/linter/homecheck/src/utils/common/CheckEntry.ts b/ets2panda/linter/homecheck/src/utils/common/CheckEntry.ts index e08dbb90f7..b8a14fa1bd 100644 --- a/ets2panda/linter/homecheck/src/utils/common/CheckEntry.ts +++ b/ets2panda/linter/homecheck/src/utils/common/CheckEntry.ts @@ -98,7 +98,7 @@ export class CheckEntry { /** * 按规则维度统计并输出告警信息,按文件维度汇总并返回告警信息。 - * + * * @returns FileReport[] 文件报告数组,每个元素包含文件名、缺陷列表和输出信息 */ public sortIssues(): FileIssues[] { @@ -235,7 +235,7 @@ export async function checkEntryBuilder(checkEntry: CheckEntry): Promise Date: Wed, 25 Jun 2025 14:15:38 +0800 Subject: [PATCH 06/16] homecheck update s2d obj and observed checks Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICHOYL Signed-off-by: xudan16 --- .../InteropS2DObjectLiteralsCheck.ts | 6 +++++ .../migration/ObservedDecoratorCheck.ts | 26 ++++++++++++++++--- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/ets2panda/linter/homecheck/src/checker/migration/InteropS2DObjectLiteralsCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/InteropS2DObjectLiteralsCheck.ts index 79c14788bd..9e316294f2 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/InteropS2DObjectLiteralsCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/InteropS2DObjectLiteralsCheck.ts @@ -33,6 +33,7 @@ import { IssueReport } from '../../model/Defects'; import { ArkClass, ClassCategory } from 'arkanalyzer/lib/core/model/ArkClass'; import { Language } from 'arkanalyzer/lib/core/model/ArkFile'; import { getLanguageStr, getLineAndColumn } from './Utils'; +import { ArkThisRef } from 'arkanalyzer'; const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'InteropS2DObjectLiteralCheck'); const gMetaData: BaseMetaData = { @@ -105,6 +106,11 @@ export class InteropS2DObjectLiteralCheck implements BaseChecker { } private checkAssignWithObjectLiteral(stmt: ArkAssignStmt, target: ArkMethod): void { + // this = thisRef 赋值语句需要跳过,否则该class一定会被扫描一遍,此次扫描多余,且可能会产生行号为-1的错误issue + // 若此class有问题,会在真正使用到此class的源码处进行告警,无需查找this ref语句 + if (stmt.getRightOp() instanceof ArkThisRef) { + return; + } const leftOpType = stmt.getLeftOp().getType(); if (!(leftOpType instanceof ClassType)) { return; diff --git a/ets2panda/linter/homecheck/src/checker/migration/ObservedDecoratorCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/ObservedDecoratorCheck.ts index 8f9c5cdb03..59c04a84d8 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/ObservedDecoratorCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/ObservedDecoratorCheck.ts @@ -78,6 +78,7 @@ export class ObservedDecoratorCheck implements BaseChecker { public check = (arkClass: ArkClass): void => { const scene = arkClass.getDeclaringArkFile().getScene(); + const projectName = arkClass.getDeclaringArkFile().getProjectName(); for (const field of arkClass.getFields()) { if (!field.getDecorators().some(d => DECORATOR_SET.has(d.getKind()))) { continue; @@ -88,6 +89,10 @@ export class ObservedDecoratorCheck implements BaseChecker { let issueClasses: Set = new Set(); // ArkAnalyzer此处有问题,若field的类型注解为unclear type,会用右边的替换左边的。 const fieldType = field.getType(); + // 此处仅对field为class类型进行检查,包含class和interface,非class类型不在本规则检查范围之内 + if (!(fieldType instanceof ClassType)) { + continue; + } const initializers = field.getInitializer(); let canFindAllTargets = true; @@ -121,10 +126,10 @@ export class ObservedDecoratorCheck implements BaseChecker { locals.add(rightOp); } else if (rightOp instanceof ArkNewExpr) { // 此处需要区分field = new cls()和field = {}两种场景,查找完毕需继续遍历stmts以解析条件表达式造成的多赋值场景 - canFindAllTargets = canFindAllTargets && this.handleNewExpr(scene, fieldType, rightOp, usedClasses); + canFindAllTargets = canFindAllTargets && this.handleNewExpr(scene, fieldType, rightOp, usedClasses, projectName); } else if (rightOp instanceof AbstractInvokeExpr) { canFindAllTargets = - canFindAllTargets && this.handleInvokeExpr(scene, fieldType, rightOp, usedClasses); + canFindAllTargets && this.handleInvokeExpr(scene, fieldType, rightOp, usedClasses, projectName); } else { // 对应场景为使用条件表达式cond ? 123 : 456赋值时 continue; @@ -160,11 +165,15 @@ export class ObservedDecoratorCheck implements BaseChecker { // 此处需要区分field = new cls()和field = {}两种场景 // 对于field = new cls()场景,需要查找此右边class的所有父class // 对于field = {}场景,需要查找左边field类型为class时的所有父class - private handleNewExpr(scene: Scene, fieldType: Type, rightOp: ArkNewExpr, targets: Set): boolean { + private handleNewExpr(scene: Scene, fieldType: Type, rightOp: ArkNewExpr, targets: Set, projectName: string): boolean { const target = scene.getClass(rightOp.getClassType().getClassSignature()); if (target === null) { return false; } + // class为非本项目的内容时,表示调用到三方库、SDK等内容,不再继续进行查找 + if (target.getDeclaringArkFile().getProjectName() !== projectName) { + return true; + } if (!target.isAnonymousClass()) { // 理论上来说ArkNewExpr中的class一定ClassCategory.CLASS,此处仍然显式的检查一次 @@ -186,6 +195,10 @@ export class ObservedDecoratorCheck implements BaseChecker { if (fieldClass === null) { return false; } + // fieldClass为非本项目的内容时,表示调用到三方库、SDK等内容,不再继续进行查找 + if (fieldClass.getDeclaringArkFile().getProjectName() !== projectName) { + return true; + } if (fieldClass.getCategory() !== ClassCategory.CLASS) { return true; } @@ -201,13 +214,18 @@ export class ObservedDecoratorCheck implements BaseChecker { scene: Scene, fieldType: Type, invokeExpr: AbstractInvokeExpr, - targets: Set + targets: Set, + projectName: string ): boolean { let canFindAllTargets = true; const callMethod = scene.getMethod(invokeExpr.getMethodSignature()); if (callMethod === null) { return false; } + // callMethod为非本项目的内容时,表示调用到三方库、SDK等内容,不再继续进行查找 + if (callMethod.getDeclaringArkFile().getProjectName() !== projectName) { + return true; + } const stmts = callMethod.getBody()?.getCfg().getStmts(); if (stmts === undefined) { return false; -- Gitee From 23ebdbba6cb58de9d0ff4fc3195e51cc019acd90 Mon Sep 17 00:00:00 2001 From: ZhongNing Date: Mon, 23 Jun 2025 20:11:07 +0800 Subject: [PATCH 07/16] fix sdk global api Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICGQA4 Test scenarios: fix bug Signed-off-by: ZhongNing --- ets2panda/linter/src/lib/TypeScriptLinter.ts | 48 ++- .../src/lib/utils/consts/ArkuiImportList.ts | 51 ++++ .../sdkwhite/decl_with_duplicate_name_sdk.ets | 28 +- ...cl_with_duplicate_name_sdk.ets.arkts2.json | 284 +++++++++++++----- .../decl_with_duplicate_name_sdk.ets.json | 32 +- 5 files changed, 326 insertions(+), 117 deletions(-) diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index 84b5a362bf..a7a275982d 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -146,6 +146,7 @@ import { globalApiAssociatedInfo } from './utils/consts/AssociatedInfo'; import { ARRAY_API_LIST } from './utils/consts/ArraysAPI'; import { ERROR_PROP_LIST } from './utils/consts/ErrorProp'; import { D_ETS, D_TS } from './utils/consts/TsSuffix'; +import { arkTsBuiltInTypeName } from './utils/consts/ArkuiImportList'; interface InterfaceSymbolTypeResult { propNames: string[]; @@ -8049,20 +8050,58 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (!hasSameApiName) { return; } - if (ts.isTypeReferenceNode(errorNode)) { errorNode = errorNode.typeName; } - const matchedApi = apiNamesArr.some((sdkInfo) => { const isSameName = sdkInfo.api_info.api_name === apiName; const isGlobal = sdkInfo.is_global; return isSameName && isGlobal; }); + const checkSymbol = this.isIdentifierFromSDK(errorNode); + const type = this.tsTypeChecker.getTypeAtLocation(errorNode); + const typeName = this.tsTypeChecker.typeToString(type); - if (matchedApi) { - this.incrementCounters(errorNode, faultId); + if (checkSymbol) { + if (arkTsBuiltInTypeName.has(typeName)) { + return; + } + if (matchedApi) { + this.incrementCounters(errorNode, faultId); + } + } + } + + private isIdentifierFromSDK(node: ts.Node): boolean { + const symbol = this.tsTypeChecker.getSymbolAtLocation(node); + if (!symbol) { + return true; } + + // Check if the symbol is from an SDK import + const declarations = symbol.getDeclarations(); + if (!declarations || declarations.length === 0) { + return true; + } + + let isLocal = false; + for (const declaration of declarations) { + if (ts.isVariableDeclaration(declaration) || + ts.isTypeAliasDeclaration(declaration) || + ts.isClassDeclaration(declaration) || + ts.isInterfaceDeclaration(declaration) || + ts.isFunctionDeclaration(declaration) || + ts.isEnumDeclaration(declaration)) { + isLocal = true; + break + } + } + + if(isLocal) { + return false; + } + + return true; } private handleSdkGlobalApi( @@ -8141,6 +8180,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { private checkCallExpressionForSdkGlobalApi(node: ts.CallExpression): void { if (ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.expression)) { const expression = node.expression.expression; + this.processApiNodeSdkGlobalApi(expression.text, expression); } } diff --git a/ets2panda/linter/src/lib/utils/consts/ArkuiImportList.ts b/ets2panda/linter/src/lib/utils/consts/ArkuiImportList.ts index cfe9c6eff0..3beae87577 100644 --- a/ets2panda/linter/src/lib/utils/consts/ArkuiImportList.ts +++ b/ets2panda/linter/src/lib/utils/consts/ArkuiImportList.ts @@ -1614,3 +1614,54 @@ export const arkuiImportList: Set = new Set([ 'sharedTransitionOptions', 'vp2px' ]); + +export const arkTsBuiltInTypeName: Set = new Set([ + 'Object', + 'Function', + 'Boolean', + 'Symbol', + 'Number', + 'BigInt', + 'Math', + 'Date', + 'String', + 'RegExp', + 'Array', + 'Int8Array', + 'Uint8Array', + 'Uint8ClampedArray', + 'Int16Array', + 'Uint16Array', + 'Int32Array', + 'Uint32Array', + 'Float32Array', + 'Float64Array', + 'BigInt64Array', + 'BigUint64Array', + 'Map', + 'Set', + 'WeakMap', + 'WeakSet', + 'ArrayBuffer', + 'SharedArrayBuffer', + 'DataView', + 'JSON', + 'Promise', + 'Generator', + 'GeneratorFunction', + 'AsyncFunction', + 'AsyncGenerator', + 'AsyncGeneratorFunction', + 'Reflect', + 'Proxy', + 'Error', + 'EvalError', + 'RangeError', + 'ReferenceError', + 'SyntaxError', + 'TypeError', + 'URIError', + 'AggregateError', + 'Intl', + 'WebAssembly' +]); \ No newline at end of file diff --git a/ets2panda/linter/test/sdkwhite/decl_with_duplicate_name_sdk.ets b/ets2panda/linter/test/sdkwhite/decl_with_duplicate_name_sdk.ets index 4584cafa7b..43e59da7f5 100755 --- a/ets2panda/linter/test/sdkwhite/decl_with_duplicate_name_sdk.ets +++ b/ets2panda/linter/test/sdkwhite/decl_with_duplicate_name_sdk.ets @@ -14,15 +14,11 @@ */ 'use static' -import { TextStyle } from './sdk/declarations/styled_string' -import { HyperlinkAttribute, HyperlinkInterface } from './sdk/declarations/hyperlink' - @Entry @Component struct Index { fontStyleAttr1: TextStyle = new TextStyle({fontColor: Color.Blue}); // Error(2) fontStyleAttr2: TextStyle; // Error - @State styleList: Array = new Array(); // Error aboutToAppear() { for (let i = 15; i < 50; i++) @@ -47,14 +43,26 @@ class TextStyleDemo2 extends TextStyle { // Error } } -let hyperlinkAttr1: HyperlinkAttribute = HyperlinkInterface; -let hyperlinkAttr2: HyperlinkAttribute = HyperlinkInterface.color(''); +let hyperlinkAttr1: HyperlinkAttribute = HyperlinkInterface; // Error +let hyperlinkAttr2: HyperlinkAttribute = HyperlinkInterface.color(''); // Error class HyperlinkTest { - prop1: HyperlinkAttribute = HyperlinkInterface; - prop2: HyperlinkAttribute = HyperlinkInterface.color(''); + prop1: HyperlinkAttribute = HyperlinkInterface; // Error + prop2: HyperlinkAttribute = HyperlinkInterface.color(''); // Error } let hyperlinkAttr3: HyperlinkAttribute; -hyperlinkAttr3 = HyperlinkInterface; -function func(x = HyperlinkInterface) { +hyperlinkAttr3 = HyperlinkInterface; // Error +function func(x = HyperlinkInterface) { // Error + +} +class A { + onBackPress: Function; + TextStyle: Function; + constructor(onBackPress: Function, TextStyle: Function) { + this.onBackPress = onBackPress; // no Error + this.TextStyle = TextStyle; // no Error + } +} +function tt(a: A) { + a.onBackPress(); } diff --git a/ets2panda/linter/test/sdkwhite/decl_with_duplicate_name_sdk.ets.arkts2.json b/ets2panda/linter/test/sdkwhite/decl_with_duplicate_name_sdk.ets.arkts2.json index 64896441f0..d351a537bd 100644 --- a/ets2panda/linter/test/sdkwhite/decl_with_duplicate_name_sdk.ets.arkts2.json +++ b/ets2panda/linter/test/sdkwhite/decl_with_duplicate_name_sdk.ets.arkts2.json @@ -15,29 +15,9 @@ ], "result": [ { - "line": 17, - "column": 1, - "endLine": 17, - "endColumn": 61, - "problem": "ImportAfterStatement", - "suggest": "", - "rule": "\"import\" statements after other statements are not allowed (arkts-no-misplaced-imports)", - "severity": "ERROR" - }, - { - "line": 18, - "column": 1, - "endLine": 18, - "endColumn": 86, - "problem": "ImportAfterStatement", - "suggest": "", - "rule": "\"import\" statements after other statements are not allowed (arkts-no-misplaced-imports)", - "severity": "ERROR" - }, - { - "line": 23, + "line": 20, "column": 19, - "endLine": 23, + "endLine": 20, "endColumn": 28, "problem": "DuplicateDeclNameFromSdk", "suggest": "", @@ -45,9 +25,9 @@ "severity": "ERROR" }, { - "line": 23, + "line": 20, "column": 35, - "endLine": 23, + "endLine": 20, "endColumn": 44, "problem": "DuplicateDeclNameFromSdk", "suggest": "", @@ -55,9 +35,19 @@ "severity": "ERROR" }, { - "line": 24, + "line": 20, + "column": 35, + "endLine": 20, + "endColumn": 44, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 21, "column": 19, - "endLine": 24, + "endLine": 21, "endColumn": 28, "problem": "DuplicateDeclNameFromSdk", "suggest": "", @@ -65,9 +55,9 @@ "severity": "ERROR" }, { - "line": 26, + "line": 22, "column": 27, - "endLine": 26, + "endLine": 22, "endColumn": 36, "problem": "DuplicateDeclNameFromSdk", "suggest": "", @@ -75,9 +65,9 @@ "severity": "ERROR" }, { - "line": 26, + "line": 22, "column": 40, - "endLine": 26, + "endLine": 22, "endColumn": 51, "problem": "GenericCallNoTypeArgs", "suggest": "", @@ -85,9 +75,9 @@ "severity": "ERROR" }, { - "line": 28, + "line": 24, "column": 14, - "endLine": 28, + "endLine": 24, "endColumn": 20, "problem": "NumericSemantics", "suggest": "", @@ -95,9 +85,9 @@ "severity": "ERROR" }, { - "line": 28, + "line": 24, "column": 18, - "endLine": 28, + "endLine": 24, "endColumn": 20, "problem": "NumericSemantics", "suggest": "", @@ -105,9 +95,9 @@ "severity": "ERROR" }, { - "line": 28, + "line": 24, "column": 26, - "endLine": 28, + "endLine": 24, "endColumn": 28, "problem": "NumericSemantics", "suggest": "", @@ -115,9 +105,9 @@ "severity": "ERROR" }, { - "line": 29, + "line": 25, "column": 31, - "endLine": 29, + "endLine": 25, "endColumn": 40, "problem": "DuplicateDeclNameFromSdk", "suggest": "", @@ -125,9 +115,19 @@ "severity": "ERROR" }, { - "line": 34, + "line": 25, + "column": 31, + "endLine": 25, + "endColumn": 40, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 30, "column": 38, - "endLine": 34, + "endLine": 30, "endColumn": 47, "problem": "DuplicateDeclNameFromSdk", "suggest": "", @@ -135,9 +135,9 @@ "severity": "ERROR" }, { - "line": 44, + "line": 40, "column": 30, - "endLine": 44, + "endLine": 40, "endColumn": 39, "problem": "DuplicateDeclNameFromSdk", "suggest": "", @@ -145,9 +145,9 @@ "severity": "ERROR" }, { - "line": 50, + "line": 46, "column": 42, - "endLine": 50, + "endLine": 46, "endColumn": 60, "problem": "DuplicateDeclNameFromSdk", "suggest": "", @@ -155,9 +155,9 @@ "severity": "ERROR" }, { - "line": 51, + "line": 47, "column": 42, - "endLine": 51, + "endLine": 47, "endColumn": 60, "problem": "DuplicateDeclNameFromSdk", "suggest": "", @@ -165,9 +165,9 @@ "severity": "ERROR" }, { - "line": 53, + "line": 49, "column": 31, - "endLine": 53, + "endLine": 49, "endColumn": 49, "problem": "DuplicateDeclNameFromSdk", "suggest": "", @@ -175,9 +175,9 @@ "severity": "ERROR" }, { - "line": 54, + "line": 50, "column": 31, - "endLine": 54, + "endLine": 50, "endColumn": 49, "problem": "DuplicateDeclNameFromSdk", "suggest": "", @@ -185,9 +185,9 @@ "severity": "ERROR" }, { - "line": 57, + "line": 53, "column": 18, - "endLine": 57, + "endLine": 53, "endColumn": 36, "problem": "DuplicateDeclNameFromSdk", "suggest": "", @@ -195,9 +195,19 @@ "severity": "ERROR" }, { - "line": 58, + "line": 54, + "column": 15, + "endLine": 54, + "endColumn": 37, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 54, "column": 19, - "endLine": 58, + "endLine": 54, "endColumn": 37, "problem": "DuplicateDeclNameFromSdk", "suggest": "", @@ -205,9 +215,19 @@ "severity": "ERROR" }, { - "line": 20, + "line": 67, + "column": 3, + "endLine": 67, + "endColumn": 16, + "problem": "ExplicitFunctionType", + "suggest": "", + "rule": "The function type should be explicit (arkts-no-ts-like-function-call)", + "severity": "ERROR" + }, + { + "line": 17, "column": 2, - "endLine": 20, + "endLine": 17, "endColumn": 7, "problem": "UIInterfaceImport", "suggest": "", @@ -215,9 +235,9 @@ "severity": "ERROR" }, { - "line": 21, + "line": 18, "column": 2, - "endLine": 21, + "endLine": 18, "endColumn": 11, "problem": "UIInterfaceImport", "suggest": "", @@ -225,9 +245,29 @@ "severity": "ERROR" }, { - "line": 23, + "line": 20, + "column": 19, + "endLine": 20, + "endColumn": 28, + "problem": "UIInterfaceImport", + "suggest": "", + "rule": "The ArkUI interface \"TextStyle\" should be imported before it is used (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 20, + "column": 35, + "endLine": 20, + "endColumn": 44, + "problem": "UIInterfaceImport", + "suggest": "", + "rule": "The ArkUI interface \"TextStyle\" should be imported before it is used (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 20, "column": 57, - "endLine": 23, + "endLine": 20, "endColumn": 62, "problem": "UIInterfaceImport", "suggest": "", @@ -235,9 +275,19 @@ "severity": "ERROR" }, { - "line": 26, + "line": 21, + "column": 19, + "endLine": 21, + "endColumn": 28, + "problem": "UIInterfaceImport", + "suggest": "", + "rule": "The ArkUI interface \"TextStyle\" should be imported before it is used (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 22, "column": 4, - "endLine": 26, + "endLine": 22, "endColumn": 9, "problem": "UIInterfaceImport", "suggest": "", @@ -245,9 +295,29 @@ "severity": "ERROR" }, { - "line": 33, + "line": 22, + "column": 27, + "endLine": 22, + "endColumn": 36, + "problem": "UIInterfaceImport", + "suggest": "", + "rule": "The ArkUI interface \"TextStyle\" should be imported before it is used (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 25, + "column": 31, + "endLine": 25, + "endColumn": 40, + "problem": "UIInterfaceImport", + "suggest": "", + "rule": "The ArkUI interface \"TextStyle\" should be imported before it is used (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 29, "column": 5, - "endLine": 33, + "endLine": 29, "endColumn": 9, "problem": "UIInterfaceImport", "suggest": "", @@ -255,9 +325,9 @@ "severity": "ERROR" }, { - "line": 34, + "line": 30, "column": 7, - "endLine": 34, + "endLine": 30, "endColumn": 14, "problem": "UIInterfaceImport", "suggest": "", @@ -265,9 +335,19 @@ "severity": "ERROR" }, { - "line": 35, + "line": 30, + "column": 38, + "endLine": 30, + "endColumn": 47, + "problem": "UIInterfaceImport", + "suggest": "", + "rule": "The ArkUI interface \"TextStyle\" should be imported before it is used (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 31, "column": 9, - "endLine": 35, + "endLine": 31, "endColumn": 17, "problem": "UIInterfaceImport", "suggest": "", @@ -275,9 +355,9 @@ "severity": "ERROR" }, { - "line": 36, + "line": 32, "column": 11, - "endLine": 36, + "endLine": 32, "endColumn": 15, "problem": "UIInterfaceImport", "suggest": "", @@ -285,13 +365,63 @@ "severity": "ERROR" }, { - "line": 24, - "column": 3, - "endLine": 24, - "endColumn": 17, - "problem": "StrictDiagnostic", - "suggest": "Property 'fontStyleAttr2' has no initializer and is not definitely assigned in the constructor.", - "rule": "Property 'fontStyleAttr2' has no initializer and is not definitely assigned in the constructor.", + "line": 40, + "column": 30, + "endLine": 40, + "endColumn": 39, + "problem": "UIInterfaceImport", + "suggest": "", + "rule": "The ArkUI interface \"TextStyle\" should be imported before it is used (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 46, + "column": 21, + "endLine": 46, + "endColumn": 39, + "problem": "UIInterfaceImport", + "suggest": "", + "rule": "The ArkUI interface \"HyperlinkAttribute\" should be imported before it is used (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 47, + "column": 21, + "endLine": 47, + "endColumn": 39, + "problem": "UIInterfaceImport", + "suggest": "", + "rule": "The ArkUI interface \"HyperlinkAttribute\" should be imported before it is used (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 49, + "column": 10, + "endLine": 49, + "endColumn": 28, + "problem": "UIInterfaceImport", + "suggest": "", + "rule": "The ArkUI interface \"HyperlinkAttribute\" should be imported before it is used (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 50, + "column": 10, + "endLine": 50, + "endColumn": 28, + "problem": "UIInterfaceImport", + "suggest": "", + "rule": "The ArkUI interface \"HyperlinkAttribute\" should be imported before it is used (arkui-modular-interface)", + "severity": "ERROR" + }, + { + "line": 52, + "column": 21, + "endLine": 52, + "endColumn": 39, + "problem": "UIInterfaceImport", + "suggest": "", + "rule": "The ArkUI interface \"HyperlinkAttribute\" should be imported before it is used (arkui-modular-interface)", "severity": "ERROR" } ] diff --git a/ets2panda/linter/test/sdkwhite/decl_with_duplicate_name_sdk.ets.json b/ets2panda/linter/test/sdkwhite/decl_with_duplicate_name_sdk.ets.json index 489a1474b5..4e18966ecf 100755 --- a/ets2panda/linter/test/sdkwhite/decl_with_duplicate_name_sdk.ets.json +++ b/ets2panda/linter/test/sdkwhite/decl_with_duplicate_name_sdk.ets.json @@ -15,33 +15,13 @@ ], "result": [ { - "line": 17, - "column": 1, - "endLine": 17, - "endColumn": 61, - "problem": "ImportAfterStatement", + "line": 54, + "column": 15, + "endLine": 54, + "endColumn": 37, + "problem": "AnyType", "suggest": "", - "rule": "\"import\" statements after other statements are not allowed (arkts-no-misplaced-imports)", - "severity": "ERROR" - }, - { - "line": 18, - "column": 1, - "endLine": 18, - "endColumn": 86, - "problem": "ImportAfterStatement", - "suggest": "", - "rule": "\"import\" statements after other statements are not allowed (arkts-no-misplaced-imports)", - "severity": "ERROR" - }, - { - "line": 24, - "column": 3, - "endLine": 24, - "endColumn": 17, - "problem": "StrictDiagnostic", - "suggest": "Property 'fontStyleAttr2' has no initializer and is not definitely assigned in the constructor.", - "rule": "Property 'fontStyleAttr2' has no initializer and is not definitely assigned in the constructor.", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", "severity": "ERROR" } ] -- Gitee From 1bd5783f380ed81732bc0896164d5353def23181 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E6=9F=A0?= Date: Tue, 24 Jun 2025 14:50:09 +0800 Subject: [PATCH 08/16] fix issue for arkts-runtime-array-check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICHC90 Test scenarios: arkts-runtime-array-check Signed-off-by: 钟柠 --- ets2panda/linter/src/lib/TypeScriptLinter.ts | 32 +++++++++++++++++++ .../linter/test/main/runtime_array_bound.ets | 5 +++ .../main/runtime_array_bound.ets.arkts2.json | 30 +++++++++++++++++ .../main/runtime_array_bound.ets.migrate.ets | 5 +++ 4 files changed, 72 insertions(+) diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index a7a275982d..776b8c5903 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -9849,6 +9849,11 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return; } + const arrayDecl = TypeScriptLinter.findArrayDeclaration(arraySym); + if (arrayDecl && TypeScriptLinter.isArrayCreatedWithOtherArrayLength(arrayDecl)) { + return; + } + const indexExpr = accessExpr.argumentExpression; const loopVarName = ts.isIdentifier(indexExpr) ? indexExpr.text : undefined; @@ -10214,4 +10219,31 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return false; } + + static isArrayCreatedWithOtherArrayLength(decl: ts.VariableDeclaration): boolean { + if (!decl.initializer || !ts.isNewExpression(decl.initializer)) { + return false; + } + + const newExpr = decl.initializer; + return ( + newExpr.arguments?.some((arg) => { + return ts.isPropertyAccessExpression(arg) && arg.name.text === 'length'; + }) ?? false + ); + } + + static findArrayDeclaration(sym: ts.Symbol): ts.VariableDeclaration | undefined { + const decls = sym.getDeclarations(); + if (!decls) { + return undefined; + } + + for (const decl of decls) { + if (ts.isVariableDeclaration(decl)) { + return decl; + } + } + return undefined; + } } diff --git a/ets2panda/linter/test/main/runtime_array_bound.ets b/ets2panda/linter/test/main/runtime_array_bound.ets index 5540265166..093c957d7b 100644 --- a/ets2panda/linter/test/main/runtime_array_bound.ets +++ b/ets2panda/linter/test/main/runtime_array_bound.ets @@ -165,3 +165,8 @@ enum TE{ } arr1[TE.AA] = 12; +let a: string[] = []; +let b: Array = new Array(a.length); +for (let i = 0; i < a.length; i++) { + b[i]; +} \ No newline at end of file diff --git a/ets2panda/linter/test/main/runtime_array_bound.ets.arkts2.json b/ets2panda/linter/test/main/runtime_array_bound.ets.arkts2.json index fb3f014d24..a42550c138 100644 --- a/ets2panda/linter/test/main/runtime_array_bound.ets.arkts2.json +++ b/ets2panda/linter/test/main/runtime_array_bound.ets.arkts2.json @@ -1853,6 +1853,36 @@ "suggest": "", "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" + }, + { + "line": 169, + "column": 24, + "endLine": 169, + "endColumn": 43, + "problem": "GenericCallNoTypeArgs", + "suggest": "", + "rule": "Type inference in case of generic function calls is limited (arkts-no-inferred-generic-params)", + "severity": "ERROR" + }, + { + "line": 170, + "column": 10, + "endLine": 170, + "endColumn": 15, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 170, + "column": 14, + "endLine": 170, + "endColumn": 15, + "problem": "NumericSemantics", + "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/runtime_array_bound.ets.migrate.ets b/ets2panda/linter/test/main/runtime_array_bound.ets.migrate.ets index 2d4beff418..b3691dd0dd 100644 --- a/ets2panda/linter/test/main/runtime_array_bound.ets.migrate.ets +++ b/ets2panda/linter/test/main/runtime_array_bound.ets.migrate.ets @@ -165,3 +165,8 @@ enum TE{ } arr1[TE.AA] = 12.0; +let a: string[] = []; +let b: Array = new Array(a.length); +for (let i: number = 0.0; i < a.length; i++) { + b[i as int]; +} \ No newline at end of file -- Gitee From a2099b52c7e9bbb959c8562512fd0c8f2fcc897c Mon Sep 17 00:00:00 2001 From: ZhongNing Date: Wed, 25 Jun 2025 17:32:43 +0800 Subject: [PATCH 09/16] Add checks for arkts-promise-void-resolve Issue:https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICHJB7 Test scenarios: new tests added to the linter Signed-off-by: ZhongNing --- ets2panda/linter/src/lib/CookBookMsg.ts | 2 + ets2panda/linter/src/lib/FaultAttrs.ts | 1 + ets2panda/linter/src/lib/FaultDesc.ts | 1 + ets2panda/linter/src/lib/Problems.ts | 1 + ets2panda/linter/src/lib/TypeScriptLinter.ts | 44 +++++++++++++++++++ .../src/lib/utils/consts/ArkTS2Rules.ts | 3 +- .../main/arkts_promise_need_void_resolve.ets | 17 +++++++ ...ts_promise_need_void_resolve.ets.args.json | 19 ++++++++ ..._promise_need_void_resolve.ets.arkts2.json | 28 ++++++++++++ .../arkts_promise_need_void_resolve.ets.json | 17 +++++++ 10 files changed, 132 insertions(+), 1 deletion(-) create mode 100755 ets2panda/linter/test/main/arkts_promise_need_void_resolve.ets create mode 100755 ets2panda/linter/test/main/arkts_promise_need_void_resolve.ets.args.json create mode 100755 ets2panda/linter/test/main/arkts_promise_need_void_resolve.ets.arkts2.json create mode 100755 ets2panda/linter/test/main/arkts_promise_need_void_resolve.ets.json diff --git a/ets2panda/linter/src/lib/CookBookMsg.ts b/ets2panda/linter/src/lib/CookBookMsg.ts index 06558eadcd..47b2e67872 100644 --- a/ets2panda/linter/src/lib/CookBookMsg.ts +++ b/ets2panda/linter/src/lib/CookBookMsg.ts @@ -369,6 +369,8 @@ cookBookTag[377] = cookBookTag[378] = 'Operator is not support (arkts-unsupport-operator)'; cookBookTag[381] = 'The code block passed to stateStyles needs to be an arrow function (arkui-statestyles-block-need-arrow-func)'; +cookBookTag[382] = + 'Promiseconstructor only supports using resolve (undefined) (arkts-promise-with-void-type-need-undefined-as-resolve-arg)'; for (let i = 0; i <= cookBookTag.length; i++) { cookBookMsg[i] = ''; diff --git a/ets2panda/linter/src/lib/FaultAttrs.ts b/ets2panda/linter/src/lib/FaultAttrs.ts index 4e22d31370..8ad56ceb82 100644 --- a/ets2panda/linter/src/lib/FaultAttrs.ts +++ b/ets2panda/linter/src/lib/FaultAttrs.ts @@ -264,3 +264,4 @@ faultsAttrs[FaultID.NumericBigintCompare] = new FaultAttributes(376); faultsAttrs[FaultID.NondecimalBigint] = new FaultAttributes(377); faultsAttrs[FaultID.UnsupportOperator] = new FaultAttributes(378); faultsAttrs[FaultID.StateStylesBlockNeedArrowFunc] = new FaultAttributes(381); +faultsAttrs[FaultID.PromiseVoidNeedResolveArg] = new FaultAttributes(382); \ No newline at end of file diff --git a/ets2panda/linter/src/lib/FaultDesc.ts b/ets2panda/linter/src/lib/FaultDesc.ts index 8716e7d241..93eecdb0dd 100644 --- a/ets2panda/linter/src/lib/FaultDesc.ts +++ b/ets2panda/linter/src/lib/FaultDesc.ts @@ -252,3 +252,4 @@ faultDesc[FaultID.PropFunctionNotSupported] = '"prop" function is not supported' faultDesc[FaultID.SetAndPropFunctionNotSupported] = '"setAndProp" function is not supported'; faultDesc[FaultID.PropNeedCallMethodForDeepCopy] = 'Deep copy needs to call the specific method'; faultDesc[FaultID.StateStylesBlockNeedArrowFunc] = 'StateStyles needs arrow function block'; +faultDesc[FaultID.PromiseVoidNeedResolveArg] = 'Promiseconstructor only supports using resolve (undefined)'; diff --git a/ets2panda/linter/src/lib/Problems.ts b/ets2panda/linter/src/lib/Problems.ts index b0db00e16a..55e32e0f57 100644 --- a/ets2panda/linter/src/lib/Problems.ts +++ b/ets2panda/linter/src/lib/Problems.ts @@ -253,6 +253,7 @@ export enum FaultID { SetAndPropFunctionNotSupported, PropNeedCallMethodForDeepCopy, StateStylesBlockNeedArrowFunc, + PromiseVoidNeedResolveArg, // this should always be last enum LAST_ID } diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index 776b8c5903..5f550dbd76 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -5242,6 +5242,50 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } this.handleSendableGenericTypes(tsNewExpr); this.handleInstantiatedJsObject(tsNewExpr, sym); + this.handlePromiseNeedVoidResolve(tsNewExpr); + } + + handlePromiseNeedVoidResolve(newExpr: ts.NewExpression): void { + if (!this.options.arkts2) { + return; + } + + if (!ts.isIdentifier(newExpr.expression) || newExpr.expression.text !== 'Promise') { + return; + } + + const typeArg = newExpr.typeArguments?.[0]; + if (!typeArg) { + return; + } + + const type = this.tsTypeChecker.getTypeAtLocation(typeArg); + if (!(type.getFlags() & ts.TypeFlags.Void)) { + return; + } + + const executor = newExpr.arguments?.[0]; + if (!executor || !ts.isFunctionLike(executor)) { + return; + } + + const resolveParam = executor.parameters[0]; + if (resolveParam?.type) { + if (ts.isFunctionTypeNode(resolveParam.type) && + resolveParam.type.parameters.length === 0) { + this.incrementCounters(resolveParam.type,FaultID.PromiseVoidNeedResolveArg); + } + } + if (executor.body) { + ts.forEachChild(executor.body, node => { + if (ts.isCallExpression(node) && + ts.isIdentifier(node.expression) && + node.expression.text === 'resolve' && + node.arguments.length === 0) { + this.incrementCounters(node,FaultID.PromiseVoidNeedResolveArg); + } + }); + } } private checkCreatingPrimitiveTypes(tsNewExpr: ts.NewExpression): void { diff --git a/ets2panda/linter/src/lib/utils/consts/ArkTS2Rules.ts b/ets2panda/linter/src/lib/utils/consts/ArkTS2Rules.ts index e78c1006f1..c20eb912c9 100644 --- a/ets2panda/linter/src/lib/utils/consts/ArkTS2Rules.ts +++ b/ets2panda/linter/src/lib/utils/consts/ArkTS2Rules.ts @@ -148,7 +148,8 @@ export const arkts2Rules: number[] = [ 375, 376, 377, - 378 + 378, + 382 ]; export const onlyArkts2SyntaxRules: Map = new Map([ diff --git a/ets2panda/linter/test/main/arkts_promise_need_void_resolve.ets b/ets2panda/linter/test/main/arkts_promise_need_void_resolve.ets new file mode 100755 index 0000000000..54a185e6c9 --- /dev/null +++ b/ets2panda/linter/test/main/arkts_promise_need_void_resolve.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 test(): Promise{ + return new Promise((resolve: () => void, reject) => { resolve() }) } \ No newline at end of file diff --git a/ets2panda/linter/test/main/arkts_promise_need_void_resolve.ets.args.json b/ets2panda/linter/test/main/arkts_promise_need_void_resolve.ets.args.json new file mode 100755 index 0000000000..b9d72da174 --- /dev/null +++ b/ets2panda/linter/test/main/arkts_promise_need_void_resolve.ets.args.json @@ -0,0 +1,19 @@ +{ + "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": "" + } + } \ No newline at end of file diff --git a/ets2panda/linter/test/main/arkts_promise_need_void_resolve.ets.arkts2.json b/ets2panda/linter/test/main/arkts_promise_need_void_resolve.ets.arkts2.json new file mode 100755 index 0000000000..83f403ba1f --- /dev/null +++ b/ets2panda/linter/test/main/arkts_promise_need_void_resolve.ets.arkts2.json @@ -0,0 +1,28 @@ +{ + "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": 17, + "column": 40, + "endLine": 17, + "endColumn": 50, + "problem": "PromiseVoidNeedResolveArg", + "suggest": "", + "rule": "Promiseconstructor only supports using resolve (undefined) (arkts-promise-with-void-type-need-undefined-as-resolve-arg)", + "severity": "ERROR" + } + ] +} \ No newline at end of file diff --git a/ets2panda/linter/test/main/arkts_promise_need_void_resolve.ets.json b/ets2panda/linter/test/main/arkts_promise_need_void_resolve.ets.json new file mode 100755 index 0000000000..127a98a334 --- /dev/null +++ b/ets2panda/linter/test/main/arkts_promise_need_void_resolve.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 -- Gitee From 8253227f052db04c413f350034a9777d14856b71 Mon Sep 17 00:00:00 2001 From: sniperc96 Date: Mon, 23 Jun 2025 14:46:57 +0800 Subject: [PATCH 10/16] change errorMsg for arkui-custom-layout Issue : https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICH5R1 Signed-off-by: sniperc96 --- ets2panda/linter/src/lib/CookBookMsg.ts | 2 +- ets2panda/linter/src/lib/TypeScriptLinter.ts | 6 +++++- ets2panda/linter/src/lib/autofixes/AutofixTitles.ts | 3 ++- ets2panda/linter/src/lib/utils/consts/ArkTS2Rules.ts | 1 + ets2panda/linter/test/main/custom_layout.ets.arkts2.json | 6 +++--- ets2panda/linter/test/main/custom_layout.ets.autofix.json | 6 +++--- 6 files changed, 15 insertions(+), 9 deletions(-) diff --git a/ets2panda/linter/src/lib/CookBookMsg.ts b/ets2panda/linter/src/lib/CookBookMsg.ts index 47b2e67872..fc1272ebf5 100644 --- a/ets2panda/linter/src/lib/CookBookMsg.ts +++ b/ets2panda/linter/src/lib/CookBookMsg.ts @@ -280,7 +280,7 @@ cookBookTag[270] = 'ArkTS1.2 cannot catch a non Error instance thrown from JS co cookBookTag[274] = 'The subclass constructor must call the parent class\'s parametered constructor (arkts-subclass-must-call-super-constructor-with-args)'; cookBookTag[275] = - 'Custom components with custom layout capability need to add the "@CustomLayout" decorator (arkui-custom-layout-need-add-decorator)'; + 'The Custom component with custom layout capability needs to add the "@CustomLayout" decorator (arkui-custom-layout-need-add-decorator)'; cookBookTag[281] = '"@Prop" decorator is not supported (arkui-no-prop-decorator)'; cookBookTag[282] = '"@StorageProp" decorator is not supported (arkui-no-storageprop-decorator)'; cookBookTag[283] = '"@LocalStorageProp" decorator is not supported (arkui-no-localstorageprop-decorator)'; diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index 5f550dbd76..33e1575db3 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -9808,7 +9808,11 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } const autofix = this.autofixer?.fixCustomLayout(node); - this.incrementCounters(node.name, FaultID.CustomLayoutNeedAddDecorator, autofix); + const name = node.name.getText(); + const errorMsg = + `The Custom component "${name}" with custom layout capability needs to add the "@CustomLayout" decorator ` + + '(arkui-custom-layout-need-add-decorator)'; + this.incrementCounters(node.name, FaultID.CustomLayoutNeedAddDecorator, autofix, errorMsg); } private handleArkTSPropertyAccess(expr: ts.BinaryExpression): void { diff --git a/ets2panda/linter/src/lib/autofixes/AutofixTitles.ts b/ets2panda/linter/src/lib/autofixes/AutofixTitles.ts index 9a990259ea..743f8e7382 100644 --- a/ets2panda/linter/src/lib/autofixes/AutofixTitles.ts +++ b/ets2panda/linter/src/lib/autofixes/AutofixTitles.ts @@ -64,5 +64,6 @@ export const cookBookRefToFixTitle: Map = new Map([ [339, 'Using \'ESValue\' interface call'], [341, 'Create JS objects using instantite'], [358, 'Replace missing attribute'], - [359, '"@LocalBuilder" transform to "@Builder"'] + [359, '"@LocalBuilder" transform to "@Builder"'], + [381, 'StateStyles needs arrow function block'] ]); diff --git a/ets2panda/linter/src/lib/utils/consts/ArkTS2Rules.ts b/ets2panda/linter/src/lib/utils/consts/ArkTS2Rules.ts index c20eb912c9..929b21e764 100644 --- a/ets2panda/linter/src/lib/utils/consts/ArkTS2Rules.ts +++ b/ets2panda/linter/src/lib/utils/consts/ArkTS2Rules.ts @@ -149,6 +149,7 @@ export const arkts2Rules: number[] = [ 376, 377, 378, + 381, 382 ]; diff --git a/ets2panda/linter/test/main/custom_layout.ets.arkts2.json b/ets2panda/linter/test/main/custom_layout.ets.arkts2.json index afc0270a64..56fe9a2758 100644 --- a/ets2panda/linter/test/main/custom_layout.ets.arkts2.json +++ b/ets2panda/linter/test/main/custom_layout.ets.arkts2.json @@ -111,7 +111,7 @@ "endColumn": 21, "problem": "CustomLayoutNeedAddDecorator", "suggest": "", - "rule": "Custom components with custom layout capability need to add the \"@CustomLayout\" decorator (arkui-custom-layout-need-add-decorator)", + "rule": "The Custom component \"CustomLayout1\" with custom layout capability needs to add the \"@CustomLayout\" decorator (arkui-custom-layout-need-add-decorator)", "severity": "ERROR" }, { @@ -181,7 +181,7 @@ "endColumn": 21, "problem": "CustomLayoutNeedAddDecorator", "suggest": "", - "rule": "Custom components with custom layout capability need to add the \"@CustomLayout\" decorator (arkui-custom-layout-need-add-decorator)", + "rule": "The Custom component \"CustomLayout2\" with custom layout capability needs to add the \"@CustomLayout\" decorator (arkui-custom-layout-need-add-decorator)", "severity": "ERROR" }, { @@ -271,7 +271,7 @@ "endColumn": 21, "problem": "CustomLayoutNeedAddDecorator", "suggest": "", - "rule": "Custom components with custom layout capability need to add the \"@CustomLayout\" decorator (arkui-custom-layout-need-add-decorator)", + "rule": "The Custom component \"CustomLayout3\" with custom layout capability needs to add the \"@CustomLayout\" decorator (arkui-custom-layout-need-add-decorator)", "severity": "ERROR" }, { diff --git a/ets2panda/linter/test/main/custom_layout.ets.autofix.json b/ets2panda/linter/test/main/custom_layout.ets.autofix.json index ffcc8bf530..23fd6cb93c 100644 --- a/ets2panda/linter/test/main/custom_layout.ets.autofix.json +++ b/ets2panda/linter/test/main/custom_layout.ets.autofix.json @@ -221,7 +221,7 @@ } ], "suggest": "", - "rule": "Custom components with custom layout capability need to add the \"@CustomLayout\" decorator (arkui-custom-layout-need-add-decorator)", + "rule": "The Custom component \"CustomLayout1\" with custom layout capability needs to add the \"@CustomLayout\" decorator (arkui-custom-layout-need-add-decorator)", "severity": "ERROR" }, { @@ -368,7 +368,7 @@ } ], "suggest": "", - "rule": "Custom components with custom layout capability need to add the \"@CustomLayout\" decorator (arkui-custom-layout-need-add-decorator)", + "rule": "The Custom component \"CustomLayout2\" with custom layout capability needs to add the \"@CustomLayout\" decorator (arkui-custom-layout-need-add-decorator)", "severity": "ERROR" }, { @@ -557,7 +557,7 @@ } ], "suggest": "", - "rule": "Custom components with custom layout capability need to add the \"@CustomLayout\" decorator (arkui-custom-layout-need-add-decorator)", + "rule": "The Custom component \"CustomLayout3\" with custom layout capability needs to add the \"@CustomLayout\" decorator (arkui-custom-layout-need-add-decorator)", "severity": "ERROR" }, { -- Gitee From a1c49615aa391099a32abf96544b1a8fb4e21f7e Mon Sep 17 00:00:00 2001 From: Fouckttt Date: Wed, 25 Jun 2025 20:32:15 +0800 Subject: [PATCH 11/16] prompts for confirmation again Issue:https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICHTS6 Test scenarios:fix Signed-off-by: Fouckttt --- ets2panda/linter/package.json | 13 +++++++------ ets2panda/linter/src/cli/CommandLineParser.ts | 4 ++++ ets2panda/linter/src/cli/LinterCLI.ts | 8 ++++++++ ets2panda/linter/src/lib/CommandLineOptions.ts | 1 + ets2panda/linter/src/lib/LinterOptions.ts | 1 + 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/ets2panda/linter/package.json b/ets2panda/linter/package.json index 349629e7fc..039fd42eb2 100644 --- a/ets2panda/linter/package.json +++ b/ets2panda/linter/package.json @@ -50,11 +50,12 @@ }, "dependencies": { "commander": "^9.4.0", + "fs-extra": "11.2.0", "homecheck": "file:./homecheck", + "json5": "2.2.3", "log4js": "^6.4.0", - "yup": "^1.4.0", - "fs-extra": "11.2.0", - "json5": "2.2.3" + "readline-sync": "^1.4.10", + "yup": "^1.4.0" }, "devDependencies": { "@eslint/compat": "latest", @@ -67,15 +68,15 @@ "eslint-plugin-n": "^17.9.0", "eslint-plugin-no-null": "^1.0.2", "glob": "^11.0.0", + "nyc": "^15.1.0", "path-scurry": "^2.0.0", "prettier": "latest", "rimraf": "^5.0.10", "shelljs": "^0.8.5", + "source-map": "^0.7.4", "typescript-eslint": "latest", "webpack": "^5.75.0", - "webpack-cli": "^5.0.1", - "nyc": "^15.1.0", - "source-map": "^0.7.4" + "webpack-cli": "^5.0.1" }, "bundleDependencies": [ "log4js", diff --git a/ets2panda/linter/src/cli/CommandLineParser.ts b/ets2panda/linter/src/cli/CommandLineParser.ts index b039c332d4..85ed75fddf 100644 --- a/ets2panda/linter/src/cli/CommandLineParser.ts +++ b/ets2panda/linter/src/cli/CommandLineParser.ts @@ -137,6 +137,9 @@ function formIdeInteractive(cmdOptions: CommandLineOptions, commanderOpts: Optio if (commanderOpts.onlyArkts2SyntaxRules) { cmdOptions.linterOptions.onlySyntax = true; } + if (commanderOpts.autofixCheck) { + cmdOptions.linterOptions.autofixCheck = true; + } } function formArkts2Options(cmdOptions: CommandLineOptions, commanderOpts: OptionValues): void { @@ -287,6 +290,7 @@ function createCommand(): Command { option('--enable-interop', 'scan whole project to report 1.1 import 1.2'). option('--rule-config ', 'Path to the rule configuration file'). option('--autofix-rule-config ', 'Path to the auofix rule configuration file'). + option('--autofix-check', 'confirm whether the user needs automatic repair'). addOption(new Option('--warnings-as-errors', 'treat warnings as errors').hideHelp(true)). addOption(new Option('--no-check-ts-as-source', 'check TS files as third-party libary').hideHelp(true)). addOption(new Option('--no-use-rt-logic', 'run linter with SDK logic').hideHelp(true)). diff --git a/ets2panda/linter/src/cli/LinterCLI.ts b/ets2panda/linter/src/cli/LinterCLI.ts index 17edbb9b4b..447a2358d1 100644 --- a/ets2panda/linter/src/cli/LinterCLI.ts +++ b/ets2panda/linter/src/cli/LinterCLI.ts @@ -17,6 +17,7 @@ import { MigrationTool } from 'homecheck'; import * as fs from 'node:fs'; import * as os from 'node:os'; import * as path from 'node:path'; +import * as readlineSync from 'readline-sync'; import * as readline from 'node:readline'; import type { CommandLineOptions } from '../lib/CommandLineOptions'; import { getHomeCheckConfigInfo, transferIssues2ProblemInfo } from '../lib/HomeCheck'; @@ -40,6 +41,13 @@ export function run(): void { } const cmdOptions = parseCommandLine(commandLineArgs); + if (cmdOptions.linterOptions.migratorMode && cmdOptions.linterOptions.autofixCheck) { + const shouldRun = readlineSync.question('Do you want to run the linter and apply migration? (y/n): ').toLowerCase(); + if (shouldRun !== 'y') { + console.log('Linting canceled by user.'); + process.exit(0); + } + } if (cmdOptions.devecoPluginModeDeprecated) { runIdeModeDeprecated(cmdOptions); diff --git a/ets2panda/linter/src/lib/CommandLineOptions.ts b/ets2panda/linter/src/lib/CommandLineOptions.ts index d1fffdfd15..21ab3de973 100644 --- a/ets2panda/linter/src/lib/CommandLineOptions.ts +++ b/ets2panda/linter/src/lib/CommandLineOptions.ts @@ -34,4 +34,5 @@ export interface CommandLineOptions { verbose?: boolean; scanWholeProjectInHomecheck?: boolean; ruleConfig?: string; + autofixCheck?: boolean; } diff --git a/ets2panda/linter/src/lib/LinterOptions.ts b/ets2panda/linter/src/lib/LinterOptions.ts index 9c75ad3c98..6985f6463a 100644 --- a/ets2panda/linter/src/lib/LinterOptions.ts +++ b/ets2panda/linter/src/lib/LinterOptions.ts @@ -50,4 +50,5 @@ export interface LinterOptions { onlySyntax?: boolean; ruleConfigTags?: Set; autofixRuleConfigTags?: Set; + autofixCheck?: boolean; } -- Gitee From dc83a030e9c9a21c456a01260bee699d72b55114 Mon Sep 17 00:00:00 2001 From: beratagaca_9a91 Date: Mon, 23 Jun 2025 15:05:12 +0300 Subject: [PATCH 12/16] fix arkts-limited-stdlib-no-import-concurrency Description: merged pr !6283 resolved Issue: #ICH82P Signed-off-by: beratagaca_9a91 --- ets2panda/linter/src/lib/TypeScriptLinter.ts | 3 +-- .../linter/src/lib/utils/consts/LimitedStdAPI.ts | 3 +-- ...rt_arktsutils_locks_asynclock.ets.arkts2.json | 16 ++++++++-------- ...t_arktsutils_locks_asynclock.ets.autofix.json | 16 ++++++++-------- ...t_arktsutils_locks_asynclock.ets.migrate.json | 16 ++++++++-------- 5 files changed, 26 insertions(+), 28 deletions(-) diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index 33e1575db3..b9db2275c1 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -70,7 +70,6 @@ import { LIMITED_STD_PROXYHANDLER_API, LIMITED_STD_REFLECT_API, MODULE_IMPORTS, - ARKTSUTILS_TEXT, ARKTSUTILS_MODULES, ARKTSUTILS_LOCKS_MEMBER } from './utils/consts/LimitedStdAPI'; @@ -7290,7 +7289,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } }; - this.checkSymbolAndExecute(symbol, ARKTSUTILS_TEXT, ARKTSUTILS_MODULES, cb); + this.checkSymbolAndExecute(symbol, ARKTSUTILS_LOCKS_MEMBER, ARKTSUTILS_MODULES, cb); } private checkSymbolAndExecute(symbol: ts.Symbol, symbolName: string, modules: string[], cb: () => void): void { diff --git a/ets2panda/linter/src/lib/utils/consts/LimitedStdAPI.ts b/ets2panda/linter/src/lib/utils/consts/LimitedStdAPI.ts index 21007148eb..eeef04d78d 100644 --- a/ets2panda/linter/src/lib/utils/consts/LimitedStdAPI.ts +++ b/ets2panda/linter/src/lib/utils/consts/LimitedStdAPI.ts @@ -158,6 +158,5 @@ export const MODULE_IMPORTS: Record = { '@ohos.taskpool': ['taskpool'] }; -export const ARKTSUTILS_TEXT = 'ArkTSUtils'; -export const ARKTSUTILS_MODULES = ['@arkts.utils']; +export const ARKTSUTILS_MODULES = ['@arkts.utils', '@kit.ArkTS']; export const ARKTSUTILS_LOCKS_MEMBER = 'locks'; diff --git a/ets2panda/linter/test/concurrent/ no_support_arktsutils_locks_asynclock.ets.arkts2.json b/ets2panda/linter/test/concurrent/ no_support_arktsutils_locks_asynclock.ets.arkts2.json index c38018cfbc..31d218b8f0 100644 --- a/ets2panda/linter/test/concurrent/ no_support_arktsutils_locks_asynclock.ets.arkts2.json +++ b/ets2panda/linter/test/concurrent/ no_support_arktsutils_locks_asynclock.ets.arkts2.json @@ -15,20 +15,20 @@ ], "result": [ { - "line": 3, - "column": 17, - "endLine": 3, - "endColumn": 27, + "line": 18, + "column": 28, + "endLine": 18, + "endColumn": 33, "problem": "LimitedStdLibNoImportConcurrency", "suggest": "", "rule": "Import Concurrency is not required (arkts-limited-stdlib-no-import-concurrency)", "severity": "ERROR" }, { - "line": 5, - "column": 17, - "endLine": 5, - "endColumn": 27, + "line": 20, + "column": 28, + "endLine": 20, + "endColumn": 33, "problem": "LimitedStdLibNoImportConcurrency", "suggest": "", "rule": "Import Concurrency is not required (arkts-limited-stdlib-no-import-concurrency)", diff --git a/ets2panda/linter/test/concurrent/ no_support_arktsutils_locks_asynclock.ets.autofix.json b/ets2panda/linter/test/concurrent/ no_support_arktsutils_locks_asynclock.ets.autofix.json index c38018cfbc..31d218b8f0 100644 --- a/ets2panda/linter/test/concurrent/ no_support_arktsutils_locks_asynclock.ets.autofix.json +++ b/ets2panda/linter/test/concurrent/ no_support_arktsutils_locks_asynclock.ets.autofix.json @@ -15,20 +15,20 @@ ], "result": [ { - "line": 3, - "column": 17, - "endLine": 3, - "endColumn": 27, + "line": 18, + "column": 28, + "endLine": 18, + "endColumn": 33, "problem": "LimitedStdLibNoImportConcurrency", "suggest": "", "rule": "Import Concurrency is not required (arkts-limited-stdlib-no-import-concurrency)", "severity": "ERROR" }, { - "line": 5, - "column": 17, - "endLine": 5, - "endColumn": 27, + "line": 20, + "column": 28, + "endLine": 20, + "endColumn": 33, "problem": "LimitedStdLibNoImportConcurrency", "suggest": "", "rule": "Import Concurrency is not required (arkts-limited-stdlib-no-import-concurrency)", diff --git a/ets2panda/linter/test/concurrent/ no_support_arktsutils_locks_asynclock.ets.migrate.json b/ets2panda/linter/test/concurrent/ no_support_arktsutils_locks_asynclock.ets.migrate.json index c38018cfbc..31d218b8f0 100644 --- a/ets2panda/linter/test/concurrent/ no_support_arktsutils_locks_asynclock.ets.migrate.json +++ b/ets2panda/linter/test/concurrent/ no_support_arktsutils_locks_asynclock.ets.migrate.json @@ -15,20 +15,20 @@ ], "result": [ { - "line": 3, - "column": 17, - "endLine": 3, - "endColumn": 27, + "line": 18, + "column": 28, + "endLine": 18, + "endColumn": 33, "problem": "LimitedStdLibNoImportConcurrency", "suggest": "", "rule": "Import Concurrency is not required (arkts-limited-stdlib-no-import-concurrency)", "severity": "ERROR" }, { - "line": 5, - "column": 17, - "endLine": 5, - "endColumn": 27, + "line": 20, + "column": 28, + "endLine": 20, + "endColumn": 33, "problem": "LimitedStdLibNoImportConcurrency", "suggest": "", "rule": "Import Concurrency is not required (arkts-limited-stdlib-no-import-concurrency)", -- Gitee From 97280da50506674557ee47c5166da269c34f3395 Mon Sep 17 00:00:00 2001 From: liqing-yang Date: Mon, 23 Jun 2025 11:46:20 +0800 Subject: [PATCH 13/16] dynamic-args-to-static: only in 1.1 files Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICH20K Signed-off-by: liqing-yang --- .../checker/migration/InteropAssignCheck.ts | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/ets2panda/linter/homecheck/src/checker/migration/InteropAssignCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/InteropAssignCheck.ts index a17b9064ba..4a15f6af6a 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/InteropAssignCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/InteropAssignCheck.ts @@ -95,33 +95,35 @@ export class InteropAssignCheck implements BaseChecker { private checkPassToFunction(target: ArkMethod, scene: Scene) { const callsites = this.cg.getInvokeStmtByMethod(target.getSignature()); - callsites.forEach(cs => { - let hasTargetArg = false; - const invoke = cs.getInvokeExpr()!; - const csMethod = cs.getCfg().getDeclaringMethod(); - invoke.getArgs().forEach(arg => { - const argTy = arg.getType(); - if (argTy instanceof PrimitiveType || this.isBoxedType(argTy)) { + callsites + .filter(cs => cs.getCfg().getDeclaringMethod().getLanguage() === Language.ARKTS1_1) + .forEach(cs => { + let hasTargetArg = false; + const invoke = cs.getInvokeExpr()!; + const csMethod = cs.getCfg().getDeclaringMethod(); + invoke.getArgs().forEach(arg => { + const argTy = arg.getType(); + if (argTy instanceof PrimitiveType || this.isBoxedType(argTy)) { + return; + } + const argTyLang = this.getTypeDefinedLang(argTy, scene) ?? csMethod?.getLanguage() ?? Language.UNKNOWN; + if (argTyLang === Language.ARKTS1_1) { + hasTargetArg = true; + } + }); + if (!hasTargetArg) { return; } - const argTyLang = this.getTypeDefinedLang(argTy, scene) ?? csMethod?.getLanguage() ?? Language.UNKNOWN; - if (argTyLang === Language.ARKTS1_1) { - hasTargetArg = true; - } + let line = cs.getOriginPositionInfo().getLineNo(); + let column = cs.getOriginPositionInfo().getColNo(); + const problem = 'Interop'; + const desc = `${this.metaData.description} (${RULE_ID})`; + const severity = this.metaData.severity; + const ruleId = this.rule.ruleId; + const filePath = csMethod?.getDeclaringArkFile()?.getFilePath() ?? ''; + const defeats = new Defects(line, column, column, problem, desc, severity, ruleId, filePath, '', true, false, false); + this.issues.push(new IssueReport(defeats, undefined)); }); - if (!hasTargetArg) { - return; - } - let line = cs.getOriginPositionInfo().getLineNo(); - let column = cs.getOriginPositionInfo().getColNo(); - const problem = 'Interop'; - const desc = `${this.metaData.description} (${RULE_ID})`; - const severity = this.metaData.severity; - const ruleId = this.rule.ruleId; - const filePath = csMethod?.getDeclaringArkFile()?.getFilePath() ?? ''; - const defeats = new Defects(line, column, column, problem, desc, severity, ruleId, filePath, '', true, false, false); - this.issues.push(new IssueReport(defeats, undefined)); - }); } private isBoxedType(checkType: Type): boolean { -- Gitee From cce7b0e0e8ccd32cd1b1cf31edef179b967a7e34 Mon Sep 17 00:00:00 2001 From: zhongning Date: Sat, 21 Jun 2025 17:53:42 +0800 Subject: [PATCH 14/16] fix issue for InteropDirectAccessToTSTypes Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICCLV1 Test scenarios:Fix bugs for InteropDirectAccessToTSTypes Signed-off-by: zhongning --- ets2panda/linter/src/lib/TypeScriptLinter.ts | 48 +- .../test/interop/ignore_files/unique_types.ts | 223 ++++++- .../linter/test/interop/unique_types.ets | 389 ++++++++++- .../test/interop/unique_types.ets.arkts2.json | 530 ++++++++++++++- .../interop/unique_types.ets.autofix.json | 608 ++++++++++++++++-- .../linter/test/interop/unique_types.ets.json | 113 +++- .../test/interop/unique_types.ets.migrate.ets | 389 ++++++++++- .../interop/unique_types.ets.migrate.json | 468 +++++++++++++- .../literals_as_prop_names.ets.arkts2.json | 10 - .../literals_as_prop_names.ets.autofix.json | 10 - .../literals_as_prop_names.ets.migrate.json | 10 - 11 files changed, 2604 insertions(+), 194 deletions(-) diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index b9db2275c1..5cd9cdf633 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -1246,7 +1246,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const baseExprSym = this.tsUtils.trueSymbolAtLocation(propertyAccessNode.expression); const baseExprType = this.tsTypeChecker.getTypeAtLocation(propertyAccessNode.expression); this.handleTsInterop(propertyAccessNode, () => { - this.checkInteropForPropertyAccess(propertyAccessNode); + const type = this.tsTypeChecker.getTypeAtLocation(propertyAccessNode.expression); + this.checkUsageOfTsTypes(type, propertyAccessNode.expression); }); this.propertyAccessExpressionForInterop(propertyAccessNode); if (this.isPrototypePropertyAccess(propertyAccessNode, exprSym, baseExprSym, baseExprType)) { @@ -1263,7 +1264,6 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (this.options.advancedClassChecks && this.tsUtils.isClassObjectExpression(propertyAccessNode.expression)) { this.incrementCounters(propertyAccessNode.expression, FaultID.ClassAsObject); } - if (!!baseExprSym && TsUtils.symbolHasEsObjectType(baseExprSym)) { const faultId = this.options.arkts2 ? FaultID.EsValueTypeError : FaultID.EsValueType; this.incrementCounters(propertyAccessNode, faultId); @@ -1405,44 +1405,16 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } } - private checkInteropForPropertyAccess(pan: ts.PropertyAccessExpression): void { - if (ts.isBinaryExpression(pan.parent)) { - this.checkAssignmentOfPan(pan.parent, pan); - } else { - const type = this.tsTypeChecker.getTypeAtLocation(pan.expression); - this.checkUsageOfTsTypes(type, pan.expression); - } - } - - private checkAssignmentOfPan(binaryExpr: ts.BinaryExpression, pan: ts.PropertyAccessExpression): void { - if (binaryExpr.left !== pan) { - return; - } - - if (binaryExpr.operatorToken.kind !== ts.SyntaxKind.EqualsToken) { - this.incrementCounters(pan, FaultID.InteropDirectAccessToTSTypes); - return; - } - - const rhs = binaryExpr.right; - const lhs = binaryExpr.left as ts.PropertyAccessExpression; - - const autofix = this.autofixer?.fixInteropTsType(binaryExpr, lhs, rhs); - this.incrementCounters(pan, FaultID.InteropDirectAccessToTSTypes, autofix); - } - private checkUsageOfTsTypes(baseType: ts.Type, node: ts.Node): void { - if (this.tsUtils.isStringType(baseType)) { - return; - } - if (this.tsUtils.isStdNumberType(baseType)) { - return; - } - if (this.tsUtils.isStdBooleanType(baseType)) { - return; + const typeString = this.tsTypeChecker.typeToString(baseType); + if ( + TsUtils.isAnyType(baseType) || + TsUtils.isUnknownType(baseType) || + this.tsUtils.isStdFunctionType(baseType) || + typeString === 'symbol' + ) { + this.incrementCounters(node, FaultID.InteropDirectAccessToTSTypes); } - - this.incrementCounters(node, FaultID.InteropDirectAccessToTSTypes); } checkUnionTypes(propertyAccessNode: ts.PropertyAccessExpression): void { diff --git a/ets2panda/linter/test/interop/ignore_files/unique_types.ts b/ets2panda/linter/test/interop/ignore_files/unique_types.ts index 1c19752b63..f56856f73a 100644 --- a/ets2panda/linter/test/interop/ignore_files/unique_types.ts +++ b/ets2panda/linter/test/interop/ignore_files/unique_types.ts @@ -13,24 +13,217 @@ * limitations under the License. */ -type SomeType = { - name: string, +// any 类型 +let any_var: any = 10; +any_var = "string"; +export {any_var} + +// unknown类型 +export let unknown_var:unknown = 10; + +// Symbol类型 +export let symbol_var: symbol = Symbol("description"); + +// Function类型 +export let function_var: Function = function() { + console.log("Hello, World!"); + return true; +}; + +export class A { + static instance = new A(); } -enum X { - a = 0, - b = '1', +export interface B { + name:string } -type UnionString = "A" | "B"; -type TemplateLiteralType = `${UnionString}_id`; +//用例一 +export function throw_number() { + throw 123; +} -export let objectLiteralType: SomeType; -export let mixedEnumType: X; -export let intersectionType: SomeType & X; -export let templateLiteralType: TemplateLiteralType; +export function throw_string() { + throw "error"; +} -export function tsFunction() { - throw 123; -}; -export let stringType: string; +export function throw_boolean() { + throw true; +} + +export function throw_bigint() { + throw 111n; +} + +export function throw_obj() { + throw { name:'error' }; +} + +export function throw_error() { + throw new Error("error"); +} + +export class SubError extends Error { + extraField: number = 123; + foo() { return 456; } +} + +export function throwErrorSubClass() { + throw new SubError(); +} +export function throwRangeError() { + throw new RangeError(); +} + +//用例二 +export class ObjectLiteralClass { + name:string = "" +} + +export interface ObjectLiteralInter { + name:string +} +//用例三 +//类装饰器 +export function MyClassDecorator(klass: Object) {} + +//属性装饰器 +export function propertyDecorator(target: Object, propertyKey: string) { + console.log(Property Decorator called on: ${target.constructor.name} with propertyKey: ${propertyKey}); +} + +//方法装饰器 +export function methodDecorator(target: Object, propertyKey: string , descriptor: PropertyDescriptor) { + console.log(Method Decorator called on: ${target.constructor.name} with propertyKey: ${propertyKey}); + descriptor.value = function (...args: any[]) { + console.log(Called: ${propertyKey} with, args); + return args[0] * 2; + }; + return descriptor; +} + +// 参数装饰器 +export function parameterDecorator(target: Object, propertyKey: string , parameterIndex: number) { + console.log(Parameter Decorator called on: ${target.constructor.name} with propertyKey: ${propertyKey} and parameterIndex: ${parameterIndex}); +} + +// 访问器装饰器 +export function accessorDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) { + const originalGet = descriptor.get; + const originalSet = descriptor.set; + + descriptor.get = function() { + console.log(Getter for ${propertyKey} called.); + return originalGet.apply(this); + }; + descriptor.set = function(value) { + console.log(Setter for ${propertyKey} called with value: ${value}); + originalSet.apply(this, [value]); + }; + return descriptor; +} + +// 装饰器工厂 +export function readonly1(isReadonly: boolean) { + return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { + if (isReadonly) { + descriptor.writable = false; + } + }; +} + +export let num_boxed = new Number(123) +export let bool_boxed = new Boolean(true) +export let str_boxed = new String('hello') +export let bigint_boxed = BigInt(123n) + +export function ts_object_method(prx: any) { + Object.getOwnPropertyDescriptor(prx, "a") // arkts-interop-ts2s-ts-object-on-static-instance * 2 + arkts-limited-stdlib not undefined + Object.getOwnPropertyDescriptors(prx) // arkts-interop-ts2s-ts-object-on-static-instance * 2 not {} + Object.getOwnPropertyNames(prx) // arkts-interop-ts2s-ts-object-on-static-instance * 2 ["a"] + Object.hasOwn(prx, "a") // true + Object.isExtensible(prx) // arkts-interop-ts2s-ts-object-on-static-instance * 2 true + Object.isFrozen(prx) // arkts-interop-ts2s-ts-object-on-static-instance * 2 false + Object.isSealed(prx) // arkts-interop-ts2s-ts-object-on-static-instance * 2 false + Object.keys(prx) // arkts-interop-ts2s-ts-object-on-static-instance * 2 ["a"] + Object.setPrototypeOf(prx, {}) // arkts-interop-ts2s-ts-object-on-static-instance * 2 + arkts-limited-stdlib OK + Object.values(prx) // arkts-interop-ts2s-ts-object-on-static-instance * 2 + arkts-no-inferred-generic-params [1] + prx.hasOwnProperty("a") // true + prx.propertyIsEnumerable("a") // true +} + +export function ts_object_method_getOwnPropertyDescriptor(prx: any) { + return Object.getOwnPropertyDescriptor(prx, "a") // arkts-interop-ts2s-ts-object-on-static-instance * 2 + arkts-limited-stdlib not undefined +} +export function ts_object_method_getOwnPropertyDescriptors(prx: any) { + return Object.getOwnPropertyDescriptors(prx)// arkts-interop-ts2s-ts-object-on-static-instance * 2 + arkts-limited-stdlib not {} +} +export function ts_object_method_getOwnPropertyNames(prx: any) { + return Object.getOwnPropertyNames(prx) // arkts-interop-ts2s-ts-object-on-static-instance * 2 ["a"] +} +export function ts_object_method_hasOwn(prx: any) { + return Object.hasOwn(prx, "a") // true +} +export function ts_object_method_isExtensible(prx: any) { + return Object.isExtensible(prx) // arkts-interop-ts2s-ts-object-on-static-instance * 2 + arkts-limited-stdlib true +} +export function ts_object_method_isFrozen(prx: any) { + return Object.isFrozen(prx) // arkts-interop-ts2s-ts-object-on-static-instance * 2 + arkts-limited-stdlib false +} + +export function ts_object_method_isSealed(prx: any) { + return Object.isSealed(prx) // arkts-interop-ts2s-ts-object-on-static-instance * 2 + arkts-limited-stdlib false +} + +export function ts_object_method_keys(prx: any) { + return Object.keys(prx) // arkts-interop-ts2s-ts-object-on-static-instance * 3 ["a"] +} + +export function ts_object_method_setPrototypeOf(prx: any) { + return Object.setPrototypeOf(prx, {}) // arkts-limited-stdlib OK +} + +export function ts_object_method_values(prx: any) { + return Object.values(prx) // arkts-interop-ts2s-ts-object-on-static-instance * 2 + arkts-no-inferred-generic-params [1] +} + +interface Iface { + a:number +} +export let interObj:Iface = {a:1} + +export function ts_reflect_method(prx: any) { + Reflect.apply(prx.getName, {a: 12}) // arkts-interop-ts2s-ts-object-on-static-instance * 2 12 + Reflect.defineProperty(prx, 'newField', {value: 7}) // arkts-interop-ts2s-ts-object-on-static-instance * 2 true + Reflect.deleteProperty(prx, "a") // arkts-interop-ts2s-ts-object-on-static-instance * 2 true + Reflect.getOwnPropertyDescriptor(prx, "a") // arkts-interop-ts2s-ts-object-on-static-instance * 2 not undefined + Reflect.ownKeys(prx) // arkts-interop-ts2s-ts-object-on-static-instance * 2 ['a'] + Reflect.isExtensible(prx) // arkts-interop-ts2s-ts-object-on-static-instance * 2 true + Reflect.set(prx, 'newField', 7) // arkts-interop-ts2s-ts-object-on-static-instance * 2 true + Reflect.setPrototypeOf(prx, {}) // arkts-interop-ts2s-ts-object-on-static-instance * 2 true +} + +export function ts_reflect_method_apply(prx: any) { + Reflect.apply(prx.getName, {a: 12}) // arkts-interop-ts2s-ts-object-on-static-instance * 2 12 +} +export function ts_reflect_method_defineProperty(prx: any) { + Reflect.defineProperty(prx, 'newField', {value: 7}) // arkts-interop-ts2s-ts-object-on-static-instance * 2 true +} +export function ts_reflect_method_deleteProperty(prx: any) { + Reflect.deleteProperty(prx, "a") // arkts-interop-ts2s-ts-object-on-static-instance * 2 true +} +export function ts_reflect_method_getOwnPropertyDescriptor(prx: any) { + Reflect.getOwnPropertyDescriptor(prx, "a") // arkts-interop-ts2s-ts-object-on-static-instance * 2 not undefined +} +export function ts_reflect_method_ownKeys(prx: any) { + Reflect.ownKeys(prx) // arkts-interop-ts2s-ts-object-on-static-instance * 2 ['a'] +} +export function ts_reflect_method_isExtensible(prx: any) { + Reflect.isExtensible(prx) // arkts-interop-ts2s-ts-object-on-static-instance * 2 true +} +export function ts_reflect_method_set(prx: any) { + Reflect.set(prx, 'newField', 7) // arkts-interop-ts2s-ts-object-on-static-instance * 2 true +} +export function ts_reflect_method_setPrototypeOf(prx: any) { + Reflect.setPrototypeOf(prx, {}) // arkts-interop-ts2s-ts-object-on-static-instance * 2 true +} \ No newline at end of file diff --git a/ets2panda/linter/test/interop/unique_types.ets b/ets2panda/linter/test/interop/unique_types.ets index da2c034f53..9c16a54d2b 100644 --- a/ets2panda/linter/test/interop/unique_types.ets +++ b/ets2panda/linter/test/interop/unique_types.ets @@ -14,22 +14,387 @@ */ import { - objectLiteralType, - intersectionType, - tsFunction, - stringType, - enumType + any_var, + unknown_var, + symbol_var, + function_var, + A, + B, + TestHelper, + throw_number, + throw_string, + throw_boolean, + throw_bigint, + throw_obj, + throw_error, + throwErrorSubClass, + SubError, + throwRangeError, + ObjectLiteralClass, + ObjectLiteralInter, + MyClassDecorator, + propertyDecorator, + methodDecorator, + parameterDecorator, + accessorDecorator, + readonly1, + num_boxed, + bool_boxed, + str_boxed, + bigint_boxed, + ts_object_method, + ts_object_method_getOwnPropertyDescriptor, + ts_object_method_getOwnPropertyDescriptors, + ts_object_method_getOwnPropertyNames, + ts_object_method_hasOwn, + ts_object_method_isExtensible, + ts_object_method_isFrozen, + ts_object_method_isSealed, + ts_object_method_keys, + ts_object_method_values, + interObj, + ts_reflect_method, + ts_reflect_method_apply, + ts_reflect_method_defineProperty, + ts_reflect_method_deleteProperty, + ts_reflect_method_getOwnPropertyDescriptor, + ts_reflect_method_ownKeys, + ts_reflect_method_isExtensible, + ts_reflect_method_set, + ts_reflect_method_setPrototypeOf } from "./ignore_files/unique_types"; -objectLiteralType.name = "test" -intersectionType.name = "test"; +typeof any_var === 'object'; +typeof unknown_var === 'number'; +typeof symbol_var === 'object'; +function_var() === true; +A.instance; +let obj: B = { name: "hello" }; -try { -tsFunction(); -} catch (e) { +export function test_ts_non_standard_exception(testCaseRet: Array) { + let test_helper = new TestHelper("TEST_TS_NON_STANDARD_EXCEPTION"); + + test_helper.test(() => { + try { + throw_number(); // arkts-interop-ts2s-ts-exception + } catch (e) { + return e as number === 123; + } + return false; + }, "e as number === 123"); + + test_helper.test(() => { + try { + throw_boolean(); // arkts-interop-ts2s-ts-exception + } catch (e) { + return e as boolean === true; + } + return false; + }, "e as boolean === true"); + + test_helper.test(() => { + try { + throw_bigint(); // arkts-interop-ts2s-ts-exception + } catch (e) { + return e as bigint === 111n; + } + return false; + }, "e as bigint === 111n"); + + test_helper.test(() => { + try { + throw_string(); // arkts-interop-ts2s-ts-exception + } catch (e) { + return e as string === "error"; + } + return false; + }, "e as string === "error""); + + test_helper.test(() => { + try { + throw_obj(); // arkts-interop-ts2s-ts-exception + } catch (e) { + return e.name === "error"; + } + return false; + }, "e.name === "error""); + + test_helper.test(() => { + try { + throw_error(); + } catch (e) { + let errObj: Error = e as Error; + return errObj.name === "error"; + } + return false; + }, "errObj.name === "error""); + + test_helper.test(() => { + try { + throwErrorSubClass(); // arkts-interop-ts2s-ts-exception + } catch (e) { + let errObj = e as SubError; + return errObj.extraField === 123 && errObj.foo() === 456; + } + return false; + }, "errObj.extraField === 123 && errObj.foo() === 456"); + + test_helper.test(() => { + let flag = false + try { + throwRangeError(); // arkts-interop-ts2s-ts-exception + } catch (e) { + let errObj: RangeError = e as RangeError; + return errObj instanceof RangeError; + } + return flag; + }, "Throw: throwRangeError"); + + testCaseRet.push(test_helper.done()); +} + +export function test_object_literal(testCaseRet: Array) { + let test_helper = new TestHelper("TEST_OBJECT_LITERAL"); + + test_helper.test(() => { + let obj: ObjectLiteralClass = { name: "hello" }; // arkts-obj-literal-generate-class-instance + return obj.name === "hello" && obj instanceof ObjectLiteralClass; + }, "obj.name === "hello""); + + test_helper.test(() => { + let obj: ObjectLiteralInter = { name: "hello" }; // arkts-obj-literal-generate-class-instance + return obj.name === "hello" && obj instanceof ObjectLiteralInter; + }, "obj.name === "hello""); + + testCaseRet.push(test_helper.done()); +} + +// 1 ArkTS使用TS装饰器 +// 规则名 arkts-interop-ts2s-no-ts-decorator +// case 1 类装饰器 top level +@MyClassDecorator // arkts-no-ts-decorators + arkts-interop-ts2s-no-ts-decorator +class K {} + +//case 2 类属性装饰器 +class MyClass { + @propertyDecorator// arkts-no-ts-decorators + myProperty: string; +} + +//case 3 方法装饰器 +class MathFunctions { + @methodDecorator// arkts-no-ts-decorators + double1(value: number): number { + return value; + } +} + +//case 4 方法装饰器 +class MyClass1 { + log(value: string, @parameterDecorator metadata: any) {// arkts-no-ts-decorators + console.log(Logged: ${value}); + } +} + +//case 5 访问器装饰器 +class Person { + private _name: string; + @accessorDecorator// arkts-no-ts-decorators + get name(): string { + return this._name; + } + set name(value: string) { + this._name = value; + } +} + +//case 6 访问器工厂 +class Person1 { + private _age: number; + @readonly(true)// arkts-no-ts-decorators + get age(): number { + return this._age; + } + set age(value: number) { + this._age = value; + } +} + +namespace NS{ + // case 7 类装饰器 top level + @MyClassDecorator// arkts-no-ts-decorators + arkts-interop-ts2s-no-ts-decorator + class K {} + + //case 8 类属性装饰器 + class MyClass { + @propertyDecorator// arkts-no-ts-decorators + myProperty: string; + } + + //case 9 方法装饰器 + class MathFunctions { + @methodDecorator// arkts-no-ts-decorators + double1(value: number): number { + return value; + } + } + + //case 10 方法装饰器 + class MyClass1 { + log(value: string, @parameterDecorator metadata: any) {// arkts-no-ts-decorators + console.log(Logged: ${value}); + } + } + + //case 11 访问器装饰器 + class Person { + private _name: string; + constructor(name: string) { + this._name = name; + } + @accessorDecorator// arkts-no-ts-decorators + get name(): string { + return this._name; + } + set name(value: string) { + this._name = value; + } + } + + //case 12 访问器工厂 + class Person1 { + private _age: number; + constructor(age: number) { + this._age = age; + } + @readonly1(true)// arkts-no-ts-decorators + get age(): number { + return this._age; + } + set age(value: number) { + this._age = value; + } + } +} + +export function test_ts_boxed_type(testCaseRet: Array) { + let test_helper = new TestHelper("TEST_TS_BOXED_TYPE"); + + test_helper.test(() => { + return typeof num_boxed === object; + }, "typeof num_boxed === object"); + + test_helper.test(() => { + return typeof bool_boxed === object; + }, "typeof bool_boxed === object"); + + test_helper.test(() => { + return typeof str_boxed === object; + }, "typeof str_boxed === object"); + + test_helper.test(() => { + return typeof bigint_boxed === object; + }, "typeof bigint_boxed === object"); + testCaseRet.push(test_helper.done()); +} + +export function test_ts_object_method(testCaseRet: Array) { + let test_helper = new TestHelper("TEST_TS_OBJECT_METHOD"); + + test_helper.test(() => { + ts_object_method(new Object2()) + ts_object_method_getOwnPropertyDescriptor(new Object2()) + ts_object_method_getOwnPropertyDescriptors(new Object2()) + ts_object_method_getOwnPropertyNames(new Object2()) + ts_object_method_hasOwn(new Object2()) + ts_object_method_isExtensible(new Object2()) + ts_object_method_isFrozen(new Object2()) + ts_object_method_isSealed(new Object2()) + ts_object_method_keys(new Object2()) + ts_object_method_keys(new Object2()) + ts_object_method_values(new Object2()) + return true; + }, "true"); + + test_helper.test(() => { + interface Iface { + a:number + } + let a1:Iface = {a:1} + ts_object_method(a1) + ts_object_method_getOwnPropertyDescriptor(a1) + ts_object_method_getOwnPropertyDescriptors(a1) + ts_object_method_getOwnPropertyNames(a1) + ts_object_method_hasOwn(a1) + ts_object_method_isExtensible(a1) + ts_object_method_isFrozen(a1) + ts_object_method_isSealed(a1) + ts_object_method_keys(a1) + ts_object_method_keys(a1) + ts_object_method_values(a1) + return true; + }, "true"); + + test_helper.test(() => { + ts_object_method(interObj) + return true; + }, "false"); + + testCaseRet.push(test_helper.done()); +} + +class Reflect2 { + a: string = 'hello' + getName() { return this.a } } -stringType = "test" //should pass +// 5 Object内置方法作用在ArkTS对象 +// 规则名 arkts-interop-ts2s-ts-object-on-static-instance +export function test_ts_reflect_method(testCaseRet: Array) { + let test_helper = new TestHelper("TEST_TS_REFLECT_METHOD"); + test_helper.test(() => { + ts_reflect_method(new Reflect2()) + ts_reflect_method_apply(new Reflect2()) + ts_reflect_method_defineProperty(new Reflect2()) + ts_reflect_method_deleteProperty(new Reflect2()) + ts_reflect_method_getOwnPropertyDescriptor(new Reflect2()) + ts_reflect_method_ownKeys(new Reflect2()) + ts_reflect_method_isExtensible(new Reflect2()) + ts_reflect_method_set(new Reflect2()) + ts_reflect_method_setPrototypeOf(new Reflect2()) + return true; + }, "reflect class 1.2 "); + + test_helper.test(() => { + interface Iface { + a:number + } + let a1:Iface = {a:1} + ts_reflect_method(a1) + ts_reflect_method_apply(a1) + ts_reflect_method_defineProperty(a1) + ts_reflect_method_deleteProperty(a1) + ts_reflect_method_getOwnPropertyDescriptor(a1) + ts_reflect_method_ownKeys(a1) + ts_reflect_method_isExtensible(a1) + ts_reflect_method_set(a1) + ts_reflect_method_setPrototypeOf(a1) + return true; + }, "reflect interface 1.2"); + + test_helper.test(() => { + ts_reflect_method(interObj) + ts_reflect_method_apply(interObj) + ts_reflect_method_defineProperty(interObj) + ts_reflect_method_deleteProperty(interObj) + ts_reflect_method_getOwnPropertyDescriptor(interObj) + ts_reflect_method_ownKeys(interObj) + ts_reflect_method_isExtensible(interObj) + ts_reflect_method_set(interObj) + ts_reflect_method_setPrototypeOf(interObj) + return true; + }, "reflect interObj 1.0 "); -enumType = "A"; //should fail + testCaseRet.push(test_helper.done()); +} \ No newline at end of file diff --git a/ets2panda/linter/test/interop/unique_types.ets.arkts2.json b/ets2panda/linter/test/interop/unique_types.ets.arkts2.json index b3274fd874..7fb34afcb3 100644 --- a/ets2panda/linter/test/interop/unique_types.ets.arkts2.json +++ b/ets2panda/linter/test/interop/unique_types.ets.arkts2.json @@ -15,63 +15,543 @@ ], "result": [ { - "line": 24, - "column": 1, - "endLine": 24, - "endColumn": 23, + "line": 68, + "column": 8, + "endLine": 68, + "endColumn": 15, "problem": "InteropDirectAccessToTSTypes", "suggest": "", "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", "severity": "ERROR" }, { - "line": 26, - "column": 1, - "endLine": 26, - "endColumn": 22, + "line": 69, + "column": 8, + "endLine": 69, + "endColumn": 19, + "problem": "InteropDirectAccessToTSTypes", + "suggest": "", + "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", + "severity": "ERROR" + }, + { + "line": 70, + "column": 8, + "endLine": 70, + "endColumn": 18, "problem": "InteropDirectAccessToTSTypes", "suggest": "", "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", "severity": "ERROR" }, { - "line": 29, + "line": 71, "column": 1, - "endLine": 29, + "endLine": 71, "endColumn": 13, - "problem": "InteropTSFunctionInvoke", + "problem": "ExplicitFunctionType", "suggest": "", - "rule": "Trying to catch typescript errors is not permitted (arkts-interop-ts2s-ts-exception)", + "rule": "The function type should be explicit (arkts-no-ts-like-function-call)", "severity": "ERROR" }, { - "line": 29, + "line": 71, "column": 1, - "endLine": 29, - "endColumn": 11, + "endLine": 71, + "endColumn": 13, "problem": "InteropDirectAccessToTSTypes", "suggest": "", "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", "severity": "ERROR" }, { - "line": 33, + "line": 76, + "column": 7, + "endLine": 76, + "endColumn": 69, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 76, + "column": 25, + "endLine": 76, + "endColumn": 35, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 80, + "column": 7, + "endLine": 80, + "endColumn": 21, + "problem": "InteropTSFunctionInvoke", + "suggest": "", + "rule": "Trying to catch typescript errors is not permitted (arkts-interop-ts2s-ts-exception)", + "severity": "ERROR" + }, + { + "line": 82, + "column": 30, + "endLine": 82, + "endColumn": 33, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 89, + "column": 7, + "endLine": 89, + "endColumn": 22, + "problem": "InteropTSFunctionInvoke", + "suggest": "", + "rule": "Trying to catch typescript errors is not permitted (arkts-interop-ts2s-ts-exception)", + "severity": "ERROR" + }, + { + "line": 98, + "column": 7, + "endLine": 98, + "endColumn": 21, + "problem": "InteropTSFunctionInvoke", + "suggest": "", + "rule": "Trying to catch typescript errors is not permitted (arkts-interop-ts2s-ts-exception)", + "severity": "ERROR" + }, + { + "line": 107, + "column": 7, + "endLine": 107, + "endColumn": 21, + "problem": "InteropTSFunctionInvoke", + "suggest": "", + "rule": "Trying to catch typescript errors is not permitted (arkts-interop-ts2s-ts-exception)", + "severity": "ERROR" + }, + { + "line": 116, + "column": 7, + "endLine": 116, + "endColumn": 18, + "problem": "InteropTSFunctionInvoke", + "suggest": "", + "rule": "Trying to catch typescript errors is not permitted (arkts-interop-ts2s-ts-exception)", + "severity": "ERROR" + }, + { + "line": 138, + "column": 36, + "endLine": 138, + "endColumn": 39, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 138, + "column": 60, + "endLine": 138, + "endColumn": 63, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 158, + "column": 7, + "endLine": 158, + "endColumn": 58, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 158, + "column": 25, + "endLine": 158, + "endColumn": 35, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 176, "column": 1, - "endLine": 33, + "endLine": 176, + "endColumn": 18, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 181, + "column": 3, + "endLine": 181, + "endColumn": 21, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 187, + "column": 3, + "endLine": 187, + "endColumn": 19, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 195, + "column": 22, + "endLine": 195, + "endColumn": 41, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 195, + "column": 52, + "endLine": 195, + "endColumn": 55, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 203, + "column": 3, + "endLine": 203, + "endColumn": 21, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 215, + "column": 3, + "endLine": 215, + "endColumn": 18, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 226, + "column": 3, + "endLine": 226, "endColumn": 20, - "problem": "InteropDirectAccessToTSTypes", + "problem": "DecoratorsNotSupported", "suggest": "", - "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", "severity": "ERROR" }, { - "line": 33, - "column": 1, - "endLine": 33, - "endColumn": 11, - "problem": "InteropDirectAccessToTSTypes", + "line": 231, + "column": 5, + "endLine": 231, + "endColumn": 23, + "problem": "DecoratorsNotSupported", "suggest": "", - "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 237, + "column": 5, + "endLine": 237, + "endColumn": 21, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 245, + "column": 24, + "endLine": 245, + "endColumn": 43, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 245, + "column": 54, + "endLine": 245, + "endColumn": 57, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 256, + "column": 5, + "endLine": 256, + "endColumn": 23, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 271, + "column": 5, + "endLine": 271, + "endColumn": 21, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 282, + "column": 7, + "endLine": 282, + "endColumn": 57, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 282, + "column": 25, + "endLine": 282, + "endColumn": 35, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 303, + "column": 7, + "endLine": 303, + "endColumn": 60, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 303, + "column": 25, + "endLine": 303, + "endColumn": 35, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 306, + "column": 26, + "endLine": 306, + "endColumn": 33, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 307, + "column": 51, + "endLine": 307, + "endColumn": 58, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 308, + "column": 52, + "endLine": 308, + "endColumn": 59, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 309, + "column": 46, + "endLine": 309, + "endColumn": 53, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 310, + "column": 33, + "endLine": 310, + "endColumn": 40, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 311, + "column": 39, + "endLine": 311, + "endColumn": 46, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 312, + "column": 35, + "endLine": 312, + "endColumn": 42, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 313, + "column": 35, + "endLine": 313, + "endColumn": 42, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 314, + "column": 31, + "endLine": 314, + "endColumn": 38, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 315, + "column": 31, + "endLine": 315, + "endColumn": 38, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 316, + "column": 33, + "endLine": 316, + "endColumn": 40, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 324, + "column": 23, + "endLine": 324, + "endColumn": 24, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 355, + "column": 7, + "endLine": 355, + "endColumn": 61, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 355, + "column": 25, + "endLine": 355, + "endColumn": 35, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 373, + "column": 23, + "endLine": 373, + "endColumn": 24, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 182, + "column": 3, + "endLine": 182, + "endColumn": 13, + "problem": "StrictDiagnostic", + "suggest": "Property 'myProperty' has no initializer and is not definitely assigned in the constructor.", + "rule": "Property 'myProperty' has no initializer and is not definitely assigned in the constructor.", + "severity": "ERROR" + }, + { + "line": 202, + "column": 11, + "endLine": 202, + "endColumn": 16, + "problem": "StrictDiagnostic", + "suggest": "Property '_name' has no initializer and is not definitely assigned in the constructor.", + "rule": "Property '_name' has no initializer and is not definitely assigned in the constructor.", + "severity": "ERROR" + }, + { + "line": 214, + "column": 11, + "endLine": 214, + "endColumn": 15, + "problem": "StrictDiagnostic", + "suggest": "Property '_age' has no initializer and is not definitely assigned in the constructor.", + "rule": "Property '_age' has no initializer and is not definitely assigned in the constructor.", + "severity": "ERROR" + }, + { + "line": 232, + "column": 5, + "endLine": 232, + "endColumn": 15, + "problem": "StrictDiagnostic", + "suggest": "Property 'myProperty' has no initializer and is not definitely assigned in the constructor.", + "rule": "Property 'myProperty' has no initializer and is not definitely assigned in the constructor.", "severity": "ERROR" } ] diff --git a/ets2panda/linter/test/interop/unique_types.ets.autofix.json b/ets2panda/linter/test/interop/unique_types.ets.autofix.json index 3bd21d1617..bdb124b2ed 100644 --- a/ets2panda/linter/test/interop/unique_types.ets.autofix.json +++ b/ets2panda/linter/test/interop/unique_types.ets.autofix.json @@ -15,85 +15,609 @@ ], "result": [ { - "line": 24, - "column": 1, - "endLine": 24, - "endColumn": 23, + "line": 68, + "column": 8, + "endLine": 68, + "endColumn": 15, + "problem": "InteropDirectAccessToTSTypes", + "suggest": "", + "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", + "severity": "ERROR" + }, + { + "line": 69, + "column": 8, + "endLine": 69, + "endColumn": 19, "problem": "InteropDirectAccessToTSTypes", + "suggest": "", + "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", + "severity": "ERROR" + }, + { + "line": 70, + "column": 8, + "endLine": 70, + "endColumn": 18, + "problem": "InteropDirectAccessToTSTypes", + "suggest": "", + "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", + "severity": "ERROR" + }, + { + "line": 71, + "column": 1, + "endLine": 71, + "endColumn": 13, + "problem": "ExplicitFunctionType", "autofix": [ { - "start": 731, - "end": 762, - "replacementText": "objectLiteralType.setProperty('name',ESValue.wrap(\"test\"))", - "line": 24, + "start": 1767, + "end": 1779, + "replacementText": "function_var.unsafeCall", + "line": 71, "column": 1, - "endLine": 24, - "endColumn": 23 + "endLine": 71, + "endColumn": 13 } ], "suggest": "", - "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", + "rule": "The function type should be explicit (arkts-no-ts-like-function-call)", "severity": "ERROR" }, { - "line": 26, + "line": 71, "column": 1, - "endLine": 26, - "endColumn": 22, + "endLine": 71, + "endColumn": 13, "problem": "InteropDirectAccessToTSTypes", + "suggest": "", + "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", + "severity": "ERROR" + }, + { + "line": 76, + "column": 7, + "endLine": 76, + "endColumn": 69, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 76, + "column": 25, + "endLine": 76, + "endColumn": 35, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 80, + "column": 7, + "endLine": 80, + "endColumn": 21, + "problem": "InteropTSFunctionInvoke", + "suggest": "", + "rule": "Trying to catch typescript errors is not permitted (arkts-interop-ts2s-ts-exception)", + "severity": "ERROR" + }, + { + "line": 82, + "column": 30, + "endLine": 82, + "endColumn": 33, + "problem": "NumericSemantics", "autofix": [ { - "start": 764, - "end": 794, - "replacementText": "intersectionType.setProperty('name',ESValue.wrap(\"test\"))", - "line": 26, - "column": 1, - "endLine": 26, - "endColumn": 22 + "start": 2118, + "end": 2121, + "replacementText": "123.0", + "line": 82, + "column": 30, + "endLine": 82, + "endColumn": 33 } ], "suggest": "", - "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" }, { - "line": 29, - "column": 1, - "endLine": 29, - "endColumn": 13, + "line": 89, + "column": 7, + "endLine": 89, + "endColumn": 22, "problem": "InteropTSFunctionInvoke", "suggest": "", "rule": "Trying to catch typescript errors is not permitted (arkts-interop-ts2s-ts-exception)", "severity": "ERROR" }, { - "line": 29, - "column": 1, - "endLine": 29, - "endColumn": 11, - "problem": "InteropDirectAccessToTSTypes", + "line": 98, + "column": 7, + "endLine": 98, + "endColumn": 21, + "problem": "InteropTSFunctionInvoke", "suggest": "", - "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", + "rule": "Trying to catch typescript errors is not permitted (arkts-interop-ts2s-ts-exception)", "severity": "ERROR" }, { - "line": 33, + "line": 107, + "column": 7, + "endLine": 107, + "endColumn": 21, + "problem": "InteropTSFunctionInvoke", + "suggest": "", + "rule": "Trying to catch typescript errors is not permitted (arkts-interop-ts2s-ts-exception)", + "severity": "ERROR" + }, + { + "line": 116, + "column": 7, + "endLine": 116, + "endColumn": 18, + "problem": "InteropTSFunctionInvoke", + "suggest": "", + "rule": "Trying to catch typescript errors is not permitted (arkts-interop-ts2s-ts-exception)", + "severity": "ERROR" + }, + { + "line": 138, + "column": 36, + "endLine": 138, + "endColumn": 39, + "problem": "NumericSemantics", + "autofix": [ + { + "start": 3384, + "end": 3387, + "replacementText": "123.0", + "line": 138, + "column": 36, + "endLine": 138, + "endColumn": 39 + } + ], + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 138, + "column": 60, + "endLine": 138, + "endColumn": 63, + "problem": "NumericSemantics", + "autofix": [ + { + "start": 3408, + "end": 3411, + "replacementText": "456.0", + "line": 138, + "column": 60, + "endLine": 138, + "endColumn": 63 + } + ], + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 158, + "column": 7, + "endLine": 158, + "endColumn": 58, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 158, + "column": 25, + "endLine": 158, + "endColumn": 35, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 176, "column": 1, - "endLine": 33, + "endLine": 176, + "endColumn": 18, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 181, + "column": 3, + "endLine": 181, + "endColumn": 21, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 187, + "column": 3, + "endLine": 187, + "endColumn": 19, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 195, + "column": 22, + "endLine": 195, + "endColumn": 41, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 195, + "column": 52, + "endLine": 195, + "endColumn": 55, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 203, + "column": 3, + "endLine": 203, + "endColumn": 21, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 215, + "column": 3, + "endLine": 215, + "endColumn": 18, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 226, + "column": 3, + "endLine": 226, "endColumn": 20, - "problem": "InteropDirectAccessToTSTypes", + "problem": "DecoratorsNotSupported", "suggest": "", - "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", "severity": "ERROR" }, { - "line": 33, - "column": 1, - "endLine": 33, - "endColumn": 11, - "problem": "InteropDirectAccessToTSTypes", + "line": 231, + "column": 5, + "endLine": 231, + "endColumn": 23, + "problem": "DecoratorsNotSupported", "suggest": "", - "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 237, + "column": 5, + "endLine": 237, + "endColumn": 21, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 245, + "column": 24, + "endLine": 245, + "endColumn": 43, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 245, + "column": 54, + "endLine": 245, + "endColumn": 57, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 256, + "column": 5, + "endLine": 256, + "endColumn": 23, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 271, + "column": 5, + "endLine": 271, + "endColumn": 21, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 282, + "column": 7, + "endLine": 282, + "endColumn": 57, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 282, + "column": 25, + "endLine": 282, + "endColumn": 35, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 303, + "column": 7, + "endLine": 303, + "endColumn": 60, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 303, + "column": 25, + "endLine": 303, + "endColumn": 35, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 306, + "column": 26, + "endLine": 306, + "endColumn": 33, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 307, + "column": 51, + "endLine": 307, + "endColumn": 58, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 308, + "column": 52, + "endLine": 308, + "endColumn": 59, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 309, + "column": 46, + "endLine": 309, + "endColumn": 53, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 310, + "column": 33, + "endLine": 310, + "endColumn": 40, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 311, + "column": 39, + "endLine": 311, + "endColumn": 46, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 312, + "column": 35, + "endLine": 312, + "endColumn": 42, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 313, + "column": 35, + "endLine": 313, + "endColumn": 42, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 314, + "column": 31, + "endLine": 314, + "endColumn": 38, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 315, + "column": 31, + "endLine": 315, + "endColumn": 38, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 316, + "column": 33, + "endLine": 316, + "endColumn": 40, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 324, + "column": 23, + "endLine": 324, + "endColumn": 24, + "problem": "NumericSemantics", + "autofix": [ + { + "start": 7971, + "end": 7972, + "replacementText": "1.0", + "line": 324, + "column": 23, + "endLine": 324, + "endColumn": 24 + } + ], + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 355, + "column": 7, + "endLine": 355, + "endColumn": 61, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 355, + "column": 25, + "endLine": 355, + "endColumn": 35, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 373, + "column": 23, + "endLine": 373, + "endColumn": 24, + "problem": "NumericSemantics", + "autofix": [ + { + "start": 9425, + "end": 9426, + "replacementText": "1.0", + "line": 373, + "column": 23, + "endLine": 373, + "endColumn": 24 + } + ], + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 182, + "column": 3, + "endLine": 182, + "endColumn": 13, + "problem": "StrictDiagnostic", + "suggest": "Property 'myProperty' has no initializer and is not definitely assigned in the constructor.", + "rule": "Property 'myProperty' has no initializer and is not definitely assigned in the constructor.", + "severity": "ERROR" + }, + { + "line": 202, + "column": 11, + "endLine": 202, + "endColumn": 16, + "problem": "StrictDiagnostic", + "suggest": "Property '_name' has no initializer and is not definitely assigned in the constructor.", + "rule": "Property '_name' has no initializer and is not definitely assigned in the constructor.", + "severity": "ERROR" + }, + { + "line": 214, + "column": 11, + "endLine": 214, + "endColumn": 15, + "problem": "StrictDiagnostic", + "suggest": "Property '_age' has no initializer and is not definitely assigned in the constructor.", + "rule": "Property '_age' has no initializer and is not definitely assigned in the constructor.", + "severity": "ERROR" + }, + { + "line": 232, + "column": 5, + "endLine": 232, + "endColumn": 15, + "problem": "StrictDiagnostic", + "suggest": "Property 'myProperty' has no initializer and is not definitely assigned in the constructor.", + "rule": "Property 'myProperty' has no initializer and is not definitely assigned in the constructor.", "severity": "ERROR" } ] diff --git a/ets2panda/linter/test/interop/unique_types.ets.json b/ets2panda/linter/test/interop/unique_types.ets.json index ca88f857e9..017acb4fb6 100644 --- a/ets2panda/linter/test/interop/unique_types.ets.json +++ b/ets2panda/linter/test/interop/unique_types.ets.json @@ -13,5 +13,116 @@ "See the License for the specific language governing permissions and", "limitations under the License." ], - "result": [] + "result": [ + { + "line": 76, + "column": 7, + "endLine": 76, + "endColumn": 69, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 158, + "column": 7, + "endLine": 158, + "endColumn": 58, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 195, + "column": 52, + "endLine": 195, + "endColumn": 55, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 245, + "column": 54, + "endLine": 245, + "endColumn": 57, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 282, + "column": 7, + "endLine": 282, + "endColumn": 57, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 303, + "column": 7, + "endLine": 303, + "endColumn": 60, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 355, + "column": 7, + "endLine": 355, + "endColumn": 61, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 182, + "column": 3, + "endLine": 182, + "endColumn": 13, + "problem": "StrictDiagnostic", + "suggest": "Property 'myProperty' has no initializer and is not definitely assigned in the constructor.", + "rule": "Property 'myProperty' has no initializer and is not definitely assigned in the constructor.", + "severity": "ERROR" + }, + { + "line": 202, + "column": 11, + "endLine": 202, + "endColumn": 16, + "problem": "StrictDiagnostic", + "suggest": "Property '_name' has no initializer and is not definitely assigned in the constructor.", + "rule": "Property '_name' has no initializer and is not definitely assigned in the constructor.", + "severity": "ERROR" + }, + { + "line": 214, + "column": 11, + "endLine": 214, + "endColumn": 15, + "problem": "StrictDiagnostic", + "suggest": "Property '_age' has no initializer and is not definitely assigned in the constructor.", + "rule": "Property '_age' has no initializer and is not definitely assigned in the constructor.", + "severity": "ERROR" + }, + { + "line": 232, + "column": 5, + "endLine": 232, + "endColumn": 15, + "problem": "StrictDiagnostic", + "suggest": "Property 'myProperty' has no initializer and is not definitely assigned in the constructor.", + "rule": "Property 'myProperty' has no initializer and is not definitely assigned in the constructor.", + "severity": "ERROR" + } + ] } \ No newline at end of file diff --git a/ets2panda/linter/test/interop/unique_types.ets.migrate.ets b/ets2panda/linter/test/interop/unique_types.ets.migrate.ets index 568c171d51..6f0585bf51 100644 --- a/ets2panda/linter/test/interop/unique_types.ets.migrate.ets +++ b/ets2panda/linter/test/interop/unique_types.ets.migrate.ets @@ -14,22 +14,387 @@ */ import { - objectLiteralType, - intersectionType, - tsFunction, - stringType, - enumType + any_var, + unknown_var, + symbol_var, + function_var, + A, + B, + TestHelper, + throw_number, + throw_string, + throw_boolean, + throw_bigint, + throw_obj, + throw_error, + throwErrorSubClass, + SubError, + throwRangeError, + ObjectLiteralClass, + ObjectLiteralInter, + MyClassDecorator, + propertyDecorator, + methodDecorator, + parameterDecorator, + accessorDecorator, + readonly1, + num_boxed, + bool_boxed, + str_boxed, + bigint_boxed, + ts_object_method, + ts_object_method_getOwnPropertyDescriptor, + ts_object_method_getOwnPropertyDescriptors, + ts_object_method_getOwnPropertyNames, + ts_object_method_hasOwn, + ts_object_method_isExtensible, + ts_object_method_isFrozen, + ts_object_method_isSealed, + ts_object_method_keys, + ts_object_method_values, + interObj, + ts_reflect_method, + ts_reflect_method_apply, + ts_reflect_method_defineProperty, + ts_reflect_method_deleteProperty, + ts_reflect_method_getOwnPropertyDescriptor, + ts_reflect_method_ownKeys, + ts_reflect_method_isExtensible, + ts_reflect_method_set, + ts_reflect_method_setPrototypeOf } from "./ignore_files/unique_types"; -objectLiteralType.setProperty('name',ESValue.wrap("test")) -intersectionType.setProperty('name',ESValue.wrap("test")); +typeof any_var === 'object'; +typeof unknown_var === 'number'; +typeof symbol_var === 'object'; +function_var.unsafeCall() === true; +A.instance; +let obj: B = { name: "hello" }; -try { -tsFunction(); -} catch (e) { +export function test_ts_non_standard_exception(testCaseRet: Array) { + let test_helper = new TestHelper("TEST_TS_NON_STANDARD_EXCEPTION"); + + test_helper.test(() => { + try { + throw_number(); // arkts-interop-ts2s-ts-exception + } catch (e) { + return e as number === 123.0; + } + return false; + }, "e as number === 123"); + + test_helper.test(() => { + try { + throw_boolean(); // arkts-interop-ts2s-ts-exception + } catch (e) { + return e as boolean === true; + } + return false; + }, "e as boolean === true"); + + test_helper.test(() => { + try { + throw_bigint(); // arkts-interop-ts2s-ts-exception + } catch (e) { + return e as bigint === 111n; + } + return false; + }, "e as bigint === 111n"); + + test_helper.test(() => { + try { + throw_string(); // arkts-interop-ts2s-ts-exception + } catch (e) { + return e as string === "error"; + } + return false; + }, "e as string === "error""); + + test_helper.test(() => { + try { + throw_obj(); // arkts-interop-ts2s-ts-exception + } catch (e) { + return e.name === "error"; + } + return false; + }, "e.name === "error""); + + test_helper.test(() => { + try { + throw_error(); + } catch (e) { + let errObj: Error = e as Error; + return errObj.name === "error"; + } + return false; + }, "errObj.name === "error""); + + test_helper.test(() => { + try { + throwErrorSubClass(); // arkts-interop-ts2s-ts-exception + } catch (e) { + let errObj = e as SubError; + return errObj.extraField === 123.0 && errObj.foo() === 456.0; + } + return false; + }, "errObj.extraField === 123 && errObj.foo() === 456"); + + test_helper.test(() => { + let flag = false + try { + throwRangeError(); // arkts-interop-ts2s-ts-exception + } catch (e) { + let errObj: RangeError = e as RangeError; + return errObj instanceof RangeError; + } + return flag; + }, "Throw: throwRangeError"); + + testCaseRet.push(test_helper.done()); +} + +export function test_object_literal(testCaseRet: Array) { + let test_helper = new TestHelper("TEST_OBJECT_LITERAL"); + + test_helper.test(() => { + let obj: ObjectLiteralClass = { name: "hello" }; // arkts-obj-literal-generate-class-instance + return obj.name === "hello" && obj instanceof ObjectLiteralClass; + }, "obj.name === "hello""); + + test_helper.test(() => { + let obj: ObjectLiteralInter = { name: "hello" }; // arkts-obj-literal-generate-class-instance + return obj.name === "hello" && obj instanceof ObjectLiteralInter; + }, "obj.name === "hello""); + + testCaseRet.push(test_helper.done()); +} + +// 1 ArkTS使用TS装饰器 +// 规则名 arkts-interop-ts2s-no-ts-decorator +// case 1 类装饰器 top level +@MyClassDecorator // arkts-no-ts-decorators + arkts-interop-ts2s-no-ts-decorator +class K {} + +//case 2 类属性装饰器 +class MyClass { + @propertyDecorator// arkts-no-ts-decorators + myProperty: string; +} + +//case 3 方法装饰器 +class MathFunctions { + @methodDecorator// arkts-no-ts-decorators + double1(value: number): number { + return value; + } +} + +//case 4 方法装饰器 +class MyClass1 { + log(value: string, @parameterDecorator metadata: any) {// arkts-no-ts-decorators + console.log(Logged: ${value}); + } +} + +//case 5 访问器装饰器 +class Person { + private _name: string; + @accessorDecorator// arkts-no-ts-decorators + get name(): string { + return this._name; + } + set name(value: string) { + this._name = value; + } +} + +//case 6 访问器工厂 +class Person1 { + private _age: number; + @readonly(true)// arkts-no-ts-decorators + get age(): number { + return this._age; + } + set age(value: number) { + this._age = value; + } +} + +namespace NS{ + // case 7 类装饰器 top level + @MyClassDecorator// arkts-no-ts-decorators + arkts-interop-ts2s-no-ts-decorator + class K {} + + //case 8 类属性装饰器 + class MyClass { + @propertyDecorator// arkts-no-ts-decorators + myProperty: string; + } + + //case 9 方法装饰器 + class MathFunctions { + @methodDecorator// arkts-no-ts-decorators + double1(value: number): number { + return value; + } + } + + //case 10 方法装饰器 + class MyClass1 { + log(value: string, @parameterDecorator metadata: any) {// arkts-no-ts-decorators + console.log(Logged: ${value}); + } + } + + //case 11 访问器装饰器 + class Person { + private _name: string; + constructor(name: string) { + this._name = name; + } + @accessorDecorator// arkts-no-ts-decorators + get name(): string { + return this._name; + } + set name(value: string) { + this._name = value; + } + } + + //case 12 访问器工厂 + class Person1 { + private _age: number; + constructor(age: number) { + this._age = age; + } + @readonly1(true)// arkts-no-ts-decorators + get age(): number { + return this._age; + } + set age(value: number) { + this._age = value; + } + } +} + +export function test_ts_boxed_type(testCaseRet: Array) { + let test_helper = new TestHelper("TEST_TS_BOXED_TYPE"); + + test_helper.test(() => { + return typeof num_boxed === object; + }, "typeof num_boxed === object"); + + test_helper.test(() => { + return typeof bool_boxed === object; + }, "typeof bool_boxed === object"); + + test_helper.test(() => { + return typeof str_boxed === object; + }, "typeof str_boxed === object"); + + test_helper.test(() => { + return typeof bigint_boxed === object; + }, "typeof bigint_boxed === object"); + testCaseRet.push(test_helper.done()); +} + +export function test_ts_object_method(testCaseRet: Array) { + let test_helper = new TestHelper("TEST_TS_OBJECT_METHOD"); + + test_helper.test(() => { + ts_object_method(new Object2()) + ts_object_method_getOwnPropertyDescriptor(new Object2()) + ts_object_method_getOwnPropertyDescriptors(new Object2()) + ts_object_method_getOwnPropertyNames(new Object2()) + ts_object_method_hasOwn(new Object2()) + ts_object_method_isExtensible(new Object2()) + ts_object_method_isFrozen(new Object2()) + ts_object_method_isSealed(new Object2()) + ts_object_method_keys(new Object2()) + ts_object_method_keys(new Object2()) + ts_object_method_values(new Object2()) + return true; + }, "true"); + + test_helper.test(() => { + interface Iface { + a:number + } + let a1:Iface = {a:1.0} + ts_object_method(a1) + ts_object_method_getOwnPropertyDescriptor(a1) + ts_object_method_getOwnPropertyDescriptors(a1) + ts_object_method_getOwnPropertyNames(a1) + ts_object_method_hasOwn(a1) + ts_object_method_isExtensible(a1) + ts_object_method_isFrozen(a1) + ts_object_method_isSealed(a1) + ts_object_method_keys(a1) + ts_object_method_keys(a1) + ts_object_method_values(a1) + return true; + }, "true"); + + test_helper.test(() => { + ts_object_method(interObj) + return true; + }, "false"); + + testCaseRet.push(test_helper.done()); +} + +class Reflect2 { + a: string = 'hello' + getName() { return this.a } } -stringType = "test" //should pass +// 5 Object内置方法作用在ArkTS对象 +// 规则名 arkts-interop-ts2s-ts-object-on-static-instance +export function test_ts_reflect_method(testCaseRet: Array) { + let test_helper = new TestHelper("TEST_TS_REFLECT_METHOD"); + test_helper.test(() => { + ts_reflect_method(new Reflect2()) + ts_reflect_method_apply(new Reflect2()) + ts_reflect_method_defineProperty(new Reflect2()) + ts_reflect_method_deleteProperty(new Reflect2()) + ts_reflect_method_getOwnPropertyDescriptor(new Reflect2()) + ts_reflect_method_ownKeys(new Reflect2()) + ts_reflect_method_isExtensible(new Reflect2()) + ts_reflect_method_set(new Reflect2()) + ts_reflect_method_setPrototypeOf(new Reflect2()) + return true; + }, "reflect class 1.2 "); + + test_helper.test(() => { + interface Iface { + a:number + } + let a1:Iface = {a:1.0} + ts_reflect_method(a1) + ts_reflect_method_apply(a1) + ts_reflect_method_defineProperty(a1) + ts_reflect_method_deleteProperty(a1) + ts_reflect_method_getOwnPropertyDescriptor(a1) + ts_reflect_method_ownKeys(a1) + ts_reflect_method_isExtensible(a1) + ts_reflect_method_set(a1) + ts_reflect_method_setPrototypeOf(a1) + return true; + }, "reflect interface 1.2"); + + test_helper.test(() => { + ts_reflect_method(interObj) + ts_reflect_method_apply(interObj) + ts_reflect_method_defineProperty(interObj) + ts_reflect_method_deleteProperty(interObj) + ts_reflect_method_getOwnPropertyDescriptor(interObj) + ts_reflect_method_ownKeys(interObj) + ts_reflect_method_isExtensible(interObj) + ts_reflect_method_set(interObj) + ts_reflect_method_setPrototypeOf(interObj) + return true; + }, "reflect interObj 1.0 "); -enumType = "A"; //should fail + testCaseRet.push(test_helper.done()); +} \ No newline at end of file diff --git a/ets2panda/linter/test/interop/unique_types.ets.migrate.json b/ets2panda/linter/test/interop/unique_types.ets.migrate.json index 6e0fbe1a85..e78688989e 100644 --- a/ets2panda/linter/test/interop/unique_types.ets.migrate.json +++ b/ets2panda/linter/test/interop/unique_types.ets.migrate.json @@ -15,43 +15,473 @@ ], "result": [ { - "line": 29, - "column": 1, - "endLine": 29, - "endColumn": 13, - "problem": "InteropTSFunctionInvoke", + "line": 68, + "column": 8, + "endLine": 68, + "endColumn": 15, + "problem": "InteropDirectAccessToTSTypes", "suggest": "", - "rule": "Trying to catch typescript errors is not permitted (arkts-interop-ts2s-ts-exception)", + "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", "severity": "ERROR" }, { - "line": 29, - "column": 1, - "endLine": 29, - "endColumn": 11, + "line": 69, + "column": 8, + "endLine": 69, + "endColumn": 19, "problem": "InteropDirectAccessToTSTypes", "suggest": "", "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", "severity": "ERROR" }, { - "line": 33, - "column": 1, - "endLine": 33, - "endColumn": 20, + "line": 70, + "column": 8, + "endLine": 70, + "endColumn": 18, "problem": "InteropDirectAccessToTSTypes", "suggest": "", "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", "severity": "ERROR" }, { - "line": 33, + "line": 76, + "column": 7, + "endLine": 76, + "endColumn": 69, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 76, + "column": 25, + "endLine": 76, + "endColumn": 35, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 80, + "column": 7, + "endLine": 80, + "endColumn": 21, + "problem": "InteropTSFunctionInvoke", + "suggest": "", + "rule": "Trying to catch typescript errors is not permitted (arkts-interop-ts2s-ts-exception)", + "severity": "ERROR" + }, + { + "line": 89, + "column": 7, + "endLine": 89, + "endColumn": 22, + "problem": "InteropTSFunctionInvoke", + "suggest": "", + "rule": "Trying to catch typescript errors is not permitted (arkts-interop-ts2s-ts-exception)", + "severity": "ERROR" + }, + { + "line": 98, + "column": 7, + "endLine": 98, + "endColumn": 21, + "problem": "InteropTSFunctionInvoke", + "suggest": "", + "rule": "Trying to catch typescript errors is not permitted (arkts-interop-ts2s-ts-exception)", + "severity": "ERROR" + }, + { + "line": 107, + "column": 7, + "endLine": 107, + "endColumn": 21, + "problem": "InteropTSFunctionInvoke", + "suggest": "", + "rule": "Trying to catch typescript errors is not permitted (arkts-interop-ts2s-ts-exception)", + "severity": "ERROR" + }, + { + "line": 116, + "column": 7, + "endLine": 116, + "endColumn": 18, + "problem": "InteropTSFunctionInvoke", + "suggest": "", + "rule": "Trying to catch typescript errors is not permitted (arkts-interop-ts2s-ts-exception)", + "severity": "ERROR" + }, + { + "line": 158, + "column": 7, + "endLine": 158, + "endColumn": 58, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 158, + "column": 25, + "endLine": 158, + "endColumn": 35, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 176, "column": 1, - "endLine": 33, - "endColumn": 11, - "problem": "InteropDirectAccessToTSTypes", + "endLine": 176, + "endColumn": 18, + "problem": "DecoratorsNotSupported", "suggest": "", - "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 181, + "column": 3, + "endLine": 181, + "endColumn": 21, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 187, + "column": 3, + "endLine": 187, + "endColumn": 19, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 195, + "column": 22, + "endLine": 195, + "endColumn": 41, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 195, + "column": 52, + "endLine": 195, + "endColumn": 55, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 203, + "column": 3, + "endLine": 203, + "endColumn": 21, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 215, + "column": 3, + "endLine": 215, + "endColumn": 18, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 226, + "column": 3, + "endLine": 226, + "endColumn": 20, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 231, + "column": 5, + "endLine": 231, + "endColumn": 23, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 237, + "column": 5, + "endLine": 237, + "endColumn": 21, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 245, + "column": 24, + "endLine": 245, + "endColumn": 43, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 245, + "column": 54, + "endLine": 245, + "endColumn": 57, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 256, + "column": 5, + "endLine": 256, + "endColumn": 23, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 271, + "column": 5, + "endLine": 271, + "endColumn": 21, + "problem": "DecoratorsNotSupported", + "suggest": "", + "rule": "Decorators are not supported(arkts-no-ts-decorators)", + "severity": "ERROR" + }, + { + "line": 282, + "column": 7, + "endLine": 282, + "endColumn": 57, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 282, + "column": 25, + "endLine": 282, + "endColumn": 35, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 303, + "column": 7, + "endLine": 303, + "endColumn": 60, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 303, + "column": 25, + "endLine": 303, + "endColumn": 35, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 306, + "column": 26, + "endLine": 306, + "endColumn": 33, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 307, + "column": 51, + "endLine": 307, + "endColumn": 58, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 308, + "column": 52, + "endLine": 308, + "endColumn": 59, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 309, + "column": 46, + "endLine": 309, + "endColumn": 53, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 310, + "column": 33, + "endLine": 310, + "endColumn": 40, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 311, + "column": 39, + "endLine": 311, + "endColumn": 46, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 312, + "column": 35, + "endLine": 312, + "endColumn": 42, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 313, + "column": 35, + "endLine": 313, + "endColumn": 42, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 314, + "column": 31, + "endLine": 314, + "endColumn": 38, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 315, + "column": 31, + "endLine": 315, + "endColumn": 38, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 316, + "column": 33, + "endLine": 316, + "endColumn": 40, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 355, + "column": 7, + "endLine": 355, + "endColumn": 61, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", + "severity": "ERROR" + }, + { + "line": 355, + "column": 25, + "endLine": 355, + "endColumn": 35, + "problem": "DynamicCtorCall", + "suggest": "", + "rule": "\"new\" expression with dynamic constructor type is not supported (arkts-no-dynamic-ctor-call)", + "severity": "ERROR" + }, + { + "line": 182, + "column": 3, + "endLine": 182, + "endColumn": 13, + "problem": "StrictDiagnostic", + "suggest": "Property 'myProperty' has no initializer and is not definitely assigned in the constructor.", + "rule": "Property 'myProperty' has no initializer and is not definitely assigned in the constructor.", + "severity": "ERROR" + }, + { + "line": 202, + "column": 11, + "endLine": 202, + "endColumn": 16, + "problem": "StrictDiagnostic", + "suggest": "Property '_name' has no initializer and is not definitely assigned in the constructor.", + "rule": "Property '_name' has no initializer and is not definitely assigned in the constructor.", + "severity": "ERROR" + }, + { + "line": 214, + "column": 11, + "endLine": 214, + "endColumn": 15, + "problem": "StrictDiagnostic", + "suggest": "Property '_age' has no initializer and is not definitely assigned in the constructor.", + "rule": "Property '_age' has no initializer and is not definitely assigned in the constructor.", + "severity": "ERROR" + }, + { + "line": 232, + "column": 5, + "endLine": 232, + "endColumn": 15, + "problem": "StrictDiagnostic", + "suggest": "Property 'myProperty' has no initializer and is not definitely assigned in the constructor.", + "rule": "Property 'myProperty' has no initializer and is not definitely assigned in the constructor.", "severity": "ERROR" } ] 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 f6d45915a0..5062fc598a 100644 --- a/ets2panda/linter/test/main/literals_as_prop_names.ets.arkts2.json +++ b/ets2panda/linter/test/main/literals_as_prop_names.ets.arkts2.json @@ -274,16 +274,6 @@ "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" }, - { - "line": 84, - "column": 12, - "endLine": 84, - "endColumn": 31, - "problem": "InteropDirectAccessToTSTypes", - "suggest": "", - "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", - "severity": "ERROR" - }, { "line": 84, "column": 36, 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 acd80dca75..f3414d739d 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 @@ -656,16 +656,6 @@ "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" }, - { - "line": 84, - "column": 12, - "endLine": 84, - "endColumn": 31, - "problem": "InteropDirectAccessToTSTypes", - "suggest": "", - "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", - "severity": "ERROR" - }, { "line": 84, "column": 36, 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 a05c4027b2..a180c18573 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 @@ -74,16 +74,6 @@ "rule": "This keyword cannot be used as identifiers (arkts-invalid-identifier)", "severity": "ERROR" }, - { - "line": 93, - "column": 12, - "endLine": 93, - "endColumn": 31, - "problem": "InteropDirectAccessToTSTypes", - "suggest": "", - "rule": "Cannot access typescript types directly (arkts-interop-ts2s-static-access-ts-type)", - "severity": "ERROR" - }, { "line": 93, "column": 36, -- Gitee From 25989e0d91af9f44bd11b8589c69b8b2b39b8b48 Mon Sep 17 00:00:00 2001 From: ZhongNing Date: Tue, 24 Jun 2025 14:12:45 +0800 Subject: [PATCH 15/16] Fix for ArrayTypeImmutable Issue:https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICHENX Test scenarios: fix bug Signed-off-by: ZhongNing --- ets2panda/linter/src/lib/TypeScriptLinter.ts | 13 ++++---- .../test/main/arkts-array-type-immutable.ets | 6 ++-- ...arkts-array-type-immutable.ets.arkts2.json | 30 +++++++++++++++++++ 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index 5cd9cdf633..a446ee8da8 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -6798,13 +6798,12 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (!this.options.arkts2) { return; } - if ( - !( - this.tsUtils.isOrDerivedFrom(lhsType, this.tsUtils.isArray) && - this.tsUtils.isOrDerivedFrom(rhsType, this.tsUtils.isArray) && - lhsType !== rhsType - ) - ) { + const isArray = + this.tsUtils.isOrDerivedFrom(lhsType, this.tsUtils.isArray) && + this.tsUtils.isOrDerivedFrom(rhsType, this.tsUtils.isArray); + const isTuple = + this.tsUtils.isOrDerivedFrom(lhsType, TsUtils.isTuple) && this.tsUtils.isOrDerivedFrom(rhsType, TsUtils.isTuple); + if (!((isArray || isTuple) && lhsType !== rhsType)) { return; } diff --git a/ets2panda/linter/test/main/arkts-array-type-immutable.ets b/ets2panda/linter/test/main/arkts-array-type-immutable.ets index c0d79ba065..8f805d8229 100644 --- a/ets2panda/linter/test/main/arkts-array-type-immutable.ets +++ b/ets2panda/linter/test/main/arkts-array-type-immutable.ets @@ -37,7 +37,7 @@ function test(a: number[]): void { } let arrayTypeImmutableA2: [number] = [1]; -let arrayTypeImmutableB2: [number | string] = arrayTypeImmutableA2; +let arrayTypeImmutableB2: [number | string] = arrayTypeImmutableA2; // error class ArrayTypeImmutableA{ arrayTypeImmutableA: number[] = [1]; @@ -45,8 +45,8 @@ class ArrayTypeImmutableA{ arrayTypeImmutableB1: (number | string)[] = this.arrayTypeImmutableA; // error arrayTypeImmutableA2: [number] = [1]; - arrayTypeImmutableB2: [number | string] = arrayTypeImmutableA2; - arrayTypeImmutableB21: [number | string] = this.arrayTypeImmutableA2; + arrayTypeImmutableB2: [number | string] = arrayTypeImmutableA2; // error + arrayTypeImmutableB21: [number | string] = this.arrayTypeImmutableA2; // error } interface IA { diff --git a/ets2panda/linter/test/main/arkts-array-type-immutable.ets.arkts2.json b/ets2panda/linter/test/main/arkts-array-type-immutable.ets.arkts2.json index fa6b50ae6c..e2441885c3 100644 --- a/ets2panda/linter/test/main/arkts-array-type-immutable.ets.arkts2.json +++ b/ets2panda/linter/test/main/arkts-array-type-immutable.ets.arkts2.json @@ -134,6 +134,16 @@ "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" }, + { + "line": 40, + "column": 5, + "endLine": 40, + "endColumn": 67, + "problem": "ArrayTypeImmutable", + "suggest": "", + "rule": "Array type is immutable in ArkTS1.2 (arkts-array-type-immutable)", + "severity": "ERROR" + }, { "line": 43, "column": 36, @@ -174,6 +184,26 @@ "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" }, + { + "line": 48, + "column": 3, + "endLine": 48, + "endColumn": 66, + "problem": "ArrayTypeImmutable", + "suggest": "", + "rule": "Array type is immutable in ArkTS1.2 (arkts-array-type-immutable)", + "severity": "ERROR" + }, + { + "line": 49, + "column": 3, + "endLine": 49, + "endColumn": 72, + "problem": "ArrayTypeImmutable", + "suggest": "", + "rule": "Array type is immutable in ArkTS1.2 (arkts-array-type-immutable)", + "severity": "ERROR" + }, { "line": 67, "column": 6, -- Gitee From 58e4be8a50d48a6ffbee5aadddab344d3d98b0f9 Mon Sep 17 00:00:00 2001 From: xudan16 Date: Tue, 24 Jun 2025 17:09:32 +0800 Subject: [PATCH 16/16] homecheck add cast expr with increment Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICHHAC Signed-off-by: xudan16 --- .../src/checker/migration/NoTSLikeAsCheck.ts | 226 ++++++++++-------- ets2panda/linter/src/lib/LinterRunner.ts | 4 - 2 files changed, 126 insertions(+), 104 deletions(-) diff --git a/ets2panda/linter/homecheck/src/checker/migration/NoTSLikeAsCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/NoTSLikeAsCheck.ts index 2cd9eab61a..3c7fb7450a 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/NoTSLikeAsCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/NoTSLikeAsCheck.ts @@ -15,46 +15,46 @@ import path from 'path'; import { - ArkMethod, + AbstractFieldRef, ArkAssignStmt, - FieldSignature, - Stmt, - Scene, - Value, - DVFGBuilder, - ArkInstanceOfExpr, - CallGraph, - ArkParameterRef, - ArkInstanceFieldRef, - ArkNamespace, - Local, ArkCastExpr, - ClassType, - classSignatureCompare, ArkField, - fileSignatureCompare, - Cfg, - BasicBlock, ArkIfStmt, + ArkInstanceFieldRef, + ArkInstanceOfExpr, + ArkMethod, + ArkNamespace, + ArkNormalBinopExpr, + ArkParameterRef, ArkUnopExpr, - RelationalBinaryOperator, + BasicBlock, + CallGraph, + Cfg, + ClassSignature, + classSignatureCompare, + ClassType, + DVFGBuilder, + FieldSignature, + fileSignatureCompare, LineColPosition, - UnaryOperator, - ArkNormalBinopExpr, + Local, NormalBinaryOperator, - AbstractFieldRef, - ClassSignature, + RelationalBinaryOperator, + Scene, + Stmt, + UnaryOperator, + Value, } from 'arkanalyzer/lib'; import Logger, { LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger'; import { BaseChecker, BaseMetaData } from '../BaseChecker'; -import { Rule, Defects, MatcherCallback } from '../../Index'; +import { Defects, MatcherCallback, Rule } from '../../Index'; import { IssueReport } from '../../model/Defects'; import { DVFG, DVFGNode } from 'arkanalyzer/lib/VFG/DVFG'; -import { CALL_DEPTH_LIMIT, getGlobalsDefineInDefaultMethod, GlobalCallGraphHelper } from './Utils'; -import { WarnInfo } from '../../utils/common/Utils'; +import { CALL_DEPTH_LIMIT, getGlobalsDefineInDefaultMethod, getLineAndColumn, GlobalCallGraphHelper } from './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'; +import { BooleanConstant, NumberConstant } from 'arkanalyzer/lib/core/base/Constant'; +import { ArkClass, NumberType } from 'arkanalyzer'; const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'NoTSLikeAsCheck'); const gMetaData: BaseMetaData = { @@ -74,6 +74,7 @@ export class NoTSLikeAsCheck implements BaseChecker { public rule: Rule; public defects: Defects[] = []; public issues: IssueReport[] = []; + private scene: Scene; private cg: CallGraph; private dvfg: DVFG; private dvfgBuilder: DVFGBuilder; @@ -88,6 +89,7 @@ export class NoTSLikeAsCheck implements BaseChecker { } public check = (scene: Scene): void => { + this.scene = scene; this.cg = GlobalCallGraphHelper.getCGInstance(scene); this.dvfg = new DVFG(this.cg); @@ -105,58 +107,38 @@ export class NoTSLikeAsCheck implements BaseChecker { globalVarMap = getGlobalsDefineInDefaultMethod(defaultMethod); } for (let clazz of arkFile.getClasses()) { - for (let field of clazz.getFields()) { - this.processClassField(field, globalVarMap, scene); - } - for (let mtd of clazz.getMethods()) { - this.processArkMethod(mtd, globalVarMap, scene); - } + this.processClass(clazz, globalVarMap); } for (let namespace of arkFile.getAllNamespacesUnderThisFile()) { - this.processNameSpace(namespace, globalVarMap, scene); + this.processNameSpace(namespace, globalVarMap); } } }; - public processNameSpace(namespace: ArkNamespace, globalVarMap: Map, scene: Scene): void { + public processClass(arkClass: ArkClass, globalVarMap: Map): void { + for (let field of arkClass.getFields()) { + this.processClassField(field, globalVarMap); + } + for (let mtd of arkClass.getMethods()) { + this.processArkMethod(mtd, globalVarMap); + } + } + + public processNameSpace(namespace: ArkNamespace, globalVarMap: Map): void { for (let ns of namespace.getNamespaces()) { - this.processNameSpace(ns, globalVarMap, scene); + this.processNameSpace(ns, globalVarMap); } for (let clazz of namespace.getClasses()) { - for (let field of clazz.getFields()) { - this.processClassField(field, globalVarMap, scene); - } - for (let mtd of clazz.getMethods()) { - this.processArkMethod(mtd, globalVarMap, scene); - } + this.processClass(clazz, globalVarMap); } } - public processClassField(field: ArkField, globalVarMap: Map, scene: Scene): void { - const stmts = field.getInitializer(); - for (const stmt of stmts) { - const castExpr = this.getCastExpr(stmt); - if (castExpr === null) { - continue; - } - // 判断cast类型断言的类型是否是class,非class的场景不在本规则检查范围内 - if (!(castExpr.getType() instanceof ClassType)) { - continue; - } - let checkAll = { value: true }; - let visited: Set = new Set(); - const result = this.checkFromStmt(stmt, scene, globalVarMap, checkAll, visited); - if (result !== null) { - this.addIssueReport(stmt, castExpr, result); - } else { - if (!checkAll.value) { - this.addIssueReport(stmt, castExpr); - } - } - } + public processClassField(field: ArkField, globalVarMap: Map): void { + const instInit = field.getDeclaringArkClass().getInstanceInitMethod(); + this.processArkMethod(instInit, globalVarMap); } - public processArkMethod(target: ArkMethod, globalVarMap: Map, scene: Scene): void { + public processArkMethod(target: ArkMethod, globalVarMap: Map): void { const stmts = target.getBody()?.getCfg().getStmts() ?? []; for (const stmt of stmts) { // cast表达式所在语句为sink点,从该点开始进行逆向数据流分析 @@ -164,6 +146,13 @@ export class NoTSLikeAsCheck implements BaseChecker { if (castExpr === null) { continue; } + + // 判断是否为cast表达式的自增自减运算,属于告警场景之一 + if (this.isCastExprWithIncrementDecrement(stmt)) { + this.addIssueReport(stmt, castExpr, undefined, true); + continue; + } + // 判断cast类型断言的类型是否是class,非class的场景不在本规则检查范围内 if (!(castExpr.getType() instanceof ClassType)) { continue; @@ -178,7 +167,7 @@ export class NoTSLikeAsCheck implements BaseChecker { let checkAll = { value: true }; let visited: Set = new Set(); - const result = this.checkFromStmt(stmt, scene, globalVarMap, checkAll, visited); + const result = this.checkFromStmt(stmt, globalVarMap, checkAll, visited); if (result !== null) { this.addIssueReport(stmt, castExpr, result); } else { @@ -189,6 +178,62 @@ export class NoTSLikeAsCheck implements BaseChecker { } } + private isCastExprWithIncrementDecrement(stmt: Stmt): boolean { + if (!(stmt instanceof ArkAssignStmt) || !(stmt.getRightOp() instanceof ArkCastExpr)) { + return false; + } + const castLocal = stmt.getLeftOp(); + if (!(castLocal instanceof Local)) { + return false; + } + // 判断是否为自增或自减语句,需要判断used stmt是否至少包含%0 = %0 + 1 和 castExpr = %0两条语句,不新增临时变量 + // 非自增或自减语句,used stmt中仅包含%1 = %0 + 1 + const usedStmts = castLocal.getUsedStmts(); + if (usedStmts.length !== 2) { + return false; + } + let selfAssignFlag = false; + let assignBackFlag = false; + for (const usedStmt of usedStmts) { + if (!(usedStmt instanceof ArkAssignStmt)) { + return false; + } + const leftOp = usedStmt.getLeftOp(); + const rightOp = usedStmt.getRightOp(); + if (leftOp instanceof Local) { + if (leftOp !== castLocal) { + return false; + } + if (!(rightOp instanceof ArkNormalBinopExpr)) { + return false; + } + const op1 = rightOp.getOp1(); + const op2 = rightOp.getOp2(); + const operator = rightOp.getOperator(); + if (op1 !== castLocal) { + return false; + } + if (operator !== NormalBinaryOperator.Addition && operator !== NormalBinaryOperator.Subtraction) { + return false; + } + if (!(op2 instanceof NumberConstant) || !(op2.getType() instanceof NumberType) || op2.getValue() !== '1') { + return false; + } + selfAssignFlag = true; + } + if (leftOp instanceof ArkCastExpr) { + if (leftOp !== stmt.getRightOp()) { + return false; + } + if (rightOp !== castLocal) { + return false; + } + assignBackFlag = true; + } + } + return selfAssignFlag && assignBackFlag; + } + private hasCheckedWithInstanceof(cfg: Cfg, stmt: Stmt): boolean { const castExpr = this.getCastExpr(stmt); if (castExpr === null) { @@ -346,14 +391,7 @@ export class NoTSLikeAsCheck implements BaseChecker { return null; } - private checkFromStmt( - stmt: Stmt, - scene: Scene, - globalVarMap: Map, - checkAll: { value: boolean }, - visited: Set, - depth: number = 0 - ): Stmt | null { + private checkFromStmt(stmt: Stmt, globalVarMap: Map, checkAll: { value: boolean }, visited: Set, depth: number = 0): Stmt | null { if (depth > CALL_DEPTH_LIMIT) { checkAll.value = false; return null; @@ -367,11 +405,11 @@ export class NoTSLikeAsCheck implements BaseChecker { continue; } visited.add(currentStmt); - if (this.isWithInterfaceAnnotation(currentStmt, scene)) { + if (this.isWithInterfaceAnnotation(currentStmt)) { return currentStmt; } - const fieldDeclareStmt = this.isCastOpFieldWithInterfaceType(currentStmt, scene); + const fieldDeclareStmt = this.isCastOpFieldWithInterfaceType(currentStmt); if (fieldDeclareStmt) { return fieldDeclareStmt; } @@ -401,7 +439,7 @@ export class NoTSLikeAsCheck implements BaseChecker { } const returnStmts = declaringMtd.getReturnStmt(); for (const stmt of returnStmts) { - const res = this.checkFromStmt(stmt, scene, globalVarMap, checkAll, visited, depth + 1); + const res = this.checkFromStmt(stmt, globalVarMap, checkAll, visited, depth + 1); if (res !== null) { return res; } @@ -414,7 +452,7 @@ export class NoTSLikeAsCheck implements BaseChecker { this.processCallsites(callsites); const argDefs = this.collectArgDefs(paramIdx, callsites); for (const stmt of argDefs) { - const res = this.checkFromStmt(stmt, scene, globalVarMap, checkAll, visited, depth + 1); + const res = this.checkFromStmt(stmt, globalVarMap, checkAll, visited, depth + 1); if (res !== null) { return res; } @@ -425,7 +463,7 @@ export class NoTSLikeAsCheck implements BaseChecker { return null; } - private isCastOpFieldWithInterfaceType(stmt: Stmt, scene: Scene): Stmt | undefined { + private isCastOpFieldWithInterfaceType(stmt: Stmt): Stmt | undefined { const obj = this.getCastOp(stmt); if (obj === null || !(obj instanceof Local)) { return undefined; @@ -440,13 +478,13 @@ export class NoTSLikeAsCheck implements BaseChecker { } const fieldDeclaring = rightOp.getFieldSignature().getDeclaringSignature(); if (fieldDeclaring instanceof ClassSignature) { - const field = scene.getClass(fieldDeclaring)?.getField(rightOp.getFieldSignature()); + const field = this.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)) { + if (this.isWithInterfaceAnnotation(lastStmt)) { return lastStmt; } } @@ -497,7 +535,7 @@ export class NoTSLikeAsCheck implements BaseChecker { } // 判断语句是否为赋值语句,且左值的类型注解为Interface,右值的类型与左值不一样 - private isWithInterfaceAnnotation(stmt: Stmt, scene: Scene): boolean { + private isWithInterfaceAnnotation(stmt: Stmt): boolean { if (!(stmt instanceof ArkAssignStmt)) { return false; } @@ -505,7 +543,7 @@ export class NoTSLikeAsCheck implements BaseChecker { if (!(leftOpType instanceof ClassType)) { return false; } - const leftOpTypeclass = scene.getClass(leftOpType.getClassSignature()); + const leftOpTypeclass = this.scene.getClass(leftOpType.getClassSignature()); if (leftOpTypeclass === null) { return false; } @@ -567,14 +605,16 @@ export class NoTSLikeAsCheck implements BaseChecker { }); } - private addIssueReport(stmt: Stmt, operand: ArkCastExpr, relatedStmt?: Stmt): void { + private addIssueReport(stmt: Stmt, operand: ArkCastExpr, relatedStmt?: Stmt, incrementCase: boolean = false): void { const severity = this.rule.alert ?? this.metaData.severity; - const warnInfo = this.getLineAndColumn(stmt, operand); + const warnInfo = getLineAndColumn(stmt, operand); const problem = 'As'; const descPrefix = 'The value in type assertion is assigned by value with interface annotation'; let desc = `(${this.rule.ruleId.replace('@migration/', '')})`; - if (relatedStmt === undefined) { + if (incrementCase) { + desc = 'Can not use neither increment nor decrement with cast expression ' + desc; + } else if (relatedStmt === undefined) { desc = `Can not check when function call chain depth exceeds ${CALL_DEPTH_LIMIT}, please check it manually ` + desc; } else { const sinkFile = stmt.getCfg().getDeclaringMethod().getDeclaringArkFile(); @@ -585,6 +625,7 @@ export class NoTSLikeAsCheck implements BaseChecker { desc = `${descPrefix} in file ${path.normalize(relatedFile.getName())}: ${relatedStmt.getOriginPositionInfo().getLineNo()} ` + desc; } } + let defects = new Defects( warnInfo.line, warnInfo.startCol, @@ -601,19 +642,4 @@ export class NoTSLikeAsCheck implements BaseChecker { ); this.issues.push(new IssueReport(defects, undefined)); } - - private getLineAndColumn(stmt: Stmt, operand: Value): WarnInfo { - const arkFile = stmt.getCfg().getDeclaringMethod().getDeclaringArkFile(); - const originPosition = stmt.getOperandOriginalPosition(operand); - if (arkFile && originPosition) { - const originPath = arkFile.getFilePath(); - const line = originPosition.getFirstLine(); - const startCol = originPosition.getFirstCol(); - const endCol = startCol; - return { line, startCol, endCol, filePath: originPath }; - } else { - logger.debug('ArkFile is null.'); - } - return { line: -1, startCol: -1, endCol: -1, filePath: '' }; - } } diff --git a/ets2panda/linter/src/lib/LinterRunner.ts b/ets2panda/linter/src/lib/LinterRunner.ts index dd5d2cc790..7ecb67b73b 100644 --- a/ets2panda/linter/src/lib/LinterRunner.ts +++ b/ets2panda/linter/src/lib/LinterRunner.ts @@ -172,7 +172,6 @@ function migrate( let lintResult: LintRunResult = initialLintResult; const problemsInfosBeforeMigrate = lintResult.problemsInfos; - // According the configration file to filter linter rule const noNeedToBeFixedProblemsInfos = new Map(); filterLinterProblems(cmdOptions, lintResult, noNeedToBeFixedProblemsInfos); @@ -181,16 +180,13 @@ function migrate( hcResults = undefined; if (!appliedFix) { - // No fixes were applied, migration is finished. break; } - // Re-compile and re-lint project after applying the fixes. linterConfig = compileLintOptions(cmdOptions, getMigrationCreateProgramCallback(updatedSourceTexts)); lintResult = lintImpl(linterConfig); } - // Write new text for updated source files. updatedSourceTexts.forEach((newText, fileName) => { if (!cmdOptions.linterOptions.noMigrationBackupFile) { qEd.QuasiEditor.backupSrcFile(fileName); -- Gitee