DAS plugins: Bump language version to 3.9

Change-Id: I880e53634c570cc25f4ff22dd01397b088b9bd07
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/447441
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Samuel Rawlins <srawlins@google.com>
This commit is contained in:
Sam Rawlins
2025-08-28 09:35:20 -07:00
committed by Commit Queue
parent 1465c1043a
commit cbfc0784de
23 changed files with 580 additions and 353 deletions
+1
View File
@@ -1,6 +1,7 @@
## 0.2.3-dev
- Require version `8.2.0` of the `analyzer` package.
- Require Dart SDK `^3.9.0`.
- Add support for automatic re-analysis of files changed on-disk (as opposed to
file contents changed in the IDE, which is already supported).
@@ -30,4 +30,5 @@ linter:
- unnecessary_library_directive
- unnecessary_parenthesis
- unreachable_from_main
- use_null_aware_elements
@@ -31,8 +31,8 @@ final class CorrectionUtils {
String? _endOfLine;
CorrectionUtils(ParsedUnitResult result)
: _unit = result.unit,
_buffer = result.content;
: _unit = result.unit,
_buffer = result.content;
/// The EOL sequence to use for this [CompilationUnit].
String get endOfLine {
@@ -131,8 +131,10 @@ final class CorrectionUtils {
/// Returns a [SourceRange] that covers [sourceRange] and extends (if
/// possible) to cover whole lines.
SourceRange getLinesRange(SourceRange sourceRange,
{bool skipLeadingEmptyLines = false}) {
SourceRange getLinesRange(
SourceRange sourceRange, {
bool skipLeadingEmptyLines = false,
}) {
// Calculate the start:
var startOffset = sourceRange.offset;
var startLineOffset = getLineContentStart(startOffset);
@@ -143,8 +145,9 @@ final class CorrectionUtils {
var endOffset = sourceRange.end;
var afterEndLineOffset = endOffset;
var lineInfo = _unit.lineInfo;
var lineStart = lineInfo
.getOffsetOfLine(lineInfo.getLocation(startLineOffset).lineNumber - 1);
var lineStart = lineInfo.getOffsetOfLine(
lineInfo.getLocation(startLineOffset).lineNumber - 1,
);
if (lineStart == startLineOffset) {
// Only consume line endings after the end of the range if there is
// nothing else on the line containing the beginning of the range.
@@ -184,10 +187,7 @@ final class CorrectionUtils {
/// Returns the text of the given [AstNode] in the unit, including preceding
/// comments.
String getNodeText(
AstNode node, {
bool withLeadingComments = false,
}) {
String getNodeText(AstNode node, {bool withLeadingComments = false}) {
var firstToken = withLeadingComments
? node.beginToken.precedingComments ?? node.beginToken
: node.beginToken;
@@ -252,8 +252,13 @@ final class CorrectionUtils {
/// Usually [includeLeading] and [ensureTrailingNewline] are set together,
/// when indenting a set of statements to go inside a block (as opposed to
/// just wrapping a nested expression that might span multiple lines).
String replaceSourceIndent(String source, String oldIndent, String newIndent,
{bool includeLeading = false, bool ensureTrailingNewline = false}) {
String replaceSourceIndent(
String source,
String oldIndent,
String newIndent, {
bool includeLeading = false,
bool ensureTrailingNewline = false,
}) {
// Prepare token ranges.
var lineRanges = <SourceRange>[];
{
@@ -323,12 +328,20 @@ final class CorrectionUtils {
/// when indenting a set of statements to go inside a block (as opposed to
/// just wrapping a nested expression that might span multiple lines).
String replaceSourceRangeIndent(
SourceRange range, String oldIndent, String newIndent,
{bool includeLeading = false, bool ensureTrailingNewline = false}) {
SourceRange range,
String oldIndent,
String newIndent, {
bool includeLeading = false,
bool ensureTrailingNewline = false,
}) {
var oldSource = getRangeText(range);
return replaceSourceIndent(oldSource, oldIndent, newIndent,
includeLeading: includeLeading,
ensureTrailingNewline: ensureTrailingNewline);
return replaceSourceIndent(
oldSource,
oldIndent,
newIndent,
includeLeading: includeLeading,
ensureTrailingNewline: ensureTrailingNewline,
);
}
/// Returns the [_InvertedCondition] for the given logical expression.
@@ -367,13 +380,21 @@ final class CorrectionUtils {
ls = _invertCondition0(le);
rs = _invertCondition0(re);
return _InvertedCondition._binary(
TokenType.BAR_BAR.precedence, ls, ' || ', rs);
TokenType.BAR_BAR.precedence,
ls,
' || ',
rs,
);
}
if (operator == TokenType.BAR_BAR) {
ls = _invertCondition0(le);
rs = _invertCondition0(re);
return _InvertedCondition._binary(
TokenType.AMPERSAND_AMPERSAND.precedence, ls, ' && ', rs);
TokenType.AMPERSAND_AMPERSAND.precedence,
ls,
' && ',
rs,
);
}
} else if (expression is IsExpression) {
var expressionSource = getNodeText(expression.expression);
@@ -432,14 +453,15 @@ class TokenUtils {
static List<Token> getTokens(String s, FeatureSet featureSet) {
try {
var tokens = <Token>[];
var scanner = Scanner(
_SourceMock(),
CharSequenceReader(s),
DiagnosticListener.nullListener,
)..configureFeatures(
featureSetForOverriding: featureSet,
featureSet: featureSet,
);
var scanner =
Scanner(
_SourceMock(),
CharSequenceReader(s),
DiagnosticListener.nullListener,
)..configureFeatures(
featureSetForOverriding: featureSet,
featureSet: featureSet,
);
var token = scanner.tokenize();
while (!token.isEof) {
tokens.add(token);
@@ -460,25 +482,37 @@ class _InvertedCondition {
_InvertedCondition(this._precedence, this._source);
static _InvertedCondition _binary(int precedence, _InvertedCondition left,
String operation, _InvertedCondition right) {
var src = _parenthesizeIfRequired(left, precedence) +
static _InvertedCondition _binary(
int precedence,
_InvertedCondition left,
String operation,
_InvertedCondition right,
) {
var src =
_parenthesizeIfRequired(left, precedence) +
operation +
_parenthesizeIfRequired(right, precedence);
return _InvertedCondition(precedence, src);
}
static _InvertedCondition _binary2(
_InvertedCondition left, String operation, _InvertedCondition right) {
_InvertedCondition left,
String operation,
_InvertedCondition right,
) {
// TODO(scheglov): consider merging with "_binary()" after testing
return _InvertedCondition(
1 << 20, '${left._source}$operation${right._source}');
1 << 20,
'${left._source}$operation${right._source}',
);
}
/// Adds enclosing parenthesis if the precedence of the [_InvertedCondition]
/// if less than the precedence of the expression we are going it to use in.
static String _parenthesizeIfRequired(
_InvertedCondition expr, int newOperatorPrecedence) {
_InvertedCondition expr,
int newOperatorPrecedence,
) {
if (expr._precedence < newOperatorPrecedence) {
return '(${expr._source})';
}
@@ -168,8 +168,10 @@ sealed class CorrectionProducer<T extends ParsedUnitResult>
}
var diagnosticOffset = diagnostic.problemMessage.offset;
var diagnosticLength = diagnostic.problemMessage.length;
return _coveringNode =
unit.nodeCovering(offset: diagnosticOffset, length: diagnosticLength);
return _coveringNode = unit.nodeCovering(
offset: diagnosticOffset,
length: diagnosticLength,
);
}
/// The length of the source range associated with the diagnostic being
@@ -242,15 +244,15 @@ final class CorrectionProducerContext {
required Token token,
required int selectionOffset,
required int selectionLength,
}) : _libraryResult = libraryResult,
_unitResult = unitResult,
_sessionHelper = AnalysisSessionHelper(unitResult.session),
_utils = dartFixContext?.correctionUtils ?? CorrectionUtils(unitResult),
_applyingBulkFixes = applyingBulkFixes,
_diagnostic = diagnostic,
_token = token,
_selectionOffset = selectionOffset,
_selectionLength = selectionLength;
}) : _libraryResult = libraryResult,
_unitResult = unitResult,
_sessionHelper = AnalysisSessionHelper(unitResult.session),
_utils = dartFixContext?.correctionUtils ?? CorrectionUtils(unitResult),
_applyingBulkFixes = applyingBulkFixes,
_diagnostic = diagnostic,
_token = token,
_selectionOffset = selectionOffset,
_selectionLength = selectionLength;
String get path => _unitResult.path;
@@ -296,8 +298,10 @@ final class CorrectionProducerContext {
int selectionOffset = -1,
int selectionLength = 0,
}) {
var node = unitResult.unit
.nodeCovering(offset: selectionOffset, length: selectionLength);
var node = unitResult.unit.nodeCovering(
offset: selectionOffset,
length: selectionLength,
);
node ??= unitResult.unit;
var token = _tokenAt(node, selectionOffset) ?? node.beginToken;
@@ -445,7 +449,8 @@ abstract class ResolvedCorrectionProducer
/// Returns the extension declaration for the given [fragment], or `null` if
/// there is no such extension.
Future<ExtensionDeclaration?> getExtensionDeclaration(
ExtensionFragment fragment) async {
ExtensionFragment fragment,
) async {
var result = await sessionHelper.getFragmentDeclaration(fragment);
var node = result?.node;
if (node is ExtensionDeclaration) {
@@ -457,7 +462,8 @@ abstract class ResolvedCorrectionProducer
/// Returns the extension type for the given [fragment], or `null` if there
/// is no such extension type.
Future<ExtensionTypeDeclaration?> getExtensionTypeDeclaration(
ExtensionTypeFragment fragment) async {
ExtensionTypeFragment fragment,
) async {
var result = await sessionHelper.getFragmentDeclaration(fragment);
var node = result?.node;
if (node is ExtensionTypeDeclaration) {
@@ -588,11 +594,10 @@ abstract class ResolvedCorrectionProducer
} else if (assignment.writeType case var expectedType?) {
// `v += myFunction();`.
var method = assignment.element;
if (method
case MethodElement(
:var returnType,
formalParameters: List(length: 1, :var first),
)) {
if (method case MethodElement(
:var returnType,
formalParameters: List(length: 1, :var first),
)) {
if (typeSystem.isAssignableTo(returnType, expectedType)) {
// The return type is assignable to the expected type, then use
// the expected parameter type.
@@ -708,10 +713,13 @@ abstract class ResolvedCorrectionProducer
/// Looks if the [expression] is directly inside a closure and returns the
/// return type of the closure.
DartType? _closureReturnType(Expression expression) {
if (expression.enclosingClosure
case FunctionExpression(:var correspondingParameter, :var staticType)) {
if (correspondingParameter?.type ?? staticType
case FunctionType(:var returnType)) {
if (expression.enclosingClosure case FunctionExpression(
:var correspondingParameter,
:var staticType,
)) {
if (correspondingParameter?.type ?? staticType case FunctionType(
:var returnType,
)) {
return returnType;
}
}
@@ -757,7 +765,7 @@ sealed class _AbstractCorrectionProducer<T extends ParsedUnitResult> {
final CorrectionProducerContext _context;
_AbstractCorrectionProducer({required CorrectionProducerContext context})
: _context = context;
: _context = context;
/// Whether the fixes are being built for the bulk-fix request.
bool get applyingBulkFixes => _context._applyingBulkFixes;
@@ -796,10 +804,11 @@ sealed class _AbstractCorrectionProducer<T extends ParsedUnitResult> {
CorrectionUtils get utils => _context._utils;
CodeStyleOptions getCodeStyleOptions(File file) =>
sessionHelper.session.analysisContext
.getAnalysisOptionsForFile(file)
.codeStyleOptions;
CodeStyleOptions getCodeStyleOptions(File file) => sessionHelper
.session
.analysisContext
.getAnalysisOptionsForFile(file)
.codeStyleOptions;
/// Returns the function body of the most deeply nested method or function
/// that encloses the [node], or `null` if the node is not in a method or
@@ -50,7 +50,7 @@ class DartFixContext implements FixContext {
/// least some getFixes requsts. Caching the response can speed up such
/// requests.
final Map<String, Future<Map<LibraryElement, Element>>>
_cachedTopLevelDeclarations = {};
_cachedTopLevelDeclarations = {};
@override
final Diagnostic diagnostic;
@@ -64,8 +64,8 @@ class DartFixContext implements FixContext {
required Diagnostic error,
this.autoTriggered = false,
CorrectionUtils? correctionUtils,
}) : diagnostic = error,
correctionUtils = correctionUtils ?? CorrectionUtils(unitResult);
}) : diagnostic = error,
correctionUtils = correctionUtils ?? CorrectionUtils(unitResult);
@override
Diagnostic get error => diagnostic;
@@ -95,9 +95,7 @@ class DartFixContext implements FixContext {
await analysisDriver.discoverAvailableFiles();
var fsState = analysisDriver.fsState;
var filter = FileStateFilter(
fsState.getFileForPath(unitResult.path),
);
var filter = FileStateFilter(fsState.getFileForPath(unitResult.path));
for (var file in fsState.knownFiles.toList()) {
if (!filter.shouldInclude(file)) {
@@ -24,13 +24,13 @@ 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 ??= {
for (var generator in producerGenerators)
generator: {
for (var MapEntry(key: lintName, value: generators)
in registeredFixGenerators.lintProducers.entries)
if (generators.contains(generator)) lintName,
},
};
for (var generator in producerGenerators)
generator: {
for (var MapEntry(key: lintName, value: generators)
in registeredFixGenerators.lintProducers.entries)
if (generators.contains(generator)) lintName,
},
};
void registerGenerator(ProducerGenerator generator) {
producerGenerators.add(generator);
@@ -13,12 +13,10 @@ 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';
Future<List<Assist>> computeAssists(DartAssistContext context,
{AssistPerformance? performance}) =>
AssistProcessor(
context,
performance: performance,
).compute();
Future<List<Assist>> computeAssists(
DartAssistContext context, {
AssistPerformance? performance,
}) => AssistProcessor(context, performance: performance).compute();
/// The computer for Dart assists.
class AssistProcessor {
@@ -29,7 +27,7 @@ class AssistProcessor {
final List<Assist> _assists = [];
AssistProcessor(this._assistContext, {AssistPerformance? performance})
: _performance = performance;
: _performance = performance;
Future<List<Assist>> compute() async {
_timer.start();
@@ -68,10 +66,7 @@ class AssistProcessor {
return;
}
change.id = assistKind.id;
change.message = formatList(
assistKind.message,
producer.assistArguments,
);
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
@@ -9,12 +9,16 @@ import 'package:analyzer/error/error.dart';
final registeredFixGenerators = _RegisteredFixGenerators();
/// A function that can be executed to create a [MultiCorrectionProducer].
typedef MultiProducerGenerator = MultiCorrectionProducer Function(
{required CorrectionProducerContext context});
typedef MultiProducerGenerator =
MultiCorrectionProducer Function({
required CorrectionProducerContext context,
});
/// A function that can be executed to create a [CorrectionProducer].
typedef ProducerGenerator = CorrectionProducer<ParsedUnitResult> Function(
{required CorrectionProducerContext context});
typedef ProducerGenerator =
CorrectionProducer<ParsedUnitResult> Function({
required CorrectionProducerContext context,
});
/// The collection of various registered [ProducerGenerator]s and
/// [MultiProducerGenerator]s, accessed through [registeredFixGenerators].
@@ -33,7 +37,7 @@ class _RegisteredFixGenerators {
///
/// The generators used for lint rules are in the [lintMultiProducers].
final Map<DiagnosticCode, List<MultiProducerGenerator>>
nonLintMultiProducers = {};
nonLintMultiProducers = {};
/// A set of generators that are used to create correction producers that
/// produce corrections that ignore diagnostics locally.
@@ -40,27 +40,35 @@ final class FixInFileProcessor {
// like many more errors than generators.
if (alreadyCalculated != null) {
generators = generators
.where((generator) => !alreadyCalculated!
.contains(getAlreadyCalculatedValue(generator)))
.where(
(generator) => !alreadyCalculated!.contains(
getAlreadyCalculatedValue(generator),
),
)
.toList(growable: false);
}
if (generators.isEmpty) {
return const <Fix>[];
}
var diagnostics = _fixContext.unitResult.diagnostics
.where((e) => diagnostic.diagnosticCode.name == e.diagnosticCode.name);
var diagnostics = _fixContext.unitResult.diagnostics.where(
(e) => diagnostic.diagnosticCode.name == e.diagnosticCode.name,
);
if (diagnostics.length < 2) {
return const <Fix>[];
}
var fixes = <Fix>[];
for (var generator in generators) {
if (generator(context: StubCorrectionProducerContext.instance)
.canBeAppliedAcrossSingleFile) {
_FixState fixState = _EmptyFixState(ChangeBuilder(
if (generator(
context: StubCorrectionProducerContext.instance,
).canBeAppliedAcrossSingleFile) {
_FixState fixState = _EmptyFixState(
ChangeBuilder(
workspace: _fixContext.workspace,
defaultEol: CorrectionUtils(_fixContext.unitResult).endOfLine));
defaultEol: CorrectionUtils(_fixContext.unitResult).endOfLine,
),
);
// First, try to fix the specific error we started from. We should only
// include fix-all-in-file when we produce an individual fix at this
@@ -73,8 +81,12 @@ final class FixInFileProcessor {
error: diagnostic,
correctionUtils: _fixContext.correctionUtils,
);
fixState =
await _fixDiagnostic(fixContext, fixState, generator, diagnostic);
fixState = await _fixDiagnostic(
fixContext,
fixState,
generator,
diagnostic,
);
// The original error was not fixable; continue to next generator.
if (!(fixState.builder as ChangeBuilderImpl).hasEdits) {
@@ -14,17 +14,21 @@ 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';
Future<List<Fix>> computeFixes(DartFixContext context,
{FixPerformance? performance,
Set<String>? skipAlreadyCalculatedIfNonNull}) async {
Future<List<Fix>> computeFixes(
DartFixContext context, {
FixPerformance? performance,
Set<String>? skipAlreadyCalculatedIfNonNull,
}) async {
return [
...await FixProcessor(context,
performance: performance,
alreadyCalculated: skipAlreadyCalculatedIfNonNull)
.compute(),
...await FixInFileProcessor(context,
alreadyCalculated: skipAlreadyCalculatedIfNonNull)
.compute(),
...await FixProcessor(
context,
performance: performance,
alreadyCalculated: skipAlreadyCalculatedIfNonNull,
).compute(),
...await FixInFileProcessor(
context,
alreadyCalculated: skipAlreadyCalculatedIfNonNull,
).compute(),
];
}
@@ -72,7 +76,9 @@ class FixProcessor {
}
var builder = ChangeBuilder(
workspace: _fixContext.workspace, defaultEol: producer.defaultEol);
workspace: _fixContext.workspace,
defaultEol: producer.defaultEol,
);
try {
var fixKind = producer.fixKind;
@@ -152,9 +158,11 @@ class FixProcessor {
for (var generator in registeredFixGenerators.ignoreProducerGenerators) {
var producer = generator(context: context);
if (producer.fixKind == ignoreErrorAnalysisFileKind) {
if (alreadyCalculated?.add('${generator.hashCode}|'
'${ignoreErrorAnalysisFileKind.id}|'
'${diagnostic.diagnosticCode.name}') ==
if (alreadyCalculated?.add(
'${generator.hashCode}|'
'${ignoreErrorAnalysisFileKind.id}|'
'${diagnostic.diagnosticCode.name}',
) ==
false) {
// We did this before and was asked to not do it again. Skip.
continue;
@@ -216,8 +216,9 @@ class IgnoreDiagnosticOnLine extends _DartIgnoreDiagnostic {
lineNumber - 1,
);
var lineStart = unitResult.lineInfo.getOffsetOfLine(lineNumber);
var line =
unitResult.content.substring(previousLineStart, lineStart).trim();
var line = unitResult.content
.substring(previousLineStart, lineStart)
.trim();
if (line.startsWith(IgnoreInfo.ignoreMatcher)) {
builder.addSimpleInsertion(lineStart - eol.length, ', $_code');
@@ -63,8 +63,10 @@ class PluginServer {
final OverlayResourceProvider _resourceProvider;
late final ByteStore _byteStore =
MemoryCachingByteStore(NullByteStore(), 1024 * 1024 * 256);
late final ByteStore _byteStore = MemoryCachingByteStore(
NullByteStore(),
1024 * 1024 * 256,
);
AnalysisContextCollectionImpl? _contextCollection;
@@ -86,8 +88,8 @@ class PluginServer {
PluginServer({
required ResourceProvider resourceProvider,
required List<Plugin> plugins,
}) : _resourceProvider = OverlayResourceProvider(resourceProvider),
_plugins = plugins {
}) : _resourceProvider = OverlayResourceProvider(resourceProvider),
_plugins = plugins {
for (var plugin in plugins) {
plugin.register(_registry);
}
@@ -98,8 +100,9 @@ class PluginServer {
///
/// Throws a [RequestFailure] if the request could not be handled.
Future<protocol.AnalysisSetPriorityFilesResult>
handleAnalysisSetPriorityFiles(
protocol.AnalysisSetPriorityFilesParams parameters) async {
handleAnalysisSetPriorityFiles(
protocol.AnalysisSetPriorityFilesParams parameters,
) async {
_priorityPaths = parameters.files.toSet();
return protocol.AnalysisSetPriorityFilesResult();
}
@@ -108,7 +111,8 @@ class PluginServer {
///
/// Throws a [RequestFailure] if the request could not be handled.
Future<protocol.EditGetAssistsResult> handleEditGetAssists(
protocol.EditGetAssistsParams parameters) async {
protocol.EditGetAssistsParams parameters,
) async {
var path = parameters.file;
var recentState = _recentState[path];
@@ -117,8 +121,9 @@ class PluginServer {
}
var (:analysisContext, :errors) = recentState;
var libraryResult =
await analysisContext.currentSession.getResolvedLibrary(path);
var libraryResult = await analysisContext.currentSession.getResolvedLibrary(
path,
);
if (libraryResult is! ResolvedLibraryResult) {
return protocol.EditGetAssistsResult(const []);
}
@@ -153,7 +158,7 @@ class PluginServer {
var corrections = [
for (var assist in assists..sort(Assist.compareAssists))
protocol.PrioritizedSourceChange(assist.kind.priority, assist.change)
protocol.PrioritizedSourceChange(assist.kind.priority, assist.change),
];
return protocol.EditGetAssistsResult(corrections);
}
@@ -162,7 +167,8 @@ class PluginServer {
///
/// Throws a [RequestFailure] if the request could not be handled.
Future<protocol.EditGetFixesResult> handleEditGetFixes(
protocol.EditGetFixesParams parameters) async {
protocol.EditGetFixesParams parameters,
) async {
var path = parameters.file;
var offset = parameters.offset;
@@ -173,8 +179,9 @@ class PluginServer {
var (:analysisContext, :errors) = recentState;
var libraryResult =
await analysisContext.currentSession.getResolvedLibrary(path);
var libraryResult = await analysisContext.currentSession.getResolvedLibrary(
path,
);
if (libraryResult is! ResolvedLibraryResult) {
return protocol.EditGetFixesResult(const []);
}
@@ -183,8 +190,9 @@ class PluginServer {
return protocol.EditGetFixesResult(const []);
}
var lintAtOffset =
errors.where((error) => error.diagnostic.offset == offset);
var lintAtOffset = errors.where(
(error) => error.diagnostic.offset == offset,
);
if (lintAtOffset.isEmpty) return protocol.EditGetFixesResult(const []);
var errorFixesList = <protocol.AnalysisErrorFixes>[];
@@ -225,26 +233,31 @@ class PluginServer {
/// Handles a 'plugin.versionCheck' request.
Future<protocol.PluginVersionCheckResult> handlePluginVersionCheck(
protocol.PluginVersionCheckParams parameters) async {
protocol.PluginVersionCheckParams parameters,
) async {
// TODO(srawlins): It seems improper for _this_ method to be the point where
// the SDK path is configured...
_sdkPath = parameters.sdkPath;
return protocol.PluginVersionCheckResult(
true, 'Plugin Server', '0.0.1', ['*.dart']);
return protocol.PluginVersionCheckResult(true, 'Plugin Server', '0.0.1', [
'*.dart',
]);
}
/// Initializes each of the registered plugins.
Future<void> initialize() async {
await Future.wait(
_plugins.map((p) => p.start()).whereType<Future<Object?>>());
_plugins.map((p) => p.start()).whereType<Future<Object?>>(),
);
}
/// Starts this plugin by listening to the given communication [channel].
void start(PluginCommunicationChannel channel) {
_channel = channel;
_channel.listen(_handleRequestZoned,
// TODO(srawlins): Implement.
onDone: () {});
_channel.listen(
_handleRequestZoned,
// TODO(srawlins): Implement.
onDone: () {},
);
}
/// This method is invoked when a new instance of [AnalysisContextCollection]
@@ -253,8 +266,10 @@ class PluginServer {
required AnalysisContextCollection contextCollection,
}) async {
_channel.sendNotification(
protocol.PluginStatusParams(analysis: protocol.AnalysisStatus(true))
.toNotification());
protocol.PluginStatusParams(
analysis: protocol.AnalysisStatus(true),
).toNotification(),
);
await _forAnalysisContexts(contextCollection, (analysisContext) async {
var paths = analysisContext.contextRoot
.analyzedFiles()
@@ -264,14 +279,13 @@ class PluginServer {
.where((p) => file_paths.isDart(_resourceProvider.pathContext, p))
.toSet();
await _analyzeFiles(
analysisContext: analysisContext,
paths: paths,
);
await _analyzeFiles(analysisContext: analysisContext, paths: paths);
});
_channel.sendNotification(
protocol.PluginStatusParams(analysis: protocol.AnalysisStatus(false))
.toNotification());
protocol.PluginStatusParams(
analysis: protocol.AnalysisStatus(false),
).toNotification(),
);
}
Future<void> _analyzeFile({
@@ -286,7 +300,8 @@ class PluginServer {
analysisOptions: analysisOptions as AnalysisOptionsImpl,
);
_channel.sendNotification(
protocol.AnalysisErrorsParams(path, diagnostics).toNotification());
protocol.AnalysisErrorsParams(path, diagnostics).toNotification(),
);
}
/// Analyzes the files at the given [paths].
@@ -312,8 +327,9 @@ class PluginServer {
String path, {
required AnalysisOptionsImpl analysisOptions,
}) async {
var libraryResult =
await analysisContext.currentSession.getResolvedLibrary(path);
var libraryResult = await analysisContext.currentSession.getResolvedLibrary(
path,
);
if (libraryResult is! ResolvedLibraryResult) {
return const [];
}
@@ -323,7 +339,9 @@ class PluginServer {
}
var listener = RecordingDiagnosticListener();
var diagnosticReporter = DiagnosticReporter(
listener, unitResult.libraryElement.firstFragment.source);
listener,
unitResult.libraryElement.firstFragment.source,
);
var currentUnit = RuleContextUnit(
file: unitResult.file,
@@ -363,8 +381,9 @@ class PluginServer {
for (var configuration in analysisOptions.pluginConfigurations) {
if (!configuration.isEnabled) continue;
// TODO(srawlins): Namespace rules by their plugin, to avoid collisions.
var rules =
Registry.ruleRegistry.enabled(configuration.diagnosticConfigs);
var rules = Registry.ruleRegistry.enabled(
configuration.diagnosticConfigs,
);
for (var rule in rules) {
rule.reporter = diagnosticReporter;
// TODO(srawlins): Enable timing similar to what the linter package's
@@ -374,13 +393,16 @@ class PluginServer {
for (var code in rules.expand((r) => r.diagnosticCodes)) {
pluginCodeMapping.putIfAbsent(code, () => configuration.name);
severityMapping.putIfAbsent(
code, () => _configuredSeverity(configuration, code));
code,
() => _configuredSeverity(configuration, code),
);
}
}
context.currentUnit = currentUnit;
currentUnit.unit.accept(
AnalysisRuleVisitor(nodeRegistry, shouldPropagateExceptions: true));
AnalysisRuleVisitor(nodeRegistry, shouldPropagateExceptions: true),
);
var ignoreInfo = IgnoreInfo.forDart(unitResult.unit, unitResult.content);
var diagnostics = listener.diagnostics.where((e) {
@@ -409,7 +431,7 @@ class PluginServer {
correction: diagnostic.correctionMessage,
// TODO(srawlins): Use a valid value here.
hasFix: true,
)
),
),
];
_recentState[path] = (
@@ -421,23 +443,27 @@ class PluginServer {
/// Converts the severity of [code] into a [protocol.AnalysisErrorSeverity].
protocol.AnalysisErrorSeverity? _configuredSeverity(
PluginConfiguration configuration, DiagnosticCode code) {
PluginConfiguration configuration,
DiagnosticCode code,
) {
var configuredSeverity =
configuration.diagnosticConfigs[code.name]?.severity;
if (configuredSeverity != null &&
configuredSeverity != ConfiguredSeverity.enable) {
var severityName = configuredSeverity.name.toUpperCase();
var severity =
protocol.AnalysisErrorSeverity.values.asNameMap()[severityName];
assert(severity != null,
'Invalid configured severity: ${configuredSeverity.name}');
var severity = protocol.AnalysisErrorSeverity.values
.asNameMap()[severityName];
assert(
severity != null,
'Invalid configured severity: ${configuredSeverity.name}',
);
return severity;
}
// Fall back to the declared severity of [code].
var severityName = code.severity.name.toUpperCase();
var severity =
protocol.AnalysisErrorSeverity.values.asNameMap()[code.severity.name];
var severity = protocol.AnalysisErrorSeverity.values
.asNameMap()[code.severity.name];
assert(severity != null, 'Invalid severity: $severityName');
return severity;
}
@@ -467,13 +493,15 @@ class PluginServer {
switch (request.method) {
case protocol.ANALYSIS_REQUEST_GET_NAVIGATION:
case protocol.ANALYSIS_REQUEST_HANDLE_WATCH_EVENTS:
var params =
protocol.AnalysisHandleWatchEventsParams.fromRequest(request);
var params = protocol.AnalysisHandleWatchEventsParams.fromRequest(
request,
);
result = await _handleAnalysisWatchEvents(params);
case protocol.ANALYSIS_REQUEST_SET_CONTEXT_ROOTS:
var params =
protocol.AnalysisSetContextRootsParams.fromRequest(request);
var params = protocol.AnalysisSetContextRootsParams.fromRequest(
request,
);
result = await _handleAnalysisSetContextRoots(params);
case protocol.ANALYSIS_REQUEST_SET_PRIORITY_FILES:
@@ -500,8 +528,9 @@ class PluginServer {
result = null;
case protocol.PLUGIN_REQUEST_SHUTDOWN:
_channel.sendResponse(protocol.PluginShutdownResult()
.toResponse(request.id, requestTime));
_channel.sendResponse(
protocol.PluginShutdownResult().toResponse(request.id, requestTime),
);
_channel.close();
return null;
@@ -510,8 +539,11 @@ class PluginServer {
result = await handlePluginVersionCheck(params);
}
if (result == null) {
return Response(request.id, requestTime,
error: RequestErrorFactory.unknownRequest(request.method));
return Response(
request.id,
requestTime,
error: RequestErrorFactory.unknownRequest(request.method),
);
}
return result.toResponse(request.id, requestTime);
}
@@ -526,18 +558,17 @@ class PluginServer {
required AnalysisContext analysisContext,
required List<String> paths,
}) async {
var analyzedPaths =
paths.where(analysisContext.contextRoot.isAnalyzed).toSet();
var analyzedPaths = paths
.where(analysisContext.contextRoot.isAnalyzed)
.toSet();
await _analyzeFiles(
analysisContext: analysisContext,
paths: analyzedPaths,
);
await _analyzeFiles(analysisContext: analysisContext, paths: analyzedPaths);
}
/// Handles an 'analysis.setContextRoots' request.
Future<protocol.AnalysisSetContextRootsResult> _handleAnalysisSetContextRoots(
protocol.AnalysisSetContextRootsParams parameters) async {
protocol.AnalysisSetContextRootsParams parameters,
) async {
var currentContextCollection = _contextCollection;
if (currentContextCollection != null) {
_contextCollection = null;
@@ -554,7 +585,8 @@ class PluginServer {
);
_contextCollection = contextCollection;
await _analyzeAllFilesInContextCollection(
contextCollection: contextCollection);
contextCollection: contextCollection,
);
return protocol.AnalysisSetContextRootsResult();
}
@@ -562,7 +594,8 @@ class PluginServer {
///
/// Throws a [RequestFailure] if the request could not be handled.
Future<protocol.AnalysisUpdateContentResult> _handleAnalysisUpdateContent(
protocol.AnalysisUpdateContentParams parameters) async {
protocol.AnalysisUpdateContentParams parameters,
) async {
var changedPaths = <String>{};
var paths = parameters.files;
paths.forEach((String path, Object overlay) {
@@ -585,14 +618,18 @@ class PluginServer {
// The server should only send a ChangeContentOverlay if there is
// already an existing overlay for the source.
throw RequestFailure(
RequestErrorFactory.invalidOverlayChangeNoContent());
RequestErrorFactory.invalidOverlayChangeNoContent(),
);
}
try {
newContent =
protocol.SourceEdit.applySequence(oldContent, overlay.edits);
newContent = protocol.SourceEdit.applySequence(
oldContent,
overlay.edits,
);
} on RangeError {
throw RequestFailure(
RequestErrorFactory.invalidOverlayChangeInvalidEdit());
RequestErrorFactory.invalidOverlayChangeInvalidEdit(),
);
}
} else if (overlay is protocol.RemoveContentOverlay) {
newContent = null;
@@ -616,7 +653,8 @@ class PluginServer {
/// Handles an 'analysis.handleWatchEvents' request.
Future<protocol.AnalysisHandleWatchEventsResult> _handleAnalysisWatchEvents(
protocol.AnalysisHandleWatchEventsParams parameters) async {
protocol.AnalysisHandleWatchEventsParams parameters,
) async {
final addedPaths = parameters.events
.where((e) => e.type == protocol.WatchEventType.ADD)
.map((e) => e.path)
@@ -640,14 +678,17 @@ class PluginServer {
}
/// Handles added files, modified files, and removed files.
Future<void> _handleContentChanged(
{List<String> addedPaths = const [],
List<String> modifiedPaths = const [],
List<String> removedPaths = const []}) async {
Future<void> _handleContentChanged({
List<String> addedPaths = const [],
List<String> modifiedPaths = const [],
List<String> removedPaths = const [],
}) async {
if (_contextCollection case var contextCollection?) {
_channel.sendNotification(
protocol.PluginStatusParams(analysis: protocol.AnalysisStatus(true))
.toNotification());
protocol.PluginStatusParams(
analysis: protocol.AnalysisStatus(true),
).toNotification(),
);
await _forAnalysisContexts(contextCollection, (analysisContext) async {
for (var path in modifiedPaths) {
analysisContext.changeFile(path);
@@ -660,11 +701,15 @@ class PluginServer {
...addedPaths,
];
await _handleAffectedFiles(
analysisContext: analysisContext, paths: affected);
analysisContext: analysisContext,
paths: affected,
);
});
_channel.sendNotification(
protocol.PluginStatusParams(analysis: protocol.AnalysisStatus(false))
.toNotification());
protocol.PluginStatusParams(
analysis: protocol.AnalysisStatus(false),
).toNotification(),
);
}
}
@@ -677,10 +722,15 @@ class PluginServer {
} on RequestFailure catch (exception) {
response = Response(id, requestTime, error: exception.error);
} catch (exception, stackTrace) {
response = Response(id, requestTime,
error: protocol.RequestError(
protocol.RequestErrorCode.PLUGIN_ERROR, exception.toString(),
stackTrace: stackTrace.toString()));
response = Response(
id,
requestTime,
error: protocol.RequestError(
protocol.RequestErrorCode.PLUGIN_ERROR,
exception.toString(),
stackTrace: stackTrace.toString(),
),
);
}
if (response != null) {
_channel.sendResponse(response);
@@ -688,25 +738,30 @@ class PluginServer {
}
Future<void> _handleRequestZoned(Request request) async {
await runZonedGuarded(
() => _handleRequest(request),
(error, stackTrace) {
_channel.sendNotification(protocol.PluginErrorParams(
false /* isFatal */, error.toString(), stackTrace.toString())
.toNotification());
},
);
await runZonedGuarded(() => _handleRequest(request), (error, stackTrace) {
_channel.sendNotification(
protocol.PluginErrorParams(
false /* isFatal */,
error.toString(),
stackTrace.toString(),
).toNotification(),
);
});
}
bool _isPriorityAnalysisContext(AnalysisContext analysisContext) =>
_priorityPaths.any(analysisContext.contextRoot.isAnalyzed);
static protocol.Location _locationFor(
CompilationUnit unit, String path, Diagnostic diagnostic) {
CompilationUnit unit,
String path,
Diagnostic diagnostic,
) {
var lineInfo = unit.lineInfo;
var startLocation = lineInfo.getLocation(diagnostic.offset);
var endLocation =
lineInfo.getLocation(diagnostic.offset + diagnostic.length);
var endLocation = lineInfo.getLocation(
diagnostic.offset + diagnostic.length,
);
return protocol.Location(
path,
diagnostic.offset,
@@ -16,7 +16,7 @@ extension StringExtension on String {
return null;
}
if (indexOfNewline > 0 && codeUnitAt(indexOfNewline - 1) == 13 /* \r */) {
if (indexOfNewline > 0 && codeUnitAt(indexOfNewline - 1) == 13 /* \r */ ) {
return '\r\n';
}
return '\n';
@@ -22,8 +22,11 @@ class Selection {
/// Initialize a newly created selection to include the characters starting at
/// the [offset] and including [length] characters, all of which fall within
/// the [coveringNode].
Selection(
{required this.offset, required this.length, required this.coveringNode});
Selection({
required this.offset,
required this.length,
required this.coveringNode,
});
bool isCoveredByNode(AstNode node) {
return node.offset <= offset && offset + length <= node.end;
@@ -297,19 +300,22 @@ class _ChildrenFinder extends SimpleAstVisitor<void> {
@override
void visitRecordTypeAnnotationNamedField(
RecordTypeAnnotationNamedField node) {
RecordTypeAnnotationNamedField node,
) {
_fromList(node.metadata);
}
@override
void visitRecordTypeAnnotationNamedFields(
RecordTypeAnnotationNamedFields node) {
RecordTypeAnnotationNamedFields node,
) {
_fromList(node.fields);
}
@override
void visitRecordTypeAnnotationPositionalField(
RecordTypeAnnotationPositionalField node) {
RecordTypeAnnotationPositionalField node,
) {
_fromList(node.metadata);
}
@@ -431,6 +437,9 @@ extension CompilationUnitExtension on CompilationUnit {
return null;
}
return Selection(
offset: offset, length: length, coveringNode: coveringNode);
offset: offset,
length: length,
coveringNode: coveringNode,
);
}
}
+1 -1
View File
@@ -4,7 +4,7 @@ version: 0.2.3-dev
repository: https://github.com/dart-lang/sdk/tree/main/pkg/analysis_server_plugin
environment:
sdk: ^3.5.0
sdk: ^3.9.0
resolution: workspace
@@ -199,10 +199,7 @@ var j = 1;
}
Future<void> test_replaceSourceIndent_noLeading_nonEmpty_lf() async {
await assertReplacedIndentation(
' a\n b\n c',
' a\n b\n c',
);
await assertReplacedIndentation(' a\n b\n c', ' a\n b\n c');
}
Future<void> test_replaceSourceIndent_noTrailing_crlf() async {
@@ -213,10 +210,7 @@ var j = 1;
}
Future<void> test_replaceSourceIndent_noTrailing_lf() async {
await assertReplacedIndentation(
' a\n b\n c',
' a\n b\n c',
);
await assertReplacedIndentation(' a\n b\n c', ' a\n b\n c');
}
Future<void> test_replaceSourceIndent_trailing_added_crlf() async {
@@ -77,15 +77,18 @@ class SingleUnitTest with ResourceProviderMixin {
testCode = result.content;
var testUnit = result.unit;
expect(result.diagnostics.where((d) {
return d.diagnosticCode != WarningCode.deadCode &&
d.diagnosticCode != WarningCode.unusedCatchClause &&
d.diagnosticCode != WarningCode.unusedCatchStack &&
d.diagnosticCode != WarningCode.unusedElement &&
d.diagnosticCode != WarningCode.unusedField &&
d.diagnosticCode != WarningCode.unusedImport &&
d.diagnosticCode != WarningCode.unusedLocalVariable;
}), isEmpty);
expect(
result.diagnostics.where((d) {
return d.diagnosticCode != WarningCode.deadCode &&
d.diagnosticCode != WarningCode.unusedCatchClause &&
d.diagnosticCode != WarningCode.unusedCatchStack &&
d.diagnosticCode != WarningCode.unusedElement &&
d.diagnosticCode != WarningCode.unusedField &&
d.diagnosticCode != WarningCode.unusedImport &&
d.diagnosticCode != WarningCode.unusedLocalVariable;
}),
isEmpty,
);
findNode = FindNode(testCode, testUnit);
return result;
@@ -19,7 +19,9 @@ class NoBoolsRule extends AnalysisRule {
@override
void registerNodeProcessors(
RuleVisitorRegistry registry, RuleContext context) {
RuleVisitorRegistry registry,
RuleContext context,
) {
var visitor = _NoBoolsVisitor(this);
registry.addBooleanLiteral(this, visitor);
}
@@ -29,14 +31,16 @@ class NoDoublesRule extends AnalysisRule {
static const LintCode code = LintCode('no_doubles', 'No doubles message');
NoDoublesRule()
: super(name: 'no_doubles', description: 'No doubles message');
: super(name: 'no_doubles', description: 'No doubles message');
@override
DiagnosticCode get diagnosticCode => code;
@override
void registerNodeProcessors(
RuleVisitorRegistry registry, RuleContext context) {
RuleVisitorRegistry registry,
RuleContext context,
) {
var visitor = _NoDoublesVisitor(this);
registry.addDoubleLiteral(this, visitor);
}
@@ -50,14 +54,16 @@ class NoDoublesWarningRule extends AnalysisRule {
);
NoDoublesWarningRule()
: super(name: 'no_doubles_warning', description: 'No doubles message');
: super(name: 'no_doubles_warning', description: 'No doubles message');
@override
DiagnosticCode get diagnosticCode => code;
@override
void registerNodeProcessors(
RuleVisitorRegistry registry, RuleContext context) {
RuleVisitorRegistry registry,
RuleContext context,
) {
var visitor = _NoDoublesVisitor(this);
registry.addDoubleLiteral(this, visitor);
}
@@ -56,22 +56,27 @@ plugins:
newFile(filePath, 'bool b = false;');
var contextRoot = protocol.ContextRoot(packagePath, []);
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
// Create a broadcast Stream of notifications, so that we can have multiple
// StreamQueues listening.
var notifications = channel.notifications.asBroadcastStream();
var analysisErrorsParamsQueue = StreamQueue(notifications
.where((n) => n.event == protocol.ANALYSIS_NOTIFICATION_ERRORS)
.map((n) => protocol.AnalysisErrorsParams.fromNotification(n))
.where((p) => p.file == filePath));
var analysisErrorsParamsQueue = StreamQueue(
notifications
.where((n) => n.event == protocol.ANALYSIS_NOTIFICATION_ERRORS)
.map((n) => protocol.AnalysisErrorsParams.fromNotification(n))
.where((p) => p.file == filePath),
);
var analysisErrorsParams = await analysisErrorsParamsQueue.next;
expect(analysisErrorsParams.errors, isEmpty);
var pluginErrorParamsQueue = StreamQueue(notifications
.where((n) => n.event == protocol.PLUGIN_NOTIFICATION_ERROR)
.map((n) => protocol.PluginErrorParams.fromNotification(n)));
var pluginErrorParamsQueue = StreamQueue(
notifications
.where((n) => n.event == protocol.PLUGIN_NOTIFICATION_ERROR)
.map((n) => protocol.PluginErrorParams.fromNotification(n)),
);
var pluginErrorParams = await pluginErrorParamsQueue.next;
expect(pluginErrorParams.isFatal, false);
expect(pluginErrorParams.message, 'Bad state: A message.');
@@ -90,8 +95,9 @@ plugins:
newFile(filePath, 'bool b = false;');
var contextRoot = protocol.ContextRoot(packagePath, []);
var response = await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
var response = await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
expect(
response.error,
@@ -112,24 +118,30 @@ plugins:
newFile(filePath, 'bool b = false;');
var contextRoot = protocol.ContextRoot(packagePath, []);
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel
.sendRequest(protocol.EditGetFixesParams(filePath, 'bool b = '.length));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
await channel.sendRequest(
protocol.EditGetFixesParams(filePath, 'bool b = '.length),
);
// Create a broadcast Stream of notifications, so that we can have multiple
// StreamQueues listening.
var notifications = channel.notifications.asBroadcastStream();
var analysisErrorsParamsQueue = StreamQueue(notifications
.where((n) => n.event == protocol.ANALYSIS_NOTIFICATION_ERRORS)
.map((n) => protocol.AnalysisErrorsParams.fromNotification(n))
.where((p) => p.file == filePath));
var analysisErrorsParamsQueue = StreamQueue(
notifications
.where((n) => n.event == protocol.ANALYSIS_NOTIFICATION_ERRORS)
.map((n) => protocol.AnalysisErrorsParams.fromNotification(n))
.where((p) => p.file == filePath),
);
var analysisErrorsParams = await analysisErrorsParamsQueue.next;
expect(analysisErrorsParams.errors.single, isNotNull);
var pluginErrorParamsQueue = StreamQueue(notifications
.where((n) => n.event == protocol.PLUGIN_NOTIFICATION_ERROR)
.map((n) => protocol.PluginErrorParams.fromNotification(n)));
var pluginErrorParamsQueue = StreamQueue(
notifications
.where((n) => n.event == protocol.PLUGIN_NOTIFICATION_ERROR)
.map((n) => protocol.PluginErrorParams.fromNotification(n)),
);
var pluginErrorParams = await pluginErrorParamsQueue.next;
expect(pluginErrorParams.isFatal, false);
expect(pluginErrorParams.message, 'Bad state: A message.');
@@ -148,11 +160,13 @@ plugins:
newFile(filePath, 'bool b = false;');
var contextRoot = protocol.ContextRoot(packagePath, []);
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var response = await channel
.sendRequest(protocol.EditGetFixesParams(filePath, 'bool b = '.length));
var response = await channel.sendRequest(
protocol.EditGetFixesParams(filePath, 'bool b = '.length),
);
expect(
response.error,
isA<protocol.RequestError>()
@@ -264,14 +278,16 @@ class _ThrowsAsyncErrorRule extends AnalysisRule {
static const LintCode code = LintCode('no_bools', 'No bools message');
_ThrowsAsyncErrorRule()
: super(name: 'no_bools', description: 'No bools desc');
: super(name: 'no_bools', description: 'No bools desc');
@override
DiagnosticCode get diagnosticCode => code;
@override
void registerNodeProcessors(
RuleVisitorRegistry registry, RuleContext context) {
RuleVisitorRegistry registry,
RuleContext context,
) {
var visitor = _ThrowsAsyncErrorVisitor(this);
registry.addBooleanLiteral(this, visitor);
}
@@ -311,14 +327,16 @@ class _ThrowsSyncErrorRule extends AnalysisRule {
static const LintCode code = LintCode('no_bools', 'No bools message');
_ThrowsSyncErrorRule()
: super(name: 'no_bools', description: 'No bools desc');
: super(name: 'no_bools', description: 'No bools desc');
@override
DiagnosticCode get diagnosticCode => code;
@override
void registerNodeProcessors(
RuleVisitorRegistry registry, RuleContext context) {
RuleVisitorRegistry registry,
RuleContext context,
) {
var visitor = _ThrowsSyncErrorVisitor(this);
registry.addBooleanLiteral(this, visitor);
}
@@ -37,10 +37,12 @@ class PluginServerTest extends PluginServerTestBase {
String get packagePath => convertPath('/package1');
StreamQueue<protocol.AnalysisErrorsParams> get _analysisErrorsParams {
return StreamQueue(channel.notifications
.where((n) => n.event == protocol.ANALYSIS_NOTIFICATION_ERRORS)
.map((n) => protocol.AnalysisErrorsParams.fromNotification(n))
.where((p) => p.file == filePath));
return StreamQueue(
channel.notifications
.where((n) => n.event == protocol.ANALYSIS_NOTIFICATION_ERRORS)
.map((n) => protocol.AnalysisErrorsParams.fromNotification(n))
.where((p) => p.file == filePath),
);
}
@override
@@ -48,7 +50,9 @@ class PluginServerTest extends PluginServerTestBase {
await super.setUp();
pluginServer = PluginServer(
resourceProvider: resourceProvider, plugins: [_NoLiteralsPlugin()]);
resourceProvider: resourceProvider,
plugins: [_NoLiteralsPlugin()],
);
await startPlugin();
}
@@ -58,8 +62,9 @@ class PluginServerTest extends PluginServerTestBase {
// ignore: no_literals/no_bools
bool b = false;
''');
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var paramsQueue = _analysisErrorsParams;
var params = await paramsQueue.next;
expect(params.errors, isEmpty);
@@ -72,8 +77,9 @@ bool b = false;
// ignore_for_file: no_literals/no_bools
''');
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var paramsQueue = _analysisErrorsParams;
var params = await paramsQueue.next;
expect(params.errors, isEmpty);
@@ -82,8 +88,9 @@ bool b = false;
Future<void> test_handleAnalysisSetContextRoots() async {
writeAnalysisOptionsWithPlugin();
newFile(filePath, 'bool b = false;');
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var paramsQueue = _analysisErrorsParams;
var params = await paramsQueue.next;
expect(params.errors, hasLength(1));
@@ -93,12 +100,16 @@ bool b = false;
Future<void> test_handleEditGetAssists() async {
writeAnalysisOptionsWithPlugin();
newFile(filePath, 'bool b = false;');
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var result = await pluginServer.handleEditGetAssists(
protocol.EditGetAssistsParams(
filePath, 'bool b = f'.length, 3 /* length */),
filePath,
'bool b = f'.length,
3 /* length */,
),
);
var assists = result.assists;
expect(assists, hasLength(1));
@@ -110,11 +121,13 @@ bool b = false;
writeAnalysisOptionsWithPlugin();
newFile(filePath, 'bool b = false;');
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var response = await channel.sendRequest(
protocol.EditGetAssistsParams(filePath, 'bool b = '.length, 1));
protocol.EditGetAssistsParams(filePath, 'bool b = '.length, 1),
);
var result = protocol.EditGetAssistsResult.fromResponse(response);
expect(result.assists, hasLength(1));
}
@@ -122,11 +135,13 @@ bool b = false;
Future<void> test_handleEditGetFixes() async {
writeAnalysisOptionsWithPlugin();
newFile(filePath, 'bool b = false;');
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var result = await pluginServer.handleEditGetFixes(
protocol.EditGetFixesParams(filePath, 'bool b = '.length));
protocol.EditGetFixesParams(filePath, 'bool b = '.length),
);
var fixes = result.fixes.single;
// The WrapInQuotes fix plus three "ignore diagnostic" fixes.
expect(fixes.fixes, hasLength(4));
@@ -136,11 +151,13 @@ bool b = false;
writeAnalysisOptionsWithPlugin();
newFile(filePath, 'bool b = false;');
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var response = await channel
.sendRequest(protocol.EditGetFixesParams(filePath, 'bool b = '.length));
var response = await channel.sendRequest(
protocol.EditGetFixesParams(filePath, 'bool b = '.length),
);
var result = protocol.EditGetFixesResult.fromResponse(response);
expect(result.fixes.first.fixes, hasLength(4));
}
@@ -148,8 +165,9 @@ bool b = false;
Future<void> test_lintCodesCanHaveCustomSeverity() async {
writeAnalysisOptionsWithPlugin({'no_doubles_warning': 'enable'});
newFile(filePath, 'double x = 3.14;');
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var paramsQueue = _analysisErrorsParams;
var params = await paramsQueue.next;
expect(params.errors, hasLength(1));
@@ -163,8 +181,9 @@ bool b = false;
Future<void> test_lintCodesCanHaveConfigurableSeverity() async {
writeAnalysisOptionsWithPlugin({'no_doubles_warning': 'error'});
newFile(filePath, 'double x = 3.14;');
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var paramsQueue = _analysisErrorsParams;
var params = await paramsQueue.next;
expect(params.errors, hasLength(1));
@@ -178,8 +197,9 @@ bool b = false;
Future<void> test_lintRulesAreDisabledByDefault() async {
writeAnalysisOptionsWithPlugin();
newFile(filePath, 'double x = 3.14;');
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var paramsQueue = _analysisErrorsParams;
var params = await paramsQueue.next;
expect(params.errors, isEmpty);
@@ -188,8 +208,9 @@ bool b = false;
Future<void> test_lintRulesCanBeEnabled() async {
writeAnalysisOptionsWithPlugin({'no_doubles': 'enable'});
newFile(filePath, 'double x = 3.14;');
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var paramsQueue = _analysisErrorsParams;
var params = await paramsQueue.next;
expect(params.errors, hasLength(1));
@@ -200,12 +221,14 @@ bool b = false;
writeAnalysisOptionsWithPlugin();
newFile(filePath, 'bool b = false;');
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
// This request is unsupported.
var response = await channel.sendRequest(
protocol.CompletionGetSuggestionsParams(filePath, 0 /* offset */));
protocol.CompletionGetSuggestionsParams(filePath, 0 /* offset */),
);
expect(response.error?.code, RequestErrorCode.UNKNOWN_REQUEST);
}
@@ -213,15 +236,19 @@ bool b = false;
Future<void> test_updateContent_addOverlay() async {
writeAnalysisOptionsWithPlugin();
newFile(filePath, 'int b = 7;');
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var paramsQueue = _analysisErrorsParams;
var params = await paramsQueue.next;
expect(params.errors, isEmpty);
await channel.sendRequest(protocol.AnalysisUpdateContentParams(
{filePath: protocol.AddContentOverlay('bool b = false;')}));
await channel.sendRequest(
protocol.AnalysisUpdateContentParams({
filePath: protocol.AddContentOverlay('bool b = false;'),
}),
);
params = await paramsQueue.next;
expect(params.errors, hasLength(1));
@@ -231,23 +258,30 @@ bool b = false;
Future<void> test_updateContent_changeOverlay() async {
writeAnalysisOptionsWithPlugin();
newFile(filePath, 'int b = 7;');
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var paramsQueue = _analysisErrorsParams;
var params = await paramsQueue.next;
expect(params.errors, isEmpty);
await channel.sendRequest(protocol.AnalysisUpdateContentParams(
{filePath: protocol.AddContentOverlay('int b = 0;')}));
await channel.sendRequest(
protocol.AnalysisUpdateContentParams({
filePath: protocol.AddContentOverlay('int b = 0;'),
}),
);
params = await paramsQueue.next;
expect(params.errors, isEmpty);
await channel.sendRequest(protocol.AnalysisUpdateContentParams({
filePath: protocol.ChangeContentOverlay(
[protocol.SourceEdit(0, 9, 'bool b = false')])
}));
await channel.sendRequest(
protocol.AnalysisUpdateContentParams({
filePath: protocol.ChangeContentOverlay([
protocol.SourceEdit(0, 9, 'bool b = false'),
]),
}),
);
params = await paramsQueue.next;
expect(params.errors, hasLength(1));
@@ -257,22 +291,29 @@ bool b = false;
Future<void> test_updateContent_removeOverlay() async {
writeAnalysisOptionsWithPlugin();
newFile(filePath, 'bool b = false;');
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var paramsQueue = _analysisErrorsParams;
var params = await paramsQueue.next;
expect(params.errors, hasLength(1));
_expectAnalysisError(params.errors.single, message: 'No bools message');
await channel.sendRequest(protocol.AnalysisUpdateContentParams(
{filePath: protocol.AddContentOverlay('int b = 7;')}));
await channel.sendRequest(
protocol.AnalysisUpdateContentParams({
filePath: protocol.AddContentOverlay('int b = 7;'),
}),
);
params = await paramsQueue.next;
expect(params.errors, isEmpty);
await channel.sendRequest(protocol.AnalysisUpdateContentParams(
{filePath: protocol.RemoveContentOverlay()}));
await channel.sendRequest(
protocol.AnalysisUpdateContentParams({
filePath: protocol.RemoveContentOverlay(),
}),
);
params = await paramsQueue.next;
expect(params.errors, hasLength(1));
@@ -282,8 +323,9 @@ bool b = false;
Future<void> test_warningRulesAreEnabledByDefault() async {
writeAnalysisOptionsWithPlugin();
newFile(filePath, 'bool b = false;');
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var paramsQueue = _analysisErrorsParams;
var params = await paramsQueue.next;
expect(params.errors, hasLength(1));
@@ -293,8 +335,9 @@ bool b = false;
Future<void> test_warningRulesCanBeDisabled() async {
writeAnalysisOptionsWithPlugin({'no_bools': 'disable'});
newFile(filePath, 'bool b = false;');
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var paramsQueue = _analysisErrorsParams;
var params = await paramsQueue.next;
expect(params.errors, isEmpty);
@@ -302,15 +345,19 @@ bool b = false;
Future<void> test_watchEvent_add() async {
writeAnalysisOptionsWithPlugin();
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var paramsQueue = _analysisErrorsParams;
newFile(filePath, 'bool b = false;');
await channel.sendRequest(protocol.AnalysisHandleWatchEventsParams(
[WatchEvent(WatchEventType.ADD, filePath)]));
await channel.sendRequest(
protocol.AnalysisHandleWatchEventsParams([
WatchEvent(WatchEventType.ADD, filePath),
]),
);
var params = await paramsQueue.next;
expect(params.errors, hasLength(1));
@@ -320,8 +367,9 @@ bool b = false;
Future<void> test_watchEvent_modify() async {
writeAnalysisOptionsWithPlugin();
newFile(filePath, 'int b = 7;');
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var paramsQueue = _analysisErrorsParams;
var params = await paramsQueue.next;
@@ -329,8 +377,11 @@ bool b = false;
newFile(filePath, 'bool b = false;');
await channel.sendRequest(protocol.AnalysisHandleWatchEventsParams(
[WatchEvent(WatchEventType.MODIFY, filePath)]));
await channel.sendRequest(
protocol.AnalysisHandleWatchEventsParams([
WatchEvent(WatchEventType.MODIFY, filePath),
]),
);
params = await paramsQueue.next;
expect(params.errors, hasLength(1));
@@ -340,8 +391,9 @@ bool b = false;
Future<void> test_watchEvent_remove() async {
writeAnalysisOptionsWithPlugin();
newFile(filePath, 'int b = 7;');
await channel
.sendRequest(protocol.AnalysisSetContextRootsParams([contextRoot]));
await channel.sendRequest(
protocol.AnalysisSetContextRootsParams([contextRoot]),
);
var paramsQueue = _analysisErrorsParams;
var params = await paramsQueue.next;
@@ -349,15 +401,19 @@ bool b = false;
deleteFile(filePath);
await channel.sendRequest(protocol.AnalysisHandleWatchEventsParams(
[WatchEvent(WatchEventType.REMOVE, filePath)]));
await channel.sendRequest(
protocol.AnalysisHandleWatchEventsParams([
WatchEvent(WatchEventType.REMOVE, filePath),
]),
);
params = await paramsQueue.next;
expect(params.errors, isEmpty);
}
void writeAnalysisOptionsWithPlugin(
[Map<String, String> diagnosticConfiguration = const {}]) {
void writeAnalysisOptionsWithPlugin([
Map<String, String> diagnosticConfiguration = const {},
]) {
var buffer = StringBuffer('''
plugins:
no_literals:
@@ -382,15 +438,21 @@ plugins:
isA<protocol.AnalysisError>()
.having((e) => e.severity, 'severity', severity)
.having(
(e) => e.type, 'type', protocol.AnalysisErrorType.STATIC_WARNING)
(e) => e.type,
'type',
protocol.AnalysisErrorType.STATIC_WARNING,
)
.having((e) => e.message, 'message', message),
);
}
}
class _InvertBoolean extends ResolvedCorrectionProducer {
static const _invertBooleanKind =
AssistKind('dart.fix.invertBooelan', 50, 'Invert Boolean value');
static const _invertBooleanKind = AssistKind(
'dart.fix.invertBooelan',
50,
'Invert Boolean value',
);
_InvertBoolean({required super.context});
@@ -424,8 +486,11 @@ class _NoLiteralsPlugin extends Plugin {
}
class _WrapInQuotes extends ResolvedCorrectionProducer {
static const _wrapInQuotesKind =
FixKind('dart.fix.wrapInQuotes', 50, 'Wrap in quotes');
static const _wrapInQuotesKind = FixKind(
'dart.fix.wrapInQuotes',
50,
'Wrap in quotes',
);
_WrapInQuotes({required super.context});
@@ -34,8 +34,12 @@ class FakeChannel implements PluginCommunicationChannel {
void close() {}
@override
void listen(void Function(protocol.Request request)? onRequest,
{void Function()? onDone, Function? onError, Function? onNotification}) {
void listen(
void Function(protocol.Request request)? onRequest, {
void Function()? onDone,
Function? onError,
Function? onNotification,
}) {
_onRequest = onRequest;
}
@@ -47,7 +51,8 @@ class FakeChannel implements PluginCommunicationChannel {
Future<protocol.Response> sendRequest(protocol.RequestParams params) {
if (_onRequest == null) {
fail(
'_onReuest is null! `listen` has not yet been called on this channel.');
'_onReuest is null! `listen` has not yet been called on this channel.',
);
}
var id = (_idCounter++).toString();
var request = params.toRequest(id);
@@ -84,7 +89,10 @@ class PluginServerTestBase with ResourceProviderMixin {
await pluginServer.handlePluginVersionCheck(
protocol.PluginVersionCheckParams(
byteStoreRoot.path, sdkRoot.path, '0.0.1'),
byteStoreRoot.path,
sdkRoot.path,
'0.0.1',
),
);
}
@@ -14,5 +14,6 @@ Future<void> main() async {
}
/// A list of all targets generated by this code generator.
final List<GeneratedContent> allTargets =
allTargetsForPackage('analysis_server_plugin');
final List<GeneratedContent> allTargets = allTargetsForPackage(
'analysis_server_plugin',
);
@@ -14,7 +14,12 @@ import 'generate.dart';
Future<void> main() async {
await allTargets.check(
pkg_root.packageRoot,
join(pkg_root.packageRoot, 'analysis_server_plugin', 'tool', 'api',
'generate.dart'),
join(
pkg_root.packageRoot,
'analysis_server_plugin',
'tool',
'api',
'generate.dart',
),
);
}