c6a35807创建于 2025年5月26日历史提交
/*
 * 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 { faultsAttrs } from '../FaultAttrs';
import { Logger } from '../Logger';
import { FaultID } from '../Problems';
import { ProblemSeverity } from '../ProblemSeverity';
import type { ProblemInfo } from '../ProblemInfo';
import { faultDesc } from '../FaultDesc';
import type { FileStatistics } from './FileStatistics';
import type { FileProblemStatistics } from './FileProblemStatistics';
import type { ProjectStatistics } from './ProjectStatistics';

export function log(...args: unknown[]): void {
  let outLine = '';
  for (let k = 0; k < args.length; k++) {
    outLine += `${args[k]} `;
  }
  Logger.info(outLine);
}

function logReport(srcFileName: string, problemInfo: ProblemInfo): void {
  const faultDescr = faultDesc[problemInfo.faultId];
  const faultType = problemInfo.type;
  Logger.info(
    `Warning: ${srcFileName} (${problemInfo.line}, ${problemInfo.column}): ${faultDescr ? faultDescr : faultType}`
  );
}

function logFileProblems(fileStats: FileStatistics): void {
  for (const problem of fileStats.problems) {
    logReport(fileStats.srcFileName, problem);
  }
}

function countProblemStats(fileStats: FileStatistics): FileProblemStatistics {
  let errors = 0;
  let warnings = 0;
  const errorLines = new Set<number>();
  const warningLines = new Set<number>();
  fileStats.problems.forEach((problemInfo: ProblemInfo) => {
    const line = problemInfo.line;
    switch (faultsAttrs[problemInfo.faultId].severity) {
      case ProblemSeverity.ERROR: {
        errors++;
        errorLines.add(line);
        break;
      }
      case ProblemSeverity.WARNING: {
        warnings++;
        warningLines.add(line);
        break;
      }
      default:
    }
  });
  const sortFunc = (a, b): number => {
    return a - b;
  };
  let errorLineNumbersString = '';
  Array.from(errorLines).
    sort(sortFunc).
    forEach((line) => {
      errorLineNumbersString += line + ', ';
    });
  let warningLineNumbersString = '';
  Array.from(warningLines).
    sort(sortFunc).
    forEach((line) => {
      warningLineNumbersString += line + ', ';
    });
  return {
    errors,
    warnings,
    errorLines: errorLines.size,
    warningLines: warningLines.size,
    errorLineNumbersString,
    warningLineNumbersString
  };
}

function logProblemFileInfo(fileStats: FileStatistics, problemStats: FileProblemStatistics): void {
  if (problemStats.errors > 0) {
    const errorRate = (problemStats.errors / fileStats.visitedNodes * 100).toFixed(2);
    const warningRate = (problemStats.warnings / fileStats.visitedNodes * 100).toFixed(2);
    log(fileStats.srcFileName, ': ', '\n\tError lines: ', problemStats.errorLineNumbersString);
    log(fileStats.srcFileName, ': ', '\n\tWarning lines: ', problemStats.warningLineNumbersString);
    log(
      '\n\tError constructs (%): ',
      errorRate,
      '\t[ of ',
      fileStats.visitedNodes,
      ' constructs ], \t',
      problemStats.errorLines,
      ' lines'
    );
    log(
      '\n\tWarning constructs (%): ',
      warningRate,
      '\t[ of ',
      fileStats.visitedNodes,
      ' constructs ], \t',
      problemStats.warningLines,
      ' lines'
    );
  }
}

function logTotalProblemsInfo(
  totalErrors: number,
  totalWarnings: number,
  totalErrorLines: number,
  totalWarningLines: number,
  totalVisitedNodes: number
): void {
  const errorRate = (totalErrors / totalVisitedNodes * 100).toFixed(2);
  const warningRate = (totalWarnings / totalVisitedNodes * 100).toFixed(2);
  log('\nTotal error constructs (%): ', errorRate);
  log('\nTotal warning constructs (%): ', warningRate);
  log('\nTotal error lines:', totalErrorLines, ' lines\n');
  log('\nTotal warning lines:', totalWarningLines, ' lines\n');
}

function logProblemsPercentageByFeatures(projectStats: ProjectStatistics, totalVisitedNodes: number): void {
  log('\nPercent by features: ');
  for (let i = 0; i < FaultID.LAST_ID; i++) {
    let nodes = 0;
    let lines = 0;
    for (const fileStats of projectStats.fileStats) {
      nodes += fileStats.nodeCounters[i];
      lines += fileStats.lineCounters[i].size;
    }
    const pecentage = (nodes / totalVisitedNodes * 100).toFixed(2).padEnd(7, ' ');
    log(faultDesc[i].padEnd(55, ' '), pecentage, '[', nodes, ' constructs / ', lines, ' lines]');
  }
}

export function logStatistics(projectStats: ProjectStatistics): void {
  let filesWithErrors = 0;
  let totalErrors = 0;
  let totalWarnings = 0;
  let totalErrorLines = 0;
  let totalWarningLines = 0;
  let totalVisitedNodes = 0;

  for (const fileStats of projectStats.fileStats) {
    logFileProblems(fileStats);

    const problemStats = countProblemStats(fileStats);
    logProblemFileInfo(fileStats, problemStats);

    if (problemStats.errors > 0) {
      filesWithErrors++;
    }

    totalErrors += problemStats.errors;
    totalWarnings += problemStats.warnings;
    totalErrorLines += problemStats.errorLines;
    totalWarningLines += problemStats.warningLines;
    totalVisitedNodes += fileStats.visitedNodes;
  }

  log('\n\n\nFiles scanned: ', projectStats.fileStats.length);
  log('\nFiles with problems: ', filesWithErrors);

  logTotalProblemsInfo(totalErrors, totalWarnings, totalErrorLines, totalWarningLines, totalVisitedNodes);
  logProblemsPercentageByFeatures(projectStats, totalVisitedNodes);
}