Skip to content

Commit

Permalink
Hide constructors that cannot be called or referenced by user code
Browse files Browse the repository at this point in the history
  • Loading branch information
srawlins committed Jun 24, 2024
1 parent 88df88c commit c35bb89
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 10 deletions.
12 changes: 6 additions & 6 deletions lib/src/generator/templates.runtime_renderers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2187,19 +2187,19 @@ class _Renderer_Constructor extends RendererBase<Constructor> {
self.renderSimpleVariable(c, remainingNames, 'bool'),
getBool: (CT_ c) => c.isConst,
),
'isDefaultConstructor': Property(
getValue: (CT_ c) => c.isDefaultConstructor,
'isFactory': Property(
getValue: (CT_ c) => c.isFactory,
renderVariable: (CT_ c, Property<CT_> self,
List<String> remainingNames) =>
self.renderSimpleVariable(c, remainingNames, 'bool'),
getBool: (CT_ c) => c.isDefaultConstructor,
getBool: (CT_ c) => c.isFactory,
),
'isFactory': Property(
getValue: (CT_ c) => c.isFactory,
'isPublic': Property(
getValue: (CT_ c) => c.isPublic,
renderVariable: (CT_ c, Property<CT_> self,
List<String> remainingNames) =>
self.renderSimpleVariable(c, remainingNames, 'bool'),
getBool: (CT_ c) => c.isFactory,
getBool: (CT_ c) => c.isPublic,
),
'isUnnamedConstructor': Property(
getValue: (CT_ c) => c.isUnnamedConstructor,
Expand Down
21 changes: 18 additions & 3 deletions lib/src/model/constructor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:analyzer/source/line_info.dart';
import 'package:dartdoc/src/element_type.dart';
import 'package:dartdoc/src/model/comment_referable.dart';
import 'package:dartdoc/src/model/model.dart';
import 'package:dartdoc/src/model_utils.dart';

class Constructor extends ModelElement with ContainerMember, TypeParameters {
@override
Expand All @@ -25,6 +26,23 @@ class Constructor extends ModelElement with ContainerMember, TypeParameters {
return super.characterLocation;
}

@override
bool get isPublic {
if (!super.isPublic) return false;
if (element.hasPrivateName) return false;
var class_ = element.enclosingElement;
if (class_ is! ClassElement) return true;
if (class_.isSealed ||
(class_.isAbstract && class_.isFinal) ||
(class_.isAbstract && class_.isInterface)) {
/// Sealed classes, abstract final classes, and abstract interface
/// classes, cannot be instantiated nor extended, from outside the
/// declaring library. Avoid documenting them.
return false;
}
return true;
}

@override
List<TypeParameter> get typeParameters =>
(enclosingElement as Constructable).typeParameters;
Expand Down Expand Up @@ -60,9 +78,6 @@ class Constructor extends ModelElement with ContainerMember, TypeParameters {

bool get isUnnamedConstructor => name == enclosingElement.name;

bool get isDefaultConstructor =>
isUnnamedConstructor || name == '${enclosingElement.name}.new';

bool get isFactory => element.isFactory;

@override
Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/inheriting_container.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ mixin Constructable implements InheritingContainer {
yield MapEntry(
'${constructor.enclosingElement.referenceName}.${constructor.referenceName}',
constructor);
if (constructor.isDefaultConstructor) {
if (constructor.isUnnamedConstructor) {
yield MapEntry('new', constructor);
}
}
Expand Down
135 changes: 135 additions & 0 deletions test/constructors_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// Copyright (c) 2024, 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:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';

import 'dartdoc_test_base.dart';
import 'src/utils.dart';

void main() {
defineReflectiveSuite(() {
defineReflectiveTests(ConstructorsTest);
});
}

@reflectiveTest
class ConstructorsTest extends DartdocTestBase {
@override
final libraryName = 'constructors';

void test_classIsAbstractFinal_unnamed() async {
var library = await bootPackageWithLibrary('''
abstract final class C {
/// Constructor.
C();
}
''');
var c = library.classes.named('C').constructors.first;
expect(c.name, equals('C'));
expect(c.isPublic, isFalse);
expect(c.documentationAsHtml, '<p>Constructor.</p>');
}

void test_classIsAbstractInterface_unnamed() async {
var library = await bootPackageWithLibrary('''
abstract interface class C {
/// Constructor.
C();
}
''');
var c = library.classes.named('C').constructors.first;
expect(c.name, equals('C'));
expect(c.isPublic, isFalse);
expect(c.documentationAsHtml, '<p>Constructor.</p>');
}

void test_classIsPrivate_named() async {
var library = await bootPackageWithLibrary('''
class C {
/// Constructor.
C._();
}
''');
var c = library.classes.named('C').constructors.first;
expect(c.name, equals('C._'));
expect(c.isPublic, isFalse);
expect(c.documentationAsHtml, '<p>Constructor.</p>');
}

void test_classIsPrivate_unnamed() async {
var library = await bootPackageWithLibrary('''
class _C {
/// Constructor.
_C();
}
''');
var c = library.classes.named('_C').constructors.first;
expect(c.name, equals('_C'));
expect(c.isPublic, isFalse);
expect(c.documentationAsHtml, '<p>Constructor.</p>');
}

void test_classIsPublic_default() async {
var library = await bootPackageWithLibrary('''
class C {}
''');
var c = library.classes.named('C').constructors.first;
expect(c.name, equals('C'));
expect(c.isPublic, isTrue);
expect(c.documentationAsHtml, '');
}

void test_classIsPublic_named() async {
var library = await bootPackageWithLibrary('''
class C {
/// Constructor.
C.named();
}
''');
var c = library.classes.named('C').constructors.first;
expect(c.name, equals('C.named'));
expect(c.isPublic, isTrue);
expect(c.documentationAsHtml, '<p>Constructor.</p>');
}

void test_classIsPublic_unnamed() async {
var library = await bootPackageWithLibrary('''
class C {
/// Constructor.
C();
}
''');
var c = library.classes.named('C').constructors.first;
expect(c.name, equals('C'));
expect(c.isPublic, isTrue);
expect(c.documentationAsHtml, '<p>Constructor.</p>');
}

void test_classIsPublic_unnamed_explicitNew() async {
var library = await bootPackageWithLibrary('''
class C {
/// Constructor.
C.new();
}
''');
var c = library.classes.named('C').constructors.first;
expect(c.name, equals('C'));
expect(c.isPublic, isTrue);
expect(c.documentationAsHtml, '<p>Constructor.</p>');
}

void test_classIsSealed_unnamed() async {
var library = await bootPackageWithLibrary('''
sealed class C {
/// Constructor.
C();
}
''');
var c = library.classes.named('C').constructors.first;
expect(c.name, equals('C'));
expect(c.isPublic, isFalse);
expect(c.documentationAsHtml, '<p>Constructor.</p>');
}
}

0 comments on commit c35bb89

Please sign in to comment.