Skip to content

Commit 9c0975a

Browse files
committed
Hide constructors that cannot be called or referenced by user code
1 parent 88df88c commit 9c0975a

File tree

4 files changed

+174
-10
lines changed

4 files changed

+174
-10
lines changed

lib/src/generator/templates.runtime_renderers.dart

+6-6
Original file line numberDiff line numberDiff line change
@@ -2187,19 +2187,19 @@ class _Renderer_Constructor extends RendererBase<Constructor> {
21872187
self.renderSimpleVariable(c, remainingNames, 'bool'),
21882188
getBool: (CT_ c) => c.isConst,
21892189
),
2190-
'isDefaultConstructor': Property(
2191-
getValue: (CT_ c) => c.isDefaultConstructor,
2190+
'isFactory': Property(
2191+
getValue: (CT_ c) => c.isFactory,
21922192
renderVariable: (CT_ c, Property<CT_> self,
21932193
List<String> remainingNames) =>
21942194
self.renderSimpleVariable(c, remainingNames, 'bool'),
2195-
getBool: (CT_ c) => c.isDefaultConstructor,
2195+
getBool: (CT_ c) => c.isFactory,
21962196
),
2197-
'isFactory': Property(
2198-
getValue: (CT_ c) => c.isFactory,
2197+
'isPublic': Property(
2198+
getValue: (CT_ c) => c.isPublic,
21992199
renderVariable: (CT_ c, Property<CT_> self,
22002200
List<String> remainingNames) =>
22012201
self.renderSimpleVariable(c, remainingNames, 'bool'),
2202-
getBool: (CT_ c) => c.isFactory,
2202+
getBool: (CT_ c) => c.isPublic,
22032203
),
22042204
'isUnnamedConstructor': Property(
22052205
getValue: (CT_ c) => c.isUnnamedConstructor,

lib/src/model/constructor.dart

+19-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:analyzer/source/line_info.dart';
77
import 'package:dartdoc/src/element_type.dart';
88
import 'package:dartdoc/src/model/comment_referable.dart';
99
import 'package:dartdoc/src/model/model.dart';
10+
import 'package:dartdoc/src/model_utils.dart';
1011

1112
class Constructor extends ModelElement with ContainerMember, TypeParameters {
1213
@override
@@ -25,6 +26,24 @@ class Constructor extends ModelElement with ContainerMember, TypeParameters {
2526
return super.characterLocation;
2627
}
2728

29+
@override
30+
bool get isPublic {
31+
if (!super.isPublic) return false;
32+
if (element.hasPrivateName) return false;
33+
var class_ = element.enclosingElement;
34+
if (class_ is! ClassElement) return true;
35+
if (element.isFactory) return true;
36+
if (class_.isSealed ||
37+
(class_.isAbstract && class_.isFinal) ||
38+
(class_.isAbstract && class_.isInterface)) {
39+
/// Sealed classes, abstract final classes, and abstract interface
40+
/// classes, cannot be instantiated nor extended, from outside the
41+
/// declaring library. Avoid documenting them.
42+
return false;
43+
}
44+
return true;
45+
}
46+
2847
@override
2948
List<TypeParameter> get typeParameters =>
3049
(enclosingElement as Constructable).typeParameters;
@@ -60,9 +79,6 @@ class Constructor extends ModelElement with ContainerMember, TypeParameters {
6079

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

63-
bool get isDefaultConstructor =>
64-
isUnnamedConstructor || name == '${enclosingElement.name}.new';
65-
6682
bool get isFactory => element.isFactory;
6783

6884
@override

lib/src/model/inheriting_container.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ mixin Constructable implements InheritingContainer {
5959
yield MapEntry(
6060
'${constructor.enclosingElement.referenceName}.${constructor.referenceName}',
6161
constructor);
62-
if (constructor.isDefaultConstructor) {
62+
if (constructor.isUnnamedConstructor) {
6363
yield MapEntry('new', constructor);
6464
}
6565
}

test/constructors_test.dart

+148
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:test/test.dart';
6+
import 'package:test_reflective_loader/test_reflective_loader.dart';
7+
8+
import 'dartdoc_test_base.dart';
9+
import 'src/utils.dart';
10+
11+
void main() {
12+
defineReflectiveSuite(() {
13+
defineReflectiveTests(ConstructorsTest);
14+
});
15+
}
16+
17+
@reflectiveTest
18+
class ConstructorsTest extends DartdocTestBase {
19+
@override
20+
final libraryName = 'constructors';
21+
22+
void test_classIsAbstractFinal_factory() async {
23+
var library = await bootPackageWithLibrary('''
24+
abstract final class C {
25+
/// Constructor.
26+
factory C() => throw 'Nope';
27+
}
28+
''');
29+
var c = library.classes.named('C').constructors.first;
30+
expect(c.name, equals('C'));
31+
expect(c.isPublic, isTrue);
32+
expect(c.documentationAsHtml, '<p>Constructor.</p>');
33+
}
34+
35+
void test_classIsAbstractFinal_unnamed() async {
36+
var library = await bootPackageWithLibrary('''
37+
abstract final class C {
38+
/// Constructor.
39+
C();
40+
}
41+
''');
42+
var c = library.classes.named('C').constructors.first;
43+
expect(c.name, equals('C'));
44+
expect(c.isPublic, isFalse);
45+
expect(c.documentationAsHtml, '<p>Constructor.</p>');
46+
}
47+
48+
void test_classIsAbstractInterface_unnamed() async {
49+
var library = await bootPackageWithLibrary('''
50+
abstract interface class C {
51+
/// Constructor.
52+
C();
53+
}
54+
''');
55+
var c = library.classes.named('C').constructors.first;
56+
expect(c.name, equals('C'));
57+
expect(c.isPublic, isFalse);
58+
expect(c.documentationAsHtml, '<p>Constructor.</p>');
59+
}
60+
61+
void test_classIsPrivate_named() async {
62+
var library = await bootPackageWithLibrary('''
63+
class C {
64+
/// Constructor.
65+
C._();
66+
}
67+
''');
68+
var c = library.classes.named('C').constructors.first;
69+
expect(c.name, equals('C._'));
70+
expect(c.isPublic, isFalse);
71+
expect(c.documentationAsHtml, '<p>Constructor.</p>');
72+
}
73+
74+
void test_classIsPrivate_unnamed() async {
75+
var library = await bootPackageWithLibrary('''
76+
class _C {
77+
/// Constructor.
78+
_C();
79+
}
80+
''');
81+
var c = library.classes.named('_C').constructors.first;
82+
expect(c.name, equals('_C'));
83+
expect(c.isPublic, isFalse);
84+
expect(c.documentationAsHtml, '<p>Constructor.</p>');
85+
}
86+
87+
void test_classIsPublic_default() async {
88+
var library = await bootPackageWithLibrary('''
89+
class C {}
90+
''');
91+
var c = library.classes.named('C').constructors.first;
92+
expect(c.name, equals('C'));
93+
expect(c.isPublic, isTrue);
94+
expect(c.documentationAsHtml, '');
95+
}
96+
97+
void test_classIsPublic_named() async {
98+
var library = await bootPackageWithLibrary('''
99+
class C {
100+
/// Constructor.
101+
C.named();
102+
}
103+
''');
104+
var c = library.classes.named('C').constructors.first;
105+
expect(c.name, equals('C.named'));
106+
expect(c.isPublic, isTrue);
107+
expect(c.documentationAsHtml, '<p>Constructor.</p>');
108+
}
109+
110+
void test_classIsPublic_unnamed() async {
111+
var library = await bootPackageWithLibrary('''
112+
class C {
113+
/// Constructor.
114+
C();
115+
}
116+
''');
117+
var c = library.classes.named('C').constructors.first;
118+
expect(c.name, equals('C'));
119+
expect(c.isPublic, isTrue);
120+
expect(c.documentationAsHtml, '<p>Constructor.</p>');
121+
}
122+
123+
void test_classIsPublic_unnamed_explicitNew() async {
124+
var library = await bootPackageWithLibrary('''
125+
class C {
126+
/// Constructor.
127+
C.new();
128+
}
129+
''');
130+
var c = library.classes.named('C').constructors.first;
131+
expect(c.name, equals('C'));
132+
expect(c.isPublic, isTrue);
133+
expect(c.documentationAsHtml, '<p>Constructor.</p>');
134+
}
135+
136+
void test_classIsSealed_unnamed() async {
137+
var library = await bootPackageWithLibrary('''
138+
sealed class C {
139+
/// Constructor.
140+
C();
141+
}
142+
''');
143+
var c = library.classes.named('C').constructors.first;
144+
expect(c.name, equals('C'));
145+
expect(c.isPublic, isFalse);
146+
expect(c.documentationAsHtml, '<p>Constructor.</p>');
147+
}
148+
}

0 commit comments

Comments
 (0)