@@ -55,6 +55,10 @@ class Sub extends Base {
55
55
void init() { ... }
56
56
}
57
57
```
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.
58
62
''' ;
59
63
60
64
class PublicMemberApiDocs extends LintRule {
@@ -75,10 +79,12 @@ class Visitor extends GeneralizingAstVisitor {
75
79
final LintRule rule;
76
80
Visitor (this .rule);
77
81
78
- void check (Declaration node) {
82
+ bool check (Declaration node) {
79
83
if (node.documentationComment == null && ! isOverridingMember (node)) {
80
84
rule.reportLint (getNodeToAnnotate (node));
85
+ return true ;
81
86
}
87
+ return false ;
82
88
}
83
89
84
90
ExecutableElement getOverriddenMember (Element member) {
@@ -99,9 +105,61 @@ class Visitor extends GeneralizingAstVisitor {
99
105
100
106
@override
101
107
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
+ }
104
133
}
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);
105
163
}
106
164
107
165
@override
@@ -115,6 +173,50 @@ class Visitor extends GeneralizingAstVisitor {
115
173
visitCompilationUnit (CompilationUnit node) {
116
174
LibraryElement library = node? .element? .library;
117
175
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
+
118
220
super .visitCompilationUnit (node);
119
221
}
120
222
@@ -150,30 +252,13 @@ class Visitor extends GeneralizingAstVisitor {
150
252
}
151
253
}
152
254
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
-
163
255
@override
164
256
visitFunctionTypeAlias (FunctionTypeAlias node) {
165
257
if (! isPrivate (node.name)) {
166
258
check (node);
167
259
}
168
260
}
169
261
170
- @override
171
- visitMethodDeclaration (MethodDeclaration node) {
172
- if (! inPrivateMember (node) && ! isPrivate (node.name)) {
173
- check (node);
174
- }
175
- }
176
-
177
262
@override
178
263
visitTopLevelVariableDeclaration (TopLevelVariableDeclaration node) {
179
264
for (VariableDeclaration decl in node.variables.variables) {
0 commit comments