Version 2.17.0-229.0.dev
Merge commit '435ebeb5a717dfeeba26b3307c220ace2f62d860' into 'dev'
diff --git a/DEPS b/DEPS
index eec5920..5cc60b6 100644
--- a/DEPS
+++ b/DEPS
@@ -601,7 +601,7 @@
"packages": [
{
"package": "fuchsia/sdk/gn/mac-amd64",
- "version": "git_revision:190502a955c482431c2edd0525e128423728b662"
+ "version": "git_revision:c9bdf5da65647923cb79c391824434125cb00bbe"
}
],
"condition": 'host_os == "mac" and host_cpu == "x64"',
@@ -611,7 +611,7 @@
"packages": [
{
"package": "fuchsia/sdk/gn/linux-amd64",
- "version": "git_revision:190502a955c482431c2edd0525e128423728b662"
+ "version": "git_revision:c9bdf5da65647923cb79c391824434125cb00bbe"
}
],
"condition": 'host_os == "linux" and host_cpu == "x64"',
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart
index 3037258..f178c40 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart
@@ -77,10 +77,19 @@
///
/// The [inferOmittedType] argument is used to get the inferred type for a
/// given [OmittedTypeAnnotation].
+ ///
+ /// If [omittedTypes] is provided, [inferOmittedType] is allowed to return
+ /// `null` for types that have not yet been inferred. In this case a fresh
+ /// name will be used for the omitted type in the generated library code and
+ /// the omitted type will be mapped to the fresh name in [omittedTypes].
+ ///
+ /// The generated library files content must be deterministic, including the
+ /// generation of fresh names for import prefixes and omitted types.
String buildAugmentationLibrary(
Iterable<MacroExecutionResult> macroResults,
ResolvedIdentifier Function(Identifier) resolveIdentifier,
- TypeAnnotation Function(OmittedTypeAnnotation) inferOmittedType);
+ TypeAnnotation? Function(OmittedTypeAnnotation) inferOmittedType,
+ {Map<OmittedTypeAnnotation, String>? omittedTypes});
/// Tell the executor to shut down and clean up any resources it may have
/// allocated.
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor/augmentation_library.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor/augmentation_library.dart
index a795bc6..0ecb10f 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor/augmentation_library.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor/augmentation_library.dart
@@ -12,49 +12,82 @@
String buildAugmentationLibrary(
Iterable<MacroExecutionResult> macroResults,
ResolvedIdentifier Function(Identifier) resolveIdentifier,
- TypeAnnotation Function(OmittedTypeAnnotation) typeInferrer) {
- StringBuffer importsBuffer = new StringBuffer();
- StringBuffer directivesBuffer = new StringBuffer();
- Map<Uri, String> importPrefixes = {};
- int nextPrefix = 0;
+ TypeAnnotation? Function(OmittedTypeAnnotation) typeInferrer,
+ {Map<OmittedTypeAnnotation, String>? omittedTypes}) {
+ Map<Uri, _SynthesizedNamePart> importNames = {};
+ Map<OmittedTypeAnnotation, _SynthesizedNamePart> typeNames = {};
+ List<_Part> importParts = [];
+ List<_Part> directivesParts = [];
+ List<_StringPart> stringParts = [];
+ StringBuffer directivesStringPartBuffer = new StringBuffer();
+
+ void flushStringParts() {
+ if (directivesStringPartBuffer.isNotEmpty) {
+ _StringPart stringPart =
+ new _StringPart(directivesStringPartBuffer.toString());
+ directivesParts.add(stringPart);
+ stringParts.add(stringPart);
+ directivesStringPartBuffer = new StringBuffer();
+ }
+ }
// Keeps track of the last part written in `lastDirectivePart`.
String lastDirectivePart = '';
- void writeDirectivePart(String part) {
+ void writeDirectiveStringPart(String part) {
lastDirectivePart = part;
- directivesBuffer.write(part);
+ directivesStringPartBuffer.write(part);
+ }
+
+ void writeDirectiveSynthesizedNamePart(_SynthesizedNamePart part) {
+ flushStringParts();
+ lastDirectivePart = '';
+ directivesParts.add(part);
}
void buildCode(Code code) {
for (Object part in code.parts) {
if (part is String) {
- writeDirectivePart(part);
+ writeDirectiveStringPart(part);
} else if (part is Code) {
buildCode(part);
} else if (part is Identifier) {
ResolvedIdentifier resolved = resolveIdentifier(part);
- String? prefix;
+ _SynthesizedNamePart? prefix;
if (resolved.uri != null) {
- prefix = importPrefixes.putIfAbsent(resolved.uri!, () {
- String prefix = 'i${nextPrefix++}';
- importsBuffer.writeln("import '${resolved.uri}' as $prefix;");
+ prefix = importNames.putIfAbsent(resolved.uri!, () {
+ _SynthesizedNamePart prefix = new _SynthesizedNamePart();
+ importParts.add(new _StringPart("import '${resolved.uri}' as "));
+ importParts.add(prefix);
+ importParts.add(new _StringPart(";\n"));
return prefix;
});
}
if (resolved.kind == IdentifierKind.instanceMember) {
// Qualify with `this.` if we don't have a receiver.
if (!lastDirectivePart.trimRight().endsWith('.')) {
- writeDirectivePart('this.');
+ writeDirectiveStringPart('this.');
}
} else if (prefix != null) {
- writeDirectivePart('${prefix}.');
+ writeDirectiveSynthesizedNamePart(prefix);
+ writeDirectiveStringPart('.');
}
if (resolved.kind == IdentifierKind.staticInstanceMember) {
- writeDirectivePart('${resolved.staticScope!}.');
+ writeDirectiveStringPart('${resolved.staticScope!}.');
}
- writeDirectivePart('${part.name}');
+ writeDirectiveStringPart('${part.name}');
} else if (part is OmittedTypeAnnotation) {
- buildCode(typeInferrer(part).code);
+ TypeAnnotation? type = typeInferrer(part);
+ if (type == null) {
+ if (omittedTypes != null) {
+ _SynthesizedNamePart name =
+ typeNames.putIfAbsent(part, () => new _SynthesizedNamePart());
+ writeDirectiveSynthesizedNamePart(name);
+ } else {
+ throw new ArgumentError("No type inferred for $part");
+ }
+ } else {
+ buildCode(type.code);
+ }
} else {
throw new ArgumentError(
'Code objects only support String, Identifier, and Code '
@@ -67,7 +100,7 @@
for (MacroExecutionResult result in macroResults) {
for (DeclarationCode augmentation in result.libraryAugmentations) {
buildCode(augmentation);
- directivesBuffer.writeln();
+ writeDirectiveStringPart('\n');
}
for (MapEntry<String, Iterable<DeclarationCode>> entry
in result.classAugmentations.entries) {
@@ -78,13 +111,79 @@
}
for (MapEntry<String, List<DeclarationCode>> entry
in mergedClassResults.entries) {
- directivesBuffer.writeln('augment class ${entry.key} {');
+ writeDirectiveStringPart('augment class ${entry.key} {\n');
for (DeclarationCode augmentation in entry.value) {
buildCode(augmentation);
- directivesBuffer.writeln();
+ writeDirectiveStringPart('\n');
}
- directivesBuffer.writeln('}');
+ writeDirectiveStringPart('}\n');
}
- return '$importsBuffer\n\n$directivesBuffer';
+ flushStringParts();
+
+ if (importNames.isNotEmpty) {
+ String prefix = _computeFreshPrefix(stringParts, 'prefix');
+ int index = 0;
+ for (_SynthesizedNamePart part in importNames.values) {
+ part.text = '$prefix${index++}';
+ }
+ }
+ if (omittedTypes != null && typeNames.isNotEmpty) {
+ String prefix = _computeFreshPrefix(stringParts, 'OmittedType');
+ int index = 0;
+ typeNames.forEach(
+ (OmittedTypeAnnotation omittedType, _SynthesizedNamePart part) {
+ String name = '$prefix${index++}';
+ part.text = name;
+ omittedTypes[omittedType] = name;
+ });
+ }
+
+ StringBuffer sb = new StringBuffer();
+ for (_Part part in importParts) {
+ sb.write(part.text);
+ }
+ sb.write('\n');
+ for (_Part part in directivesParts) {
+ sb.write(part.text);
+ }
+
+ return sb.toString();
}
}
+
+abstract class _Part {
+ String get text;
+}
+
+class _SynthesizedNamePart implements _Part {
+ late String text;
+}
+
+class _StringPart implements _Part {
+ final String text;
+
+ _StringPart(this.text);
+}
+
+/// Computes a name starting with [name] that is unique with respect to the
+/// text in [stringParts].
+///
+/// This algorithm assumes that no two parts in [stringParts] occur in direct
+/// sequence where they are used, i.e. there is always at least one
+/// [_SynthesizedNamePart] between them.
+String _computeFreshPrefix(List<_StringPart> stringParts, String name) {
+ int index = -1;
+ String prefix = name;
+ for (_StringPart part in stringParts) {
+ while (part.text.contains(prefix)) {
+ index++;
+ prefix = '$name$index';
+ }
+ }
+ if (index > 0) {
+ // Add a separator when an index was needed. This is to ensure that
+ // suffixing number to [prefix] doesn't blend the digits.
+ prefix = '${prefix}_';
+ }
+ return prefix;
+}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor/executor_base.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor/executor_base.dart
index bbcea72..5609883 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor/executor_base.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor/executor_base.dart
@@ -316,7 +316,8 @@
String buildAugmentationLibrary(
Iterable<MacroExecutionResult> macroResults,
ResolvedIdentifier Function(Identifier) resolveIdentifier,
- TypeAnnotation Function(OmittedTypeAnnotation) inferOmittedType) =>
+ TypeAnnotation? Function(OmittedTypeAnnotation) inferOmittedType,
+ {Map<OmittedTypeAnnotation, String>? omittedTypes}) =>
throw new StateError('Unreachable');
@override
diff --git a/pkg/_fe_analyzer_shared/test/macros/executor/augmentation_library_test.dart b/pkg/_fe_analyzer_shared/test/macros/executor/augmentation_library_test.dart
index 78d960a..cc99e93 100644
--- a/pkg/_fe_analyzer_shared/test/macros/executor/augmentation_library_test.dart
+++ b/pkg/_fe_analyzer_shared/test/macros/executor/augmentation_library_test.dart
@@ -48,37 +48,37 @@
(OmittedTypeAnnotation i) =>
(i as TestOmittedTypeAnnotation).inferredType);
expect(library, equalsIgnoringWhitespace('''
- import 'dart:core' as i0;
+ import 'dart:core' as prefix0;
- i0.int get i0j0 => 0;
- i0.int get i0j1 => 1;
- i0.int get i0j2 => 2;
- i0.int get i1j0 => 1;
- i0.int get i1j1 => 2;
- i0.int get i1j2 => 3;
+ prefix0.int get i0j0 => 0;
+ prefix0.int get i0j1 => 1;
+ prefix0.int get i0j2 => 2;
+ prefix0.int get i1j0 => 1;
+ prefix0.int get i1j1 => 2;
+ prefix0.int get i1j2 => 3;
augment class Foo00 {
- i0.int get i => 0;
- i0.int get j => 0;
+ prefix0.int get i => 0;
+ prefix0.int get j => 0;
}
augment class Foo01 {
- i0.int get i => 0;
- i0.int get j => 1;
+ prefix0.int get i => 0;
+ prefix0.int get j => 1;
}
augment class Foo02 {
- i0.int get i => 0;
- i0.int get j => 2;
+ prefix0.int get i => 0;
+ prefix0.int get j => 2;
}
augment class Foo10 {
- i0.int get i => 1;
- i0.int get j => 0;
+ prefix0.int get i => 1;
+ prefix0.int get j => 0;
}
augment class Foo11 {
- i0.int get i => 1;
- i0.int get j => 1;
+ prefix0.int get i => 1;
+ prefix0.int get j => 1;
}
augment class Foo12 {
- i0.int get i => 1;
- i0.int get j => 2;
+ prefix0.int get i => 1;
+ prefix0.int get j => 2;
}
'''));
});
@@ -151,15 +151,15 @@
(OmittedTypeAnnotation i) =>
(i as TestOmittedTypeAnnotation).inferredType);
expect(library, equalsIgnoringWhitespace('''
- import 'package:foo/foo.dart' as i0;
- import 'package:builder/builder.dart' as i1;
- import 'package:bar/bar.dart' as i2;
- import 'dart:core' as i3;
+ import 'package:foo/foo.dart' as prefix0;
+ import 'package:builder/builder.dart' as prefix1;
+ import 'package:bar/bar.dart' as prefix2;
+ import 'dart:core' as prefix3;
- class FooBuilder<T extends i0.Foo> implements i1.Builder<i2.Bar<T>> {
- late i3.int baz;
+ class FooBuilder<T extends prefix0.Foo> implements prefix1.Builder<prefix2.Bar<T>> {
+ late prefix3.int baz;
- i2.Bar<T> build() => new i2.Bar()..baz = i2.Bar.zap;
+ prefix2.Bar<T> build() => new prefix2.Bar()..baz = prefix2.Bar.zap;
}
'''));
});
@@ -185,11 +185,102 @@
(OmittedTypeAnnotation i) =>
(i as TestOmittedTypeAnnotation).inferredType);
expect(library, equalsIgnoringWhitespace('''
- import 'dart:core' as i0;
+ import 'dart:core' as prefix0;
- i0.int x = 1;
+ prefix0.int x = 1;
'''));
});
+
+ test('can handle name conflicts', () {
+ var omittedType0 = TestOmittedTypeAnnotation();
+ var omittedType1 = TestOmittedTypeAnnotation();
+
+ var omittedTypeIdentifier = TestIdentifier(
+ id: RemoteInstance.uniqueId,
+ name: 'OmittedType',
+ kind: IdentifierKind.topLevelMember,
+ staticScope: null,
+ uri: Uri.parse('package:foo/foo.dart'));
+ var omittedTypeIdentifier0 = TestIdentifier(
+ id: RemoteInstance.uniqueId,
+ name: 'OmittedType0',
+ kind: IdentifierKind.topLevelMember,
+ staticScope: null,
+ uri: Uri.parse('package:bar/bar.dart'));
+ var prefixInstanceMember = TestIdentifier(
+ id: RemoteInstance.uniqueId,
+ name: 'prefix',
+ kind: IdentifierKind.instanceMember,
+ staticScope: null,
+ uri: Uri.parse('package:bar/bar.dart'));
+ var prefix0InstanceMember = TestIdentifier(
+ id: RemoteInstance.uniqueId,
+ name: 'prefix0',
+ kind: IdentifierKind.instanceMember,
+ staticScope: null,
+ uri: Uri.parse('package:bar/bar.dart'));
+ var prefix1StaticMember = TestIdentifier(
+ id: RemoteInstance.uniqueId,
+ name: 'prefix1',
+ kind: IdentifierKind.staticInstanceMember,
+ staticScope: 'OmittedType1',
+ uri: Uri.parse('package:bar/bar.dart'));
+ var results = [
+ MacroExecutionResultImpl(
+ classAugmentations: {},
+ libraryAugmentations: [
+ DeclarationCode.fromParts([
+ 'class OmittedType {\n ',
+ omittedType0.code,
+ ' method(',
+ omittedType1.code,
+ ' o) {\n ',
+ intIdentifier,
+ ' ${prefixInstanceMember.name} = 0;\n ',
+ omittedTypeIdentifier,
+ ' ${prefix0InstanceMember.name} = ',
+ 'new ',
+ omittedTypeIdentifier,
+ '();\n ',
+ 'new ',
+ omittedTypeIdentifier0,
+ '()..',
+ prefixInstanceMember,
+ ' = ',
+ prefix1StaticMember,
+ ';',
+ '\n }',
+ '\n}',
+ ]),
+ ],
+ newTypeNames: [
+ 'OmittedType',
+ ],
+ )
+ ];
+ var omittedTypes = <OmittedTypeAnnotation, String>{};
+ var library = _TestExecutor().buildAugmentationLibrary(
+ results,
+ (Identifier i) => (i as TestIdentifier).resolved,
+ (OmittedTypeAnnotation i) =>
+ (i as TestOmittedTypeAnnotation).inferredType,
+ omittedTypes: omittedTypes);
+ expect(library, equalsIgnoringWhitespace('''
+ import 'dart:core' as prefix2_0;
+ import 'package:foo/foo.dart' as prefix2_1;
+ import 'package:bar/bar.dart' as prefix2_2;
+
+ class OmittedType {
+ OmittedType2_0 method(OmittedType2_1 o) {
+ prefix2_0.int prefix = 0;
+ prefix2_1.OmittedType prefix0 = new prefix2_1.OmittedType();
+ new prefix2_2.OmittedType0()..prefix = prefix2_2.OmittedType1.prefix1;
+ }
+ }
+ '''));
+ expect(omittedTypes[omittedType0], 'OmittedType2_0');
+ expect(omittedTypes[omittedType1], 'OmittedType2_1');
+ });
});
}
diff --git a/pkg/_fe_analyzer_shared/test/macros/util.dart b/pkg/_fe_analyzer_shared/test/macros/util.dart
index c1167f8..6049823 100644
--- a/pkg/_fe_analyzer_shared/test/macros/util.dart
+++ b/pkg/_fe_analyzer_shared/test/macros/util.dart
@@ -117,14 +117,14 @@
@override
Future<TypeAnnotation> inferType(
TestOmittedTypeAnnotation omittedType) async =>
- omittedType.inferredType;
+ omittedType.inferredType!;
}
/// Knows its inferred type ahead of time.
class TestOmittedTypeAnnotation extends OmittedTypeAnnotationImpl {
- final TypeAnnotation inferredType;
+ final TypeAnnotation? inferredType;
- TestOmittedTypeAnnotation(this.inferredType)
+ TestOmittedTypeAnnotation([this.inferredType])
: super(id: RemoteInstance.uniqueId);
}
@@ -155,8 +155,12 @@
} else if (part is IdentifierImpl) {
buffer.write(part.name);
} else if (part is TestOmittedTypeAnnotation) {
- buffer.write('/*inferred*/');
- part.inferredType.code.debugString(buffer);
+ if (part.inferredType != null) {
+ buffer.write('/*inferred*/');
+ part.inferredType!.code.debugString(buffer);
+ } else {
+ buffer.write('/*omitted*/');
+ }
} else {
buffer.write(part as String);
}
diff --git a/pkg/analysis_server/lib/lsp_protocol/protocol_custom_generated.dart b/pkg/analysis_server/lib/lsp_protocol/protocol_custom_generated.dart
index 7d095d7..8475456 100644
--- a/pkg/analysis_server/lib/lsp_protocol/protocol_custom_generated.dart
+++ b/pkg/analysis_server/lib/lsp_protocol/protocol_custom_generated.dart
@@ -1605,3 +1605,81 @@
@override
String toString() => jsonEncoder.convert(toJson());
}
+
+class ValidateRefactorResult implements ToJsonable {
+ static const jsonHandler = LspJsonHandler(
+ ValidateRefactorResult.canParse, ValidateRefactorResult.fromJson);
+
+ ValidateRefactorResult({required this.valid, this.message});
+ static ValidateRefactorResult fromJson(Map<String, Object?> json) {
+ final validJson = json['valid'];
+ final valid = validJson as bool;
+ final messageJson = json['message'];
+ final message = messageJson as String?;
+ return ValidateRefactorResult(valid: valid, message: message);
+ }
+
+ final String? message;
+ final bool valid;
+
+ Map<String, Object?> toJson() {
+ var __result = <String, Object?>{};
+ __result['valid'] = valid;
+ if (message != null) {
+ __result['message'] = message;
+ }
+ return __result;
+ }
+
+ static bool canParse(Object? obj, LspJsonReporter reporter) {
+ if (obj is Map<String, Object?>) {
+ reporter.push('valid');
+ try {
+ if (!obj.containsKey('valid')) {
+ reporter.reportError('must not be undefined');
+ return false;
+ }
+ final valid = obj['valid'];
+ if (valid == null) {
+ reporter.reportError('must not be null');
+ return false;
+ }
+ if (!(valid is bool)) {
+ reporter.reportError('must be of type bool');
+ return false;
+ }
+ } finally {
+ reporter.pop();
+ }
+ reporter.push('message');
+ try {
+ final message = obj['message'];
+ if (message != null && !(message is String)) {
+ reporter.reportError('must be of type String');
+ return false;
+ }
+ } finally {
+ reporter.pop();
+ }
+ return true;
+ } else {
+ reporter.reportError('must be of type ValidateRefactorResult');
+ return false;
+ }
+ }
+
+ @override
+ bool operator ==(Object other) {
+ if (other is ValidateRefactorResult &&
+ other.runtimeType == ValidateRefactorResult) {
+ return valid == other.valid && message == other.message && true;
+ }
+ return false;
+ }
+
+ @override
+ int get hashCode => Object.hash(valid, message);
+
+ @override
+ String toString() => jsonEncoder.convert(toJson());
+}
diff --git a/pkg/analysis_server/lib/src/lsp/constants.dart b/pkg/analysis_server/lib/src/lsp/constants.dart
index 55257c6..cb2da70 100644
--- a/pkg/analysis_server/lib/src/lsp/constants.dart
+++ b/pkg/analysis_server/lib/src/lsp/constants.dart
@@ -67,6 +67,7 @@
static const fixAll = 'edit.fixAll';
static const sendWorkspaceEdit = 'edit.sendWorkspaceEdit';
static const performRefactor = 'refactor.perform';
+ static const validateRefactor = 'refactor.validate';
}
abstract class CustomMethods {
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/abstract_refactor.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/abstract_refactor.dart
new file mode 100644
index 0000000..cc504be
--- /dev/null
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/abstract_refactor.dart
@@ -0,0 +1,197 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
+import 'package:analysis_server/lsp_protocol/protocol_special.dart';
+import 'package:analysis_server/src/lsp/constants.dart';
+import 'package:analysis_server/src/lsp/handlers/commands/simple_edit_handler.dart';
+import 'package:analysis_server/src/lsp/handlers/handlers.dart';
+import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
+import 'package:analysis_server/src/lsp/progress.dart';
+import 'package:analysis_server/src/protocol_server.dart';
+import 'package:analysis_server/src/services/refactoring/refactoring.dart';
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
+
+final _manager = LspRefactorManager._();
+
+/// A base class for refactoring commands that need to create Refactorings from
+/// client-supplied arguments.
+abstract class AbstractRefactorCommandHandler extends SimpleEditCommandHandler {
+ AbstractRefactorCommandHandler(LspAnalysisServer server) : super(server);
+
+ @override
+ String get commandName => 'Perform Refactor';
+
+ LspRefactorManager get manager => _manager;
+
+ FutureOr<ErrorOr<void>> execute(
+ String path,
+ String kind,
+ int offset,
+ int length,
+ Map<String, Object?>? options,
+ CancellationToken cancellationToken,
+ ProgressReporter reporter,
+ int? docVersion);
+
+ Future<ErrorOr<Refactoring>> getRefactoring(
+ RefactoringKind kind,
+ ResolvedUnitResult result,
+ int offset,
+ int length,
+ Map<String, dynamic>? options,
+ ) async {
+ switch (kind) {
+ case RefactoringKind.EXTRACT_METHOD:
+ final refactor = ExtractMethodRefactoring(
+ server.searchEngine, result, offset, length);
+
+ var preferredName = options != null ? options['name'] as String : null;
+ // checkInitialConditions will populate names with suggestions.
+ if (preferredName == null) {
+ await refactor.checkInitialConditions();
+ if (refactor.names.isNotEmpty) {
+ preferredName = refactor.names.first;
+ }
+ }
+ refactor.name = preferredName ?? 'newMethod';
+
+ // Defaults to true, but may be surprising if users didn't have an option
+ // to opt in.
+ refactor.extractAll = false;
+ return success(refactor);
+
+ case RefactoringKind.EXTRACT_LOCAL_VARIABLE:
+ final refactor = ExtractLocalRefactoring(result, offset, length);
+
+ var preferredName = options != null ? options['name'] as String : null;
+ // checkInitialConditions will populate names with suggestions.
+ if (preferredName == null) {
+ await refactor.checkInitialConditions();
+ if (refactor.names.isNotEmpty) {
+ preferredName = refactor.names.first;
+ }
+ }
+ refactor.name = preferredName ?? 'newVariable';
+
+ // Defaults to true, but may be surprising if users didn't have an option
+ // to opt in.
+ refactor.extractAll = false;
+ return success(refactor);
+
+ case RefactoringKind.EXTRACT_WIDGET:
+ final refactor = ExtractWidgetRefactoring(
+ server.searchEngine, result, offset, length);
+ // Provide a default name for clients that do not have any custom
+ // handling.
+ // Clients can use the information documented for refactor.perform to
+ // inject their own user-provided names until LSP has some native
+ // support:
+ // https://github.com/microsoft/language-server-protocol/issues/764
+ refactor.name =
+ options != null ? options['name'] as String : 'NewWidget';
+ return success(refactor);
+
+ case RefactoringKind.INLINE_LOCAL_VARIABLE:
+ final refactor =
+ InlineLocalRefactoring(server.searchEngine, result, offset);
+ return success(refactor);
+
+ case RefactoringKind.INLINE_METHOD:
+ final refactor =
+ InlineMethodRefactoring(server.searchEngine, result, offset);
+ return success(refactor);
+
+ case RefactoringKind.CONVERT_GETTER_TO_METHOD:
+ final node = NodeLocator(offset).searchWithin(result.unit);
+ final element = server.getElementOfNode(node);
+ if (element != null) {
+ if (element is PropertyAccessorElement) {
+ final refactor = ConvertGetterToMethodRefactoring(
+ server.searchEngine, result.session, element);
+ return success(refactor);
+ }
+ }
+ return error(ServerErrorCodes.InvalidCommandArguments,
+ 'Location supplied to $commandName $kind is not longer valid');
+
+ case RefactoringKind.CONVERT_METHOD_TO_GETTER:
+ final node = NodeLocator(offset).searchWithin(result.unit);
+ final element = server.getElementOfNode(node);
+ if (element != null) {
+ if (element is ExecutableElement) {
+ final refactor = ConvertMethodToGetterRefactoring(
+ server.searchEngine, result.session, element);
+ return success(refactor);
+ }
+ }
+ return error(ServerErrorCodes.InvalidCommandArguments,
+ 'Location supplied to $commandName $kind is not longer valid');
+
+ default:
+ return error(ServerErrorCodes.InvalidCommandArguments,
+ 'Unknown RefactoringKind $kind was supplied to $commandName');
+ }
+ }
+
+ @override
+ Future<ErrorOr<void>> handle(List<Object?>? arguments,
+ ProgressReporter reporter, CancellationToken cancellationToken) async {
+ if (arguments == null ||
+ arguments.length != 6 ||
+ arguments[0] is! String || // kind
+ arguments[1] is! String || // path
+ (arguments[2] != null && arguments[2] is! int) || // docVersion
+ arguments[3] is! int || // offset
+ arguments[4] is! int || // length
+ // options
+ // Important: This arguments position is documented in
+ // tool/lsp_spec/README.md to allow clients with custom code (such as
+ // VS Code) to intercept the request and inject options (such as a
+ // user-provided name). Any changes to these arguments must be backwards
+ // compatible, keeping the options in this position.
+ (arguments[5] != null && arguments[5] is! Map<String, Object?>)) {
+ return ErrorOr.error(ResponseError(
+ code: ServerErrorCodes.InvalidCommandArguments,
+ message:
+ '$commandName requires 6 parameters: RefactoringKind, docVersion, filePath, offset, length, options (optional)',
+ ));
+ }
+
+ final kind = arguments[0] as String;
+ final path = arguments[1] as String;
+ final docVersion = arguments[2] as int?;
+ final offset = arguments[3] as int;
+ final length = arguments[4] as int;
+ final options = arguments[5] as Map<String, Object?>?;
+
+ return execute(path, kind, offset, length, options, cancellationToken,
+ reporter, docVersion);
+ }
+}
+
+/// Manages a running refactor to help ensure only one refactor runs at a time.
+class LspRefactorManager {
+ /// The cancellation token for the current in-progress refactor (or null).
+ CancelableToken? _currentRefactoringCancellationToken;
+
+ LspRefactorManager._();
+
+ /// Begins a new refactor, cancelling any other in-progress refactors.
+ void begin(CancelableToken cancelToken) {
+ _currentRefactoringCancellationToken?.cancel();
+ _currentRefactoringCancellationToken = cancelToken;
+ }
+
+ /// Marks a refactor as no longer current.
+ void end(CancelableToken cancelToken) {
+ if (_currentRefactoringCancellationToken == cancelToken) {
+ _currentRefactoringCancellationToken = null;
+ }
+ }
+}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
index 5523d17..3690cf5 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
@@ -2,58 +2,38 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'dart:async';
+
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/constants.dart';
-import 'package:analysis_server/src/lsp/handlers/commands/simple_edit_handler.dart';
+import 'package:analysis_server/src/lsp/handlers/commands/abstract_refactor.dart';
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
import 'package:analysis_server/src/lsp/mapping.dart';
import 'package:analysis_server/src/lsp/progress.dart';
import 'package:analysis_server/src/protocol_server.dart';
-import 'package:analysis_server/src/services/refactoring/refactoring.dart';
-import 'package:analyzer/dart/analysis/results.dart';
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/dart/ast/utilities.dart';
-final _manager = _RefactorManager();
-
-class PerformRefactorCommandHandler extends SimpleEditCommandHandler {
+class PerformRefactorCommandHandler extends AbstractRefactorCommandHandler {
PerformRefactorCommandHandler(LspAnalysisServer server) : super(server);
@override
String get commandName => 'Perform Refactor';
@override
- Future<ErrorOr<void>> handle(List<Object?>? arguments,
- ProgressReporter reporter, CancellationToken cancellationToken) async {
- if (arguments == null ||
- arguments.length != 6 ||
- arguments[0] is! String || // kind
- arguments[1] is! String || // path
- (arguments[2] != null && arguments[2] is! int) || // docVersion
- arguments[3] is! int || // offset
- arguments[4] is! int || // length
- // options
- (arguments[5] != null && arguments[5] is! Map<String, dynamic>)) {
- // length
- return ErrorOr.error(ResponseError(
- code: ServerErrorCodes.InvalidCommandArguments,
- message:
- '$commandName requires 6 parameters: RefactoringKind, docVersion, filePath, offset, length, options (optional)',
- ));
- }
-
- final kind = arguments[0] as String;
- final path = arguments[1] as String;
- final docVersion = arguments[2] as int?;
- final offset = arguments[3] as int;
- final length = arguments[4] as int;
- final options = arguments[5] as Map<String, Object?>?;
-
+ FutureOr<ErrorOr<void>> execute(
+ String path,
+ String kind,
+ int offset,
+ int length,
+ Map<String, Object?>? options,
+ CancellationToken cancellationToken,
+ ProgressReporter reporter,
+ int? docVersion,
+ ) async {
final result = await requireResolvedUnit(path);
return result.mapResult((result) async {
- final refactoring = await _getRefactoring(
+ final refactoring = await getRefactoring(
RefactoringKind(kind), result, offset, length, options);
return refactoring.mapResult((refactoring) async {
// If the token we were given is not cancellable, replace it with one that
@@ -63,7 +43,7 @@
final cancelableToken = cancellationToken is CancelableToken
? cancellationToken
: CancelableToken();
- _manager.begin(cancelableToken);
+ manager.begin(cancelableToken);
try {
reporter.begin('Refactoring…');
@@ -98,128 +78,10 @@
final edit = createWorkspaceEdit(server, change);
return await sendWorkspaceEditToClient(edit);
} finally {
- _manager.end(cancelableToken);
+ manager.end(cancelableToken);
reporter.end();
}
});
});
}
-
- Future<ErrorOr<Refactoring>> _getRefactoring(
- RefactoringKind kind,
- ResolvedUnitResult result,
- int offset,
- int length,
- Map<String, dynamic>? options,
- ) async {
- switch (kind) {
- case RefactoringKind.EXTRACT_METHOD:
- final refactor = ExtractMethodRefactoring(
- server.searchEngine, result, offset, length);
-
- var preferredName = options != null ? options['name'] as String : null;
- // checkInitialConditions will populate names with suggestions.
- if (preferredName == null) {
- await refactor.checkInitialConditions();
- if (refactor.names.isNotEmpty) {
- preferredName = refactor.names.first;
- }
- }
- refactor.name = preferredName ?? 'newMethod';
-
- // Defaults to true, but may be surprising if users didn't have an option
- // to opt in.
- refactor.extractAll = false;
- return success(refactor);
-
- case RefactoringKind.EXTRACT_LOCAL_VARIABLE:
- final refactor = ExtractLocalRefactoring(result, offset, length);
-
- var preferredName = options != null ? options['name'] as String : null;
- // checkInitialConditions will populate names with suggestions.
- if (preferredName == null) {
- await refactor.checkInitialConditions();
- if (refactor.names.isNotEmpty) {
- preferredName = refactor.names.first;
- }
- }
- refactor.name = preferredName ?? 'newVariable';
-
- // Defaults to true, but may be surprising if users didn't have an option
- // to opt in.
- refactor.extractAll = false;
- return success(refactor);
-
- case RefactoringKind.EXTRACT_WIDGET:
- final refactor = ExtractWidgetRefactoring(
- server.searchEngine, result, offset, length);
- // TODO(dantup): For now we don't have a good way to prompt the user
- // for a method name so we just use a placeholder and expect them to
- // rename (this is what C#/Omnisharp does), but there's an open request
- // to handle this better.
- // https://github.com/microsoft/language-server-protocol/issues/764
- refactor.name =
- options != null ? options['name'] as String : 'NewWidget';
- return success(refactor);
-
- case RefactoringKind.INLINE_LOCAL_VARIABLE:
- final refactor =
- InlineLocalRefactoring(server.searchEngine, result, offset);
- return success(refactor);
-
- case RefactoringKind.INLINE_METHOD:
- final refactor =
- InlineMethodRefactoring(server.searchEngine, result, offset);
- return success(refactor);
-
- case RefactoringKind.CONVERT_GETTER_TO_METHOD:
- final node = NodeLocator(offset).searchWithin(result.unit);
- final element = server.getElementOfNode(node);
- if (element != null) {
- if (element is PropertyAccessorElement) {
- final refactor = ConvertGetterToMethodRefactoring(
- server.searchEngine, result.session, element);
- return success(refactor);
- }
- }
- return error(ServerErrorCodes.InvalidCommandArguments,
- 'Location supplied to $commandName $kind is not longer valid');
-
- case RefactoringKind.CONVERT_METHOD_TO_GETTER:
- final node = NodeLocator(offset).searchWithin(result.unit);
- final element = server.getElementOfNode(node);
- if (element != null) {
- if (element is ExecutableElement) {
- final refactor = ConvertMethodToGetterRefactoring(
- server.searchEngine, result.session, element);
- return success(refactor);
- }
- }
- return error(ServerErrorCodes.InvalidCommandArguments,
- 'Location supplied to $commandName $kind is not longer valid');
-
- default:
- return error(ServerErrorCodes.InvalidCommandArguments,
- 'Unknown RefactoringKind $kind was supplied to $commandName');
- }
- }
-}
-
-/// Manages a running refactor to help ensure only one refactor runs at a time.
-class _RefactorManager {
- /// The cancellation token for the current in-progress refactor (or null).
- CancelableToken? _currentRefactoringCancellationToken;
-
- /// Begins a new refactor, cancelling any other in-progress refactors.
- void begin(CancelableToken cancelToken) {
- _currentRefactoringCancellationToken?.cancel();
- _currentRefactoringCancellationToken = cancelToken;
- }
-
- /// Marks a refactor as no longer current.
- void end(CancelableToken cancelToken) {
- if (_currentRefactoringCancellationToken == cancelToken) {
- _currentRefactoringCancellationToken = null;
- }
- }
}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/validate_refactor.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/validate_refactor.dart
new file mode 100644
index 0000000..6c54c7c
--- /dev/null
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/validate_refactor.dart
@@ -0,0 +1,75 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analysis_server/lsp_protocol/protocol_custom_generated.dart';
+import 'package:analysis_server/lsp_protocol/protocol_special.dart';
+import 'package:analysis_server/src/lsp/handlers/commands/abstract_refactor.dart';
+import 'package:analysis_server/src/lsp/handlers/handlers.dart';
+import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
+import 'package:analysis_server/src/lsp/progress.dart';
+import 'package:analysis_server/src/protocol_server.dart';
+import 'package:analyzer/dart/analysis/session.dart';
+
+class ValidateRefactorCommandHandler extends AbstractRefactorCommandHandler {
+ ValidateRefactorCommandHandler(LspAnalysisServer server) : super(server);
+
+ @override
+ String get commandName => 'Validate Refactor';
+
+ @override
+ FutureOr<ErrorOr<ValidateRefactorResult>> execute(
+ String path,
+ String kind,
+ int offset,
+ int length,
+ Map<String, Object?>? options,
+ CancellationToken cancellationToken,
+ ProgressReporter reporter,
+ int? docVersion,
+ ) async {
+ // In order to prevent clients asking users for a method/widget name and
+ // then failing because of something like "Cannot extract closure as method"
+ // this command allows the client to call `checkInitialConditions()` after
+ // the user selects the action but before prompting for a name.
+ //
+ // We do not perform that check when building the code actions because there
+ // will be no visibility of the reason why the refactor is not available to
+ // the user.
+
+ final result = await requireResolvedUnit(path);
+ return result.mapResult((result) async {
+ final refactoring = await getRefactoring(
+ RefactoringKind(kind), result, offset, length, options);
+ return refactoring.mapResult((refactoring) async {
+ // If the token we were given is not cancellable, replace it with one that
+ // is for the rest of this request, as a future refactor may need to cancel
+ // this request.
+ // The original token should be kept and also checked for cancellation.
+ final cancelableToken = cancellationToken is CancelableToken
+ ? cancellationToken
+ : CancelableToken();
+ manager.begin(cancelableToken);
+
+ try {
+ reporter.begin('Preparing Refactor…');
+ final status = await refactoring.checkInitialConditions();
+
+ if (status.hasError) {
+ return success(
+ ValidateRefactorResult(valid: false, message: status.message!));
+ }
+
+ return success(ValidateRefactorResult(valid: true));
+ } on InconsistentAnalysisException {
+ return failure(fileModifiedError);
+ } finally {
+ manager.end(cancelableToken);
+ reporter.end();
+ }
+ });
+ });
+ }
+}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_execute_command.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_execute_command.dart
index 02c8a93..cdc6fa5 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_execute_command.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_execute_command.dart
@@ -10,6 +10,7 @@
import 'package:analysis_server/src/lsp/handlers/commands/perform_refactor.dart';
import 'package:analysis_server/src/lsp/handlers/commands/send_workspace_edit.dart';
import 'package:analysis_server/src/lsp/handlers/commands/sort_members.dart';
+import 'package:analysis_server/src/lsp/handlers/commands/validate_refactor.dart';
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
import 'package:analysis_server/src/lsp/progress.dart';
@@ -25,6 +26,7 @@
Commands.organizeImports: OrganizeImportsCommandHandler(server),
Commands.fixAll: FixAllCommandHandler(server),
Commands.performRefactor: PerformRefactorCommandHandler(server),
+ Commands.validateRefactor: ValidateRefactorCommandHandler(server),
Commands.sendWorkspaceEdit: SendWorkspaceEditCommandHandler(server),
},
super(server);
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_super_parameters.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_super_parameters.dart
index 5f7e010..ac0df68 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_super_parameters.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_super_parameters.dart
@@ -77,6 +77,7 @@
var parameter = _parameterFor(parameterMap, argument.expression);
if (parameter != null &&
parameter.isNamed &&
+ parameter.element.name == argument.name.label.name &&
!referencedParameters.contains(parameter.element)) {
var data = _dataForParameter(
parameter,
diff --git a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
index ac78b0d..10690ba 100644
--- a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
@@ -4,6 +4,7 @@
import 'dart:async';
+import 'package:analysis_server/lsp_protocol/protocol_custom_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/src/lsp/constants.dart';
import 'package:analysis_server/src/lsp/json_parsing.dart';
@@ -433,6 +434,82 @@
await verifyCodeActionEdits(
codeAction, withoutMarkers(content), expectedContent);
}
+
+ Future<void> test_validLocation_failsInitialValidation() async {
+ const content = '''
+f() {
+ var a = 0;
+ doFoo([[() => print(a)]]);
+ print(a);
+}
+
+void doFoo(void Function() a) => a();
+
+ ''';
+ newFile2(mainFilePath, withoutMarkers(content));
+ await initialize();
+
+ final codeActions = await getCodeActions(mainFileUri.toString(),
+ range: rangeFromMarkers(content));
+ final codeAction =
+ findCommand(codeActions, Commands.performRefactor, extractMethodTitle)!;
+
+ final command = codeAction.map(
+ (command) => command,
+ (codeAction) => codeAction.command!,
+ );
+
+ // Call the `refactor.validate` command with the same arguments.
+ // Clients that want validation behaviour will need to implement this
+ // themselves (via middleware).
+ final response = await executeCommand(
+ Command(
+ title: command.title,
+ command: Commands.validateRefactor,
+ arguments: command.arguments),
+ decoder: ValidateRefactorResult.fromJson,
+ );
+
+ expect(response.valid, isFalse);
+ expect(response.message, contains('Cannot extract closure as method'));
+ }
+
+ Future<void> test_validLocation_passesInitialValidation() async {
+ const content = '''
+f() {
+ doFoo([[() => print(1)]]);
+}
+
+void doFoo(void Function() a) => a();
+
+ ''';
+ newFile2(mainFilePath, withoutMarkers(content));
+ await initialize();
+
+ final codeActions = await getCodeActions(mainFileUri.toString(),
+ range: rangeFromMarkers(content));
+ final codeAction =
+ findCommand(codeActions, Commands.performRefactor, extractMethodTitle)!;
+
+ final command = codeAction.map(
+ (command) => command,
+ (codeAction) => codeAction.command!,
+ );
+
+ // Call the `Commands.validateRefactor` command with the same arguments.
+ // Clients that want validation behaviour will need to implement this
+ // themselves (via middleware).
+ final response = await executeCommand(
+ Command(
+ title: command.title,
+ command: Commands.validateRefactor,
+ arguments: command.arguments),
+ decoder: ValidateRefactorResult.fromJson,
+ );
+
+ expect(response.valid, isTrue);
+ expect(response.message, isNull);
+ }
}
@reflectiveTest
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index fbfbeb1..c74663d 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -868,8 +868,11 @@
return executeCommand(command);
}
- Future<Object?> executeCommand(Command command,
- {Either2<int, String>? workDoneToken}) async {
+ Future<T> executeCommand<T>(
+ Command command, {
+ T Function(Map<String, Object?>)? decoder,
+ Either2<int, String>? workDoneToken,
+ }) async {
final request = makeRequest(
Method.workspace_executeCommand,
ExecuteCommandParams(
@@ -878,7 +881,8 @@
workDoneToken: workDoneToken,
),
);
- return expectSuccessfulResponseTo(request, (result) => result);
+ return expectSuccessfulResponseTo<T, Map<String, Object?>>(
+ request, decoder ?? (result) => result as T);
}
void expect(Object? actual, Matcher matcher, {String? reason}) =>
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_super_parameters_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_super_parameters_test.dart
index b8517d5..1b070d0 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_super_parameters_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_super_parameters_test.dart
@@ -281,6 +281,25 @@
''');
}
+ Future<void> test_named_oneWithNameChange() async {
+ await resolveTestCode('''
+class A {
+ A({int? x, int? y});
+}
+class B extends A {
+ B({int? x, int? z}) : super(x: x, y: z);
+}
+''');
+ await assertHasFix('''
+class A {
+ A({int? x, int? y});
+}
+class B extends A {
+ B({super.x, int? z}) : super(y: z);
+}
+''');
+ }
+
Future<void> test_named_only() async {
await resolveTestCode('''
class A {
diff --git a/pkg/analysis_server/tool/lsp_spec/generate_all.dart b/pkg/analysis_server/tool/lsp_spec/generate_all.dart
index 58a60e2..f050549 100644
--- a/pkg/analysis_server/tool/lsp_spec/generate_all.dart
+++ b/pkg/analysis_server/tool/lsp_spec/generate_all.dart
@@ -286,6 +286,14 @@
],
baseType: 'TextEdit',
),
+ // Return type for refactor.validate command.
+ interface(
+ 'ValidateRefactorResult',
+ [
+ field('valid', type: 'boolean'),
+ field('message', type: 'string', canBeUndefined: true),
+ ],
+ ),
TypeAlias(
null,
Token.identifier('TextDocumentEditEdits'),
diff --git a/pkg/analyzer/lib/dart/analysis/analysis_context.dart b/pkg/analyzer/lib/dart/analysis/analysis_context.dart
index 2a49b01..4003c68 100644
--- a/pkg/analyzer/lib/dart/analysis/analysis_context.dart
+++ b/pkg/analyzer/lib/dart/analysis/analysis_context.dart
@@ -53,5 +53,14 @@
/// The file is expected to be a Dart file, reporting non-Dart files, such
/// as configuration files `analysis_options.yaml`, `package_config.json`,
/// etc will not re-create analysis contexts.
+ ///
+ /// This will invalidate any previously returned [AnalysisSession], to
+ /// get a new analysis session apply pending file changes:
+ /// ```dart
+ /// analysisContext.changeFile(...);
+ /// await analysisContext.applyPendingFileChanges();
+ /// var analysisSession = analysisContext.currentSession;
+ /// var resolvedUnit = analysisSession.getResolvedUnit(...);
+ /// ```
void changeFile(String path);
}
diff --git a/pkg/front_end/test/macros/application/data/pkgs/macro/lib/macro.dart b/pkg/front_end/test/macros/application/data/pkgs/macro/lib/macro.dart
index 5a90a29..3cc37c6 100644
--- a/pkg/front_end/test/macros/application/data/pkgs/macro/lib/macro.dart
+++ b/pkg/front_end/test/macros/application/data/pkgs/macro/lib/macro.dart
@@ -361,4 +361,41 @@
return "${superClass?.identifier.name}";
}'''));
}
+}
+
+macro
+
+class ImportConflictMacro implements FunctionDefinitionMacro {
+ const ImportConflictMacro();
+
+ FutureOr<void> buildDefinitionForFunction(FunctionDeclaration function,
+ FunctionDefinitionBuilder builder) {
+ builder.augment(new FunctionBodyCode.fromParts([
+ '{\n ',
+ 'var ',
+ 'prefix',
+ ' = ',
+ function.positionalParameters
+ .elementAt(0)
+ .type
+ .code,
+ ';\n ',
+ 'var prefix0',
+ ' = ',
+ function.positionalParameters
+ .elementAt(1)
+ .type
+ .code,
+ ';\n ',
+ 'var pre',
+ 'fix',
+ '10 = ',
+ function.positionalParameters
+ .elementAt(2)
+ .type
+ .code,
+ ';\n',
+ '}',
+ ]));
+ }
}
\ No newline at end of file
diff --git a/pkg/front_end/test/macros/application/data/tests/import_conflict.dart b/pkg/front_end/test/macros/application/data/tests/import_conflict.dart
new file mode 100644
index 0000000..44c42bb
--- /dev/null
+++ b/pkg/front_end/test/macros/application/data/tests/import_conflict.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*library:
+Definitions:
+import 'dart:core' as prefix2_0;
+import 'dart:async' as prefix2_1;
+import 'dart:math' as prefix2_2;
+import 'dart:convert' as prefix2_3;
+
+augment void function(prefix2_0.int i, prefix2_1.FutureOr<prefix2_2.Random> f, prefix2_3.JsonCodec c, ) {
+ var prefix = prefix2_0.int;
+ var prefix0 = prefix2_1.FutureOr<prefix2_2.Random>;
+ var prefix10 = prefix2_3.JsonCodec;
+}
+*/
+
+import 'package:macro/macro.dart';
+import 'dart:async';
+import 'dart:math';
+import 'dart:convert';
+
+@ImportConflictMacro()
+/*member: function:
+augment void function(int i, FutureOr<Random> f, JsonCodec c, ) {
+ var prefix = int;
+ var prefix0 = FutureOr<Random>;
+ var prefix10 = JsonCodec;
+}*/
+external void function(int i, FutureOr<Random> f, JsonCodec c);
diff --git a/pkg/front_end/test/macros/application/data/tests/import_conflict.dart.expect b/pkg/front_end/test/macros/application/data/tests/import_conflict.dart.expect
new file mode 100644
index 0000000..f688800
--- /dev/null
+++ b/pkg/front_end/test/macros/application/data/tests/import_conflict.dart.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "package:macro/macro.dart" as mac;
+import "dart:core" as core;
+import "dart:math" as math;
+import "dart:convert" as con;
+
+import "package:macro/macro.dart";
+import "dart:async";
+import "dart:math";
+import "dart:convert";
+
+@#C1
+static method /* from org-dartlang-augmentation:/a/b/c/main.dart-0 */ function(core::int i, FutureOr<math::Random>f, con::JsonCodec c) → void {
+ core::Type prefix = #C2;
+ core::Type prefix0 = #C3;
+ core::Type prefix10 = #C4;
+}
+
+constants {
+ #C1 = mac::ImportConflictMacro {}
+ #C2 = TypeLiteralConstant(core::int*)
+ #C3 = TypeLiteralConstant(FutureOr<math::Random*>*)
+ #C4 = TypeLiteralConstant(con::JsonCodec*)
+}
diff --git a/pkg/front_end/test/macros/application/data/tests/parameters.dart b/pkg/front_end/test/macros/application/data/tests/parameters.dart
index c71841a..dae087e 100644
--- a/pkg/front_end/test/macros/application/data/tests/parameters.dart
+++ b/pkg/front_end/test/macros/application/data/tests/parameters.dart
@@ -4,19 +4,18 @@
/*library:
Definitions:
-import 'dart:core' as i0;
+import 'dart:core' as prefix0;
-
-augment void topLevelFunction1(i0.int a, ) {
+augment void topLevelFunction1(prefix0.int a, ) {
throw 42;
}
-augment void topLevelFunction2(i0.int a, i0.int b, ) {
+augment void topLevelFunction2(prefix0.int a, prefix0.int b, ) {
throw 42;
}
-augment void topLevelFunction3(i0.int a, [i0.int? b, ]) {
+augment void topLevelFunction3(prefix0.int a, [prefix0.int? b, ]) {
throw 42;
}
-augment void topLevelFunction4(i0.int a, {i0.int? b, i0.int? c, }) {
+augment void topLevelFunction4(prefix0.int a, {prefix0.int? b, prefix0.int? c, }) {
throw 42;
}
*/
diff --git a/pkg/front_end/test/macros/application/data/tests/subtypes.dart b/pkg/front_end/test/macros/application/data/tests/subtypes.dart
index b4028fd..b275017 100644
--- a/pkg/front_end/test/macros/application/data/tests/subtypes.dart
+++ b/pkg/front_end/test/macros/application/data/tests/subtypes.dart
@@ -4,25 +4,24 @@
/*library:
Definitions:
-import 'org-dartlang-test:///a/b/c/main.dart' as i0;
+import 'org-dartlang-test:///a/b/c/main.dart' as prefix0;
-
-augment i0.A topLevelFunction1(i0.A a, ) {
+augment prefix0.A topLevelFunction1(prefix0.A a, ) {
print('isExactly=true');
print('isSubtype=true');
throw 42;
}
-augment i0.B2 topLevelFunction2(i0.B1 a, ) {
+augment prefix0.B2 topLevelFunction2(prefix0.B1 a, ) {
print('isExactly=false');
print('isSubtype=true');
throw 42;
}
-augment i0.C2 topLevelFunction3(i0.C1 a, ) {
+augment prefix0.C2 topLevelFunction3(prefix0.C1 a, ) {
print('isExactly=false');
print('isSubtype=false');
throw 42;
}
-augment i0.D2 topLevelFunction4(i0.D1 a, ) {
+augment prefix0.D2 topLevelFunction4(prefix0.D1 a, ) {
print('isExactly=false');
print('isSubtype=false');
throw 42;
diff --git a/pkg/front_end/test/macros/application/data/tests/supertypes.dart b/pkg/front_end/test/macros/application/data/tests/supertypes.dart
index 37c4038..5bf8b9e 100644
--- a/pkg/front_end/test/macros/application/data/tests/supertypes.dart
+++ b/pkg/front_end/test/macros/application/data/tests/supertypes.dart
@@ -4,26 +4,25 @@
/*library:
Definitions:
-import 'dart:core' as i0;
-
+import 'dart:core' as prefix0;
augment class A {
-augment i0.String getSuperClass() {
+augment prefix0.String getSuperClass() {
return "Object";
}
}
augment class B {
-augment i0.String getSuperClass() {
+augment prefix0.String getSuperClass() {
return "A";
}
}
augment class M {
-augment i0.String getSuperClass() {
+augment prefix0.String getSuperClass() {
return "Object";
}
}
augment class C {
-augment i0.String getSuperClass() {
+augment prefix0.String getSuperClass() {
return "A";
}
}
diff --git a/pkg/front_end/test/macros/application/data/tests/type_annotations.dart b/pkg/front_end/test/macros/application/data/tests/type_annotations.dart
index f61a9a2..0ad8e21 100644
--- a/pkg/front_end/test/macros/application/data/tests/type_annotations.dart
+++ b/pkg/front_end/test/macros/application/data/tests/type_annotations.dart
@@ -4,32 +4,31 @@
/*library:
Definitions:
-import 'dart:core' as i0;
-import 'dart:math' as i1;
-
+import 'dart:core' as prefix0;
+import 'dart:math' as prefix1;
augment void topLevelFunction1() {
throw 42;
}
-augment i0.dynamic topLevelFunction2() {
+augment prefix0.dynamic topLevelFunction2() {
throw 42;
}
-augment i0.int topLevelFunction3() {
+augment prefix0.int topLevelFunction3() {
throw 42;
}
-augment i0.dynamic topLevelFunction4() {
+augment prefix0.dynamic topLevelFunction4() {
throw 42;
}
-augment i1.Random topLevelFunction5() {
+augment prefix1.Random topLevelFunction5() {
throw 42;
}
-augment i0.List<i0.int> topLevelFunction6() {
+augment prefix0.List<prefix0.int> topLevelFunction6() {
throw 42;
}
-augment i0.Map<i1.Random, i0.List<i0.int>> topLevelFunction7() {
+augment prefix0.Map<prefix1.Random, prefix0.List<prefix0.int>> topLevelFunction7() {
throw 42;
}
-augment i0.Map<i0.int?, i0.String>? topLevelFunction8() {
+augment prefix0.Map<prefix0.int?, prefix0.String>? topLevelFunction8() {
throw 42;
}
*/
diff --git a/pkg/front_end/test/macros/application/data/tests/types.dart b/pkg/front_end/test/macros/application/data/tests/types.dart
index 5da560d..6e3dacf 100644
--- a/pkg/front_end/test/macros/application/data/tests/types.dart
+++ b/pkg/front_end/test/macros/application/data/tests/types.dart
@@ -4,24 +4,23 @@
/*library:
Types:
-import 'dart:core' as i0;
-import 'package:macro/macro.dart' as i1;
-
+import 'dart:core' as prefix0;
+import 'package:macro/macro.dart' as prefix1;
class topLevelFunction1GeneratedClass {
external void method();
}
class topLevelFunction2GeneratedClass {
- external i0.dynamic method();
+ external prefix0.dynamic method();
}
class topLevelFunction3GeneratedClass {
- external i0.int method();
+ external prefix0.int method();
}
class topLevelFunction4GeneratedClass {
- external i1.FunctionTypesMacro1? method();
+ external prefix1.FunctionTypesMacro1? method();
}
class topLevelFunction5GeneratedClass {
- external i0.dynamic method();
+ external prefix0.dynamic method();
}*/
import 'package:macro/macro.dart';
diff --git a/pkg/front_end/test/macros/application/data/tests/types.dart.expect b/pkg/front_end/test/macros/application/data/tests/types.dart.expect
index e36ef4f..ed9d33c 100644
--- a/pkg/front_end/test/macros/application/data/tests/types.dart.expect
+++ b/pkg/front_end/test/macros/application/data/tests/types.dart.expect
@@ -3,8 +3,8 @@
import "dart:core" as core;
import "package:macro/macro.dart" as mac;
-import "dart:core" as i0;
-import "package:macro/macro.dart" as i1;
+import "dart:core" as prefix0;
+import "package:macro/macro.dart" as prefix1;
import "package:macro/macro.dart";
class topLevelFunction1GeneratedClass extends core::Object { // from org-dartlang-augmentation:/a/b/c/main.dart-0
diff --git a/pkg/front_end/test/macros/declaration/macro_declaration_test.dart b/pkg/front_end/test/macros/declaration/macro_declaration_test.dart
index a3486a1..d1e3f3b 100644
--- a/pkg/front_end/test/macros/declaration/macro_declaration_test.dart
+++ b/pkg/front_end/test/macros/declaration/macro_declaration_test.dart
@@ -297,7 +297,8 @@
String buildAugmentationLibrary(
Iterable<MacroExecutionResult> macroResults,
ResolvedIdentifier Function(Identifier) resolveIdentifier,
- TypeAnnotation Function(OmittedTypeAnnotation) inferOmittedType) {
+ TypeAnnotation? Function(OmittedTypeAnnotation) inferOmittedType,
+ {Map<OmittedTypeAnnotation, String>? omittedTypes}) {
return '';
}
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index ac64436..9c7b439 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -122,6 +122,7 @@
binds
bj
bk
+blend
blindly
blob
blobs
@@ -1249,6 +1250,7 @@
substed
substitutes
substitutor
+suffixing
suggests
suite
sum
diff --git a/runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc b/runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc
index 6b546ad..4a4067b 100644
--- a/runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc
+++ b/runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc
@@ -1133,11 +1133,11 @@
}
intptr_t PassAsPointerAndValue(void* ptr, intptr_t value) {
- return reinterpret_cast<intptr_t>(value);
+ return value;
}
intptr_t PassAsValueAndPointer(intptr_t value, void* ptr) {
- return reinterpret_cast<intptr_t>(value);
+ return value;
}
intptr_t* AllocateResource(intptr_t value) {
diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc
index 6cb8860..8bac5cf 100644
--- a/runtime/bin/file_win.cc
+++ b/runtime/bin/file_win.cc
@@ -304,6 +304,11 @@
class StringRAII {
public:
+ explicit StringRAII(StringRAII& origin) {
+ own_ = origin.own_;
+ s_ = origin.release();
+ }
+
explicit StringRAII(const char* s) : s_(s), own_(false) {}
explicit StringRAII(char* s) : s_(s), own_(true) {}
~StringRAII() {
@@ -385,9 +390,10 @@
// Long relative path have to be converted to absolute path before prefixing.
bool is_ok = true;
- StringRAII absolute_path_raii = File::IsAbsolutePath(path)
- ? StringRAII(path)
- : ConvertToAbsolutePath(path, &is_ok);
+ StringRAII absolute_path_raii(
+ File::IsAbsolutePath(path)
+ ? StringRAII(path)
+ : StringRAII(ConvertToAbsolutePath(path, &is_ok)));
if (!is_ok) {
return StringRAII(path);
}
diff --git a/runtime/bin/snapshot_utils.cc b/runtime/bin/snapshot_utils.cc
index 11b0ead..243fac3 100644
--- a/runtime/bin/snapshot_utils.cc
+++ b/runtime/bin/snapshot_utils.cc
@@ -26,9 +26,8 @@
static const int64_t kAppSnapshotHeaderSize = 5 * kInt64Size;
static const int64_t kAppSnapshotPageSize = 16 * KB;
-static const char kMachOAppSnapshotSegmentName[] __attribute__((unused)) =
- "__CUSTOM";
-static const char kMachOAppSnapshotSectionName[] __attribute__((unused)) =
+static const char kMachOAppSnapshotSegmentName[] DART_UNUSED = "__CUSTOM";
+static const char kMachOAppSnapshotSectionName[] DART_UNUSED =
"__dart_app_snap";
class MappedAppSnapshot : public AppSnapshot {
diff --git a/runtime/bin/utils_win.cc b/runtime/bin/utils_win.cc
index 174ed7f..1c542f2 100644
--- a/runtime/bin/utils_win.cc
+++ b/runtime/bin/utils_win.cc
@@ -50,7 +50,8 @@
FILETIME GetFiletimeFromMillis(int64_t millis) {
static const int64_t kTimeScaler = 10000; // 100 ns to ms.
- TimeStamp t = {.t_ = millis * kTimeScaler + kFileTimeEpoch};
+ TimeStamp t;
+ t.t_ = millis * kTimeScaler + kFileTimeEpoch;
return t.ft_;
}
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph_test.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph_test.cc
index ca7fcc2..c3682ed 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph_test.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph_test.cc
@@ -326,7 +326,7 @@
ILMatcher cursor(flow_graph, entry, true);
// clang-format off
- RELEASE_ASSERT(cursor.TryMatch({
+ std::initializer_list<MatchCode> expected = {
kMatchAndMoveFunctionEntry,
kMatchAndMoveCheckStackOverflow,
kMoveDebugStepChecks,
@@ -339,7 +339,8 @@
kMatchAndMoveClosureCall,
kMoveDebugStepChecks,
kMatchReturn,
- }));
+ };
+ RELEASE_ASSERT(cursor.TryMatch(expected));
// clang-format on
}
diff --git a/runtime/vm/message_snapshot.cc b/runtime/vm/message_snapshot.cc
index 22de126..cc40ebb 100644
--- a/runtime/vm/message_snapshot.cc
+++ b/runtime/vm/message_snapshot.cc
@@ -26,28 +26,50 @@
namespace dart {
-static Dart_CObject cobj_null = {.type = Dart_CObject_kNull,
- .value = {.as_int64 = 0}};
-static Dart_CObject cobj_sentinel = {.type = Dart_CObject_kUnsupported};
-static Dart_CObject cobj_transition_sentinel = {.type =
- Dart_CObject_kUnsupported};
-static Dart_CObject cobj_empty_array = {
- .type = Dart_CObject_kArray,
- .value = {.as_array = {.length = 0, .values = nullptr}}};
-static Dart_CObject cobj_zero_array_element = {.type = Dart_CObject_kInt32,
- .value = {.as_int32 = 0}};
-static Dart_CObject* cobj_zero_array_values[1] = {&cobj_zero_array_element};
-static Dart_CObject cobj_zero_array = {
- .type = Dart_CObject_kArray,
- .value = {.as_array = {.length = 1, .values = &cobj_zero_array_values[0]}}};
-static Dart_CObject cobj_dynamic_type = {.type = Dart_CObject_kUnsupported};
-static Dart_CObject cobj_void_type = {.type = Dart_CObject_kUnsupported};
-static Dart_CObject cobj_empty_type_arguments = {.type =
- Dart_CObject_kUnsupported};
-static Dart_CObject cobj_true = {.type = Dart_CObject_kBool,
- .value = {.as_bool = true}};
-static Dart_CObject cobj_false = {.type = Dart_CObject_kBool,
- .value = {.as_bool = false}};
+
+static Dart_CObject cobj_sentinel = {Dart_CObject_kUnsupported, {false}};
+static Dart_CObject cobj_transition_sentinel = {Dart_CObject_kUnsupported,
+ {false}};
+static Dart_CObject cobj_dynamic_type = {Dart_CObject_kUnsupported, {false}};
+static Dart_CObject cobj_void_type = {Dart_CObject_kUnsupported, {false}};
+static Dart_CObject cobj_empty_type_arguments = {Dart_CObject_kUnsupported,
+ {false}};
+static Dart_CObject cobj_true = {Dart_CObject_kBool, {true}};
+static Dart_CObject cobj_false = {Dart_CObject_kBool, {false}};
+
+// Workaround for lack of designated initializers until we adopt c++20
+class PredefinedCObjects {
+ public:
+ static PredefinedCObjects& getInstance() {
+ static PredefinedCObjects instance;
+ return instance;
+ }
+
+ static Dart_CObject* cobj_null() { return &getInstance().cobj_null_; }
+ static Dart_CObject* cobj_empty_array() { return &getInstance().cobj_empty_array_; }
+ static Dart_CObject* cobj_zero_array() { return &getInstance().cobj_zero_array_; }
+
+ private:
+ PredefinedCObjects() {
+ cobj_null_.type = Dart_CObject_kNull;
+ cobj_null_.value.as_int64 = 0;
+ cobj_empty_array_.type = Dart_CObject_kArray;
+ cobj_empty_array_.value.as_array = {0, nullptr};
+ cobj_zero_array_element.type = Dart_CObject_kInt32;
+ cobj_zero_array_element.value.as_int32 = 0;
+ cobj_zero_array_values[0] = {&cobj_zero_array_element};
+ cobj_zero_array_.type = Dart_CObject_kArray;
+ cobj_zero_array_.value.as_array = {1, &cobj_zero_array_values[0]};
+ }
+
+ Dart_CObject cobj_null_;
+ Dart_CObject cobj_empty_array_;
+ Dart_CObject* cobj_zero_array_values[1];
+ Dart_CObject cobj_zero_array_element;
+ Dart_CObject cobj_zero_array_;
+
+ DISALLOW_COPY_AND_ASSIGN(PredefinedCObjects);
+};
enum class MessagePhase {
kBeforeTypes = 0,
@@ -2801,7 +2823,7 @@
for (intptr_t i = 0; i < count; i++) {
Dart_CObject* array = reinterpret_cast<Dart_CObject*>(objects_[i]);
intptr_t length = array->value.as_array.length;
- s->WriteRef(&cobj_null); // TypeArguments
+ s->WriteRef(PredefinedCObjects::cobj_null()); // TypeArguments
for (intptr_t j = 0; j < length; j++) {
s->WriteRef(array->value.as_array.values[j]);
}
@@ -3242,7 +3264,7 @@
intptr_t cid;
switch (object->type) {
case Dart_CObject_kNull:
- ForwardRef(object, &cobj_null);
+ ForwardRef(object, PredefinedCObjects::cobj_null());
return true;
case Dart_CObject_kBool:
ForwardRef(object, object->value.as_bool ? &cobj_true : &cobj_false);
@@ -3640,11 +3662,11 @@
}
void ApiMessageSerializer::AddBaseObjects() {
- AddBaseObject(&cobj_null);
+ AddBaseObject(PredefinedCObjects::cobj_null());
AddBaseObject(&cobj_sentinel);
AddBaseObject(&cobj_transition_sentinel);
- AddBaseObject(&cobj_empty_array);
- AddBaseObject(&cobj_zero_array);
+ AddBaseObject(PredefinedCObjects::cobj_empty_array());
+ AddBaseObject(PredefinedCObjects::cobj_zero_array());
AddBaseObject(&cobj_dynamic_type);
AddBaseObject(&cobj_void_type);
AddBaseObject(&cobj_empty_type_arguments);
@@ -3653,11 +3675,11 @@
}
void ApiMessageDeserializer::AddBaseObjects() {
- AddBaseObject(&cobj_null);
+ AddBaseObject(PredefinedCObjects::cobj_null());
AddBaseObject(&cobj_sentinel);
AddBaseObject(&cobj_transition_sentinel);
- AddBaseObject(&cobj_empty_array);
- AddBaseObject(&cobj_zero_array);
+ AddBaseObject(PredefinedCObjects::cobj_empty_array());
+ AddBaseObject(PredefinedCObjects::cobj_zero_array());
AddBaseObject(&cobj_dynamic_type);
AddBaseObject(&cobj_void_type);
AddBaseObject(&cobj_empty_type_arguments);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index fe33347..9c49a86 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -10455,12 +10455,14 @@
// code (in which case the caller might get different answers if it obtains
// the guarded cid multiple times).
Thread* thread = Thread::Current();
+#if defined(DART_PRECOMPILED_RUNTIME)
+ ASSERT(!thread->IsInsideCompiler() || is_static());
+#else
ASSERT(!thread->IsInsideCompiler() ||
-#if !defined(DART_PRECOMPILED_RUNTIME)
((CompilerState::Current().should_clone_fields() == !IsOriginal())) ||
-#endif
is_static());
#endif
+#endif
return LoadNonPointer<ClassIdTagType, std::memory_order_relaxed>(
&untag()->guarded_cid_);
}
@@ -10470,12 +10472,14 @@
// Same assert as guarded_cid(), because is_nullable() also needs to be
// consistent for the background compiler.
Thread* thread = Thread::Current();
+#if defined(DART_PRECOMPILED_RUNTIME)
+ ASSERT(!thread->IsInsideCompiler() || is_static());
+#else
ASSERT(!thread->IsInsideCompiler() ||
-#if !defined(DART_PRECOMPILED_RUNTIME)
((CompilerState::Current().should_clone_fields() == !IsOriginal())) ||
-#endif
is_static());
#endif
+#endif
return is_nullable_unsafe();
}
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 8c352db..64209d3 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -269,7 +269,12 @@
// exceptions. This allows triggering the normal TSAN shadow stack unwinding
// implementation.
// -> See https://dartbug.com/47472#issuecomment-948235479 for details.
+#if defined(USING_THREAD_SANITIZER)
void* setjmp_function = reinterpret_cast<void*>(&setjmp);
+#else
+ // MSVC (on Windows) is not happy with getting address of purely intrinsic.
+ void* setjmp_function = nullptr;
+#endif
jmp_buf* setjmp_buffer = nullptr;
uword exception_pc = 0;
uword exception_sp = 0;
diff --git a/tools/VERSION b/tools/VERSION
index 3c727f4..d901ea1 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 17
PATCH 0
-PRERELEASE 228
+PRERELEASE 229
PRERELEASE_PATCH 0
\ No newline at end of file