1/* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { faultsAttrs } from '../FaultAttrs'; 17import { Logger } from '../Logger'; 18import { FaultID } from '../Problems'; 19import { ProblemSeverity } from '../ProblemSeverity'; 20import type { ProblemInfo } from '../ProblemInfo'; 21import { faultDesc } from '../FaultDesc'; 22import type { FileStatistics } from './FileStatistics'; 23import type { FileProblemStatistics } from './FileProblemStatistics'; 24import type { ProjectStatistics } from './ProjectStatistics'; 25 26export function log(...args: unknown[]): void { 27 let outLine = ''; 28 for (let k = 0; k < args.length; k++) { 29 outLine += `${args[k]} `; 30 } 31 Logger.info(outLine); 32} 33 34function logReport(srcFileName: string, problemInfo: ProblemInfo): void { 35 const faultDescr = faultDesc[problemInfo.faultId]; 36 const faultType = problemInfo.type; 37 Logger.info( 38 `Warning: ${srcFileName} (${problemInfo.line}, ${problemInfo.column}): ${faultDescr ? faultDescr : faultType}` 39 ); 40} 41 42function logFileProblems(fileStats: FileStatistics): void { 43 for (const problem of fileStats.problems) { 44 logReport(fileStats.srcFileName, problem); 45 } 46} 47 48function countProblemStats(fileStats: FileStatistics): FileProblemStatistics { 49 let errors = 0; 50 let warnings = 0; 51 const errorLines = new Set<number>(); 52 const warningLines = new Set<number>(); 53 fileStats.problems.forEach((problemInfo: ProblemInfo) => { 54 const line = problemInfo.line; 55 switch (faultsAttrs[problemInfo.faultId].severity) { 56 case ProblemSeverity.ERROR: { 57 errors++; 58 errorLines.add(line); 59 break; 60 } 61 case ProblemSeverity.WARNING: { 62 warnings++; 63 warningLines.add(line); 64 break; 65 } 66 default: 67 } 68 }); 69 const sortFunc = (a, b): number => { 70 return a - b; 71 }; 72 let errorLineNumbersString = ''; 73 Array.from(errorLines). 74 sort(sortFunc). 75 forEach((line) => { 76 errorLineNumbersString += line + ', '; 77 }); 78 let warningLineNumbersString = ''; 79 Array.from(warningLines). 80 sort(sortFunc). 81 forEach((line) => { 82 warningLineNumbersString += line + ', '; 83 }); 84 return { 85 errors, 86 warnings, 87 errorLines: errorLines.size, 88 warningLines: warningLines.size, 89 errorLineNumbersString, 90 warningLineNumbersString 91 }; 92} 93 94function logProblemFileInfo(fileStats: FileStatistics, problemStats: FileProblemStatistics): void { 95 if (problemStats.errors > 0) { 96 const errorRate = (problemStats.errors / fileStats.visitedNodes * 100).toFixed(2); 97 const warningRate = (problemStats.warnings / fileStats.visitedNodes * 100).toFixed(2); 98 log(fileStats.srcFileName, ': ', '\n\tError lines: ', problemStats.errorLineNumbersString); 99 log(fileStats.srcFileName, ': ', '\n\tWarning lines: ', problemStats.warningLineNumbersString); 100 log( 101 '\n\tError constructs (%): ', 102 errorRate, 103 '\t[ of ', 104 fileStats.visitedNodes, 105 ' constructs ], \t', 106 problemStats.errorLines, 107 ' lines' 108 ); 109 log( 110 '\n\tWarning constructs (%): ', 111 warningRate, 112 '\t[ of ', 113 fileStats.visitedNodes, 114 ' constructs ], \t', 115 problemStats.warningLines, 116 ' lines' 117 ); 118 } 119} 120 121function logTotalProblemsInfo( 122 totalErrors: number, 123 totalWarnings: number, 124 totalErrorLines: number, 125 totalWarningLines: number, 126 totalVisitedNodes: number 127): void { 128 const errorRate = (totalErrors / totalVisitedNodes * 100).toFixed(2); 129 const warningRate = (totalWarnings / totalVisitedNodes * 100).toFixed(2); 130 log('\nTotal error constructs (%): ', errorRate); 131 log('\nTotal warning constructs (%): ', warningRate); 132 log('\nTotal error lines:', totalErrorLines, ' lines\n'); 133 log('\nTotal warning lines:', totalWarningLines, ' lines\n'); 134} 135 136function logProblemsPercentageByFeatures(projectStats: ProjectStatistics, totalVisitedNodes: number): void { 137 log('\nPercent by features: '); 138 for (let i = 0; i < FaultID.LAST_ID; i++) { 139 let nodes = 0; 140 let lines = 0; 141 for (const fileStats of projectStats.fileStats) { 142 nodes += fileStats.nodeCounters[i]; 143 lines += fileStats.lineCounters[i].size; 144 } 145 const pecentage = (nodes / totalVisitedNodes * 100).toFixed(2).padEnd(7, ' '); 146 log(faultDesc[i].padEnd(55, ' '), pecentage, '[', nodes, ' constructs / ', lines, ' lines]'); 147 } 148} 149 150export function logStatistics(projectStats: ProjectStatistics): void { 151 let filesWithErrors = 0; 152 let totalErrors = 0; 153 let totalWarnings = 0; 154 let totalErrorLines = 0; 155 let totalWarningLines = 0; 156 let totalVisitedNodes = 0; 157 158 for (const fileStats of projectStats.fileStats) { 159 logFileProblems(fileStats); 160 161 const problemStats = countProblemStats(fileStats); 162 logProblemFileInfo(fileStats, problemStats); 163 164 if (problemStats.errors > 0) { 165 filesWithErrors++; 166 } 167 168 totalErrors += problemStats.errors; 169 totalWarnings += problemStats.warnings; 170 totalErrorLines += problemStats.errorLines; 171 totalWarningLines += problemStats.warningLines; 172 totalVisitedNodes += fileStats.visitedNodes; 173 } 174 175 log('\n\n\nFiles scanned: ', projectStats.fileStats.length); 176 log('\nFiles with problems: ', filesWithErrors); 177 178 logTotalProblemsInfo(totalErrors, totalWarnings, totalErrorLines, totalWarningLines, totalVisitedNodes); 179 logProblemsPercentageByFeatures(projectStats, totalVisitedNodes); 180} 181