Skip to content

Commit

Permalink
Support changes for induced modifiers in analyzer (#3371)
Browse files Browse the repository at this point in the history
* Initial implementation

* induced modifiers support

* Fix up tests and clean up unused bits we might do later
  • Loading branch information
jcollins-g committed Mar 23, 2023
1 parent 203a5e6 commit a094d22
Show file tree
Hide file tree
Showing 8 changed files with 502 additions and 376 deletions.
670 changes: 336 additions & 334 deletions lib/resources/docs.dart.js

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions lib/resources/docs.dart.js.map

Large diffs are not rendered by default.

44 changes: 22 additions & 22 deletions lib/src/generator/templates.runtime_renderers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6807,6 +6807,20 @@ class _Renderer_InheritingContainer extends RendererBase<InheritingContainer> {
_render_Field(e, ast, r.template, sink, parent: r));
},
),
'containerModifiers': Property(
getValue: (CT_ c) => c.containerModifiers,
renderVariable: (CT_ c, Property<CT_> self,
List<String> remainingNames) =>
self.renderSimpleVariable(
c, remainingNames, 'List<ContainerModifier>'),
renderIterable: (CT_ c, RendererBase<CT_> r,
List<MustachioNode> ast, StringSink sink) {
return c.containerModifiers.map((e) => renderSimple(
e, ast, r.template, sink,
parent: r,
getters: _invisibleGetters['ContainerModifier']!));
},
),
'declaredFields': Property(
getValue: (CT_ c) => c.declaredFields,
renderVariable: (CT_ c, Property<CT_> self,
Expand Down Expand Up @@ -7092,28 +7106,6 @@ class _Renderer_InheritingContainer extends RendererBase<InheritingContainer> {
parent: r);
},
),
'modifiers': Property(
getValue: (CT_ c) => c.modifiers,
renderVariable:
(CT_ c, Property<CT_> self, List<String> remainingNames) {
if (remainingNames.isEmpty) {
return self.getValue(c).toString();
}
var name = remainingNames.first;
var nextProperty =
_Renderer_String.propertyMap().getValue(name);
return nextProperty.renderVariable(
self.getValue(c) as String,
nextProperty,
[...remainingNames.skip(1)]);
},
isNullValue: (CT_ c) => false,
renderValue: (CT_ c, RendererBase<CT_> r,
List<MustachioNode> ast, StringSink sink) {
_render_String(c.modifiers, ast, r.template, sink,
parent: r);
},
),
'publicInheritedFields': Property(
getValue: (CT_ c) => c.publicInheritedFields,
renderVariable: (CT_ c, Property<CT_> self,
Expand Down Expand Up @@ -15847,6 +15839,14 @@ const _invisibleGetters = {
'returnType',
'runtimeType'
},
'ContainerModifier': {
'displayName',
'hashCode',
'hideIfPresent',
'name',
'order',
'runtimeType'
},
'Context': {'current', 'hashCode', 'runtimeType', 'separator', 'style'},
'DartType': {
'alias',
Expand Down
6 changes: 3 additions & 3 deletions lib/src/model/class.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class Class extends InheritingContainer
bool get isAbstract => element.isAbstract;

@override
bool get isBase => element.isBase;
bool get isBase => element.isBase && !element.isSealed;

bool get isErrorOrException {
bool isError(InterfaceElement element) =>
Expand All @@ -64,10 +64,10 @@ class Class extends InheritingContainer
}

@override
bool get isFinal => element.isFinal;
bool get isFinal => element.isFinal && !element.isSealed;

@override
bool get isInterface => element.isInterface;
bool get isInterface => element.isInterface && !element.isSealed;

@override
bool get isMixinClass => element.isMixinClass;
Expand Down
50 changes: 50 additions & 0 deletions lib/src/model/container_modifiers.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) 2023, 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:collection/collection.dart' show IterableExtension;

/// Represents a single modifier applicable to containers.
class ContainerModifier implements Comparable<ContainerModifier> {
final String name;
final String displayName;

/// If this modifier is present with any of these modifiers, it should
/// not be displayed as part of a fullKind prefix.
final Set<ContainerModifier> hideIfPresent;

/// The display order of this modifier.
final int order;
const ContainerModifier._(
this.name, {
required this.order,
String? displayName,
Set<ContainerModifier>? hideIfPresent,
}) : displayName = displayName ?? name,
hideIfPresent = hideIfPresent ?? const <ContainerModifier>{};

@override
String toString() => displayName;

@override
int compareTo(ContainerModifier a) => order.compareTo(a.order);

static const ContainerModifier sealed =
ContainerModifier._('sealed', order: 0);
static const ContainerModifier abstract =
ContainerModifier._('abstract', order: 0, hideIfPresent: {sealed});
static const ContainerModifier base = ContainerModifier._('base', order: 1);
static const ContainerModifier interface =
ContainerModifier._('interface', order: 2);
static const ContainerModifier finalModifier =
ContainerModifier._('final', order: 3);
static const ContainerModifier mixin = ContainerModifier._('mixin', order: 4);
}

extension ContainerModifiers on Iterable<ContainerModifier> {
/// Returns a string suitable for prefixing the class name in Dartdoc
/// title bars based on given modifiers.
String modifiersAsFullKindPrefix() => sorted((a, b) => a.compareTo(b))
.where((m) => !m.hideIfPresent.any(contains))
.join(' ');
}
23 changes: 11 additions & 12 deletions lib/src/model/inheriting_container.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:analyzer/dart/element/type.dart';
import 'package:collection/collection.dart' show IterableExtension;
import 'package:dartdoc/src/element_type.dart';
import 'package:dartdoc/src/model/comment_referable.dart';
import 'package:dartdoc/src/model/container_modifiers.dart';
import 'package:dartdoc/src/model/extension_target.dart';
import 'package:dartdoc/src/model/model.dart';
import 'package:dartdoc/src/model_utils.dart' as model_utils;
Expand Down Expand Up @@ -86,16 +87,14 @@ abstract class InheritingContainer extends Container
/// Class modifiers from the Dart feature specification.
///
/// These apply to or have some meaning for [Class]es and [Mixin]s.
late String modifiers = [
if (isSealed) 'sealed' else if (isAbstract) 'abstract',
if (isBase)
'base'
else if (isInterface)
'interface'
else if (isFinal)
'final',
if (isMixinClass) 'mixin',
].join(' ');
late List<ContainerModifier> containerModifiers = [
if (isAbstract) ContainerModifier.abstract,
if (isSealed) ContainerModifier.sealed,
if (isBase) ContainerModifier.base,
if (isInterface) ContainerModifier.interface,
if (isFinal) ContainerModifier.finalModifier,
if (isMixinClass) ContainerModifier.mixin,
];

late final List<ModelElement> _allModelElements = [
...super.allModelElements,
Expand Down Expand Up @@ -269,8 +268,8 @@ abstract class InheritingContainer extends Container
Library get enclosingElement => library;

String get fullkind {
if (modifiers.isNotEmpty) {
return '$modifiers $kind';
if (containerModifiers.isNotEmpty) {
return '${containerModifiers.modifiersAsFullKindPrefix()} $kind';
}
return kind;
}
Expand Down
46 changes: 46 additions & 0 deletions test/class_modifiers_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,50 @@ base mixin O {}
expect(Nmixin.fullkind, equals('mixin'));
expect(Omixin.fullkind, equals('base mixin'));
}

void test_abstractSealed() async {
var library = await bootPackageWithLibrary('''
abstract class A {}
sealed class B extends A {}
''');
var Bclass = library.classes.named('B');
expect(Bclass.fullkind, equals('sealed class')); // *not* sealed abstract
}

void test_inferredModifiers() async {
var library = await bootPackageWithLibrary('''
base class A {}
sealed class B extends A {}
base class C extends B {}
interface class D {}
sealed class E extends D {}
interface class F extends E {}
final class G {}
sealed class H extends G {}
final class I extends H {}
class J {}
base mixin K on J {}
sealed class L extends J with K {}
base class M extends L {}
''');
var Bclass = library.classes.named('B');
var Cclass = library.classes.named('C');
var Eclass = library.classes.named('E');
var Fclass = library.classes.named('F');
var Hclass = library.classes.named('H');
var Iclass = library.classes.named('I');
var Lclass = library.classes.named('L');
var Mclass = library.classes.named('M');
expect(Bclass.fullkind, equals('sealed class')); // *not* sealed base
expect(Cclass.fullkind, equals('base class'));
expect(Eclass.fullkind, equals('sealed class'));
expect(Fclass.fullkind, equals('interface class'));
expect(Hclass.fullkind, equals('sealed class'));
expect(Iclass.fullkind, equals('final class'));
expect(Lclass.fullkind, equals('sealed class'));
expect(Mclass.fullkind, equals('base class'));
}
}
29 changes: 29 additions & 0 deletions test/container_modifiers_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) 2023, 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:dartdoc/src/model/container_modifiers.dart';
import 'package:test/test.dart';

void main() {
group('fullKind string tests', () {
test('basic', () {
var l = {
ContainerModifier.base,
ContainerModifier.interface,
ContainerModifier.abstract
};
expect(l.modifiersAsFullKindPrefix(), equals('abstract base interface'));
});

test('hide abstract on sealed', () {
var l = {ContainerModifier.abstract, ContainerModifier.sealed};
expect(l.modifiersAsFullKindPrefix(), equals('sealed'));
});

test('empty', () {
var l = <ContainerModifier>{};
expect(l.modifiersAsFullKindPrefix(), equals(''));
});
});
}

0 comments on commit a094d22

Please sign in to comment.