Version 2.14.0-6.0.dev
Merge commit '3c597080546a5990dee18473c8065bc89308d951' into 'dev'
diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights.dart b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
index 2a97366..0233e2e 100644
--- a/pkg/analysis_server/lib/src/computer/computer_highlights.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
@@ -2,8 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// @dart = 2.9
-
import 'package:analysis_server/lsp_protocol/protocol_generated.dart'
show SemanticTokenTypes, SemanticTokenModifiers;
import 'package:analysis_server/src/lsp/constants.dart'
@@ -24,7 +22,7 @@
/// A computer for [HighlightRegion]s and LSP [SemanticTokenInfo] in a Dart [CompilationUnit].
class DartUnitHighlightsComputer {
final CompilationUnit _unit;
- final SourceRange range;
+ final SourceRange? range;
final _regions = <HighlightRegion>[];
final _semanticTokens = <SemanticTokenInfo>[];
@@ -57,11 +55,11 @@
}
void _addCommentRanges() {
- var token = _unit.beginToken;
+ Token? token = _unit.beginToken;
while (token != null) {
- Token commentToken = token.precedingComments;
+ Token? commentToken = token.precedingComments;
while (commentToken != null) {
- HighlightRegionType highlightType;
+ HighlightRegionType? highlightType;
if (commentToken.type == TokenType.MULTI_LINE_COMMENT) {
if (commentToken.lexeme.startsWith('/**')) {
highlightType = HighlightRegionType.COMMENT_DOCUMENTATION;
@@ -155,15 +153,16 @@
if (element is! ClassElement) {
return false;
}
- ClassElement classElement = element;
// prepare type
HighlightRegionType type;
- if (node.parent is TypeName &&
- node.parent.parent is ConstructorName &&
- node.parent.parent.parent is InstanceCreationExpression) {
+ var parent = node.parent;
+ var grandParent = parent?.parent;
+ if (parent is TypeName &&
+ grandParent is ConstructorName &&
+ grandParent.parent is InstanceCreationExpression) {
// new Class()
type = HighlightRegionType.CONSTRUCTOR;
- } else if (classElement.isEnum) {
+ } else if (element.isEnum) {
type = HighlightRegionType.ENUM;
} else {
type = HighlightRegionType.CLASS;
@@ -184,7 +183,7 @@
var element = node.writeOrReadElement;
if (element is LocalVariableElement) {
var elementType = element.type;
- if (elementType?.isDynamic == true) {
+ if (elementType.isDynamic) {
var type = node.inDeclarationContext()
? HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_DECLARATION
: HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_REFERENCE;
@@ -193,7 +192,7 @@
}
if (element is ParameterElement) {
var elementType = element.type;
- if (elementType?.isDynamic == true) {
+ if (elementType.isDynamic) {
var type = node.inDeclarationContext()
? HighlightRegionType.DYNAMIC_PARAMETER_DECLARATION
: HighlightRegionType.DYNAMIC_PARAMETER_REFERENCE;
@@ -207,11 +206,11 @@
var element = node.writeOrReadElement;
if (element is FieldFormalParameterElement) {
if (node.parent is FieldFormalParameter) {
- element = (element as FieldFormalParameterElement).field;
+ element = element.field;
}
}
// prepare type
- HighlightRegionType type;
+ HighlightRegionType? type;
if (element is FieldElement) {
var enclosingElement = element.enclosingElement;
if (enclosingElement is ClassElement && enclosingElement.isEnum) {
@@ -283,13 +282,12 @@
return false;
}
// getter or setter
- var propertyAccessorElement = element as PropertyAccessorElement;
var isTopLevel = element.enclosingElement is CompilationUnitElement;
HighlightRegionType type;
- if (propertyAccessorElement.isGetter) {
+ if (element.isGetter) {
if (isTopLevel) {
type = HighlightRegionType.TOP_LEVEL_GETTER_DECLARATION;
- } else if (propertyAccessorElement.isStatic) {
+ } else if (element.isStatic) {
type = HighlightRegionType.STATIC_GETTER_DECLARATION;
} else {
type = HighlightRegionType.INSTANCE_GETTER_DECLARATION;
@@ -297,7 +295,7 @@
} else {
if (isTopLevel) {
type = HighlightRegionType.TOP_LEVEL_SETTER_DECLARATION;
- } else if (propertyAccessorElement.isStatic) {
+ } else if (element.isStatic) {
type = HighlightRegionType.STATIC_SETTER_DECLARATION;
} else {
type = HighlightRegionType.INSTANCE_SETTER_DECLARATION;
@@ -347,8 +345,7 @@
if (element is! MethodElement) {
return false;
}
- var methodElement = element as MethodElement;
- var isStatic = methodElement.isStatic;
+ var isStatic = element.isStatic;
// OK
HighlightRegionType type;
if (node.inDeclarationContext()) {
@@ -443,9 +440,10 @@
int offset,
int length,
HighlightRegionType type, {
- SemanticTokenTypes semanticTokenType,
- Set<SemanticTokenModifiers> semanticTokenModifiers,
+ SemanticTokenTypes? semanticTokenType,
+ Set<SemanticTokenModifiers>? semanticTokenModifiers,
}) {
+ final range = this.range;
if (range != null) {
final end = offset + length;
// Skip token if it ends before the range of starts after the range.
@@ -470,8 +468,8 @@
bool _addRegion_node(
AstNode node,
HighlightRegionType type, {
- SemanticTokenTypes semanticTokenType,
- Set<SemanticTokenModifiers> semanticTokenModifiers,
+ SemanticTokenTypes? semanticTokenType,
+ Set<SemanticTokenModifiers>? semanticTokenModifiers,
}) {
var offset = node.offset;
var length = node.length;
@@ -493,10 +491,10 @@
}
void _addRegion_token(
- Token token,
+ Token? token,
HighlightRegionType type, {
- SemanticTokenTypes semanticTokenType,
- Set<SemanticTokenModifiers> semanticTokenModifiers,
+ SemanticTokenTypes? semanticTokenType,
+ Set<SemanticTokenModifiers>? semanticTokenModifiers,
}) {
if (token != null) {
var offset = token.offset;
diff --git a/pkg/analysis_server/lib/src/utilities/mocks.dart b/pkg/analysis_server/lib/src/utilities/mocks.dart
index 6c4134a..5022dcd 100644
--- a/pkg/analysis_server/lib/src/utilities/mocks.dart
+++ b/pkg/analysis_server/lib/src/utilities/mocks.dart
@@ -2,12 +2,9 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// @dart = 2.9
-
import 'dart:async';
import 'package:analysis_server/protocol/protocol.dart';
-import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/channel/channel.dart';
import 'package:analysis_server/src/plugin/notification_manager.dart';
import 'package:analysis_server/src/plugin/plugin_manager.dart';
@@ -27,14 +24,14 @@
StreamController<Response>.broadcast();
StreamController<Notification> notificationController =
StreamController<Notification>(sync: true);
- Completer<Response> errorCompleter;
+ Completer<Response>? errorCompleter;
List<Response> responsesReceived = [];
List<Notification> notificationsReceived = [];
bool _closed = false;
- String name;
+ String? name;
MockServerChannel();
@@ -50,7 +47,7 @@
@override
void listen(void Function(Request request) onRequest,
- {Function onError, void Function() onDone}) {
+ {Function? onError, void Function()? onDone}) {
requestController.stream
.listen(onRequest, onError: onError, onDone: onDone);
}
@@ -62,11 +59,12 @@
return;
}
notificationsReceived.add(notification);
+ final errorCompleter = this.errorCompleter;
if (errorCompleter != null && notification.event == 'server.error') {
- print(
- '[server.error] test: $name message: ${notification.params['message']}');
- errorCompleter.completeError(ServerError(notification.params['message']),
- StackTrace.fromString(notification.params['stackTrace']));
+ var params = notification.params!;
+ print('[server.error] test: $name message: ${params['message']}');
+ errorCompleter.completeError(ServerError(params['message'] as String),
+ StackTrace.fromString(params['stackTrace'] as String));
}
// Wrap send notification in future to simulate websocket
// TODO(scheglov) ask Dan why and decide what to do
@@ -118,9 +116,9 @@
var response =
responseController.stream.firstWhere((response) => response.id == id);
if (throwOnError) {
- errorCompleter = Completer<Response>();
+ var completer = errorCompleter = Completer<Response>();
try {
- return Future.any([response, errorCompleter.future]);
+ return Future.any([response, completer.future]);
} finally {
errorCompleter = null;
}
@@ -143,11 +141,11 @@
/// A plugin manager that simulates broadcasting requests to plugins by
/// hard-coding the responses.
class TestPluginManager implements PluginManager {
- plugin.AnalysisSetPriorityFilesParams analysisSetPriorityFilesParams;
- plugin.AnalysisSetSubscriptionsParams analysisSetSubscriptionsParams;
- plugin.AnalysisUpdateContentParams analysisUpdateContentParams;
- plugin.RequestParams broadcastedRequest;
- Map<PluginInfo, Future<plugin.Response>> broadcastResults;
+ plugin.AnalysisSetPriorityFilesParams? analysisSetPriorityFilesParams;
+ plugin.AnalysisSetSubscriptionsParams? analysisSetSubscriptionsParams;
+ plugin.AnalysisUpdateContentParams? analysisUpdateContentParams;
+ plugin.RequestParams? broadcastedRequest;
+ Map<PluginInfo, Future<plugin.Response>>? broadcastResults;
@override
List<PluginInfo> plugins = [];
@@ -192,7 +190,7 @@
@override
Map<PluginInfo, Future<plugin.Response>> broadcastRequest(
plugin.RequestParams params,
- {analyzer.ContextRoot contextRoot}) {
+ {analyzer.ContextRoot? contextRoot}) {
broadcastedRequest = params;
return broadcastResults ?? <PluginInfo, Future<plugin.Response>>{};
}
@@ -209,7 +207,7 @@
}
@override
- List<PluginInfo> pluginsForContextRoot(analyzer.ContextRoot contextRoot) {
+ List<PluginInfo> pluginsForContextRoot(analyzer.ContextRoot? contextRoot) {
fail('Unexpected invocation of pluginsForContextRoot');
}
diff --git a/pkg/analysis_server/test/src/computer/highlights_computer_test.dart b/pkg/analysis_server/test/src/computer/highlights_computer_test.dart
index 3b3aacb..08682eb 100644
--- a/pkg/analysis_server/test/src/computer/highlights_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/highlights_computer_test.dart
@@ -2,8 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// @dart = 2.9
-
import 'package:analysis_server/src/computer/computer_highlights.dart';
import 'package:analysis_server/src/protocol_server.dart';
import 'package:test/test.dart';
@@ -19,9 +17,9 @@
@reflectiveTest
class Highlights2ComputerTest extends AbstractContextTest {
- String sourcePath;
- String content;
- List<HighlightRegion> highlights;
+ late String sourcePath;
+ late String content;
+ late List<HighlightRegion> highlights;
@override
void setUp() {
@@ -122,7 +120,7 @@
expect(result.errors, isEmpty);
}
- var computer = DartUnitHighlightsComputer(result.unit);
+ var computer = DartUnitHighlightsComputer(result.unit!);
highlights = computer.compute();
}
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 35f7890..6024381 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -632,7 +632,7 @@
throw ArgumentError('$uri is not a library.');
}
- var unitResult = await getUnitElement(file.path!);
+ var unitResult = await getUnitElement(file.path);
return unitResult.element.library;
},
(externalLibrary) async {
@@ -662,10 +662,8 @@
var units = <ParsedUnitResult>[];
for (var unitFile in file.libraryFiles) {
var unitPath = unitFile.path;
- if (unitPath != null) {
- var unitResult = parseFileSync(unitPath);
- units.add(unitResult);
- }
+ var unitResult = parseFileSync(unitPath);
+ units.add(unitResult);
}
return ParsedLibraryResultImpl(currentSession, path, file.uri, units);
@@ -685,7 +683,7 @@
if (file.isPart) {
throw ArgumentError('Is a part: $uri');
}
- return getParsedLibrary(file.path!);
+ return getParsedLibrary(file.path);
},
(externalLibrary) {
return ParsedLibraryResultImpl.external(currentSession, uri);
@@ -759,7 +757,7 @@
if (file.isPart) {
throw ArgumentError('Is a part: $uri');
}
- return getResolvedLibrary(file.path!);
+ return getResolvedLibrary(file.path);
},
(externalLibrary) async {
return ResolvedLibraryResultImpl.external(currentSession, uri);
@@ -925,7 +923,7 @@
FileState file = _fileTracker.getFile(path);
RecordingErrorListener listener = RecordingErrorListener();
CompilationUnit unit = file.parse(listener);
- return ParsedUnitResultImpl(currentSession, file.path!, file.uri,
+ return ParsedUnitResultImpl(currentSession, file.path, file.uri,
file.content, file.lineInfo, file.isPart, unit, listener.errors);
}
@@ -1403,28 +1401,27 @@
Map<FileState, UnitAnalysisResult> unitResults = analyzer.analyze();
var resolvedUnits = <ResolvedUnitResult>[];
- for (var unitFile in unitResults.keys) {
- if (unitFile.path != null) {
- var unitResult = unitResults[unitFile]!;
- resolvedUnits.add(
- ResolvedUnitResultImpl(
- currentSession,
- unitFile.path!,
- unitFile.uri,
- unitFile.exists,
- unitFile.content,
- unitFile.lineInfo,
- unitFile.isPart,
- unitResult.unit,
- unitResult.errors,
- ),
- );
- }
+ for (var entry in unitResults.entries) {
+ var unitFile = entry.key;
+ var unitResult = entry.value;
+ resolvedUnits.add(
+ ResolvedUnitResultImpl(
+ currentSession,
+ unitFile.path,
+ unitFile.uri,
+ unitFile.exists,
+ unitFile.content,
+ unitFile.lineInfo,
+ unitFile.isPart,
+ unitResult.unit,
+ unitResult.errors,
+ ),
+ );
}
return ResolvedLibraryResultImpl(
currentSession,
- library.path!,
+ library.path,
library.uri,
resolvedUnits.first.libraryElement,
resolvedUnits,
@@ -1610,7 +1607,7 @@
_updateHasErrorOrWarningFlag(file, errors);
return AnalysisResult(
currentSession,
- file.path!,
+ file.path,
file.uri,
file.exists,
content,
@@ -1627,7 +1624,7 @@
FileState file, List<AnalysisDriverUnitError> serialized) {
List<AnalysisError> errors = <AnalysisError>[];
for (AnalysisDriverUnitError error in serialized) {
- var analysisError = ErrorEncoding.decode(file.source!, error);
+ var analysisError = ErrorEncoding.decode(file.source, error);
if (analysisError != null) {
errors.add(analysisError);
}
@@ -1666,7 +1663,7 @@
// TODO(scheglov) Find a better way to report this.
return AnalysisResult(
currentSession,
- file.path!,
+ file.path,
file.uri,
file.exists,
null,
@@ -1675,7 +1672,7 @@
'missing',
null,
[
- AnalysisError(file.source!, 0, 0,
+ AnalysisError(file.source, 0, 0,
CompileTimeErrorCode.MISSING_DART_LIBRARY, [missingUri])
],
null);
@@ -1696,9 +1693,7 @@
var libraryFile = _fsState.getFileForPath(path);
for (var file in libraryFile.libraryFiles) {
var path = file.path;
- if (path != null) {
- fileContentMap[path] = file.content;
- }
+ fileContentMap[path] = file.content;
}
_exceptionController.add(
@@ -1737,7 +1732,7 @@
List<AnalysisDriverExceptionFileBuilder> contextFiles = libraryFile
.transitiveFiles
.map((file) => AnalysisDriverExceptionFileBuilder(
- path: file.path!, content: file.content))
+ path: file.path, content: file.content))
.toList();
contextFiles.sort((a, b) => a.path.compareTo(b.path));
AnalysisDriverExceptionContextBuilder contextBuilder =
@@ -2409,7 +2404,7 @@
}
FileState file = filesToCheck![filesToCheckIndex++];
if (file.referencedNames.contains(name)) {
- referencingFiles.add(file.path!);
+ referencingFiles.add(file.path);
}
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index fbb35e3..0577376 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -92,13 +92,13 @@
final FileSystemState _fsState;
/// The absolute path of the file.
- final String? path;
+ final String path;
/// The absolute URI of the file.
final Uri uri;
/// The [Source] of the file with the [uri].
- final Source? source;
+ final Source source;
/// The [WorkspacePackage] that contains this file.
///
@@ -111,12 +111,12 @@
/// possibly additional enabled experiments (from the analysis options file,
/// or from SDK allowed experiments).
///
- /// This feature set is then restricted, with the [_packageLanguageVersion],
+ /// This feature set is then restricted, with the [packageLanguageVersion],
/// or with a `@dart` language override token in the file header.
- final FeatureSet? _contextFeatureSet;
+ final FeatureSet _contextFeatureSet;
/// The language version for the package that contains this file.
- final Version? packageLanguageVersion;
+ final Version packageLanguageVersion;
int id = fileObjectId++;
int? refreshId;
@@ -371,7 +371,7 @@
String get _invalidTransitiveSignature {
return (ApiSignature()
- ..addString(path!)
+ ..addString(path)
..addBytes(unlinkedSignature))
.toHex();
}
@@ -434,7 +434,7 @@
_invalidateCurrentUnresolvedData();
{
- var rawFileState = _fsState._fileContentCache.get(path!, allowCached);
+ var rawFileState = _fsState._fileContentCache.get(path, allowCached);
_content = rawFileState.content;
_exists = rawFileState.exists;
_contentHash = rawFileState.contentHash;
@@ -444,8 +444,8 @@
{
var signature = ApiSignature();
signature.addUint32List(_fsState._saltForUnlinked);
- signature.addFeatureSet(_contextFeatureSet!);
- signature.addLanguageVersion(packageLanguageVersion!);
+ signature.addFeatureSet(_contextFeatureSet);
+ signature.addLanguageVersion(packageLanguageVersion);
signature.addString(_contentHash!);
signature.addBool(_exists!);
_unlinkedSignature = signature.toByteList();
@@ -522,11 +522,7 @@
@override
String toString() {
- if (path == null) {
- return '<unresolved>';
- } else {
- return '[id: $id][rid: $refreshId]$uri = $path';
- }
+ return '[id: $id][rid: $refreshId]$uri = $path';
}
CompilationUnitImpl _createEmptyCompilationUnit() {
@@ -534,13 +530,13 @@
var unit = astFactory.compilationUnit(
beginToken: token,
endToken: token,
- featureSet: _contextFeatureSet!,
+ featureSet: _contextFeatureSet,
);
unit.lineInfo = LineInfo(const <int>[0]);
unit.languageVersion = LibraryLanguageVersion(
- package: packageLanguageVersion!,
+ package: packageLanguageVersion,
override: null,
);
@@ -610,23 +606,19 @@
}
CompilationUnitImpl _parse(AnalysisErrorListener errorListener) {
- if (source == null) {
- return _createEmptyCompilationUnit();
- }
-
CharSequenceReader reader = CharSequenceReader(content);
- Scanner scanner = Scanner(source!, reader, errorListener)
+ Scanner scanner = Scanner(source, reader, errorListener)
..configureFeatures(
- featureSetForOverriding: _contextFeatureSet!,
- featureSet: _contextFeatureSet!.restrictToVersion(
- packageLanguageVersion!,
+ featureSetForOverriding: _contextFeatureSet,
+ featureSet: _contextFeatureSet.restrictToVersion(
+ packageLanguageVersion,
),
);
Token token = scanner.tokenize(reportScannerErrors: false);
LineInfo lineInfo = LineInfo(scanner.lineStarts);
Parser parser = Parser(
- source!,
+ source,
errorListener,
featureSet: scanner.featureSet,
);
@@ -635,7 +627,7 @@
var unit = parser.parseCompilationUnit(token);
unit.lineInfo = lineInfo;
unit.languageVersion = LibraryLanguageVersion(
- package: packageLanguageVersion!,
+ package: packageLanguageVersion,
override: scanner.overrideVersion,
);
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index 1b7434b..399bc43 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -176,15 +176,13 @@
// This must happen after all other diagnostics have been computed but
// before the list of diagnostics has been filtered.
for (var file in _library.libraryFiles) {
- if (file.source != null) {
- IgnoreValidator(
- _getErrorReporter(file),
- _getErrorListener(file).errors,
- _fileToIgnoreInfo[file]!,
- _fileToLineInfo[file]!,
- _analysisOptions.unignorableNames,
- ).reportErrors();
- }
+ IgnoreValidator(
+ _getErrorReporter(file),
+ _getErrorListener(file).errors,
+ _fileToIgnoreInfo[file]!,
+ _fileToLineInfo[file]!,
+ _analysisOptions.unignorableNames,
+ ).reportErrors();
}
timerLibraryAnalyzerVerify.stop();
@@ -256,10 +254,6 @@
}
void _computeHints(FileState file, CompilationUnit unit) {
- if (file.source == null) {
- return;
- }
-
AnalysisErrorListener errorListener = _getErrorListener(file);
ErrorReporter errorReporter = _getErrorReporter(file);
@@ -333,10 +327,6 @@
void _computeLints(FileState file, LinterContextUnit currentUnit,
List<LinterContextUnit> allUnits) {
var unit = currentUnit.unit;
- if (file.source == null) {
- return;
- }
-
ErrorReporter errorReporter = _getErrorReporter(file);
var nodeRegistry = NodeLintRegistry(_analysisOptions.enableTiming);
@@ -370,10 +360,6 @@
}
void _computeVerifyErrors(FileState file, CompilationUnit unit) {
- if (file.source == null) {
- return;
- }
-
RecordingErrorListener errorListener = _getErrorListener(file);
CodeChecker checker = CodeChecker(
@@ -478,7 +464,7 @@
RecordingErrorListener listener = _getErrorListener(file);
return ErrorReporter(
listener,
- file.source!,
+ file.source,
isNonNullableByDefault: _libraryElement.isNonNullableByDefault,
);
});
@@ -665,10 +651,6 @@
void _resolveFile(FileState file, CompilationUnit unit) {
var source = file.source;
- if (source == null) {
- return;
- }
-
RecordingErrorListener errorListener = _getErrorListener(file);
var unitElement = unit.declaredElement as CompilationUnitElementImpl;
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_context.dart b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
index 94a44cf..7401cb1 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_context.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
@@ -138,7 +138,7 @@
librariesLinkedTimer.start();
testView.linkedCycles.add(
- cycle.libraries.map((e) => e.path!).toSet(),
+ cycle.libraries.map((e) => e.path).toSet(),
);
timerInputLibraries.start();
@@ -146,7 +146,6 @@
var inputLibraries = <link2.LinkInputLibrary>[];
for (var libraryFile in cycle.libraries) {
var librarySource = libraryFile.source;
- if (librarySource == null) continue;
var inputUnits = <link2.LinkInputUnit>[];
var partIndex = -1;
@@ -163,7 +162,7 @@
inputUnits.add(
link2.LinkInputUnit(
partUriStr,
- file.source!,
+ file.source,
isSynthetic,
unit,
),
@@ -316,7 +315,7 @@
var fileContentMap = <String, String>{};
for (var libraryFile in cycle.libraries) {
for (var file in libraryFile.libraryFiles) {
- fileContentMap[file.path!] = file.content;
+ fileContentMap[file.path] = file.content;
}
}
throw CaughtExceptionWithFiles(exception, stackTrace, fileContentMap);
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_graph.dart b/pkg/analyzer/lib/src/dart/analysis/library_graph.dart
index f4dcec5..d21d4e1 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_graph.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_graph.dart
@@ -110,8 +110,8 @@
// Sort libraries to produce stable signatures.
scc.sort((first, second) {
- var firstPath = first.file.path!;
- var secondPath = second.file.path!;
+ var firstPath = first.file.path;
+ var secondPath = second.file.path;
return firstPath.compareTo(secondPath);
});
@@ -128,7 +128,7 @@
for (var node in scc) {
cycle.libraries.add(node.file);
- signature.addLanguageVersion(node.file.packageLanguageVersion!);
+ signature.addLanguageVersion(node.file.packageLanguageVersion);
signature.addString(node.file.uriStr);
signature.addInt(node.file.libraryFiles.length);
diff --git a/pkg/analyzer/lib/src/dart/analysis/search.dart b/pkg/analyzer/lib/src/dart/analysis/search.dart
index 7d24cf9..9e3c4b0 100644
--- a/pkg/analyzer/lib/src/dart/analysis/search.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/search.dart
@@ -149,8 +149,8 @@
if (files != null) {
for (FileState file in files) {
- if (searchedFiles.add(file.path!, this)) {
- var index = await _driver.getIndex(file.path!);
+ if (searchedFiles.add(file.path, this)) {
+ var index = await _driver.getIndex(file.path);
if (index != null) {
var request = _IndexRequest(index);
request.addSubtypes(id, results, file);
@@ -174,7 +174,7 @@
List<FileState> knownFiles = _driver.fsState.knownFiles.toList();
for (FileState file in knownFiles) {
- var unitResult = await _driver.getUnitElement(file.path!);
+ var unitResult = await _driver.getUnitElement(file.path);
if (unitResult.state == ResultState.VALID) {
CompilationUnitElement unitElement = unitResult.element;
unitElement.accessors.forEach(addElement);
@@ -245,7 +245,7 @@
FileState library = _driver.fsState.getFileForPath(libraryPath);
for (FileState file in library.libraryFiles) {
if (file.path == path || file.referencedNames.contains(name)) {
- files.add(file.path!);
+ files.add(file.path);
}
}
}
@@ -316,7 +316,7 @@
const {
IndexRelationKind.IS_REFERENCED_BY: SearchResultKind.REFERENCE
},
- file.path!);
+ file.path);
}
}
}
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index 26ad6fe..d64b16b 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -12,6 +12,7 @@
import 'package:analyzer/dart/element/type_system.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
+import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_system.dart' show TypeSystemImpl;
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
@@ -245,8 +246,14 @@
/// Gets the decorated type of [element] from [_variables], performing any
/// necessary substitutions.
- DecoratedType getOrComputeElementType(Element element,
- {DecoratedType targetType}) {
+ ///
+ /// [node] is used as the AST node for the edge origin if any graph edges need
+ /// to be created. [targetType], if provided, indicates the type of the
+ /// target (receiver) for a method, getter, or setter invocation.
+ /// [targetExpression], if provided, is the expression for the target
+ /// (receiver) for a method, getter, or setter invocation.
+ DecoratedType getOrComputeElementType(AstNode node, Element element,
+ {DecoratedType targetType, Expression targetExpression}) {
Map<TypeParameterElement, DecoratedType> substitution;
Element baseElement = element.declaration;
if (targetType != null) {
@@ -262,19 +269,65 @@
} else {
assert(enclosingElement is ExtensionElement);
final extensionElement = enclosingElement as ExtensionElement;
- final extendedType =
- _typeSystem.resolveToBound(extensionElement.extendedType);
- if (extendedType is InterfaceType) {
- if (extensionElement.typeParameters.isNotEmpty) {
- substitution = _decoratedClassHierarchy
- .asInstanceOf(targetType, extendedType.element)
- .asSubstitution;
+ // The semantics of calling an extension method or extension property
+ // are essentially the same as calling a static function where the
+ // receiver is passed as an invisible `this` parameter whose type is the
+ // extension's "on" type. If the extension declaration has type
+ // parameters, they behave like inferred type parameters of the static
+ // function.
+ //
+ // So what we need to do is (1) create a set of DecoratedTypes to
+ // represent the inferred types of the type parameters, (2) ensure that
+ // the receiver type is assignable to "on" type (with those decorated
+ // types substituted into it), and (3) substitute those decorated types
+ // into the declared type of the extension method or extension property,
+ // so that the caller will match up parameter types and the return type
+ // appropriately.
+ //
+ // Taking each step in turn:
+ // (1) create a set of decorated types to represent the inferred types
+ // of the type parameters. Note that we must make sure each of these
+ // types satisfies its associated bound.
+ var typeParameters = extensionElement.typeParameters;
+ if (typeParameters.isNotEmpty) {
+ var preMigrationSubstitution = (element as Member).substitution.map;
+ substitution = {};
+ var target = NullabilityNodeTarget.text('extension');
+ for (int i = 0; i < typeParameters.length; i++) {
+ var typeParameter = typeParameters[i];
+ var decoratedTypeArgument = DecoratedType.forImplicitType(
+ typeProvider,
+ preMigrationSubstitution[typeParameter],
+ _graph,
+ target.typeArgument(i));
+ substitution[typeParameter] = decoratedTypeArgument;
+ var edgeOrigin =
+ InferredTypeParameterInstantiationOrigin(source, node);
+ _checkAssignment(edgeOrigin, FixReasonTarget.root,
+ source: decoratedTypeArgument,
+ destination:
+ _variables.decoratedTypeParameterBound(typeParameter),
+ hard: true);
}
- } else {
- // TODO(srawlins): Handle generic typedef. Others?
- _unimplemented(
- null, 'Extension on $extendedType (${extendedType.runtimeType}');
}
+ // (2) ensure that the receiver type is assignable to "on" type (with
+ // those decorated types substituted into it)
+ var onType = _variables.decoratedElementType(extensionElement);
+ if (substitution != null) {
+ onType = onType.substitute(substitution);
+ }
+ _checkAssignment(InferredTypeParameterInstantiationOrigin(source, node),
+ FixReasonTarget.root,
+ source: targetType,
+ destination: onType,
+ hard: targetExpression == null ||
+ _postDominatedLocals.isReferenceInScope(targetExpression));
+ // (3) substitute those decorated types into the declared type of the
+ // extension method or extension property, so that the caller will match
+ // up parameter types and the return type appropriately.
+ //
+ // There's nothing more we need to do here. The substitution below
+ // will do the job.
}
}
DecoratedType decoratedBaseType;
@@ -510,8 +563,8 @@
_dispatch(rightOperand);
return _makeNullableDynamicType(node);
} else {
- var calleeType =
- getOrComputeElementType(callee, targetType: targetType);
+ var calleeType = getOrComputeElementType(node, callee,
+ targetType: targetType, targetExpression: leftOperand);
assert(calleeType.positionalParameters.isNotEmpty); // TODO(paulberry)
_handleAssignment(rightOperand,
destinationType: calleeType.positionalParameters[0]);
@@ -727,7 +780,8 @@
ConstructorFieldInitializer node) {
_fieldsNotInitializedByConstructor.remove(node.fieldName.staticElement);
_handleAssignment(node.expression,
- destinationType: getOrComputeElementType(node.fieldName.staticElement));
+ destinationType:
+ getOrComputeElementType(node, node.fieldName.staticElement));
return null;
}
@@ -756,12 +810,13 @@
// be reached.
_requiredHintedParameters.add(node.declaredElement);
} else {
- _graph.makeNullable(getOrComputeElementType(node.declaredElement).node,
+ _graph.makeNullable(
+ getOrComputeElementType(node, node.declaredElement).node,
OptionalFormalParameterOrigin(source, node));
}
} else {
_handleAssignment(defaultValue,
- destinationType: getOrComputeElementType(node.declaredElement),
+ destinationType: getOrComputeElementType(node, node.declaredElement),
fromDefaultValue: true);
}
return null;
@@ -1077,7 +1132,8 @@
// so that we don't unnecessarily propagate nullabilities everywhere?
result = _makeNullableDynamicType(node);
} else {
- var calleeType = getOrComputeElementType(callee, targetType: targetType);
+ var calleeType = getOrComputeElementType(node, callee,
+ targetType: targetType, targetExpression: target);
// TODO(paulberry): substitute if necessary
_handleAssignment(node.index,
destinationType: calleeType.positionalParameters[0]);
@@ -1142,7 +1198,8 @@
nullabilityNode, InstanceCreationOrigin(source, node));
var createdType = DecoratedType(node.staticType, nullabilityNode,
typeArguments: decoratedTypeArguments);
- var calleeType = getOrComputeElementType(callee, targetType: createdType);
+ var calleeType =
+ getOrComputeElementType(node, callee, targetType: createdType);
for (var i = 0; i < decoratedTypeArguments.length; ++i) {
_checkAssignment(parameterEdgeOrigins?.elementAt(i),
FixReasonTarget.root.typeArgument(i),
@@ -1281,7 +1338,8 @@
// type of `X`.
calleeType = targetType;
} else if (callee != null) {
- calleeType = getOrComputeElementType(callee, targetType: targetType);
+ calleeType = getOrComputeElementType(node, callee,
+ targetType: targetType, targetExpression: target);
if (callee is PropertyAccessorElement) {
calleeType = calleeType.returnType;
}
@@ -1380,8 +1438,8 @@
// so that we don't unnecessarily propagate nullabilities everywhere?
writeType = _makeNullableDynamicType(node);
} else {
- var calleeType =
- getOrComputeElementType(callee, targetType: targetType);
+ var calleeType = getOrComputeElementType(node, callee,
+ targetType: targetType, targetExpression: operand);
writeType = _fixNumericTypes(calleeType.returnType, node.staticType);
}
if (operand is SimpleIdentifier) {
@@ -1425,8 +1483,8 @@
// so that we don't unnecessarily propagate nullabilities everywhere?
staticType = _makeNullableDynamicType(node);
} else {
- var calleeType =
- getOrComputeElementType(callee, targetType: targetType);
+ var calleeType = getOrComputeElementType(node, callee,
+ targetType: targetType, targetExpression: operand);
if (isIncrementOrDecrement) {
staticType = _fixNumericTypes(calleeType.returnType, node.staticType);
} else {
@@ -1585,7 +1643,7 @@
var promotedType = _flowAnalysis.variableRead(node, staticElement);
if (promotedType != null) return promotedType;
}
- var type = getOrComputeElementType(staticElement);
+ var type = getOrComputeElementType(node, staticElement);
if (!node.inDeclarationContext() &&
node.inGetterContext() &&
!_lateHintedLocals.contains(staticElement) &&
@@ -1600,13 +1658,14 @@
if (staticElement.enclosingElement is ClassElement) {
targetType = _thisOrSuper(node);
}
- result = getOrComputeElementType(staticElement, targetType: targetType);
+ result =
+ getOrComputeElementType(node, staticElement, targetType: targetType);
} else if (staticElement is PropertyAccessorElement) {
if (staticElement.enclosingElement is ClassElement) {
targetType = _thisOrSuper(node);
}
var elementType =
- getOrComputeElementType(staticElement, targetType: targetType);
+ getOrComputeElementType(node, staticElement, targetType: targetType);
result = staticElement.isGetter
? elementType.returnType
: elementType.positionalParameters[0];
@@ -1619,7 +1678,7 @@
result = _makeNullableVoidType(node);
} else if (staticElement.enclosingElement is ClassElement &&
(staticElement.enclosingElement as ClassElement).isEnum) {
- result = getOrComputeElementType(staticElement);
+ result = getOrComputeElementType(node, staticElement);
} else {
// TODO(paulberry)
_unimplemented(node,
@@ -1694,7 +1753,8 @@
}
var createdType = DecoratedType(callee.returnType, nullabilityNode,
typeArguments: typeArguments);
- var calleeType = getOrComputeElementType(callee, targetType: createdType);
+ var calleeType =
+ getOrComputeElementType(node, callee, targetType: createdType);
var constructorTypeParameters = callee.enclosingElement.typeParameters;
_handleInvocationArguments(
@@ -2315,7 +2375,8 @@
}
if (destinationLocalVariable != null) {
_dispatch(destinationExpression);
- destinationType = getOrComputeElementType(destinationLocalVariable);
+ destinationType = getOrComputeElementType(
+ destinationExpression, destinationLocalVariable);
} else {
destinationType = _dispatch(destinationExpression);
}
@@ -2349,8 +2410,9 @@
hard: _postDominatedLocals
.isReferenceInScope(assignmentExpression.leftHandSide));
DecoratedType compoundOperatorType = getOrComputeElementType(
- compoundOperatorMethod,
- targetType: destinationType);
+ compoundOperatorInfo, compoundOperatorMethod,
+ targetType: destinationType,
+ targetExpression: compoundOperatorInfo.leftHandSide);
assert(compoundOperatorType.positionalParameters.isNotEmpty);
_checkAssignment(edgeOrigin, FixReasonTarget.root,
source: sourceType,
@@ -2997,7 +3059,8 @@
nullabilityNode, CallTearOffOrigin(source, node));
calleeType = targetType.withNode(nullabilityNode);
} else if (callee != null) {
- calleeType = getOrComputeElementType(callee, targetType: targetType);
+ calleeType = getOrComputeElementType(node, callee,
+ targetType: targetType, targetExpression: target);
}
if (calleeType == null) {
// Dynamic dispatch.
@@ -3051,10 +3114,10 @@
} else if ((callee is MethodElement || callee is PropertyAccessorElement) &&
callee.enclosingElement is ExtensionElement) {
// Extension methods can be called on a `null` target, when the `on` type
- // of the extension is nullable.
- return _handleAssignment(target,
- destinationType:
- _variables.decoratedElementType(callee.enclosingElement));
+ // of the extension is nullable. Note: we don't need to check whether the
+ // target type is assignable to the extended type; that is done in
+ // [getOrComputeElementType].
+ return _dispatch(target);
} else {
return _checkExpressionNotNull(target);
}
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index f4d8542..c069791 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -2138,6 +2138,37 @@
await _checkSingleFileChanges(content, expected, removeViaComments: true);
}
+ Future<void> test_extension_complex() async {
+ var content = '''
+import 'already_migrated.dart';
+class D<V> extends C<V> {}
+abstract class Foo {
+ D<List<int>> get z;
+ List<int> test() => z.x ?? [];
+}
+''';
+ var alreadyMigrated = '''
+// @dart=2.12
+extension E<T> on C<T> {
+ T? get x => y;
+}
+class C<U> {
+ U? y;
+}
+''';
+ var expected = '''
+import 'already_migrated.dart';
+class D<V> extends C<V> {}
+abstract class Foo {
+ D<List<int>> get z;
+ List<int> test() => z.x ?? [];
+}
+''';
+ await _checkSingleFileChanges(content, expected, migratedInput: {
+ '$projectPath/lib/already_migrated.dart': alreadyMigrated
+ });
+ }
+
Future<void> test_extension_extended_type_nullability_intent() async {
var content = '''
extension E on C {
@@ -2183,7 +2214,7 @@
await _checkSingleFileChanges(content, expected);
}
- Future<void> test_extension_null_check_non_nullable() async {
+ Future<void> test_extension_null_check_non_nullable_method() async {
var content = '''
class C {}
extension E on C/*!*/ {
@@ -2211,6 +2242,90 @@
await _checkSingleFileChanges(content, expected);
}
+ Future<void> test_extension_null_check_non_nullable_binary() async {
+ var content = '''
+class C {}
+extension E on C/*!*/ {
+ void operator+(int other) {}
+}
+void f(C c, bool b) {
+ if (b) {
+ c + 0;
+ }
+}
+void g() => f(null, false);
+''';
+ var expected = '''
+class C {}
+extension E on C {
+ void operator+(int other) {}
+}
+void f(C? c, bool b) {
+ if (b) {
+ c! + 0;
+ }
+}
+void g() => f(null, false);
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
+ Future<void> test_extension_null_check_non_nullable_prefix() async {
+ var content = '''
+class C {}
+extension E on C/*!*/ {
+ void operator-() {}
+}
+void f(C c, bool b) {
+ if (b) {
+ -c;
+ }
+}
+void g() => f(null, false);
+''';
+ var expected = '''
+class C {}
+extension E on C {
+ void operator-() {}
+}
+void f(C? c, bool b) {
+ if (b) {
+ -c!;
+ }
+}
+void g() => f(null, false);
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
+ Future<void> test_extension_null_check_non_nullable_index() async {
+ var content = '''
+class C {}
+extension E on C/*!*/ {
+ void operator[](int index) {}
+}
+void f(C c, bool b) {
+ if (b) {
+ c[0];
+ }
+}
+void g() => f(null, false);
+''';
+ var expected = '''
+class C {}
+extension E on C {
+ void operator[](int index) {}
+}
+void f(C? c, bool b) {
+ if (b) {
+ c![0];
+ }
+}
+void g() => f(null, false);
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
Future<void> test_extension_null_check_non_nullable_generic() async {
var content = '''
class C {}
@@ -2480,6 +2595,25 @@
await _checkSingleFileChanges(content, expected);
}
+ Future<void> test_extension_on_type_substitution() async {
+ var content = '''
+extension E<T> on T {
+ T get foo => this;
+}
+List<int> f(List<int/*?*/> x) => x.foo;
+''';
+ // To see that the return type of `f` must be `List<int?`, the migration
+ // tool needs to substitute the actual type argument (`T=List<int?>`) into
+ // the extension's "on" type.
+ var expected = '''
+extension E<T> on T {
+ T get foo => this;
+}
+List<int?> f(List<int?> x) => x.foo;
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
Future<void> test_extension_override() async {
var content = '''
extension E on int {
@@ -2544,6 +2678,38 @@
await _checkSingleFileChanges(content, expected);
}
+ Future<void> test_extension_use_can_imply_non_null_intent() async {
+ var content = '''
+extension E<T extends Object/*!*/> on T/*!*/ {
+ void foo() {}
+}
+f(int i) {
+ i.foo();
+}
+g(bool b, int/*?*/ j) {
+ if (b) {
+ f(j);
+ }
+}
+''';
+ // Since the extension declaration says `T extends Object/*!*/`, `i` will
+ // not be made nullable.
+ var expected = '''
+extension E<T extends Object> on T {
+ void foo() {}
+}
+f(int i) {
+ i.foo();
+}
+g(bool b, int? j) {
+ if (b) {
+ f(j!);
+ }
+}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
Future<void> test_field_final_uninitalized_used() async {
var content = '''
class C {
diff --git a/tools/VERSION b/tools/VERSION
index ce86f3f..7c0b250 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 5
+PRERELEASE 6
PRERELEASE_PATCH 0
\ No newline at end of file