Files
AI-Check-Test/.gitea/checker/src/main/java/com/codechecker/analyzer/ClassChangeAnalyzer.java
2026-06-09 11:20:24 +08:00

128 lines
5.7 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.codechecker.analyzer;
import com.codechecker.config.AppConfig;
import com.codechecker.git.GitChangeScanner;
import com.codechecker.model.ChangedClassFile;
import com.codechecker.model.ClassChangeKind;
import com.codechecker.model.ClassChangeReport;
import com.codechecker.model.FieldChange;
import com.codechecker.model.FieldInfo;
import com.codechecker.parser.ClassDeclParser;
import com.codechecker.parser.ClassFieldParser;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 编排 git 扫描、字段 diff、影响分析生成待通知的 ClassChangeReport 列表。
*/
public class ClassChangeAnalyzer {
private final GitChangeScanner gitScanner;
private final ClassFieldParser classFieldParser = new ClassFieldParser();
private final FieldDiffEngine fieldDiffEngine = new FieldDiffEngine();
private final ImpactAnalyzer impactAnalyzer = new ImpactAnalyzer();
private final ClassDeclParser classDeclParser = new ClassDeclParser();
public ClassChangeAnalyzer(GitChangeScanner gitScanner) {
this.gitScanner = gitScanner;
}
/** 扫描变更文件并逐条分析,无实质变更的 MODIFIED 会被跳过 */
public List<ClassChangeReport> analyze(Path repoRoot, AppConfig config, String oldSha, String newSha,
Map<String, com.codechecker.model.ApiEndpoint> endpointIndex) throws IOException {
List<ChangedClassFile> changedFiles = gitScanner.scanChangedClasses(oldSha, newSha);
List<ClassChangeReport> reports = new ArrayList<>();
for (ChangedClassFile changedFile : changedFiles) {
if (changedFile.getStatus() == ChangedClassFile.ChangeStatus.DELETED) {
reports.add(analyzeDeleted(changedFile, config, repoRoot, oldSha, endpointIndex));
continue;
}
ClassChangeReport report = analyzeModifiedOrRenamed(changedFile, config, repoRoot, oldSha, newSha, endpointIndex);
if (report != null) {
reports.add(report);
}
}
return reports;
}
/** 处理删除:标记 DELETED 并分析影响(基于旧源码) */
private ClassChangeReport analyzeDeleted(ChangedClassFile changedFile, AppConfig config, Path repoRoot,
String oldSha, Map<String, com.codechecker.model.ApiEndpoint> endpointIndex)
throws IOException {
String path = changedFile.getRelativePath();
String oldSource = gitScanner.readFileAtCommit(oldSha, path);
String classDescription = classDeclParser.extractClassDescription(
oldSource, changedFile.getClassName());
ClassChangeReport report = new ClassChangeReport(
changedFile.getClassName(),
null,
changedFile.getClassType(),
ClassChangeKind.DELETED,
path,
config.isDtoEntityConversionEnabled(),
classDescription
);
impactAnalyzer.analyze(report, endpointIndex, config, repoRoot, oldSource, oldSource);
return report;
}
/** 处理修改/重命名:字段 diff → 判定 changeKind → 影响分析 */
private ClassChangeReport analyzeModifiedOrRenamed(ChangedClassFile changedFile, AppConfig config,
Path repoRoot, String oldSha, String newSha,
Map<String, com.codechecker.model.ApiEndpoint> endpointIndex)
throws IOException {
String oldPath = changedFile.pathForOldCommit();
String newPath = changedFile.getRelativePath();
String oldSource = gitScanner.readFileAtCommit(oldSha, oldPath);
String newSource = gitScanner.readFileAtCommit(newSha, newPath);
if (newSource == null || newSource.isBlank()) {
newSource = gitScanner.readFileAtHead(newPath);
}
String oldFallback = ClassDeclParser.classNameFromPath(oldPath);
String newFallback = ClassDeclParser.classNameFromPath(newPath);
String oldClassName = changedFile.getOldClassName() != null
? changedFile.getOldClassName()
: classDeclParser.resolveClassName(oldSource, oldFallback);
String newClassName = classDeclParser.resolveClassName(newSource, newFallback);
List<FieldInfo> oldFields = classFieldParser.parseFields(oldSource, oldClassName);
List<FieldInfo> newFields = classFieldParser.parseFields(newSource, newClassName);
List<FieldChange> fieldChanges = fieldDiffEngine.diff(oldFields, newFields);
boolean renamed = !oldClassName.equals(newClassName);
ClassChangeKind changeKind;
if (renamed && fieldChanges.isEmpty()) {
changeKind = ClassChangeKind.RENAME_ONLY;
} else if (renamed) {
changeKind = ClassChangeKind.RENAME_AND_FIELDS;
} else if (!fieldChanges.isEmpty()) {
changeKind = ClassChangeKind.FIELDS_ONLY;
} else {
return null;
}
String classDescription = classDeclParser.extractClassDescription(newSource, newClassName);
ClassChangeReport report = new ClassChangeReport(
newClassName,
renamed ? oldClassName : null,
changedFile.getClassType(),
changeKind,
newPath,
config.isDtoEntityConversionEnabled(),
classDescription
);
fieldChanges.forEach(report::addFieldChange);
impactAnalyzer.analyze(report, endpointIndex, config, repoRoot, newSource, oldSource);
return report;
}
}