DAS plugins: Move Assist code to analysis_server_plugin package
The PluginServer class needs access to AssistProcessor in order to compute assists. That class needs access to a few other classes, which then must also be moved: * assist_core.dart - the Assist class * assist_dart.dart - the DartAssistContext class * assist_generators.dart - the registeredAssistGenerators variable * assist_performance.dart - the AssistPerformance and GetAssistsPerformance classes * assist_processor.dart - the AssistProcessor class with it's singular API, `compute()` * performance.dart - the ProducerRequestPerformance class * the `addCaretAtOffset` helper function, refactored into a `withCaretAt` extension method This change is functionally a no-op. Change-Id: Ic883d21e9cc8c3db1f6093f830f01ec6eb9a0976 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/416680 Commit-Queue: Samuel Rawlins <srawlins@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Phil Quitslund <pquitslund@google.com>
This commit is contained in:
committed by
Commit Queue
parent
0f2c6d7302
commit
331c700f33
@@ -29,9 +29,7 @@ import 'package:analysis_server/src/protocol_server.dart' as server;
|
||||
import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
|
||||
import 'package:analysis_server/src/server/diagnostic_server.dart';
|
||||
import 'package:analysis_server/src/server/message_scheduler.dart';
|
||||
import 'package:analysis_server/src/server/performance.dart';
|
||||
import 'package:analysis_server/src/services/completion/completion_performance.dart';
|
||||
import 'package:analysis_server/src/services/correction/assist_performance.dart';
|
||||
import 'package:analysis_server/src/services/correction/fix_performance.dart';
|
||||
import 'package:analysis_server/src/services/correction/namespace.dart';
|
||||
import 'package:analysis_server/src/services/dart_tooling_daemon/dtd_services.dart';
|
||||
@@ -50,6 +48,8 @@ import 'package:analysis_server/src/utilities/process.dart';
|
||||
import 'package:analysis_server/src/utilities/request_statistics.dart';
|
||||
import 'package:analysis_server/src/utilities/tee_string_sink.dart';
|
||||
import 'package:analysis_server/src/utilities/timing_byte_store.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/assist_performance.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/performance.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
import 'package:analyzer/dart/analysis/session.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
// 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 'package:analysis_server/plugin/edit/assist/assist_core.dart';
|
||||
import 'package:analysis_server/src/services/correction/assist.dart';
|
||||
import 'package:analysis_server/src/services/correction/assist_internal.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/assist_core.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/assist_processor.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/dart_change_workspace.dart';
|
||||
import 'package:analyzer/dart/analysis/session.dart';
|
||||
import 'package:analyzer/instrumentation/service.dart';
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:analysis_server/plugin/edit/assist/assist_core.dart';
|
||||
import 'package:analysis_server/protocol/protocol.dart';
|
||||
import 'package:analysis_server/protocol/protocol_generated.dart';
|
||||
import 'package:analysis_server/src/handler/legacy/legacy_handler.dart';
|
||||
@@ -12,8 +11,9 @@ import 'package:analysis_server/src/legacy_analysis_server.dart';
|
||||
import 'package:analysis_server/src/plugin/result_converter.dart';
|
||||
import 'package:analysis_server/src/request_handler_mixin.dart';
|
||||
import 'package:analysis_server/src/services/correction/assist.dart';
|
||||
import 'package:analysis_server/src/services/correction/assist_internal.dart';
|
||||
import 'package:analysis_server/src/services/correction/assist_performance.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/assist_core.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/assist_performance.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/assist_processor.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/dart_change_workspace.dart';
|
||||
import 'package:analyzer/dart/analysis/session.dart';
|
||||
import 'package:analyzer/src/exception/exception.dart';
|
||||
|
||||
@@ -91,7 +91,6 @@ import 'package:analysis_server/src/server/diagnostic_server.dart';
|
||||
import 'package:analysis_server/src/server/error_notifier.dart';
|
||||
import 'package:analysis_server/src/server/features.dart';
|
||||
import 'package:analysis_server/src/server/message_scheduler.dart';
|
||||
import 'package:analysis_server/src/server/performance.dart';
|
||||
import 'package:analysis_server/src/server/sdk_configuration.dart';
|
||||
import 'package:analysis_server/src/services/completion/completion_state.dart';
|
||||
import 'package:analysis_server/src/services/execution/execution_context.dart';
|
||||
@@ -99,6 +98,7 @@ import 'package:analysis_server/src/services/flutter/widget_descriptions.dart';
|
||||
import 'package:analysis_server/src/services/refactoring/legacy/refactoring_manager.dart';
|
||||
import 'package:analysis_server/src/utilities/extensions/resource_provider.dart';
|
||||
import 'package:analysis_server/src/utilities/process.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/performance.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
import 'package:analyzer/dart/analysis/session.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
|
||||
@@ -5,20 +5,20 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:analysis_server/lsp_protocol/protocol.dart';
|
||||
import 'package:analysis_server/plugin/edit/assist/assist_core.dart';
|
||||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/code_actions/abstract_code_actions_producer.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/protocol_server.dart'
|
||||
hide AnalysisOptions, Position;
|
||||
import 'package:analysis_server/src/services/correction/assist.dart';
|
||||
import 'package:analysis_server/src/services/correction/assist_internal.dart';
|
||||
import 'package:analysis_server/src/services/correction/assist_performance.dart';
|
||||
import 'package:analysis_server/src/services/correction/fix_performance.dart';
|
||||
import 'package:analysis_server/src/services/refactoring/framework/refactoring_context.dart';
|
||||
import 'package:analysis_server/src/services/refactoring/framework/refactoring_processor.dart';
|
||||
import 'package:analysis_server/src/services/refactoring/legacy/refactoring.dart';
|
||||
import 'package:analysis_server_plugin/edit/fix/dart_fix_context.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/assist_core.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/assist_performance.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/assist_processor.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/dart_change_workspace.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/fix_processor.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
|
||||
@@ -28,8 +28,8 @@ import 'package:analysis_server/src/server/detachable_filesystem_manager.dart';
|
||||
import 'package:analysis_server/src/server/diagnostic_server.dart';
|
||||
import 'package:analysis_server/src/server/error_notifier.dart';
|
||||
import 'package:analysis_server/src/server/message_scheduler.dart';
|
||||
import 'package:analysis_server/src/server/performance.dart';
|
||||
import 'package:analysis_server/src/utilities/process.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/performance.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
import 'package:analyzer/dart/analysis/session.dart';
|
||||
import 'package:analyzer/error/error.dart';
|
||||
@@ -1205,7 +1205,12 @@ class LspAnalysisServer extends AnalysisServer {
|
||||
// TODO(dantup): Consider supporting per-workspace config by
|
||||
// calling workspace/configuration whenever workspace folders change
|
||||
// and caching the config for each one.
|
||||
: _workspaceFolders.map((root) => resourceProvider.pathContext.join(root, excludePath)),
|
||||
: _workspaceFolders.map(
|
||||
(root) => resourceProvider.pathContext.join(
|
||||
root,
|
||||
excludePath,
|
||||
),
|
||||
),
|
||||
)
|
||||
.map(pathContext.normalize)
|
||||
.toSet();
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
// 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 'package:analysis_server/src/utilities/strings.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/performance.dart';
|
||||
import 'package:analyzer/src/util/performance/operation_performance.dart';
|
||||
|
||||
abstract class ProducerRequestPerformance extends RequestPerformance {
|
||||
final String path;
|
||||
|
||||
final String snippet;
|
||||
final List<ProducerTiming> producerTimings;
|
||||
ProducerRequestPerformance({
|
||||
required String operation,
|
||||
required this.path,
|
||||
required super.performance,
|
||||
super.requestLatency,
|
||||
super.startTime,
|
||||
required String content,
|
||||
required int offset,
|
||||
required this.producerTimings,
|
||||
}) : snippet = addCaretAtOffset(content, offset),
|
||||
super(operation: 'GetAssists');
|
||||
|
||||
int get elapsedInMilliseconds => performance.elapsed.inMilliseconds;
|
||||
}
|
||||
|
||||
class RequestPerformance {
|
||||
static var _nextId = 1;
|
||||
final int id;
|
||||
final OperationPerformance performance;
|
||||
final int? requestLatency;
|
||||
final String operation;
|
||||
final DateTime? startTime;
|
||||
|
||||
RequestPerformance({
|
||||
required this.operation,
|
||||
required this.performance,
|
||||
this.requestLatency,
|
||||
this.startTime,
|
||||
}) : id = _nextId++;
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
// 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 'package:analysis_server/src/server/performance.dart';
|
||||
import 'package:analysis_server/src/utilities/strings.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/performance.dart';
|
||||
import 'package:analysis_server_plugin/src/utilities/string_extensions.dart';
|
||||
|
||||
/// Overall performance of a code completion operation.
|
||||
class CompletionPerformance extends RequestPerformance {
|
||||
@@ -18,7 +18,7 @@ class CompletionPerformance extends RequestPerformance {
|
||||
super.requestLatency,
|
||||
required String content,
|
||||
required int offset,
|
||||
}) : snippet = addCaretAtOffset(content, offset),
|
||||
}) : snippet = content.withCaretAt(offset),
|
||||
super(operation: 'Completion');
|
||||
|
||||
String get computedSuggestionCountStr {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// 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 'package:analysis_server/plugin/edit/assist/assist_dart.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/assist_dart.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/change_workspace.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
import 'package:analyzer/instrumentation/service.dart';
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
// 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 'package:analysis_server/plugin/edit/assist/assist_core.dart';
|
||||
import 'package:analysis_server/plugin/edit/assist/assist_dart.dart';
|
||||
import 'package:analysis_server/src/services/correction/assist_generators.dart';
|
||||
import 'package:analysis_server/src/services/correction/assist_performance.dart';
|
||||
import 'package:analysis_server/src/services/correction/dart/add_diagnostic_property_reference.dart';
|
||||
import 'package:analysis_server/src/services/correction/dart/add_digit_separators.dart';
|
||||
import 'package:analysis_server/src/services/correction/dart/add_return_type.dart';
|
||||
@@ -76,15 +72,8 @@ import 'package:analysis_server/src/services/correction/dart/split_and_condition
|
||||
import 'package:analysis_server/src/services/correction/dart/split_variable_declaration.dart';
|
||||
import 'package:analysis_server/src/services/correction/dart/surround_with.dart';
|
||||
import 'package:analysis_server/src/services/correction/dart/use_curly_braces.dart';
|
||||
import 'package:analysis_server_plugin/edit/dart/correction_producer.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/assist_generators.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/fix_generators.dart';
|
||||
import 'package:analyzer/error/error.dart';
|
||||
import 'package:analyzer/src/dart/ast/utilities.dart';
|
||||
import 'package:analyzer/src/generated/java_core.dart';
|
||||
import 'package:analyzer_plugin/utilities/assist/assist.dart'
|
||||
hide AssistContributor;
|
||||
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
|
||||
import 'package:analyzer_plugin/utilities/change_builder/conflicting_edit_exception.dart';
|
||||
|
||||
/// The set of built-in generators used to produce assists.
|
||||
const Set<ProducerGenerator> _builtInGenerators = {
|
||||
@@ -178,131 +167,3 @@ void registerBuiltInAssistGenerators() {
|
||||
registeredAssistGenerators.registerMultiGenerator,
|
||||
);
|
||||
}
|
||||
|
||||
/// The computer for Dart assists.
|
||||
class AssistProcessor {
|
||||
final AssistPerformance? _performance;
|
||||
final DartAssistContext _assistContext;
|
||||
final Stopwatch _timer = Stopwatch();
|
||||
|
||||
final List<Assist> _assists = [];
|
||||
|
||||
AssistProcessor(this._assistContext, {AssistPerformance? performance})
|
||||
: _performance = performance;
|
||||
|
||||
Future<List<Assist>> compute() async {
|
||||
_timer.start();
|
||||
await _addFromProducers();
|
||||
_timer.stop();
|
||||
_performance?.computeTime = _timer.elapsed;
|
||||
return _assists;
|
||||
}
|
||||
|
||||
void _addAssistFromBuilder(
|
||||
ChangeBuilder builder,
|
||||
AssistKind kind, {
|
||||
List<Object>? args,
|
||||
}) {
|
||||
var change = builder.sourceChange;
|
||||
if (change.edits.isEmpty) {
|
||||
return;
|
||||
}
|
||||
change.id = kind.id;
|
||||
change.message = formatList(kind.message, args);
|
||||
_assists.add(Assist(kind, change));
|
||||
}
|
||||
|
||||
Future<void> _addFromProducers() async {
|
||||
var context = CorrectionProducerContext.createResolved(
|
||||
libraryResult: _assistContext.libraryResult,
|
||||
unitResult: _assistContext.unitResult,
|
||||
selectionOffset: _assistContext.selectionOffset,
|
||||
selectionLength: _assistContext.selectionLength,
|
||||
);
|
||||
|
||||
Future<void> compute(CorrectionProducer producer) async {
|
||||
var builder = ChangeBuilder(
|
||||
workspace: _assistContext.workspace,
|
||||
eol: producer.eol,
|
||||
);
|
||||
try {
|
||||
if (_performance != null) {
|
||||
var startTime = _timer.elapsedMilliseconds;
|
||||
await producer.compute(builder);
|
||||
_performance.producerTimings.add((
|
||||
className: producer.runtimeType.toString(),
|
||||
elapsedTime: _timer.elapsedMilliseconds - startTime,
|
||||
));
|
||||
} else {
|
||||
await producer.compute(builder);
|
||||
}
|
||||
|
||||
var assistKind = producer.assistKind;
|
||||
if (assistKind != null) {
|
||||
_addAssistFromBuilder(
|
||||
builder,
|
||||
assistKind,
|
||||
args: producer.assistArguments,
|
||||
);
|
||||
}
|
||||
} on ConflictingEditException catch (exception, stackTrace) {
|
||||
// Handle the exception by (a) not adding an assist based on the
|
||||
// producer and (b) logging the exception.
|
||||
_assistContext.instrumentationService.logException(
|
||||
exception,
|
||||
stackTrace,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (var generator in registeredAssistGenerators.producerGenerators) {
|
||||
if (!_generatorAppliesToAnyLintRule(
|
||||
generator,
|
||||
registeredAssistGenerators.lintRuleMap[generator] ?? {},
|
||||
)) {
|
||||
var producer = generator(context: context);
|
||||
await compute(producer);
|
||||
}
|
||||
}
|
||||
for (var multiGenerator
|
||||
in registeredAssistGenerators.multiProducerGenerators) {
|
||||
var multiProducer = multiGenerator(context: context);
|
||||
for (var producer in await multiProducer.producers) {
|
||||
await compute(producer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether [generator] applies to any enabled lint rule, among
|
||||
/// [errorCodes].
|
||||
bool _generatorAppliesToAnyLintRule(
|
||||
ProducerGenerator generator,
|
||||
Set<LintCode> errorCodes,
|
||||
) {
|
||||
if (errorCodes.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var selectionEnd =
|
||||
_assistContext.selectionOffset + _assistContext.selectionLength;
|
||||
var locator = NodeLocator(_assistContext.selectionOffset, selectionEnd);
|
||||
var node = locator.searchWithin(_assistContext.unitResult.unit);
|
||||
if (node == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var fileOffset = node.offset;
|
||||
for (var error in _assistContext.unitResult.errors) {
|
||||
var errorSource = error.source;
|
||||
if (_assistContext.unitResult.path == errorSource.fullName) {
|
||||
if (fileOffset >= error.offset &&
|
||||
fileOffset <= error.offset + error.length) {
|
||||
if (errorCodes.contains(error.errorCode)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// 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 'package:analysis_server/src/server/performance.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/performance.dart';
|
||||
|
||||
/// Overall performance of a request for quick fixes operation.
|
||||
class GetFixesPerformance extends ProducerRequestPerformance {
|
||||
|
||||
@@ -12,7 +12,7 @@ import 'package:analysis_server/src/lsp/error_or.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_states.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/server/message_scheduler.dart';
|
||||
import 'package:analysis_server/src/server/performance.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/performance.dart';
|
||||
import 'package:analyzer/src/util/performance/operation_performance.dart';
|
||||
import 'package:dtd/dtd.dart';
|
||||
import 'package:json_rpc_2/json_rpc_2.dart';
|
||||
|
||||
@@ -16,9 +16,7 @@ import 'package:analysis_server/src/lsp/lsp_analysis_server.dart'
|
||||
show LspAnalysisServer;
|
||||
import 'package:analysis_server/src/plugin/plugin_manager.dart';
|
||||
import 'package:analysis_server/src/server/http_server.dart';
|
||||
import 'package:analysis_server/src/server/performance.dart';
|
||||
import 'package:analysis_server/src/services/completion/completion_performance.dart';
|
||||
import 'package:analysis_server/src/services/correction/assist_performance.dart';
|
||||
import 'package:analysis_server/src/services/correction/fix_performance.dart';
|
||||
import 'package:analysis_server/src/socket_server.dart';
|
||||
import 'package:analysis_server/src/status/ast_writer.dart';
|
||||
@@ -26,6 +24,8 @@ import 'package:analysis_server/src/status/element_writer.dart';
|
||||
import 'package:analysis_server/src/status/pages.dart';
|
||||
import 'package:analysis_server/src/utilities/profiling.dart';
|
||||
import 'package:analysis_server/src/utilities/stream_string_stink.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/assist_performance.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/performance.dart';
|
||||
import 'package:analyzer/dart/analysis/context_root.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
import 'package:analyzer/src/context/source.dart';
|
||||
|
||||
@@ -6,7 +6,7 @@ import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:analysis_server/src/server/performance.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/performance.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
String escape(String? text) => text == null ? '' : htmlEscape.convert(text);
|
||||
|
||||
@@ -12,35 +12,6 @@ const int CHAR_DOLLAR = 0x24;
|
||||
/// "_"
|
||||
const int CHAR_UNDERSCORE = 0x5F;
|
||||
|
||||
/// Build a string from [contents] that includes a caret (`^`) at the
|
||||
/// given [offset].
|
||||
///
|
||||
/// This string is useful for displaying to users in a diagnostic context.
|
||||
String addCaretAtOffset(String contents, int offset) {
|
||||
if (offset < 0 || contents.length < offset) {
|
||||
return '???';
|
||||
}
|
||||
var start = offset;
|
||||
while (start > 0) {
|
||||
var ch = contents[start - 1];
|
||||
if (ch == '\r' || ch == '\n') {
|
||||
break;
|
||||
}
|
||||
--start;
|
||||
}
|
||||
var end = offset;
|
||||
while (end < contents.length) {
|
||||
var ch = contents[end];
|
||||
if (ch == '\r' || ch == '\n') {
|
||||
break;
|
||||
}
|
||||
++end;
|
||||
}
|
||||
var prefix = contents.substring(start, offset);
|
||||
var suffix = contents.substring(offset, end);
|
||||
return '$prefix^$suffix';
|
||||
}
|
||||
|
||||
String? capitalize(String? str) {
|
||||
if (str == null || str.isEmpty) {
|
||||
return str;
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
// 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 'package:analysis_server/plugin/edit/assist/assist_core.dart';
|
||||
import 'package:analysis_server/src/cider/assists.dart';
|
||||
import 'package:analysis_server/src/services/correction/assist.dart';
|
||||
import 'package:analysis_server/src/services/correction/assist_internal.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/assist_core.dart';
|
||||
import 'package:analyzer/source/line_info.dart';
|
||||
import 'package:analyzer_plugin/protocol/protocol_common.dart' show SourceEdit;
|
||||
import 'package:analyzer_plugin/utilities/assist/assist.dart';
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
// 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 'package:analysis_server/plugin/edit/assist/assist_core.dart';
|
||||
import 'package:analysis_server/src/services/correction/assist.dart';
|
||||
import 'package:analysis_server/src/services/correction/assist_internal.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/assist_core.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/assist_processor.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/change_workspace.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/dart_change_workspace.dart';
|
||||
import 'package:analyzer/src/test_utilities/platform.dart';
|
||||
|
||||
+3
-8
@@ -7,16 +7,14 @@ import 'package:analyzer_plugin/protocol/protocol_common.dart'
|
||||
import 'package:analyzer_plugin/utilities/assist/assist.dart';
|
||||
|
||||
/// A description of a single proposed assist.
|
||||
///
|
||||
/// Clients may not extend, implement or mix-in this class.
|
||||
class Assist {
|
||||
final class Assist {
|
||||
/// A description of the assist being proposed.
|
||||
final AssistKind kind;
|
||||
|
||||
/// The change to be made in order to apply the assist.
|
||||
final SourceChange change;
|
||||
|
||||
/// Initialize a newly created assist to have the given [kind] and [change].
|
||||
/// Initializes a newly created assist to have the given [kind] and [change].
|
||||
Assist(this.kind, this.change);
|
||||
|
||||
@override
|
||||
@@ -24,10 +22,7 @@ class Assist {
|
||||
return 'Assist(kind=$kind, change=$change)';
|
||||
}
|
||||
|
||||
/// A function that can be used to sort assists by their relevance.
|
||||
///
|
||||
/// The most relevant assists will be sorted before assists with a lower
|
||||
/// relevance. Assists with the same relevance are sorted alphabetically.
|
||||
/// Compares two assists by their relevance, then their message.
|
||||
static int compareAssists(Assist a, Assist b) {
|
||||
if (a.kind.priority != b.kind.priority) {
|
||||
// A higher priority indicates a higher relevance
|
||||
+6
-6
@@ -10,22 +10,22 @@ import 'package:analyzer/instrumentation/service.dart';
|
||||
///
|
||||
/// Clients may not extend, implement or mix-in this class.
|
||||
abstract class DartAssistContext {
|
||||
/// Return the instrumentation service used to report errors that prevent a
|
||||
/// fix from being composed.
|
||||
/// The instrumentation service used to report errors that prevent a fix from
|
||||
/// being composed.
|
||||
InstrumentationService get instrumentationService;
|
||||
|
||||
/// The resolved library result in which assist operates.
|
||||
/// The resolved library result in which an assist operates.
|
||||
ResolvedLibraryResult get libraryResult;
|
||||
|
||||
/// The length of the selection.
|
||||
int get selectionLength;
|
||||
|
||||
/// The start of the selection.
|
||||
/// The starting offset of the selection.
|
||||
int get selectionOffset;
|
||||
|
||||
/// The unit result in which assist operates.
|
||||
/// The unit result in which an assist operates.
|
||||
ResolvedUnitResult get unitResult;
|
||||
|
||||
/// The workspace in which the fix contributor operates.
|
||||
/// The workspace in which an assist operates.
|
||||
ChangeWorkspace get workspace;
|
||||
}
|
||||
+1
-2
@@ -23,8 +23,7 @@ class _RegisteredAssistGenerators {
|
||||
|
||||
/// A mapping from registered _assist_ producer generators to the [LintCode]s
|
||||
/// for which they may also act as a _fix_ producer generator.
|
||||
Map<ProducerGenerator, Set<LintCode>> get lintRuleMap =>
|
||||
_lintRuleMap ??= {
|
||||
Map<ProducerGenerator, Set<LintCode>> get lintRuleMap => _lintRuleMap ??= {
|
||||
for (var generator in producerGenerators)
|
||||
generator: {
|
||||
for (var MapEntry(key: lintName, value: generators)
|
||||
-1
@@ -2,7 +2,6 @@
|
||||
// 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 'package:analysis_server/src/server/performance.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/performance.dart';
|
||||
|
||||
/// A callback for recording assist request timings.
|
||||
@@ -0,0 +1,131 @@
|
||||
// Copyright (c) 2025, 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 'package:analysis_server_plugin/edit/dart/correction_producer.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/assist_core.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/assist_dart.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/assist_generators.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/assist_performance.dart';
|
||||
import 'package:analysis_server_plugin/src/correction/fix_generators.dart';
|
||||
import 'package:analyzer/error/error.dart';
|
||||
import 'package:analyzer/src/dart/ast/utilities.dart';
|
||||
import 'package:analyzer/src/generated/java_core.dart';
|
||||
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
|
||||
import 'package:analyzer_plugin/utilities/change_builder/conflicting_edit_exception.dart';
|
||||
|
||||
/// The computer for Dart assists.
|
||||
class AssistProcessor {
|
||||
final AssistPerformance? _performance;
|
||||
final DartAssistContext _assistContext;
|
||||
final Stopwatch _timer = Stopwatch();
|
||||
|
||||
final List<Assist> _assists = [];
|
||||
|
||||
AssistProcessor(this._assistContext, {AssistPerformance? performance})
|
||||
: _performance = performance;
|
||||
|
||||
Future<List<Assist>> compute() async {
|
||||
_timer.start();
|
||||
await _addFromProducers();
|
||||
_timer.stop();
|
||||
_performance?.computeTime = _timer.elapsed;
|
||||
return _assists;
|
||||
}
|
||||
|
||||
Future<void> _addFromProducer(CorrectionProducer producer) async {
|
||||
var builder = ChangeBuilder(
|
||||
workspace: _assistContext.workspace,
|
||||
eol: producer.eol,
|
||||
);
|
||||
try {
|
||||
if (_performance != null) {
|
||||
var startTime = _timer.elapsedMilliseconds;
|
||||
await producer.compute(builder);
|
||||
_performance.producerTimings.add((
|
||||
className: producer.runtimeType.toString(),
|
||||
elapsedTime: _timer.elapsedMilliseconds - startTime,
|
||||
));
|
||||
} else {
|
||||
await producer.compute(builder);
|
||||
}
|
||||
|
||||
var assistKind = producer.assistKind;
|
||||
if (assistKind != null) {
|
||||
var change = builder.sourceChange;
|
||||
if (change.edits.isEmpty) {
|
||||
return;
|
||||
}
|
||||
change.id = assistKind.id;
|
||||
change.message = formatList(
|
||||
assistKind.message,
|
||||
producer.assistArguments,
|
||||
);
|
||||
_assists.add(Assist(assistKind, change));
|
||||
}
|
||||
} on ConflictingEditException catch (exception, stackTrace) {
|
||||
// Handle the exception by (a) not adding an assist based on the
|
||||
// producer and (b) logging the exception.
|
||||
_assistContext.instrumentationService.logException(exception, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _addFromProducers() async {
|
||||
var context = CorrectionProducerContext.createResolved(
|
||||
libraryResult: _assistContext.libraryResult,
|
||||
unitResult: _assistContext.unitResult,
|
||||
selectionOffset: _assistContext.selectionOffset,
|
||||
selectionLength: _assistContext.selectionLength,
|
||||
);
|
||||
|
||||
for (var generator in registeredAssistGenerators.producerGenerators) {
|
||||
if (!_generatorAppliesToAnyLintRule(
|
||||
generator,
|
||||
registeredAssistGenerators.lintRuleMap[generator] ?? {},
|
||||
)) {
|
||||
var producer = generator(context: context);
|
||||
await _addFromProducer(producer);
|
||||
}
|
||||
}
|
||||
for (var multiGenerator
|
||||
in registeredAssistGenerators.multiProducerGenerators) {
|
||||
var multiProducer = multiGenerator(context: context);
|
||||
for (var producer in await multiProducer.producers) {
|
||||
await _addFromProducer(producer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether [generator] applies to any enabled lint rule, among
|
||||
/// [errorCodes].
|
||||
bool _generatorAppliesToAnyLintRule(
|
||||
ProducerGenerator generator,
|
||||
Set<LintCode> errorCodes,
|
||||
) {
|
||||
if (errorCodes.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var selectionEnd =
|
||||
_assistContext.selectionOffset + _assistContext.selectionLength;
|
||||
var locator = NodeLocator(_assistContext.selectionOffset, selectionEnd);
|
||||
var node = locator.searchWithin(_assistContext.unitResult.unit);
|
||||
if (node == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var fileOffset = node.offset;
|
||||
for (var error in _assistContext.unitResult.errors) {
|
||||
var errorSource = error.source;
|
||||
if (_assistContext.unitResult.path == errorSource.fullName) {
|
||||
if (fileOffset >= error.offset &&
|
||||
fileOffset <= error.offset + error.length) {
|
||||
if (errorCodes.contains(error.errorCode)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,9 @@
|
||||
// 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 'package:analysis_server_plugin/src/utilities/string_extensions.dart';
|
||||
import 'package:analyzer/src/util/performance/operation_performance.dart';
|
||||
|
||||
/// Timing information for a (correction) producer's call to `compute()`.
|
||||
typedef ProducerTiming = ({
|
||||
/// The producer class name.
|
||||
@@ -10,3 +13,42 @@ typedef ProducerTiming = ({
|
||||
/// The time elapsed during `compute()`.
|
||||
int elapsedTime,
|
||||
});
|
||||
|
||||
abstract class ProducerRequestPerformance extends RequestPerformance {
|
||||
final String path;
|
||||
|
||||
final String snippet;
|
||||
final List<ProducerTiming> producerTimings;
|
||||
|
||||
ProducerRequestPerformance({
|
||||
// TODO(srawlins): This should probably be used in the super call?
|
||||
// ignore: avoid_unused_constructor_parameters
|
||||
required String operation,
|
||||
required this.path,
|
||||
required super.performance,
|
||||
super.requestLatency,
|
||||
super.startTime,
|
||||
required String content,
|
||||
required int offset,
|
||||
required this.producerTimings,
|
||||
}) : snippet = content.withCaretAt(offset),
|
||||
super(operation: 'GetAssists');
|
||||
|
||||
int get elapsedInMilliseconds => performance.elapsed.inMilliseconds;
|
||||
}
|
||||
|
||||
class RequestPerformance {
|
||||
static var _nextId = 1;
|
||||
final int id;
|
||||
final OperationPerformance performance;
|
||||
final int? requestLatency;
|
||||
final String operation;
|
||||
final DateTime? startTime;
|
||||
|
||||
RequestPerformance({
|
||||
required this.operation,
|
||||
required this.performance,
|
||||
this.requestLatency,
|
||||
this.startTime,
|
||||
}) : id = _nextId++;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2025, 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.
|
||||
|
||||
extension StringExtension on String {
|
||||
/// Builds a string from `this` that includes a caret (`^`) at the given
|
||||
/// [offset].
|
||||
///
|
||||
/// This string is useful for displaying to users in a diagnostic context.
|
||||
String withCaretAt(int offset) {
|
||||
if (offset < 0 || length < offset) {
|
||||
return '???';
|
||||
}
|
||||
var start = offset;
|
||||
while (start > 0) {
|
||||
var ch = this[start - 1];
|
||||
if (ch == '\r' || ch == '\n') {
|
||||
break;
|
||||
}
|
||||
--start;
|
||||
}
|
||||
var end = offset;
|
||||
while (end < length) {
|
||||
var ch = this[end];
|
||||
if (ch == '\r' || ch == '\n') {
|
||||
break;
|
||||
}
|
||||
++end;
|
||||
}
|
||||
var prefix = substring(start, offset);
|
||||
var suffix = substring(offset, end);
|
||||
return '$prefix^$suffix';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user