Reland "[analysis_server] Analyze fix data in fix_data folder"

This is a reland of commit bbacf39e9c

Original change's description:
> [analysis_server] Analyze fix data in fix_data folder
>
> Fixes part of https://github.com/dart-lang/sdk/issues/52126.
>
> Change-Id: Ib4bd7830a2f644eacedccd375c7c8dc60f040d33
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/296801
> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>

Change-Id: I571c1e4f87fdf0095d003d496f3c5d88e5cf0ff8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/297940
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Danny Tuppeny 2023-04-25 00:08:54 +00:00 committed by Commit Queue
parent b508533666
commit 86e3305538
4 changed files with 112 additions and 12 deletions

View file

@ -344,14 +344,28 @@ class ContextManagerImpl implements ContextManager {
callbacks.recordAnalysisErrors(path, convertedErrors);
}
/// Use the given analysis [driver] to analyze the content of yaml files
/// inside [folder].
void _analyzeFixDataFolder(
AnalysisDriver driver, Folder folder, String packageName) {
for (var resource in folder.getChildren()) {
if (resource is File) {
if (resource.shortName.endsWith('.yaml')) {
_analyzeFixDataYaml(driver, resource, packageName);
}
} else if (resource is Folder) {
_analyzeFixDataFolder(driver, resource, packageName);
}
}
}
/// Use the given analysis [driver] to analyze the content of the
/// data file at the given [path].
void _analyzeFixDataYaml(AnalysisDriver driver, String path) {
/// given [File].
void _analyzeFixDataYaml(
AnalysisDriver driver, File file, String packageName) {
var convertedErrors = const <protocol.AnalysisError>[];
try {
var file = resourceProvider.getFile(path);
var packageName = file.parent.parent.shortName;
var content = _readFile(path);
var content = file.readAsStringSync();
var errorListener = RecordingErrorListener();
var errorReporter = ErrorReporter(
errorListener,
@ -368,7 +382,7 @@ class ContextManagerImpl implements ContextManager {
// If the file cannot be analyzed, fall through to clear any previous
// errors.
}
callbacks.recordAnalysisErrors(path, convertedErrors);
callbacks.recordAnalysisErrors(file.path, convertedErrors);
}
/// Use the given analysis [driver] to analyze the content of the pubspec file
@ -436,10 +450,31 @@ class ContextManagerImpl implements ContextManager {
}
void _checkForFixDataYamlUpdate(String path) {
String? extractPackageNameFromPath(String path) {
String? packageName;
var pathSegments = pathContext.split(path);
if (pathContext.basename(path) == file_paths.fixDataYaml &&
pathSegments.length >= 3) {
// packageName/lib/fix_data.yaml
packageName = pathSegments[pathSegments.length - 3];
} else {
var fixDataIndex = pathSegments.indexOf('fix_data');
if (fixDataIndex >= 2) {
// packageName/lib/fix_data/foo/bar/fix.yaml
packageName = pathSegments[fixDataIndex - 2];
}
}
return packageName;
}
if (file_paths.isFixDataYaml(pathContext, path)) {
var driver = getDriverFor(path);
if (driver != null) {
_analyzeFixDataYaml(driver, path);
String? packageName = extractPackageNameFromPath(path);
if (packageName != null) {
var file = resourceProvider.getFile(path);
_analyzeFixDataYaml(driver, file, packageName);
}
}
}
}
@ -529,11 +564,19 @@ class ContextManagerImpl implements ContextManager {
_analyzeAnalysisOptionsYaml(driver, optionsFile.path);
}
var packageName = rootFolder.shortName;
var fixDataYamlFile = rootFolder
.getChildAssumingFolder('lib')
.getChildAssumingFile(file_paths.fixDataYaml);
if (fixDataYamlFile.exists) {
_analyzeFixDataYaml(driver, fixDataYamlFile.path);
_analyzeFixDataYaml(driver, fixDataYamlFile, packageName);
}
var fixDataFolder = rootFolder
.getChildAssumingFolder('lib')
.getChildAssumingFolder('fix_data');
if (fixDataFolder.exists) {
_analyzeFixDataFolder(driver, fixDataFolder, packageName);
}
var pubspecFile =

View file

@ -164,7 +164,9 @@ class ServerCapabilitiesComputer {
final analysisOptionsFile = TextDocumentFilterWithScheme(
language: 'yaml', scheme: 'file', pattern: '**/analysis_options.yaml');
final fixDataFile = TextDocumentFilterWithScheme(
language: 'yaml', scheme: 'file', pattern: '**/lib/fix_data.yaml');
language: 'yaml',
scheme: 'file',
pattern: '**/lib/{fix_data.yaml,fix_data/**.yaml}');
ServerCapabilitiesComputer(this._server);
ServerCapabilities computeServerCapabilities(

View file

@ -238,6 +238,28 @@ class A {}
assertNoErrors(b_path);
}
Future<void> test_fileSystem_addFile_fixDataFolderYaml() async {
var path = '$testPackageLibPath/fix_data/foo.yaml';
newFile('$testPackageLibPath/a.dart', '');
await setRoots(included: [workspaceRootPath], excluded: []);
// No `fix_data.yaml` to analyze yet.
assertNoErrorsNotification(path);
// Create it, will be analyzed.
newFile(path, '0: 1');
await pumpEventQueue();
await server.onAnalysisComplete;
// And it has errors.
assertHasErrors(path);
// We don't recreate analysis contexts.
_assertFlushedResults([]);
}
Future<void> test_fileSystem_addFile_fixDataYaml() async {
var path = '$testPackageLibPath/fix_data.yaml';
@ -531,6 +553,34 @@ class A {}
assertNoErrors(b_path);
}
Future<void> test_fileSystem_changeFile_fixDataFolderYaml() async {
var path = '$testPackageLibPath/fix_data/foo.yaml';
newFile('$testPackageLibPath/a.dart', '');
// This file has an error.
newFile(path, '0: 1');
await setRoots(included: [workspaceRootPath], excluded: []);
// The file was analyzed.
assertHasErrors(path);
// Replace with the content that does not have errors.
newFile(path, r'''
version: 1
transforms: []
''');
await pumpEventQueue();
await server.onAnalysisComplete;
// And it has errors.
assertNoErrors(path);
// We don't recreate analysis contexts.
_assertFlushedResults([]);
}
Future<void> test_fileSystem_changeFile_fixDataYaml() async {
var path = '$testPackageLibPath/fix_data.yaml';
@ -544,7 +594,7 @@ class A {}
// The file was analyzed.
assertHasErrors(path);
// Replace with the context that does not have errors.
// Replace with the content that does not have errors.
newFile(path, r'''
version: 1
transforms: []

View file

@ -31,6 +31,9 @@ const String dotDartTool = '.dart_tool';
/// The name of the data file used to specify data-driven fixes.
const String fixDataYaml = 'fix_data.yaml';
/// The name of the data folder used to specify data-driven fixes.
const String fixDataYamlFolder = 'fix_data';
/// The name of the package config files.
const String packageConfigJson = 'package_config.json';
@ -65,10 +68,12 @@ bool isDart(p.Context pathContext, String path) {
return pathContext.extension(path) == '.dart';
}
/// Return `true` if the [path] is a `fix_data.yaml` file.
/// Return `true` if the [path] is a `fix_data.yaml` or `fix_data/**.yaml` file.
/// Such files specify data-driven fixes.
bool isFixDataYaml(p.Context pathContext, String path) {
return pathContext.basename(path) == fixDataYaml;
return pathContext.basename(path) == fixDataYaml ||
(pathContext.split(path).contains('fix_data') &&
pathContext.extension(path) == '.yaml');
}
/// Return `true` if the given [path] refers to a file that is assumed to be