blob: 329f3fe01ecd57aaf61308a7d785e2a718401ceb [file] [log] [blame]
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/field_name_non_promotability_info.dart';
import 'package:analyzer/src/summary2/export.dart';
import 'package:analyzer/src/summary2/macro_application_error.dart';
import 'package:analyzer/src/summary2/macro_type_location.dart';
import 'package:analyzer/src/task/inference_error.dart';
import 'package:analyzer_utilities/testing/tree_string_sink.dart';
import 'package:collection/collection.dart';
import 'package:test/test.dart';
import '../../util/element_printer.dart';
import 'resolved_ast_printer.dart';
String getLibraryText({
required LibraryElementImpl library,
required ElementTextConfiguration configuration,
}) {
var buffer = StringBuffer();
var sink = TreeStringSink(
sink: buffer,
indent: '',
);
var elementPrinter = ElementPrinter(
sink: sink,
configuration: ElementPrinterConfiguration(),
);
var writer = _ElementWriter(
sink: sink,
elementPrinter: elementPrinter,
configuration: configuration,
);
writer.writeLibraryElement(library);
return buffer.toString();
}
class ElementTextConfiguration {
bool Function(Object) filter;
List<Pattern>? macroDiagnosticMessagePatterns;
bool withAllSupertypes = false;
bool withAugmentedWithoutAugmentation = false;
bool withCodeRanges = false;
bool withConstantInitializers = true;
bool withConstructors = true;
bool withDisplayName = false;
bool withExportScope = false;
bool withFunctionTypeParameters = false;
bool withImports = true;
bool withLibraryAugmentations = false;
bool withMacroStackTraces = false;
bool withMetadata = true;
bool withNonSynthetic = false;
bool withPropertyLinking = false;
bool withRedirectedConstructors = false;
bool withReturnType = true;
bool withSyntheticDartCoreImport = false;
ElementTextConfiguration({
this.filter = _filterTrue,
});
static bool _filterTrue(Object element) => true;
}
/// Writes the canonical text presentation of elements.
class _ElementWriter {
final TreeStringSink _sink;
final ElementPrinter _elementPrinter;
final ElementTextConfiguration configuration;
final _IdMap _idMap = _IdMap();
_ElementWriter({
required TreeStringSink sink,
required ElementPrinter elementPrinter,
required this.configuration,
}) : _sink = sink,
_elementPrinter = elementPrinter;
void writeLibraryElement(LibraryElementImpl e) {
expect(e.enclosingElement, isNull);
_sink.writelnWithIndent('library');
_sink.withIndent(() {
var name = e.name;
if (name.isNotEmpty) {
_sink.writelnWithIndent('name: $name');
}
var nameOffset = e.nameOffset;
if (nameOffset != -1) {
_sink.writelnWithIndent('nameOffset: $nameOffset');
}
_writeLibraryOrAugmentationElement(e);
for (var part in e.parts) {
if (part.uri case DirectiveUriWithUnitImpl uri) {
expect(uri.unit.libraryOrAugmentationElement, same(e));
}
}
_writeElements('parts', e.parts, (part) {
_writePartElement(part, onlyId: false);
});
// All fragments have this library.
for (var unit in e.units) {
expect(unit.library, same(e));
}
if (configuration.withExportScope) {
_sink.writelnWithIndent('exportedReferences');
_sink.withIndent(() {
_writeExportedReferences(e);
});
_sink.writelnWithIndent('exportNamespace');
_sink.withIndent(() {
_writeExportNamespace(e);
});
}
_writeFieldNameNonPromotabilityInfo(e.fieldNameNonPromotabilityInfo);
_writeMacroDiagnostics(e);
});
}
void _assertNonSyntheticElementSelf(Element element) {
expect(element.isSynthetic, isFalse);
expect(element.nonSynthetic, same(element));
}
ResolvedAstPrinter _createAstPrinter() {
return ResolvedAstPrinter(
sink: _sink,
elementPrinter: _elementPrinter,
configuration: ResolvedNodeTextConfiguration()
// TODO(scheglov): https://github.com/dart-lang/sdk/issues/49101
..withParameterElements = false,
withOffsets: true,
);
}
void _validateAugmentedInstanceElement(InstanceElementImpl e) {
InstanceElementImpl? current = e;
while (current != null) {
expect(current.augmented, same(e.augmented));
expect(current.thisType, same(e.thisType));
switch (e) {
case ExtensionElementImpl():
current as ExtensionElementImpl;
expect(current.extendedType, same(e.extendedType));
case ExtensionTypeElementImpl():
current as ExtensionTypeElementImpl;
expect(current.primaryConstructor, same(e.primaryConstructor));
expect(current.representation, same(e.representation));
expect(current.typeErasure, same(e.typeErasure));
}
current = current.augmentationTarget;
}
}
void _writeAugmentation(ElementImpl e) {
if (e case AugmentableElement(:var augmentation?)) {
_elementPrinter.writeNamedElement('augmentation', augmentation);
}
}
void _writeAugmentationElement(LibraryAugmentationElementImpl e) {
_writeLibraryOrAugmentationElement(e);
}
void _writeAugmentationImportElement(AugmentationImportElementImpl e) {
var uri = e.uri;
_sink.writeIndentedLine(() {
_writeDirectiveUri(e.uri);
});
_sink.withIndent(() {
_writeEnclosingElement(e);
_writeMetadata(e);
if (uri is DirectiveUriWithAugmentationImpl) {
_writeAugmentationElement(uri.augmentation);
}
});
}
void _writeAugmentationTarget(ElementImpl e) {
if (e is AugmentableElement && e.isAugmentation) {
if (e.augmentationTarget case var target?) {
_elementPrinter.writeNamedElement(
'augmentationTarget',
target,
);
} else if (e.augmentationTargetAny case var targetAny?) {
_elementPrinter.writeNamedElement(
'augmentationTargetAny',
targetAny,
);
}
}
}
void _writeAugmented(InstanceElementImpl e) {
if (e.augmentationTarget != null) {
return;
}
// No augmentation, not interesting.
if (e.augmentation == null) {
expect(e.augmented, TypeMatcher<NotAugmentedInstanceElementImpl>());
if (!configuration.withAugmentedWithoutAugmentation) {
return;
}
}
var augmented = e.augmented;
void writeFields() {
var sorted = augmented.fields.sortedBy((e) => e.name);
_elementPrinter.writeElementList('fields', sorted);
}
void writeConstructors() {
if (!configuration.withConstructors) {
return;
}
if (augmented is AugmentedInterfaceElementImpl) {
var sorted = augmented.constructors.sortedBy((e) => e.name);
expect(sorted, isNotEmpty);
_elementPrinter.writeElementList('constructors', sorted);
}
}
void writeAccessors() {
var sorted = augmented.accessors.sortedBy((e) => e.name);
_elementPrinter.writeElementList('accessors', sorted);
}
void writeMethods() {
var sorted = augmented.methods.sortedBy((e) => e.name);
_elementPrinter.writeElementList('methods', sorted);
}
_sink.writelnWithIndent('augmented');
_sink.withIndent(() {
switch (augmented) {
case AugmentedClassElement():
_elementPrinter.writeTypeList('mixins', augmented.mixins);
_elementPrinter.writeTypeList('interfaces', augmented.interfaces);
writeFields();
writeConstructors();
writeAccessors();
writeMethods();
case AugmentedEnumElement():
_elementPrinter.writeTypeList('mixins', augmented.mixins);
_elementPrinter.writeTypeList('interfaces', augmented.interfaces);
writeFields();
_elementPrinter.writeElementList(
'constants',
augmented.constants.sortedBy((e) => e.name),
);
writeConstructors();
writeAccessors();
writeMethods();
case AugmentedExtensionElement():
writeFields();
writeAccessors();
writeMethods();
case AugmentedExtensionTypeElement():
_elementPrinter.writeTypeList('interfaces', augmented.interfaces);
writeFields();
writeConstructors();
writeAccessors();
writeMethods();
case AugmentedMixinElement():
_elementPrinter.writeTypeList(
'superclassConstraints',
augmented.superclassConstraints,
);
_elementPrinter.writeTypeList('interfaces', augmented.interfaces);
writeFields();
writeAccessors();
writeMethods();
default:
// TODO(scheglov): Add other types and properties
throw UnimplementedError('${e.runtimeType}');
}
});
}
void _writeBodyModifiers(ExecutableElement e) {
if (e.isAsynchronous) {
expect(e.isSynchronous, isFalse);
_sink.write(' async');
}
if (e.isSynchronous && e.isGenerator) {
expect(e.isAsynchronous, isFalse);
_sink.write(' sync');
}
_sink.writeIf(e.isGenerator, '*');
if (e is ExecutableElementImpl && e.invokesSuperSelf) {
_sink.write(' invokesSuperSelf');
}
}
void _writeCodeRange(Element e) {
if (configuration.withCodeRanges && !e.isSynthetic) {
e as ElementImpl;
_sink.writelnWithIndent('codeOffset: ${e.codeOffset}');
_sink.writelnWithIndent('codeLength: ${e.codeLength}');
}
}
void _writeConstantInitializer(Element e) {
if (configuration.withConstantInitializers) {
if (e is ConstVariableElement) {
var initializer = e.constantInitializer;
if (initializer != null) {
_sink.writelnWithIndent('constantInitializer');
_sink.withIndent(() {
_writeNode(initializer);
});
}
}
}
}
void _writeConstructorElement(ConstructorElement e) {
e as ConstructorElementImpl;
// Check that the reference exists, and filled with the element.
var reference = e.reference;
if (reference == null) {
fail('Every constructor must have a reference.');
}
_sink.writeIndentedLine(() {
_sink.writeIf(e.isAugmentation, 'augment ');
_sink.writeIf(e.isSynthetic, 'synthetic ');
_sink.writeIf(e.isExternal, 'external ');
_sink.writeIf(e.isConst, 'const ');
_sink.writeIf(e.isFactory, 'factory ');
expect(e.isAbstract, isFalse);
_writeName(e);
});
_sink.withIndent(() {
_writeReference(e);
_writeEnclosingElement(e);
_writeDocumentation(e);
_writeMetadata(e);
_writeSinceSdkVersion(e);
_writeCodeRange(e);
_writeDisplayName(e);
var periodOffset = e.periodOffset;
var nameEnd = e.nameEnd;
if (periodOffset != null && nameEnd != null) {
_sink.writelnWithIndent('periodOffset: $periodOffset');
_sink.writelnWithIndent('nameEnd: $nameEnd');
}
_writeParameterElements(e.parameters);
_writeElements(
'constantInitializers',
e.constantInitializers,
_writeNode,
);
var superConstructor = e.superConstructor;
if (superConstructor != null) {
var enclosingElement = superConstructor.enclosingElement;
if (enclosingElement is ClassElement &&
!enclosingElement.isDartCoreObject) {
_elementPrinter.writeNamedElement(
'superConstructor',
superConstructor,
);
}
}
var redirectedConstructor = e.redirectedConstructor;
if (redirectedConstructor != null) {
_elementPrinter.writeNamedElement(
'redirectedConstructor',
redirectedConstructor,
);
}
_writeNonSyntheticElement(e);
_writeMacroDiagnostics(e);
_writeAugmentationTarget(e);
_writeAugmentation(e);
});
expect(e.isAsynchronous, isFalse);
expect(e.isGenerator, isFalse);
if (e.isSynthetic) {
expect(e.nameOffset, -1);
expect(e.nonSynthetic, same(e.enclosingElement));
} else {
expect(e.nameOffset, isPositive);
}
}
void _writeDirectiveUri(DirectiveUri uri) {
if (uri is DirectiveUriWithAugmentationImpl) {
_sink.write('${uri.augmentation.source.uri}');
} else if (uri is DirectiveUriWithLibraryImpl) {
_sink.write('${uri.library.source.uri}');
} else if (uri is DirectiveUriWithUnit) {
_sink.write('${uri.unit.source.uri}');
} else if (uri is DirectiveUriWithSource) {
_sink.write("source '${uri.source.uri}'");
} else if (uri is DirectiveUriWithRelativeUri) {
_sink.write("relativeUri '${uri.relativeUri}'");
} else if (uri is DirectiveUriWithRelativeUriString) {
_sink.write("relativeUriString '${uri.relativeUriString}'");
} else {
_sink.write('noRelativeUriString');
}
}
void _writeDisplayName(Element e) {
if (configuration.withDisplayName) {
_sink.writelnWithIndent('displayName: ${e.displayName}');
}
}
void _writeDocumentation(Element element) {
var documentation = element.documentationComment;
if (documentation != null) {
var str = documentation;
str = str.replaceAll('\n', r'\n');
str = str.replaceAll('\r', r'\r');
_sink.writelnWithIndent('documentationComment: $str');
}
}
void _writeElements<T extends Object>(
String name,
List<T> elements,
void Function(T) f,
) {
var filtered = elements.where(configuration.filter).toList();
if (filtered.isNotEmpty) {
_sink.writelnWithIndent(name);
_sink.withIndent(() {
for (var element in filtered) {
f(element);
}
});
}
}
void _writeEnclosingElement(ElementImpl e) {
_elementPrinter.writeNamedElement(
'enclosingElement',
e.enclosingElement,
);
switch (e) {
case CompilationUnitElementImpl():
if (identical(e.library.definingCompilationUnit, e)) {
expect(e.enclosingElement3, isNull);
} else {
expect(
e.enclosingElement3,
TypeMatcher<CompilationUnitElementImpl>(),
);
_elementPrinter.writeNamedElement(
'enclosingElement3',
e.enclosingElement3,
);
}
case LibraryImportElementImpl():
case LibraryExportElementImpl():
case PartElementImpl():
case PrefixElementImpl():
expect(
e.enclosingElement3,
TypeMatcher<CompilationUnitElementImpl>(),
);
_elementPrinter.writeNamedElement(
'enclosingElement3',
e.enclosingElement3,
);
default:
expect(e.enclosingElement3, same(e.enclosingElement));
}
}
void _writeExportedReferences(LibraryElementImpl e) {
var exportedReferences = e.exportedReferences.toList();
exportedReferences.sortBy((e) => e.reference.toString());
for (var exported in exportedReferences) {
_sink.writeIndentedLine(() {
if (exported is ExportedReferenceDeclared) {
_sink.write('declared ');
} else if (exported is ExportedReferenceExported) {
_sink.write('exported${exported.locations} ');
}
_elementPrinter.writeReference(exported.reference);
});
}
}
void _writeExportNamespace(LibraryElement e) {
var map = e.exportNamespace.definedNames;
var sortedEntries = map.entries.sortedBy((entry) => entry.key);
for (var entry in sortedEntries) {
_elementPrinter.writeNamedElement(entry.key, entry.value);
}
}
void _writeExtensionElement(ExtensionElementImpl e) {
_sink.writeIndentedLine(() {
_sink.writeIf(e.isAugmentation, 'augment ');
_writeName(e);
});
_sink.withIndent(() {
_writeReference(e);
_writeEnclosingElement(e);
_writeDocumentation(e);
_writeMetadata(e);
_writeSinceSdkVersion(e);
_writeCodeRange(e);
_writeTypeParameterElements(e.typeParameters);
if (e.augmentationTarget == null) {
_writeType('extendedType', e.extendedType);
}
_writeMacroDiagnostics(e);
_writeAugmentationTarget(e);
_writeAugmentation(e);
_writeElements('fields', e.fields, _writePropertyInducingElement);
_writeElements('accessors', e.accessors, _writePropertyAccessorElement);
_writeMethods(e.methods);
_validateAugmentedInstanceElement(e);
_writeAugmented(e);
});
_assertNonSyntheticElementSelf(e);
}
void _writeFieldFormalParameterField(ParameterElement e) {
if (e is FieldFormalParameterElement) {
var field = e.field;
if (field != null) {
_elementPrinter.writeNamedElement('field', field);
} else {
_sink.writelnWithIndent('field: <null>');
}
}
}
void _writeFieldNameNonPromotabilityInfo(
Map<String, FieldNameNonPromotabilityInfo>? info,
) {
if (info == null || info.isEmpty) {
return;
}
_sink.writelnWithIndent('fieldNameNonPromotabilityInfo');
_sink.withIndent(() {
for (var entry in info.entries) {
_sink.writelnWithIndent(entry.key);
_sink.withIndent(() {
_elementPrinter.writeElementList(
'conflictingFields',
entry.value.conflictingFields,
);
_elementPrinter.writeElementList(
'conflictingGetters',
entry.value.conflictingGetters,
);
_elementPrinter.writeElementList(
'conflictingNsmClasses',
entry.value.conflictingNsmClasses,
);
});
}
});
}
void _writeFunctionElement(FunctionElementImpl e) {
expect(e.isStatic, isTrue);
_sink.writeIndentedLine(() {
_sink.writeIf(e.isAugmentation, 'augment ');
_sink.writeIf(e.isExternal, 'external ');
_writeName(e);
_writeBodyModifiers(e);
});
_sink.withIndent(() {
_writeReference(e);
_writeEnclosingElement(e);
_writeDocumentation(e);
_writeMetadata(e);
_writeSinceSdkVersion(e);
_writeCodeRange(e);
_writeTypeParameterElements(e.typeParameters);
_writeParameterElements(e.parameters);
_writeReturnType(e.returnType);
_writeMacroDiagnostics(e);
_writeAugmentationTarget(e);
_writeAugmentation(e);
});
_assertNonSyntheticElementSelf(e);
}
void _writeImportElementPrefix(ImportElementPrefixImpl? prefix) {
if (prefix != null) {
_sink.writeIf(prefix is DeferredImportElementPrefix, ' deferred');
_sink.write(' as ');
_writeName(prefix.element);
}
}
void _writeInterfaceElement(InterfaceElementImpl e) {
_sink.writeIndentedLine(() {
if (e.isAugmentation) {
_sink.write('augment ');
}
switch (e) {
case ClassElementImpl():
_sink.writeIf(e.isAbstract, 'abstract ');
_sink.writeIf(e.isMacro, 'macro ');
_sink.writeIf(e.isSealed, 'sealed ');
_sink.writeIf(e.isBase, 'base ');
_sink.writeIf(e.isInterface, 'interface ');
_sink.writeIf(e.isFinal, 'final ');
_writeNotSimplyBounded(e);
_sink.writeIf(e.isMixinClass, 'mixin ');
_sink.write('class ');
_sink.writeIf(e.isMixinApplication, 'alias ');
case EnumElementImpl():
_writeNotSimplyBounded(e);
_sink.write('enum ');
case ExtensionTypeElementImpl():
_sink.writeIf(
e.hasRepresentationSelfReference,
'hasRepresentationSelfReference ',
);
_sink.writeIf(
e.hasImplementsSelfReference,
'hasImplementsSelfReference ',
);
_writeNotSimplyBounded(e);
case MixinElementImpl():
_sink.writeIf(e.isBase, 'base ');
_writeNotSimplyBounded(e);
_sink.write('mixin ');
}
_writeName(e);
});
_sink.withIndent(() {
_writeReference(e);
_writeEnclosingElement(e);
_writeDocumentation(e);
_writeMetadata(e);
_writeSinceSdkVersion(e);
_writeCodeRange(e);
_writeTypeParameterElements(e.typeParameters);
_writeMacroDiagnostics(e);
_writeAugmentationTarget(e);
_writeAugmentation(e);
if (!e.isAugmentation) {
var supertype = e.supertype;
if (supertype != null &&
(supertype.element.name != 'Object' || e.mixins.isNotEmpty)) {
_writeType('supertype', supertype);
}
}
if (e is ExtensionTypeElementImpl) {
if (e.augmentationTarget == null) {
_elementPrinter.writeNamedElement('representation', e.representation);
_elementPrinter.writeNamedElement(
'primaryConstructor', e.primaryConstructor);
_elementPrinter.writeNamedType('typeErasure', e.typeErasure);
}
}
if (e is MixinElementImpl) {
_elementPrinter.writeTypeList(
'superclassConstraints',
e.superclassConstraints,
);
}
_elementPrinter.writeTypeList('mixins', e.mixins);
_elementPrinter.writeTypeList('interfaces', e.interfaces);
if (configuration.withAllSupertypes) {
var sorted = e.allSupertypes.sortedBy((t) => t.element.name);
_elementPrinter.writeTypeList('allSupertypes', sorted);
}
_writeElements('fields', e.fields, _writePropertyInducingElement);
var constructors = e.constructors;
if (e is MixinElement) {
expect(constructors, isEmpty);
} else if (configuration.withConstructors) {
_writeElements('constructors', constructors, _writeConstructorElement);
}
_writeElements('accessors', e.accessors, _writePropertyAccessorElement);
_writeMethods(e.methods);
_validateAugmentedInstanceElement(e);
_writeAugmented(e);
});
_assertNonSyntheticElementSelf(e);
}
void _writeLibraryAugmentations(LibraryElementImpl e) {
if (configuration.withLibraryAugmentations) {
var augmentations = e.augmentations;
if (augmentations.isNotEmpty) {
_sink.writelnWithIndent('augmentations');
_sink.withIndent(() {
for (var element in augmentations) {
_sink.writeIndent();
_elementPrinter.writeElement(element);
}
});
}
}
}
void _writeLibraryExportElement(LibraryExportElementImpl e) {
e.location;
_sink.writeIndentedLine(() {
_writeDirectiveUri(e.uri);
});
_sink.withIndent(() {
_writeReference(e);
_writeEnclosingElement(e);
_writeMetadata(e);
_writeNamespaceCombinators(e.combinators);
});
_assertNonSyntheticElementSelf(e);
}
void _writeLibraryImportElement(LibraryImportElementImpl e) {
e.location;
_sink.writeIndentedLine(() {
_writeDirectiveUri(e.uri);
_sink.writeIf(e.isSynthetic, ' synthetic');
_writeImportElementPrefix(e.prefix);
});
_sink.withIndent(() {
_writeReference(e);
_writeEnclosingElement(e);
_writeMetadata(e);
_writeNamespaceCombinators(e.combinators);
});
}
void _writeLibraryOrAugmentationElement(LibraryOrAugmentationElementImpl e) {
_writeReference(e);
if (e is LibraryAugmentationElementImpl) {
if (e.macroGenerated case var macroGenerated?) {
_sink.writelnWithIndent('macroGeneratedCode');
_sink.writeln('---');
_sink.write(macroGenerated.code);
_sink.writeln('---');
}
}
_writeDocumentation(e);
_writeMetadata(e);
_writeSinceSdkVersion(e);
if (configuration.withImports) {
var imports = e.libraryImports.where((import) {
return configuration.withSyntheticDartCoreImport || !import.isSynthetic;
}).toList();
_writeElements(
'libraryImports',
imports,
_writeLibraryImportElement,
);
_writeElements('prefixes', e.prefixes, _writePrefixElement);
}
_writeElements(
'libraryExports',
e.libraryExports,
_writeLibraryExportElement,
);
var definingUnit = e.definingCompilationUnit;
expect(definingUnit.libraryOrAugmentationElement, same(e));
if (configuration.filter(definingUnit)) {
_sink.writelnWithIndent('definingUnit');
_sink.withIndent(() {
_writeUnitElement(definingUnit);
});
}
if (e is LibraryElementImpl) {
_writeLibraryAugmentations(e);
}
_writeElements('augmentationImports', e.augmentationImports,
_writeAugmentationImportElement);
}
void _writeMacroDiagnostics(Element e) {
void writeTypeAnnotationLocation(TypeAnnotationLocation location) {
switch (location) {
case AliasedTypeLocation():
writeTypeAnnotationLocation(location.parent);
_sink.writelnWithIndent('AliasedTypeLocation');
case ElementTypeLocation():
_sink.writelnWithIndent('ElementTypeLocation');
_sink.withIndent(() {
_elementPrinter.writeNamedElement('element', location.element);
});
case ExtendsClauseTypeLocation():
writeTypeAnnotationLocation(location.parent);
_sink.writelnWithIndent('ExtendsClauseTypeLocation');
case FormalParameterTypeLocation():
writeTypeAnnotationLocation(location.parent);
_sink.writelnWithIndent('FormalParameterTypeLocation');
_sink.withIndent(() {
_sink.writelnWithIndent('index: ${location.index}');
});
case ListIndexTypeLocation():
writeTypeAnnotationLocation(location.parent);
_sink.writelnWithIndent('ListIndexTypeLocation');
_sink.withIndent(() {
_sink.writelnWithIndent('index: ${location.index}');
});
case RecordNamedFieldTypeLocation():
writeTypeAnnotationLocation(location.parent);
_sink.writelnWithIndent('RecordNamedFieldTypeLocation');
_sink.withIndent(() {
_sink.writelnWithIndent('index: ${location.index}');
});
case RecordPositionalFieldTypeLocation():
writeTypeAnnotationLocation(location.parent);
_sink.writelnWithIndent('RecordPositionalFieldTypeLocation');
_sink.withIndent(() {
_sink.writelnWithIndent('index: ${location.index}');
});
case ReturnTypeLocation():
writeTypeAnnotationLocation(location.parent);
_sink.writelnWithIndent('ReturnTypeLocation');
case VariableTypeLocation():
writeTypeAnnotationLocation(location.parent);
_sink.writelnWithIndent('VariableTypeLocation');
default:
// TODO(scheglov): Handle this case.
throw UnimplementedError('${location.runtimeType}');
}
}
/// Returns `true` if patterns were printed.
/// Returns `false` if no patterns configured.
bool printMessagePatterns(String message) {
var patterns = configuration.macroDiagnosticMessagePatterns;
if (patterns == null) {
return false;
}
_sink.writelnWithIndent('contains');
_sink.withIndent(() {
for (var pattern in patterns) {
if (message.contains(pattern)) {
_sink.writelnWithIndent(pattern);
}
}
});
return true;
}
void writeMessage(MacroDiagnosticMessage object) {
// Write the message.
if (!printMessagePatterns(object.message)) {
var message = object.message;
const stackTraceText = '#0';
var stackTraceIndex = message.indexOf(stackTraceText);
if (stackTraceIndex >= 0) {
var end = stackTraceIndex + stackTraceText.length;
var withoutStackTrace = message.substring(0, end);
if (configuration.withMacroStackTraces) {
_sink.writelnWithIndent('message:\n$message');
} else {
_sink.writelnWithIndent('message:\n$withoutStackTrace <cut>');
}
} else {
_sink.writelnWithIndent('message: $message');
}
}
// Write the target.
var target = object.target;
switch (target) {
case ApplicationMacroDiagnosticTarget():
_sink.writelnWithIndent('target: ApplicationMacroDiagnosticTarget');
_sink.withIndent(() {
_sink.writelnWithIndent(
'annotationIndex: ${target.annotationIndex}',
);
});
case ElementMacroDiagnosticTarget():
_sink.writelnWithIndent('target: ElementMacroDiagnosticTarget');
_sink.withIndent(() {
_elementPrinter.writeNamedElement('element', target.element);
});
case ElementAnnotationMacroDiagnosticTarget():
_sink.writelnWithIndent(
'target: ElementAnnotationMacroDiagnosticTarget',
);
_sink.withIndent(() {
_elementPrinter.writeNamedElement('element', target.element);
_sink.writelnWithIndent(
'annotationIndex: ${target.annotationIndex}',
);
});
case TypeAnnotationMacroDiagnosticTarget():
_sink.writelnWithIndent(
'target: TypeAnnotationMacroDiagnosticTarget',
);
_sink.withIndent(() {
writeTypeAnnotationLocation(target.location);
});
}
}
if (e case MacroTargetElement macroTarget) {
_sink.writeElements(
'macroDiagnostics',
macroTarget.macroDiagnostics,
(diagnostic) {
switch (diagnostic) {
case ArgumentMacroDiagnostic():
_sink.writelnWithIndent('ArgumentMacroDiagnostic');
_sink.withIndent(() {
_sink.writelnWithIndent(
'annotationIndex: ${diagnostic.annotationIndex}',
);
_sink.writelnWithIndent(
'argumentIndex: ${diagnostic.argumentIndex}',
);
_sink.writelnWithIndent('message: ${diagnostic.message}');
});
case DeclarationsIntrospectionCycleDiagnostic():
_sink.writelnWithIndent(
'DeclarationsIntrospectionCycleDiagnostic',
);
_sink.withIndent(() {
_sink.writelnWithIndent(
'annotationIndex: ${diagnostic.annotationIndex}',
);
_elementPrinter.writeNamedElement(
'introspectedElement',
diagnostic.introspectedElement,
);
_sink.writeElements(
'components',
diagnostic.components,
(component) {
_sink.writelnWithIndent(
'DeclarationsIntrospectionCycleComponent',
);
_sink.withIndent(() {
_elementPrinter.writeNamedElement(
'element',
component.element,
);
_sink.writelnWithIndent(
'annotationIndex: ${component.annotationIndex}',
);
_elementPrinter.writeNamedElement(
'introspectedElement',
component.introspectedElement,
);
});
},
);
});
case ExceptionMacroDiagnostic():
_sink.writelnWithIndent('ExceptionMacroDiagnostic');
_sink.withIndent(() {
_sink.writelnWithIndent(
'annotationIndex: ${diagnostic.annotationIndex}',
);
if (!printMessagePatterns(diagnostic.message)) {
_sink.writelnWithIndent(
'message: ${diagnostic.message}',
);
}
if (configuration.withMacroStackTraces) {
_sink.writelnWithIndent(
'stackTrace:\n${diagnostic.stackTrace}',
);
}
});
case InvalidMacroTargetDiagnostic():
_sink.writelnWithIndent('InvalidMacroTargetDiagnostic');
_sink.withIndent(() {
_sink.writelnWithIndent(
'annotationIndex: ${diagnostic.annotationIndex}',
);
_sink.writeElements(
'supportedKinds',
diagnostic.supportedKinds,
(kindName) {
_sink.writelnWithIndent(kindName);
},
);
});
case MacroDiagnostic():
_sink.writelnWithIndent('MacroDiagnostic');
_sink.withIndent(() {
_sink.writelnWithIndent('message: MacroDiagnosticMessage');
_sink.withIndent(() {
writeMessage(diagnostic.message);
});
_sink.writeElements(
'contextMessages',
diagnostic.contextMessages,
(message) {
_sink.writelnWithIndent('MacroDiagnosticMessage');
_sink.withIndent(() {
writeMessage(message);
});
},
);
_sink.writelnWithIndent(
'severity: ${diagnostic.severity.name}',
);
if (diagnostic.correctionMessage case var correctionMessage?) {
_sink.writelnWithIndent(
'correctionMessage: $correctionMessage',
);
}
});
case NotAllowedDeclarationDiagnostic():
_sink.writelnWithIndent('NotAllowedDeclarationDiagnostic');
_sink.withIndent(() {
_sink.writelnWithIndent(
'annotationIndex: ${diagnostic.annotationIndex}',
);
_sink.writelnWithIndent(
'phase: ${diagnostic.phase.name}',
);
var nodeRangesStr = diagnostic.nodeRanges
.map((r) => '(${r.offset}, ${r.length})')
.join(' ');
_sink.writelnWithIndent('nodeRanges: $nodeRangesStr');
_sink.writeln('---');
_sink.write(diagnostic.code);
_sink.writeln('---');
});
}
},
);
}
}
void _writeMetadata(Element element) {
if (configuration.withMetadata) {
var annotations = element.metadata;
if (annotations.isNotEmpty) {
_sink.writelnWithIndent('metadata');
_sink.withIndent(() {
for (var annotation in annotations) {
annotation as ElementAnnotationImpl;
_writeNode(annotation.annotationAst);
}
});
}
}
}
void _writeMethodElement(MethodElementImpl e) {
_sink.writeIndentedLine(() {
_sink.writeIf(e.isAugmentation, 'augment ');
_sink.writeIf(e.isSynthetic, 'synthetic ');
_sink.writeIf(e.isStatic, 'static ');
_sink.writeIf(e.isAbstract, 'abstract ');
_sink.writeIf(e.isExternal, 'external ');
_writeName(e);
_writeBodyModifiers(e);
});
_sink.withIndent(() {
_writeReference(e);
_writeEnclosingElement(e);
_writeDocumentation(e);
_writeMetadata(e);
_writeSinceSdkVersion(e);
_writeCodeRange(e);
_writeTypeInferenceError(e);
_writeTypeParameterElements(e.typeParameters);
_writeParameterElements(e.parameters);
_writeReturnType(e.returnType);
_writeNonSyntheticElement(e);
_writeMacroDiagnostics(e);
_writeAugmentationTarget(e);
_writeAugmentation(e);
});
if (e.isSynthetic && e.enclosingElement is EnumElementImpl) {
expect(e.name, 'toString');
expect(e.nonSynthetic, same(e.enclosingElement));
} else {
_assertNonSyntheticElementSelf(e);
}
}
void _writeMethods(List<MethodElementImpl> elements) {
_writeElements('methods', elements, _writeMethodElement);
}
void _writeName(Element e) {
String name;
switch (e) {
case ExtensionElement(name: null):
name = '<null>';
default:
name = e.name!;
}
if (e is PropertyAccessorElement && e.isSetter) {
expect(name, endsWith('='));
}
_sink.write(name);
_sink.write(name.isNotEmpty ? ' @' : '@');
_sink.write(e.nameOffset);
}
void _writeNamespaceCombinator(NamespaceCombinator e) {
_sink.writeIndentedLine(() {
if (e is ShowElementCombinator) {
_sink.write('show: ');
_sink.write(e.shownNames.join(', '));
} else if (e is HideElementCombinator) {
_sink.write('hide: ');
_sink.write(e.hiddenNames.join(', '));
}
});
}
void _writeNamespaceCombinators(List<NamespaceCombinator> elements) {
_writeElements('combinators', elements, _writeNamespaceCombinator);
}
void _writeNode(AstNode node) {
_sink.writeIndent();
node.accept(
_createAstPrinter(),
);
}
void _writeNonSyntheticElement(Element e) {
if (configuration.withNonSynthetic) {
_elementPrinter.writeNamedElement('nonSynthetic', e.nonSynthetic);
}
}
void _writeNotSimplyBounded(InterfaceElementImpl e) {
if (e.isAugmentation) {
return;
}
_sink.writeIf(!e.isSimplyBounded, 'notSimplyBounded ');
}
void _writeParameterElement(ParameterElement e) {
e as ParameterElementImpl;
if (e.isNamed && e.enclosingElement is ExecutableElement) {
expect(e.reference, isNotNull);
} else {
expect(e.reference, isNull);
}
_sink.writeIndentedLine(() {
if (e.isRequiredPositional) {
_sink.write('requiredPositional ');
} else if (e.isOptionalPositional) {
_sink.write('optionalPositional ');
} else if (e.isRequiredNamed) {
_sink.write('requiredNamed ');
} else if (e.isOptionalNamed) {
_sink.write('optionalNamed ');
}
if (e is ConstVariableElement) {
_sink.write('default ');
}
_sink.writeIf(e.isConst, 'const ');
_sink.writeIf(e.isCovariant, 'covariant ');
_sink.writeIf(e.isFinal, 'final ');
if (e is FieldFormalParameterElement) {
_sink.write('this.');
} else if (e is SuperFormalParameterElement) {
_sink.writeIf(e.hasDefaultValue, 'hasDefaultValue ');
_sink.write('super.');
}
_writeName(e);
});
_sink.withIndent(() {
_writeReference(e);
_writeType('type', e.type);
_writeMetadata(e);
_writeSinceSdkVersion(e);
_writeCodeRange(e);
_writeTypeParameterElements(e.typeParameters);
_writeParameterElements(e.parameters);
_writeConstantInitializer(e);
_writeNonSyntheticElement(e);
_writeFieldFormalParameterField(e);
_writeSuperConstructorParameter(e);
});
}
void _writeParameterElements(List<ParameterElement> elements) {
_writeElements('parameters', elements, _writeParameterElement);
}
void _writePartElement(
PartElementImpl e, {
required bool onlyId,
}) {
_sink.writelnWithIndent(_idMap[e]);
if (onlyId) {
return;
}
_sink.withIndent(() {
var uri = e.uri;
_sink.writeIndentedLine(() {
_sink.write('uri: ');
_writeDirectiveUri(e.uri);
});
_writeMetadata(e);
if (uri is DirectiveUriWithUnitImpl) {
_writeUnitElement(uri.unit);
}
});
}
void _writePrefixElement(PrefixElementImpl e) {
_sink.writeIndentedLine(() {
_writeName(e);
});
_sink.withIndent(() {
_writeReference(e);
_writeEnclosingElement(e);
});
}
void _writePropertyAccessorElement(PropertyAccessorElement e) {
e as PropertyAccessorElementImpl;
var variable = e.variable2;
if (variable != null) {
var variableEnclosing = variable.enclosingElement;
if (variableEnclosing is CompilationUnitElement) {
expect(variableEnclosing.topLevelVariables, contains(variable));
} else if (variableEnclosing is InterfaceElement) {
expect(variableEnclosing.fields, contains(variable));
}
} else {
expect(e.isAugmentation, isTrue);
expect(e.augmentationTarget, isNull);
}
if (e.isSynthetic) {
expect(e.nameOffset, -1);
} else {
expect(e.nameOffset, isPositive);
_assertNonSyntheticElementSelf(e);
}
_sink.writeIndentedLine(() {
_sink.writeIf(e.isAugmentation, 'augment ');
_sink.writeIf(e.isSynthetic, 'synthetic ');
_sink.writeIf(e.isStatic, 'static ');
_sink.writeIf(e.isAbstract, 'abstract ');
_sink.writeIf(e.isExternal, 'external ');
if (e.isGetter) {
_sink.write('get ');
} else {
_sink.write('set ');
}
_writeName(e);
_writeBodyModifiers(e);
});
void writeLinking() {
if (configuration.withPropertyLinking) {
_sink.writelnWithIndent('id: ${_idMap[e]}');
if (e.variable2 case var variable?) {
_sink.writelnWithIndent('variable: ${_idMap[variable]}');
} else {
_sink.writelnWithIndent('variable: <null>');
}
}
}
_sink.withIndent(() {
_writeReference(e);
_writeEnclosingElement(e);
_writeDocumentation(e);
_writeMetadata(e);
_writeSinceSdkVersion(e);
_writeCodeRange(e);
expect(e.typeParameters, isEmpty);
_writeParameterElements(e.parameters);
_writeReturnType(e.returnType);
_writeNonSyntheticElement(e);
writeLinking();
_writeMacroDiagnostics(e);
_writeAugmentationTarget(e);
_writeAugmentation(e);
});
}
void _writePropertyInducingElement(PropertyInducingElement e) {
e as PropertyInducingElementImpl;
DartType type = e.type;
expect(type, isNotNull);
if (e.isSynthetic) {
expect(e.nameOffset, -1);
} else {
if (!e.isAugmentation) {
expect(e.getter, isNotNull);
}
expect(e.nameOffset, isPositive);
_assertNonSyntheticElementSelf(e);
}
_sink.writeIndentedLine(() {
_sink.writeIf(e.isAugmentation, 'augment ');
_sink.writeIf(e.isSynthetic, 'synthetic ');
_sink.writeIf(e.isStatic, 'static ');
_sink.writeIf(e is FieldElementImpl && e.isAbstract, 'abstract ');
_sink.writeIf(e is FieldElementImpl && e.isCovariant, 'covariant ');
_sink.writeIf(e is FieldElementImpl && e.isExternal, 'external ');
_sink.writeIf(e.isLate, 'late ');
_sink.writeIf(e.isFinal, 'final ');
_sink.writeIf(e.isConst, 'const ');
if (e is FieldElementImpl) {
_sink.writeIf(e.isEnumConstant, 'enumConstant ');
_sink.writeIf(e.isPromotable, 'promotable ');
}
_writeName(e);
});
void writeLinking() {
if (configuration.withPropertyLinking) {
_sink.writelnWithIndent('id: ${_idMap[e]}');
var getter = e.getter;
if (getter != null) {
_sink.writelnWithIndent('getter: ${_idMap[getter]}');
}
var setter = e.setter;
if (setter != null) {
_sink.writelnWithIndent('setter: ${_idMap[setter]}');
}
}
}
_sink.withIndent(() {
_writeReference(e);
_writeEnclosingElement(e);
_writeDocumentation(e);
_writeMetadata(e);
_writeSinceSdkVersion(e);
_writeCodeRange(e);
_writeTypeInferenceError(e);
_writeType('type', e.type);
_writeShouldUseTypeForInitializerInference(e);
_writeConstantInitializer(e);
_writeNonSyntheticElement(e);
writeLinking();
_writeMacroDiagnostics(e);
_writeAugmentationTarget(e);
_writeAugmentation(e);
});
}
void _writeReference(ElementImpl e) {
if (e.reference case var reference?) {
_sink.writeIndentedLine(() {
_sink.write('reference: ');
_elementPrinter.writeReference(reference);
});
}
}
void _writeReturnType(DartType type) {
if (configuration.withReturnType) {
_writeType('returnType', type);
}
}
void _writeShouldUseTypeForInitializerInference(
PropertyInducingElementImpl e,
) {
if (e.isSynthetic) return;
if (!e.hasInitializer) return;
_sink.writelnWithIndent(
'shouldUseTypeForInitializerInference: '
'${e.shouldUseTypeForInitializerInference}',
);
}
void _writeSinceSdkVersion(Element e) {
var sinceSdkVersion = e.sinceSdkVersion;
if (sinceSdkVersion != null) {
_sink.writelnWithIndent('sinceSdkVersion: $sinceSdkVersion');
}
}
void _writeSuperConstructorParameter(ParameterElement e) {
if (e is SuperFormalParameterElement) {
var superParameter = e.superConstructorParameter;
if (superParameter != null) {
_elementPrinter.writeNamedElement(
'superConstructorParameter',
superParameter,
);
} else {
_sink.writelnWithIndent('superConstructorParameter: <null>');
}
}
}
void _writeType(String name, DartType type) {
_elementPrinter.writeNamedType(name, type);
if (configuration.withFunctionTypeParameters) {
if (type is FunctionType) {
_sink.withIndent(() {
_writeParameterElements(type.parameters);
});
}
}
}
void _writeTypeAliasElement(TypeAliasElement e) {
e as TypeAliasElementImpl;
_sink.writeIndentedLine(() {
_sink.writeIf(e.isAugmentation, 'augment ');
_sink.writeIf(e.isFunctionTypeAliasBased, 'functionTypeAliasBased ');
_sink.writeIf(!e.isSimplyBounded, 'notSimplyBounded ');
_writeName(e);
});
_sink.withIndent(() {
_writeReference(e);
_writeDocumentation(e);
_writeMetadata(e);
_writeSinceSdkVersion(e);
_writeCodeRange(e);
_writeTypeParameterElements(e.typeParameters);
var aliasedType = e.aliasedType;
_writeType('aliasedType', aliasedType);
var aliasedElement = e.aliasedElement;
if (aliasedElement is GenericFunctionTypeElementImpl) {
_sink.writelnWithIndent('aliasedElement: GenericFunctionTypeElement');
_sink.withIndent(() {
_writeTypeParameterElements(aliasedElement.typeParameters);
_writeParameterElements(aliasedElement.parameters);
_writeReturnType(aliasedElement.returnType);
});
}
_writeMacroDiagnostics(e);
_writeAugmentationTarget(e);
_writeAugmentation(e);
});
_assertNonSyntheticElementSelf(e);
}
void _writeTypeInferenceError(Element e) {
TopLevelInferenceError? inferenceError;
if (e is MethodElementImpl) {
inferenceError = e.typeInferenceError;
} else if (e is PropertyInducingElementImpl) {
inferenceError = e.typeInferenceError;
}
if (inferenceError != null) {
String kindName = inferenceError.kind.toString();
if (kindName.startsWith('TopLevelInferenceErrorKind.')) {
kindName = kindName.substring('TopLevelInferenceErrorKind.'.length);
}
_sink.writelnWithIndent('typeInferenceError: $kindName');
_sink.withIndent(() {
if (kindName == 'dependencyCycle') {
_sink.writelnWithIndent('arguments: ${inferenceError?.arguments}');
}
});
}
}
void _writeTypeParameterElement(TypeParameterElement e) {
e as TypeParameterElementImpl;
_sink.writeIndentedLine(() {
_sink.write('${e.variance.name} ');
_writeName(e);
});
_sink.withIndent(() {
_writeCodeRange(e);
var bound = e.bound;
if (bound != null) {
_writeType('bound', bound);
}
var defaultType = e.defaultType;
if (defaultType != null) {
_writeType('defaultType', defaultType);
}
_writeMetadata(e);
});
_assertNonSyntheticElementSelf(e);
}
void _writeTypeParameterElements(List<TypeParameterElement> elements) {
_writeElements('typeParameters', elements, _writeTypeParameterElement);
}
void _writeUnitElement(CompilationUnitElementImpl e) {
_writeReference(e);
_writeEnclosingElement(e);
if (configuration.withImports) {
var imports = e.libraryImports.where((import) {
return configuration.withSyntheticDartCoreImport || !import.isSynthetic;
}).toList();
_writeElements('libraryImports', imports, _writeLibraryImportElement);
}
_writeElements(
'libraryImportPrefixes',
e.libraryImportPrefixes,
_writePrefixElement,
);
_writeElements(
'libraryExports', e.libraryExports, _writeLibraryExportElement);
_writeElements('parts', e.parts, (part) {
_writePartElement(part, onlyId: true);
});
_writeElements('classes', e.classes, _writeInterfaceElement);
_writeElements('enums', e.enums, _writeInterfaceElement);
_writeElements('extensions', e.extensions, _writeExtensionElement);
_writeElements(
'extensionTypes',
e.extensionTypes,
_writeInterfaceElement,
);
_writeElements('mixins', e.mixins, _writeInterfaceElement);
_writeElements('typeAliases', e.typeAliases, _writeTypeAliasElement);
_writeElements(
'topLevelVariables',
e.topLevelVariables,
_writePropertyInducingElement,
);
_writeElements(
'accessors',
e.accessors,
_writePropertyAccessorElement,
);
_writeElements('functions', e.functions, _writeFunctionElement);
}
}
class _IdMap {
final Map<Element, String> fieldMap = Map.identity();
final Map<Element, String> getterMap = Map.identity();
final Map<Element, String> partMap = Map.identity();
final Map<Element, String> setterMap = Map.identity();
String operator [](Element element) {
if (element is FieldElement) {
return fieldMap[element] ??= 'field_${fieldMap.length}';
} else if (element is TopLevelVariableElement) {
return fieldMap[element] ??= 'variable_${fieldMap.length}';
} else if (element is PropertyAccessorElement && element.isGetter) {
return getterMap[element] ??= 'getter_${getterMap.length}';
} else if (element is PartElementImpl) {
return partMap[element] ??= 'part_${partMap.length}';
} else if (element is PropertyAccessorElement && element.isSetter) {
return setterMap[element] ??= 'setter_${setterMap.length}';
} else {
return '???';
}
}
}