mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 03:27:43 +00:00
[analysis_server] Prepare server for handling multiple URI schemes
This is a slight refactor that should not change any behaviour extracted to make a future CL smaller. It: 1. replaces the previous `dartFiles` filter that was specifically for the `file://` scheme with a `List` that can be added to in future. 2. wraps calls to pathContext.fromUri() and pathContext.toUri() in all LSP server to go through a new class (`ClientUriConverter`) that will be extended to support mapping between to custom URI schemes (instead of `file:///`) for generated files. Change-Id: Ie8eadcca3cfd708e4dfde07c22d411101cc9ca0b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/346540 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Phil Quitslund <pquitslund@google.com>
This commit is contained in:
parent
017749f2fe
commit
da07f7a3e2
|
@ -36,6 +36,7 @@ import 'package:analysis_server/src/services/search/search_engine_internal.dart'
|
|||
import 'package:analysis_server/src/services/user_prompts/dart_fix_prompt_manager.dart';
|
||||
import 'package:analysis_server/src/services/user_prompts/survey_manager.dart';
|
||||
import 'package:analysis_server/src/services/user_prompts/user_prompts.dart';
|
||||
import 'package:analysis_server/src/utilities/client_uri_converter.dart';
|
||||
import 'package:analysis_server/src/utilities/file_string_sink.dart';
|
||||
import 'package:analysis_server/src/utilities/null_string_sink.dart';
|
||||
import 'package:analysis_server/src/utilities/process.dart';
|
||||
|
@ -91,6 +92,16 @@ abstract class AnalysisServer {
|
|||
/// A flag indicating whether plugins are supported in this build.
|
||||
static final bool supportsPlugins = true;
|
||||
|
||||
/// The full set of URI schemes that the server can support.
|
||||
///
|
||||
/// Which schemes are valid for a given server invocation may depend on the
|
||||
/// clients capabilities so being present in this set does not necessarily
|
||||
/// mean the scheme is valid to send to the client.
|
||||
///
|
||||
/// The [uriConverter] handles mapping of internal analyzer file
|
||||
/// paths/references to URIs and back.
|
||||
static const supportedUriSchemes = {'file'};
|
||||
|
||||
/// The options of this server instance.
|
||||
AnalysisServerOptions options;
|
||||
|
||||
|
@ -212,6 +223,10 @@ abstract class AnalysisServer {
|
|||
/// the last idle state.
|
||||
final Set<String> filesResolvedSinceLastIdle = {};
|
||||
|
||||
/// A converter to change incoming client URIs into analyzer file references
|
||||
/// (and back).
|
||||
ClientUriConverter uriConverter;
|
||||
|
||||
AnalysisServer(
|
||||
this.options,
|
||||
this.sdkManager,
|
||||
|
@ -227,6 +242,8 @@ abstract class AnalysisServer {
|
|||
bool enableBlazeWatcher = false,
|
||||
DartFixPromptManager? dartFixPromptManager,
|
||||
}) : resourceProvider = OverlayResourceProvider(baseResourceProvider),
|
||||
uriConverter =
|
||||
ClientUriConverter.noop(baseResourceProvider.pathContext),
|
||||
pubApi = PubApi(instrumentationService, httpClient,
|
||||
Platform.environment['PUB_HOSTED_URL']) {
|
||||
// We can only spawn processes (eg. to run pub commands) when backed by
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analysis_server/lsp_protocol/protocol.dart';
|
||||
import 'package:analysis_server/src/analysis_server.dart';
|
||||
import 'package:analysis_server/src/services/refactoring/framework/refactoring_processor.dart';
|
||||
|
||||
/// The characters that will cause the editor to automatically commit the selected
|
||||
|
@ -53,8 +54,10 @@ final analysisOptionsFile = TextDocumentFilterWithScheme(
|
|||
final analyzingProgressToken = ProgressToken.t2('ANALYZING');
|
||||
|
||||
/// A [TextDocumentFilterWithScheme] for Dart file.
|
||||
final dartFiles =
|
||||
TextDocumentFilterWithScheme(language: 'dart', scheme: 'file');
|
||||
final dartFiles = [
|
||||
for (final scheme in AnalysisServer.supportedUriSchemes)
|
||||
TextDocumentFilterWithScheme(language: 'dart', scheme: scheme)
|
||||
];
|
||||
|
||||
final emptyWorkspaceEdit = WorkspaceEdit();
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ abstract class AbstractCodeActionsProducer
|
|||
Diagnostic createDiagnostic(
|
||||
LineInfo lineInfo, engine.ErrorsResultImpl result, AnalysisError error) {
|
||||
return pluginToDiagnostic(
|
||||
server.pathContext,
|
||||
server.uriConverter,
|
||||
(_) => lineInfo,
|
||||
protocol.newAnalysisError_fromEngine(result, error),
|
||||
supportedTags: supportedDiagnosticTags,
|
||||
|
@ -133,7 +133,7 @@ abstract class AbstractCodeActionsProducer
|
|||
return engine.ErrorsResultImpl(
|
||||
session: session,
|
||||
file: file,
|
||||
uri: server.pathContext.toUri(path),
|
||||
uri: server.uriConverter.toClientUri(path),
|
||||
lineInfo: lineInfo,
|
||||
isAugmentation: false,
|
||||
isLibrary: true,
|
||||
|
|
|
@ -172,7 +172,7 @@ class DartCodeActionsProducer extends AbstractCodeActionsProducer {
|
|||
final fixes = await fixContributor.computeFixes(context);
|
||||
if (fixes.isNotEmpty) {
|
||||
final diagnostic = toDiagnostic(
|
||||
server.pathContext,
|
||||
server.uriConverter,
|
||||
unit,
|
||||
error,
|
||||
supportedTags: supportedDiagnosticTags,
|
||||
|
|
|
@ -80,7 +80,7 @@ class PluginCodeActionsProducer extends AbstractCodeActionsProducer {
|
|||
Iterable<CodeActionWithPriority> _convertFixes(
|
||||
plugin.AnalysisErrorFixes fixes) {
|
||||
final diagnostic = pluginToDiagnostic(
|
||||
server.pathContext,
|
||||
server.uriConverter,
|
||||
(_) => lineInfo,
|
||||
fixes.error,
|
||||
supportedTags: supportedDiagnosticTags,
|
||||
|
|
|
@ -77,7 +77,7 @@ class SuperHandler
|
|||
return success(null);
|
||||
}
|
||||
|
||||
return success(toLocation(pathContext, location, locationLineInfo));
|
||||
return success(toLocation(uriConverter, location, locationLineInfo));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ class CallHierarchyRegistrations extends FeatureRegistration
|
|||
|
||||
@override
|
||||
ToJsonable? get options =>
|
||||
CallHierarchyRegistrationOptions(documentSelector: [dartFiles]);
|
||||
CallHierarchyRegistrationOptions(documentSelector: dartFiles);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_prepareCallHierarchy;
|
||||
|
@ -393,7 +393,7 @@ mixin _CallHierarchyUtils on HandlerHelperMixin<AnalysisServer> {
|
|||
name: item.displayName,
|
||||
detail: item.containerName,
|
||||
kind: toSymbolKind(supportedSymbolKinds, item.kind),
|
||||
uri: pathContext.toUri(item.file),
|
||||
uri: uriConverter.toClientUri(item.file),
|
||||
range: sourceRangeToRange(lineInfo, item.codeRange),
|
||||
selectionRange: sourceRangeToRange(lineInfo, item.nameRange),
|
||||
);
|
||||
|
@ -419,7 +419,7 @@ mixin _CallHierarchyUtils on HandlerHelperMixin<AnalysisServer> {
|
|||
displayName: item.name,
|
||||
containerName: item.detail,
|
||||
kind: fromSymbolKind(item.kind),
|
||||
file: pathContext.fromUri(item.uri),
|
||||
file: uriConverter.fromClientUri(item.uri),
|
||||
nameRange: nameRange.result,
|
||||
codeRange: codeRange.result,
|
||||
);
|
||||
|
|
|
@ -47,7 +47,7 @@ class ChangeWorkspaceFoldersHandler
|
|||
List<String> _convertWorkspaceFolders(List<WorkspaceFolder> folders) {
|
||||
return folders
|
||||
.where((wf) => wf.uri.isScheme('file'))
|
||||
.map((wf) => pathContext.fromUri(wf.uri))
|
||||
.map((wf) => uriConverter.fromClientUri(wf.uri))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -834,7 +834,7 @@ class CompletionRegistrations extends FeatureRegistration
|
|||
(
|
||||
Method.textDocument_completion,
|
||||
CompletionRegistrationOptions(
|
||||
documentSelector: [dartFiles],
|
||||
documentSelector: dartFiles,
|
||||
triggerCharacters: dartCompletionTriggerCharacters,
|
||||
allCommitCharacters:
|
||||
previewCommitCharacters ? dartCompletionCommitCharacters : null,
|
||||
|
|
|
@ -148,8 +148,8 @@ class CompletionResolveHandler
|
|||
final autoImportDisplayUri = libraryUri.isScheme('file')
|
||||
// Compute the relative path and then put into a URI so the display
|
||||
// always uses forward slashes (as a URI) regardless of platform.
|
||||
? pathContext.toUri(pathContext.relative(
|
||||
pathContext.fromUri(libraryUri),
|
||||
? uriConverter.toClientUri(pathContext.relative(
|
||||
uriConverter.fromClientUri(libraryUri),
|
||||
from: pathContext.dirname(file),
|
||||
))
|
||||
: libraryUri;
|
||||
|
|
|
@ -217,7 +217,7 @@ class DefinitionHandler extends LspMessageHandler<TextDocumentPositionParams,
|
|||
Location? _toLocation(
|
||||
AnalysisNavigationParams mergedResults, NavigationTarget target) {
|
||||
final targetFilePath = mergedResults.files[target.fileIndex];
|
||||
final targetFileUri = pathContext.toUri(targetFilePath);
|
||||
final targetFileUri = uriConverter.toClientUri(targetFilePath);
|
||||
final targetLineInfo = server.getLineInfo(targetFilePath);
|
||||
return targetLineInfo != null
|
||||
? navigationTargetToLocation(targetFileUri, target, targetLineInfo)
|
||||
|
@ -228,7 +228,7 @@ class DefinitionHandler extends LspMessageHandler<TextDocumentPositionParams,
|
|||
LineInfo sourceLineInfo, NavigationTarget target) {
|
||||
final region = mergedResults.regions.first;
|
||||
final targetFilePath = mergedResults.files[target.fileIndex];
|
||||
final targetFileUri = pathContext.toUri(targetFilePath);
|
||||
final targetFileUri = uriConverter.toClientUri(targetFilePath);
|
||||
final targetLineInfo = server.getLineInfo(targetFilePath);
|
||||
|
||||
return targetLineInfo != null
|
||||
|
|
|
@ -70,7 +70,7 @@ class DocumentColorRegistrations extends FeatureRegistration
|
|||
|
||||
@override
|
||||
DocumentColorRegistrationOptions get options =>
|
||||
DocumentColorRegistrationOptions(documentSelector: [dartFiles]);
|
||||
DocumentColorRegistrationOptions(documentSelector: dartFiles);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_documentColor;
|
||||
|
|
|
@ -59,7 +59,7 @@ class DocumentLinkRegistrations extends FeatureRegistration
|
|||
|
||||
@override
|
||||
ToJsonable? get options => DocumentLinkRegistrationOptions(
|
||||
documentSelector: [dartFiles],
|
||||
documentSelector: dartFiles,
|
||||
resolveProvider: false,
|
||||
);
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ class DocumentSymbolHandler extends SharedMessageHandler<DocumentSymbolParams,
|
|||
} else {
|
||||
// Otherwise, we need to use the original flat SymbolInformation.
|
||||
final allSymbols = <SymbolInformation>[];
|
||||
final documentUri = pathContext.toUri(path);
|
||||
final documentUri = uriConverter.toClientUri(path);
|
||||
|
||||
// Adds a symbol and it's children recursively, supplying the parent
|
||||
// name as required by SymbolInformation.
|
||||
|
|
|
@ -67,7 +67,7 @@ class FormatOnTypeRegistrations extends FeatureRegistration
|
|||
@override
|
||||
ToJsonable? get options {
|
||||
return DocumentOnTypeFormattingRegistrationOptions(
|
||||
documentSelector: [dartFiles], // This is currently Dart-specific
|
||||
documentSelector: dartFiles, // This is currently Dart-specific
|
||||
firstTriggerCharacter: dartTypeFormattingCharacters.first,
|
||||
moreTriggerCharacter: dartTypeFormattingCharacters.skip(1).toList(),
|
||||
);
|
||||
|
|
|
@ -65,7 +65,7 @@ class FormatRangeRegistrations extends FeatureRegistration
|
|||
|
||||
@override
|
||||
ToJsonable? get options => DocumentRangeFormattingRegistrationOptions(
|
||||
documentSelector: [dartFiles], // This is currently Dart-specific
|
||||
documentSelector: dartFiles, // This is currently Dart-specific
|
||||
);
|
||||
|
||||
@override
|
||||
|
|
|
@ -91,7 +91,7 @@ class ImplementationHandler
|
|||
return null;
|
||||
}
|
||||
return Location(
|
||||
uri: pathContext.toUri(unitElement.source.fullName),
|
||||
uri: uriConverter.toClientUri(unitElement.source.fullName),
|
||||
range: toRange(
|
||||
unitElement.lineInfo,
|
||||
element.nameOffset,
|
||||
|
|
|
@ -44,13 +44,13 @@ class InitializeMessageHandler
|
|||
// Only file URIs are supported, but there's no way to signal this to
|
||||
// the LSP client (and certainly not before initialization).
|
||||
if (uri.isScheme('file')) {
|
||||
workspacePaths.add(pathContext.fromUri(uri));
|
||||
workspacePaths.add(uriConverter.fromClientUri(uri));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rootUri != null) {
|
||||
if (rootUri.isScheme('file')) {
|
||||
workspacePaths.add(pathContext.fromUri(rootUri));
|
||||
workspacePaths.add(uriConverter.fromClientUri(rootUri));
|
||||
}
|
||||
} else if (rootPath != null) {
|
||||
workspacePaths.add(rootPath);
|
||||
|
|
|
@ -64,7 +64,7 @@ class InlayHintRegistrations extends FeatureRegistration
|
|||
|
||||
@override
|
||||
ToJsonable? get options => InlayHintRegistrationOptions(
|
||||
documentSelector: [dartFiles],
|
||||
documentSelector: dartFiles,
|
||||
resolveProvider: false,
|
||||
);
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ class ReferencesHandler
|
|||
|
||||
return convert(collector.targets, (NavigationTarget target) {
|
||||
final targetFilePath = collector.files[target.fileIndex];
|
||||
final targetFileUri = pathContext.toUri(targetFilePath);
|
||||
final targetFileUri = uriConverter.toClientUri(targetFilePath);
|
||||
final lineInfo = server.getLineInfo(targetFilePath);
|
||||
return lineInfo != null
|
||||
? navigationTargetToLocation(targetFileUri, target, lineInfo)
|
||||
|
@ -88,7 +88,7 @@ class ReferencesHandler
|
|||
return null;
|
||||
}
|
||||
return Location(
|
||||
uri: pathContext.toUri(result.file),
|
||||
uri: uriConverter.toClientUri(result.file),
|
||||
range: toRange(
|
||||
file.lineInfo,
|
||||
result.sourceRange.offset,
|
||||
|
|
|
@ -251,7 +251,7 @@ class RenameHandler extends LspMessageHandler<RenameParams, WorkspaceEdit?>
|
|||
if (shouldRename) {
|
||||
final newPath = pathContext.join(folder, newFilename);
|
||||
final renameEdit =
|
||||
createRenameEdit(pathContext, declaringFile, newPath);
|
||||
createRenameEdit(uriConverter, declaringFile, newPath);
|
||||
workspaceEdit = mergeWorkspaceEdits([workspaceEdit, renameEdit]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ class SelectionRangeRegistrations extends FeatureRegistration
|
|||
|
||||
@override
|
||||
ToJsonable? get options =>
|
||||
SelectionRangeRegistrationOptions(documentSelector: [dartFiles]);
|
||||
SelectionRangeRegistrationOptions(documentSelector: dartFiles);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_selectionRange;
|
||||
|
|
|
@ -133,7 +133,7 @@ class TypeDefinitionHandler extends SharedMessageHandler<TypeDefinitionParams,
|
|||
/// Creates an LSP [Location] for the server [location].
|
||||
Location _toLocation(plugin.Location location, LineInfo lineInfo) {
|
||||
return Location(
|
||||
uri: pathContext.toUri(location.file),
|
||||
uri: uriConverter.toClientUri(location.file),
|
||||
range: toRange(lineInfo, location.offset, location.length),
|
||||
);
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ class TypeDefinitionHandler extends SharedMessageHandler<TypeDefinitionParams,
|
|||
return LocationLink(
|
||||
originSelectionRange:
|
||||
toRange(originLineInfo, originEntity.offset, originEntity.length),
|
||||
targetUri: pathContext.toUri(targetLocation.file),
|
||||
targetUri: uriConverter.toClientUri(targetLocation.file),
|
||||
targetRange: codeRange,
|
||||
targetSelectionRange: nameRange,
|
||||
);
|
||||
|
@ -200,7 +200,7 @@ class TypeDefinitionRegistrations extends FeatureRegistration
|
|||
|
||||
@override
|
||||
ToJsonable? get options => TextDocumentRegistrationOptions(
|
||||
documentSelector: [dartFiles], // This is currently Dart-specific
|
||||
documentSelector: dartFiles, // This is currently Dart-specific
|
||||
);
|
||||
|
||||
@override
|
||||
|
|
|
@ -81,7 +81,7 @@ class TypeHierarchyRegistrations extends FeatureRegistration
|
|||
|
||||
@override
|
||||
ToJsonable? get options => TypeHierarchyRegistrationOptions(
|
||||
documentSelector: [dartFiles],
|
||||
documentSelector: dartFiles,
|
||||
);
|
||||
|
||||
@override
|
||||
|
@ -198,7 +198,7 @@ mixin _TypeHierarchyUtils on HandlerHelperMixin<AnalysisServer> {
|
|||
return TypeHierarchyItem(
|
||||
name: item.displayName,
|
||||
kind: SymbolKind.Class,
|
||||
uri: pathContext.toUri(item.file),
|
||||
uri: uriConverter.toClientUri(item.file),
|
||||
range: sourceRangeToRange(lineInfo, item.codeRange),
|
||||
selectionRange: sourceRangeToRange(lineInfo, item.nameRange),
|
||||
data: TypeHierarchyItemInfo(
|
||||
|
|
|
@ -102,7 +102,7 @@ class WorkspaceSymbolHandler extends SharedMessageHandler<WorkspaceSymbolParams,
|
|||
declaration.codeLength,
|
||||
);
|
||||
final location = Location(
|
||||
uri: pathContext.toUri(filePath),
|
||||
uri: uriConverter.toClientUri(filePath),
|
||||
range: range,
|
||||
);
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import 'package:analysis_server/src/lsp/handlers/handler_reject.dart';
|
|||
import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
|
||||
import 'package:analysis_server/src/lsp/progress.dart';
|
||||
import 'package:analysis_server/src/request_handler_mixin.dart';
|
||||
import 'package:analysis_server/src/utilities/client_uri_converter.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
import 'package:analyzer/source/line_info.dart';
|
||||
import 'package:analyzer/src/util/performance/operation_performance.dart';
|
||||
|
@ -76,6 +77,8 @@ mixin HandlerHelperMixin<S extends AnalysisServer> {
|
|||
|
||||
S get server;
|
||||
|
||||
ClientUriConverter get uriConverter => server.uriConverter;
|
||||
|
||||
ErrorOr<T> analysisFailedError<T>(String path) => error<T>(
|
||||
ServerErrorCodes.FileAnalysisFailed, 'Analysis failed for file', path);
|
||||
|
||||
|
|
|
@ -305,7 +305,7 @@ class LspAnalysisServer extends AnalysisServer {
|
|||
// Dart settings for each workspace folder.
|
||||
for (final folder in folders)
|
||||
ConfigurationItem(
|
||||
scopeUri: pathContext.toUri(folder),
|
||||
scopeUri: uriConverter.toClientUri(folder),
|
||||
section: 'dart',
|
||||
),
|
||||
// Global Dart settings. This comes last to simplify matching up the
|
||||
|
@ -362,7 +362,7 @@ class LspAnalysisServer extends AnalysisServer {
|
|||
OptionalVersionedTextDocumentIdentifier getVersionedDocumentIdentifier(
|
||||
String path) {
|
||||
return OptionalVersionedTextDocumentIdentifier(
|
||||
uri: pathContext.toUri(path), version: getDocumentVersion(path));
|
||||
uri: uriConverter.toClientUri(path), version: getDocumentVersion(path));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -621,7 +621,7 @@ class LspAnalysisServer extends AnalysisServer {
|
|||
|
||||
void publishClosingLabels(String path, List<ClosingLabel> labels) {
|
||||
final params = PublishClosingLabelsParams(
|
||||
uri: pathContext.toUri(path), labels: labels);
|
||||
uri: uriConverter.toClientUri(path), labels: labels);
|
||||
final message = NotificationMessage(
|
||||
method: CustomMethods.publishClosingLabels,
|
||||
params: params,
|
||||
|
@ -643,7 +643,7 @@ class LspAnalysisServer extends AnalysisServer {
|
|||
}
|
||||
|
||||
final params = PublishDiagnosticsParams(
|
||||
uri: pathContext.toUri(path), diagnostics: errors);
|
||||
uri: uriConverter.toClientUri(path), diagnostics: errors);
|
||||
final message = NotificationMessage(
|
||||
method: Method.textDocument_publishDiagnostics,
|
||||
params: params,
|
||||
|
@ -654,7 +654,7 @@ class LspAnalysisServer extends AnalysisServer {
|
|||
|
||||
void publishFlutterOutline(String path, FlutterOutline outline) {
|
||||
final params = PublishFlutterOutlineParams(
|
||||
uri: pathContext.toUri(path), outline: outline);
|
||||
uri: uriConverter.toClientUri(path), outline: outline);
|
||||
final message = NotificationMessage(
|
||||
method: CustomMethods.publishFlutterOutline,
|
||||
params: params,
|
||||
|
@ -664,8 +664,8 @@ class LspAnalysisServer extends AnalysisServer {
|
|||
}
|
||||
|
||||
void publishOutline(String path, Outline outline) {
|
||||
final params =
|
||||
PublishOutlineParams(uri: pathContext.toUri(path), outline: outline);
|
||||
final params = PublishOutlineParams(
|
||||
uri: uriConverter.toClientUri(path), outline: outline);
|
||||
final message = NotificationMessage(
|
||||
method: CustomMethods.publishOutline,
|
||||
params: params,
|
||||
|
|
|
@ -18,6 +18,7 @@ import 'package:analysis_server/src/protocol_server.dart' as server
|
|||
hide AnalysisError;
|
||||
import 'package:analysis_server/src/services/completion/dart/feature_computer.dart';
|
||||
import 'package:analysis_server/src/services/snippets/snippet.dart';
|
||||
import 'package:analysis_server/src/utilities/client_uri_converter.dart';
|
||||
import 'package:analysis_server/src/utilities/extensions/string.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart' as server;
|
||||
import 'package:analyzer/error/error.dart' as server;
|
||||
|
@ -30,7 +31,6 @@ import 'package:analyzer/src/error/codes.dart';
|
|||
import 'package:analyzer/src/utilities/extensions/collection.dart';
|
||||
import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin;
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
const languageSourceName = 'dart';
|
||||
|
||||
|
@ -109,13 +109,13 @@ lsp.WorkspaceEdit createPlainWorkspaceEdit(
|
|||
|
||||
/// Create a [WorkspaceEdit] that renames [oldPath] to [newPath].
|
||||
WorkspaceEdit createRenameEdit(
|
||||
path.Context pathContext, String oldPath, String newPath) {
|
||||
ClientUriConverter uriConverter, String oldPath, String newPath) {
|
||||
final changes =
|
||||
<Either4<CreateFile, DeleteFile, RenameFile, TextDocumentEdit>>[];
|
||||
|
||||
final rename = RenameFile(
|
||||
oldUri: pathContext.toUri(oldPath),
|
||||
newUri: pathContext.toUri(newPath),
|
||||
oldUri: uriConverter.toClientUri(oldPath),
|
||||
newUri: uriConverter.toClientUri(newPath),
|
||||
);
|
||||
|
||||
final renameUnion =
|
||||
|
@ -549,7 +549,7 @@ lsp.LocationLink? navigationTargetToLocationLink(
|
|||
}
|
||||
|
||||
lsp.Diagnostic pluginToDiagnostic(
|
||||
path.Context pathContext,
|
||||
ClientUriConverter uriConverter,
|
||||
server.LineInfo? Function(String) getLineInfo,
|
||||
plugin.AnalysisError error, {
|
||||
required Set<lsp.DiagnosticTag>? supportedTags,
|
||||
|
@ -560,7 +560,7 @@ lsp.Diagnostic pluginToDiagnostic(
|
|||
if (contextMessages != null && contextMessages.isNotEmpty) {
|
||||
relatedInformation = contextMessages
|
||||
.map((message) => pluginToDiagnosticRelatedInformation(
|
||||
pathContext, getLineInfo, message))
|
||||
uriConverter, getLineInfo, message))
|
||||
.whereNotNull()
|
||||
.toList();
|
||||
}
|
||||
|
@ -598,11 +598,11 @@ lsp.Diagnostic pluginToDiagnostic(
|
|||
}
|
||||
|
||||
lsp.DiagnosticRelatedInformation? pluginToDiagnosticRelatedInformation(
|
||||
path.Context pathContext,
|
||||
ClientUriConverter uriConverter,
|
||||
server.LineInfo? Function(String) getLineInfo,
|
||||
plugin.DiagnosticMessage message) {
|
||||
final file = message.location.file;
|
||||
final uri = pathContext.toUri(file);
|
||||
final uri = uriConverter.toClientUri(file);
|
||||
final lineInfo = getLineInfo(file);
|
||||
// We shouldn't get context messages for something we can't get a LineInfo for
|
||||
// but if we did, it's better to omit the context than fail to send the errors.
|
||||
|
@ -1075,14 +1075,14 @@ lsp.CompletionItem toCompletionItem(
|
|||
}
|
||||
|
||||
lsp.Diagnostic toDiagnostic(
|
||||
path.Context pathContext,
|
||||
ClientUriConverter uriConverter,
|
||||
server.ResolvedUnitResult result,
|
||||
server.AnalysisError error, {
|
||||
required Set<lsp.DiagnosticTag> supportedTags,
|
||||
required bool clientSupportsCodeDescription,
|
||||
}) {
|
||||
return pluginToDiagnostic(
|
||||
pathContext,
|
||||
uriConverter,
|
||||
(_) => result.lineInfo,
|
||||
server.newAnalysisError_fromEngine(result, error),
|
||||
supportedTags: supportedTags,
|
||||
|
@ -1170,10 +1170,10 @@ List<lsp.DocumentHighlight> toHighlights(
|
|||
.toList();
|
||||
}
|
||||
|
||||
lsp.Location toLocation(path.Context pathContext, server.Location location,
|
||||
server.LineInfo lineInfo) =>
|
||||
lsp.Location toLocation(ClientUriConverter uriConverter,
|
||||
server.Location location, server.LineInfo lineInfo) =>
|
||||
lsp.Location(
|
||||
uri: pathContext.toUri(location.file),
|
||||
uri: uriConverter.toClientUri(location.file),
|
||||
range: toRange(
|
||||
lineInfo,
|
||||
location.offset,
|
||||
|
|
|
@ -22,7 +22,7 @@ class LspNotificationManager extends AbstractNotificationManager {
|
|||
String filePath, List<protocol.AnalysisError> errors) {
|
||||
final diagnostics = errors
|
||||
.map((error) => pluginToDiagnostic(
|
||||
pathContext,
|
||||
server.uriConverter,
|
||||
(path) => server.getLineInfo(path),
|
||||
error,
|
||||
supportedTags: server.lspClientCapabilities?.diagnosticTags,
|
||||
|
|
|
@ -67,7 +67,7 @@ abstract class FeatureRegistration {
|
|||
/// functionality in most handlers.
|
||||
List<TextDocumentFilterWithScheme> get fullySupportedTypes {
|
||||
return {
|
||||
dartFiles,
|
||||
...dartFiles,
|
||||
...pluginTypes,
|
||||
}.toList();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) 2024, 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:path/path.dart' as path;
|
||||
|
||||
/// A class for converting between internal analyzer file paths/references and
|
||||
/// URIs used by clients.
|
||||
///
|
||||
/// The simplest form of this class simple translates between file paths and
|
||||
/// `file://` URIs but depending on client capabilities some paths/URIs may be
|
||||
/// re-written to support features like virtual files for macros.
|
||||
class ClientUriConverter {
|
||||
final path.Context _context;
|
||||
|
||||
/// Creates a converter that does nothing besides translation between file
|
||||
/// paths and `file://` URIs.
|
||||
ClientUriConverter.noop(this._context);
|
||||
|
||||
/// Converts a URI provided by the client into a file path/reference that can
|
||||
/// be used by the analyzer.
|
||||
String fromClientUri(Uri uri) {
|
||||
return _context.fromUri(uri);
|
||||
}
|
||||
|
||||
/// Converts a file path/reference from the analyzer into a URI to be sent to
|
||||
/// the client.
|
||||
Uri toClientUri(String filePath) {
|
||||
return _context.toUri(filePath);
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ import 'package:analysis_server/lsp_protocol/protocol.dart';
|
|||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/feature_computer.dart';
|
||||
import 'package:analysis_server/src/utilities/client_uri_converter.dart';
|
||||
import 'package:analyzer/source/line_info.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:language_server_protocol/json_parsing.dart';
|
||||
|
@ -822,6 +823,8 @@ mixin LspVerifyEditHelpersMixin on LspEditHelpersMixin {
|
|||
|
||||
String get projectFolderPath;
|
||||
|
||||
ClientUriConverter get uriConverter;
|
||||
|
||||
/// A function to get the current contents of a file to apply edits.
|
||||
String? getCurrentFileContent(Uri uri);
|
||||
|
||||
|
@ -835,5 +838,5 @@ mixin LspVerifyEditHelpersMixin on LspEditHelpersMixin {
|
|||
/// Formats a path relative to the project root always using forward slashes.
|
||||
///
|
||||
/// This is used in the text format for comparing edits.
|
||||
String relativeUri(Uri uri) => relativePath(pathContext.fromUri(uri));
|
||||
String relativeUri(Uri uri) => relativePath(uriConverter.fromClientUri(uri));
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
|
|||
import 'package:analysis_server/src/plugin/plugin_manager.dart';
|
||||
import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
|
||||
import 'package:analysis_server/src/services/user_prompts/dart_fix_prompt_manager.dart';
|
||||
import 'package:analysis_server/src/utilities/client_uri_converter.dart';
|
||||
import 'package:analysis_server/src/utilities/mocks.dart';
|
||||
import 'package:analyzer/instrumentation/instrumentation.dart';
|
||||
import 'package:analyzer/src/dart/analysis/experiments.dart';
|
||||
|
@ -70,6 +71,9 @@ abstract class AbstractLspAnalysisServerTest
|
|||
@override
|
||||
Stream<Message> get serverToClient => channel.serverToClient;
|
||||
|
||||
@override
|
||||
ClientUriConverter get uriConverter => server.uriConverter;
|
||||
|
||||
DiscoveredPluginInfo configureTestPlugin({
|
||||
plugin.ResponseResult? respondWith,
|
||||
plugin.Notification? notification,
|
||||
|
|
|
@ -7,6 +7,7 @@ import 'dart:convert';
|
|||
import 'package:analysis_server/lsp_protocol/protocol.dart';
|
||||
import 'package:analysis_server/src/protocol/protocol_internal.dart';
|
||||
import 'package:analysis_server/src/protocol_server.dart';
|
||||
import 'package:analysis_server/src/utilities/client_uri_converter.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:test/test.dart';
|
||||
|
||||
|
@ -34,6 +35,9 @@ abstract class LspOverLegacyTest extends PubPackageAnalysisServerTest
|
|||
|
||||
Uri get testFileUri => toUri(convertPath(testFilePath));
|
||||
|
||||
@override
|
||||
ClientUriConverter get uriConverter => server.uriConverter;
|
||||
|
||||
Future<void> addOverlay(String filePath, String content) {
|
||||
return handleSuccessfulRequest(
|
||||
AnalysisUpdateContentParams({
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright (c) 2024, 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/client_uri_converter.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../../../tool/codebase/failing_tests.dart';
|
||||
import '../../abstract_single_unit.dart';
|
||||
|
||||
void main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(ClientUriConverterTest);
|
||||
});
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class ClientUriConverterTest extends AbstractSingleUnitTest {
|
||||
Future<void> test_noop_fromUri() async {
|
||||
var converter = ClientUriConverter.noop(pathContext);
|
||||
|
||||
for (var fileUri in [
|
||||
Uri.file(convertPath('/a/b.dart')),
|
||||
Uri.file(convertPath('/a/b.txt')),
|
||||
Uri.file(convertPath('/a/b.macro.dart')),
|
||||
Uri.file(convertPath('/a/b')),
|
||||
Uri.file(convertPath('/')),
|
||||
]) {
|
||||
// For no-op, should be the same as simple fromUri on pathContext.
|
||||
expect(converter.fromClientUri(fileUri), pathContext.fromUri(fileUri));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> test_noop_toUri() async {
|
||||
var converter = ClientUriConverter.noop(pathContext);
|
||||
|
||||
for (var filePath in [
|
||||
convertPath('/a/b.dart'),
|
||||
convertPath('/a/b.txt'),
|
||||
convertPath('/a/b.macro.dart'),
|
||||
convertPath('/a/b'),
|
||||
convertPath('/'),
|
||||
]) {
|
||||
// For no-op, should be the same as simple toUri on pathContext.
|
||||
expect(converter.toClientUri(filePath), pathContext.toUri(filePath));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import 'client_uri_converter_test.dart' as client_uri_converter;
|
||||
import 'extensions/test_all.dart' as extensions;
|
||||
import 'flutter_test.dart' as flutter;
|
||||
import 'import_analyzer_test.dart' as import_analyzer;
|
||||
|
@ -15,6 +16,7 @@ import 'strings_test.dart' as strings;
|
|||
|
||||
void main() {
|
||||
defineReflectiveSuite(() {
|
||||
client_uri_converter.main();
|
||||
extensions.main();
|
||||
flutter.main();
|
||||
import_analyzer.main();
|
||||
|
|
|
@ -56,7 +56,7 @@ final argParser = ArgParser()
|
|||
'Download the latest version of the LSP spec before generating types');
|
||||
|
||||
final String languageServerProtocolPackagePath =
|
||||
'$sdkRootPath/third_party/pkg/language_server_protocol';
|
||||
path.join(sdkRootPath, 'third_party', 'pkg', 'language_server_protocol');
|
||||
|
||||
final String licenseComment = LineSplitter.split(
|
||||
File(localLicensePath).readAsStringSync())
|
||||
|
|
Loading…
Reference in a new issue