Skip to content
This repository was archived by the owner on Nov 20, 2024. It is now read-only.

Commit 199e981

Browse files
committed
Check for documented getters when checking setters (#237).
Update `public_member_api_docs` to follow dartdoc when verifying property accessor docs. Fixes: https://github.com/dart-lang/linter/issues/237 BUG= [email protected] Review URL: https://codereview.chromium.org//1992863002 .
1 parent 601f7f9 commit 199e981

File tree

2 files changed

+137
-20
lines changed

2 files changed

+137
-20
lines changed

lib/src/rules/public_member_api_docs.dart

Lines changed: 105 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ class Sub extends Base {
5555
void init() { ... }
5656
}
5757
```
58+
59+
Note that consistent with `dartdoc`, an exception to the rule is made when
60+
documented getters have corresponding undocumented setters. In this case the
61+
setters inherit the docs from the getters.
5862
''';
5963

6064
class PublicMemberApiDocs extends LintRule {
@@ -75,10 +79,12 @@ class Visitor extends GeneralizingAstVisitor {
7579
final LintRule rule;
7680
Visitor(this.rule);
7781

78-
void check(Declaration node) {
82+
bool check(Declaration node) {
7983
if (node.documentationComment == null && !isOverridingMember(node)) {
8084
rule.reportLint(getNodeToAnnotate(node));
85+
return true;
8186
}
87+
return false;
8288
}
8389

8490
ExecutableElement getOverriddenMember(Element member) {
@@ -99,9 +105,61 @@ class Visitor extends GeneralizingAstVisitor {
99105

100106
@override
101107
visitClassDeclaration(ClassDeclaration node) {
102-
if (!isPrivate(node.name)) {
103-
check(node);
108+
if (isPrivate(node.name)) {
109+
return;
110+
}
111+
112+
check(node);
113+
114+
// Check methods
115+
116+
Map<String, MethodDeclaration> getters = <String, MethodDeclaration>{};
117+
Map<String, MethodDeclaration> setters = <String, MethodDeclaration>{};
118+
119+
// Non-getters/setters.
120+
List<MethodDeclaration> methods = <MethodDeclaration>[];
121+
122+
// Identify getter/setter pairs.
123+
for (ClassMember member in node.members) {
124+
if (member is MethodDeclaration && !isPrivate(member.name)) {
125+
if (member.isGetter) {
126+
getters[member.name.name] = member;
127+
} else if (member.isSetter) {
128+
setters[member.name.name] = member;
129+
} else {
130+
methods.add(member);
131+
}
132+
}
104133
}
134+
135+
// Check all getters, and collect offenders along the way.
136+
List<MethodDeclaration> missingDocs = <MethodDeclaration>[];
137+
for (MethodDeclaration getter in getters.values) {
138+
if (check(getter)) {
139+
missingDocs.add(getter);
140+
}
141+
}
142+
143+
// But only setters whose getter is missing a doc.
144+
for (MethodDeclaration setter in setters.values) {
145+
MethodDeclaration getter = getters[setter.name.name];
146+
if (getter == null) {
147+
//Look for an inherited getter.
148+
ExecutableElement getter =
149+
manager.lookupMember(node.element, setter.name.name);
150+
if (getter is PropertyAccessorElement) {
151+
if (getter.documentationComment != null) {
152+
continue;
153+
}
154+
}
155+
check(setter);
156+
} else if (missingDocs.contains(getter)) {
157+
check(setter);
158+
}
159+
}
160+
161+
// Check remaining methods.
162+
methods.forEach(check);
105163
}
106164

107165
@override
@@ -115,6 +173,50 @@ class Visitor extends GeneralizingAstVisitor {
115173
visitCompilationUnit(CompilationUnit node) {
116174
LibraryElement library = node?.element?.library;
117175
manager = library == null ? null : new InheritanceManager(library);
176+
177+
Map<String, FunctionDeclaration> getters = <String, FunctionDeclaration>{};
178+
Map<String, FunctionDeclaration> setters = <String, FunctionDeclaration>{};
179+
180+
// Check functions.
181+
182+
// Non-getters/setters.
183+
List<FunctionDeclaration> functions = <FunctionDeclaration>[];
184+
185+
// Identify getter/setter pairs.
186+
for (CompilationUnitMember member in node.declarations) {
187+
if (member is FunctionDeclaration) {
188+
Identifier name = member.name;
189+
if (!isPrivate(name) && name.name != 'main') {
190+
if (member.isGetter) {
191+
getters[member.name.name] = member;
192+
} else if (member.isSetter) {
193+
setters[member.name.name] = member;
194+
} else {
195+
functions.add(member);
196+
}
197+
}
198+
}
199+
}
200+
201+
// Check all getters, and collect offenders along the way.
202+
List<FunctionDeclaration> missingDocs = <FunctionDeclaration>[];
203+
for (FunctionDeclaration getter in getters.values) {
204+
if (check(getter)) {
205+
missingDocs.add(getter);
206+
}
207+
}
208+
209+
// But only setters whose getter is missing a doc.
210+
for (FunctionDeclaration setter in setters.values) {
211+
FunctionDeclaration getter = getters[setter.name.name];
212+
if (getter != null && missingDocs.contains(getter)) {
213+
check(setter);
214+
}
215+
}
216+
217+
// Check remaining functions.
218+
functions.forEach(check);
219+
118220
super.visitCompilationUnit(node);
119221
}
120222

@@ -150,30 +252,13 @@ class Visitor extends GeneralizingAstVisitor {
150252
}
151253
}
152254

153-
@override
154-
visitFunctionDeclaration(FunctionDeclaration node) {
155-
if (node.parent is! CompilationUnit) {
156-
return; // Skip inner functions.
157-
}
158-
if (!isPrivate(node.name) && node.name.name != 'main') {
159-
check(node);
160-
}
161-
}
162-
163255
@override
164256
visitFunctionTypeAlias(FunctionTypeAlias node) {
165257
if (!isPrivate(node.name)) {
166258
check(node);
167259
}
168260
}
169261

170-
@override
171-
visitMethodDeclaration(MethodDeclaration node) {
172-
if (!inPrivateMember(node) && !isPrivate(node.name)) {
173-
check(node);
174-
}
175-
}
176-
177262
@override
178263
visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
179264
for (VariableDeclaration decl in node.variables.variables) {

test/rules/public_member_api_docs.dart

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@
66

77
abstract class A //LINT
88
{
9+
10+
/// Zapp.
11+
int get zapp => 0;
12+
set zapp(int z) //OK
13+
{ }
14+
15+
int get zapp2 => 0; //LINT
16+
/// Zapp.
17+
set zapp2(int z) { }
18+
919
static const Z = 1; //LINT
1020
static int _Z = 13; //OK
1121

@@ -27,6 +37,16 @@ abstract class A //LINT
2737
c(); //LINT
2838
}
2939

40+
/// Zapp.
41+
int get zapp => 0;
42+
set zapp(int z) //OK
43+
{ }
44+
45+
int get zapp2 => 0; //LINT
46+
/// Zapp.
47+
set zapp2(int z) { }
48+
49+
3050
main() //OK
3151
{ }
3252

@@ -68,3 +88,15 @@ int _h; //OK
6888

6989
int gg, //LINT
7090
_gg; //OK
91+
92+
/// ZZ.
93+
class ZZ {
94+
/// Z.
95+
int get z => 0;
96+
}
97+
98+
/// ZZZ.
99+
class ZZZ extends ZZ {
100+
set z(int z) //OK
101+
{ }
102+
}

0 commit comments

Comments
 (0)