blob: 6d79e0324473f6ee07ad46d3caef477ef1405831 [file] [log] [blame]
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'package:analysis_server/lsp_protocol/protocol.dart';
import 'package:analysis_server/src/lsp/handlers/code_actions/abstract_code_actions_producer.dart';
import 'package:analysis_server/src/services/correction/fix/analysis_options/fix_generator.dart';
import 'package:analyzer/source/line_info.dart';
import 'package:analyzer/src/analysis_options/analysis_options_provider.dart';
import 'package:analyzer/src/generated/source.dart' show SourceFactory;
import 'package:analyzer/src/task/options.dart';
import 'package:analyzer/src/workspace/pub.dart';
import 'package:yaml/yaml.dart';
/// Produces [CodeAction]s from analysis options fixes.
class AnalysisOptionsCodeActionsProducer extends AbstractCodeActionsProducer {
AnalysisOptionsCodeActionsProducer(
super.server,
super.file,
super.lineInfo, {
required super.offset,
required super.length,
required super.shouldIncludeKind,
required super.capabilities,
});
@override
String get name => 'ServerAnalysisOptionsActionsComputer';
@override
Future<List<CodeActionWithPriority>> getAssistActions() async => [];
@override
Future<List<CodeActionWithPriority>> getFixActions() async {
final session = await server.getAnalysisSession(path);
if (session == null) {
return [];
}
final driver = server.getAnalysisDriver(path);
if (driver == null) {
return [];
}
final resourceProvider = server.resourceProvider;
final sourceFactory = driver.sourceFactory;
final optionsFile = resourceProvider.getFile(path);
final content = safelyRead(optionsFile);
if (content == null) {
return [];
}
final lineInfo = LineInfo.fromContent(content);
final options = _getOptions(sourceFactory, content);
if (options == null) {
return [];
}
final contextRoot = session.analysisContext.contextRoot;
final package = contextRoot.workspace.findPackageFor(optionsFile.path);
final sdkVersionConstraint =
(package is PubWorkspacePackage) ? package.sdkVersionConstraint : null;
final errors = analyzeAnalysisOptions(
optionsFile.createSource(),
content,
sourceFactory,
contextRoot.root.path,
sdkVersionConstraint,
);
final codeActions = <CodeActionWithPriority>[];
for (final error in errors) {
final generator = AnalysisOptionsFixGenerator(
resourceProvider, error, content, options);
final fixes = await generator.computeFixes();
if (fixes.isEmpty) {
continue;
}
final result = createResult(session, lineInfo, errors);
final diagnostic = createDiagnostic(lineInfo, result, error);
codeActions.addAll(
fixes.map((fix) {
final action =
createFixAction(fix.change, diagnostic, path, lineInfo);
return (action: action, priority: fix.kind.priority);
}),
);
}
return codeActions;
}
@override
Future<List<Either2<CodeAction, Command>>> getRefactorActions() async => [];
@override
Future<List<Either2<CodeAction, Command>>> getSourceActions() async => [];
YamlMap? _getOptions(SourceFactory sourceFactory, String content) {
var optionsProvider = AnalysisOptionsProvider(sourceFactory);
try {
return optionsProvider.getOptionsFromString(content);
} on OptionsFormatException {
return null;
}
}
}