Index: lib/src/rules/public_member_api_docs.dart |
diff --git a/lib/src/rules/public_member_api_docs.dart b/lib/src/rules/public_member_api_docs.dart |
index 3954b039763c853b225e5189ab11e008a3d6595f..aad776d193ed1ea53f96575e3a3756ee3909babd 100644 |
--- a/lib/src/rules/public_member_api_docs.dart |
+++ b/lib/src/rules/public_member_api_docs.dart |
@@ -55,6 +55,10 @@ class Sub extends Base { |
void init() { ... } |
} |
``` |
+ |
+Note that consistent with `dartdoc`, an exception to the rule is made when |
+documented getters have corresponding undocumented setters. In this case the |
+setters inherit the docs from the getters. |
'''; |
class PublicMemberApiDocs extends LintRule { |
@@ -75,10 +79,12 @@ class Visitor extends GeneralizingAstVisitor { |
final LintRule rule; |
Visitor(this.rule); |
- void check(Declaration node) { |
+ bool check(Declaration node) { |
if (node.documentationComment == null && !isOverridingMember(node)) { |
rule.reportLint(getNodeToAnnotate(node)); |
+ return true; |
} |
+ return false; |
} |
ExecutableElement getOverriddenMember(Element member) { |
@@ -99,9 +105,61 @@ class Visitor extends GeneralizingAstVisitor { |
@override |
visitClassDeclaration(ClassDeclaration node) { |
- if (!isPrivate(node.name)) { |
- check(node); |
+ if (isPrivate(node.name)) { |
+ return; |
+ } |
+ |
+ check(node); |
+ |
+ // Check methods |
+ |
+ Map<String, MethodDeclaration> getters = <String, MethodDeclaration>{}; |
+ Map<String, MethodDeclaration> setters = <String, MethodDeclaration>{}; |
+ |
+ // Non-getters/setters. |
+ List<MethodDeclaration> methods = <MethodDeclaration>[]; |
+ |
+ // Identify getter/setter pairs. |
+ for (ClassMember member in node.members) { |
+ if (member is MethodDeclaration && !isPrivate(member.name)) { |
+ if (member.isGetter) { |
+ getters[member.name.name] = member; |
+ } else if (member.isSetter) { |
+ setters[member.name.name] = member; |
+ } else { |
+ methods.add(member); |
+ } |
+ } |
} |
+ |
+ // Check all getters, and collect offenders along the way. |
+ List<MethodDeclaration> missingDocs = <MethodDeclaration>[]; |
+ for (MethodDeclaration getter in getters.values) { |
+ if (check(getter)) { |
+ missingDocs.add(getter); |
+ } |
+ } |
+ |
+ // But only setters whose getter is missing a doc. |
+ for (MethodDeclaration setter in setters.values) { |
+ MethodDeclaration getter = getters[setter.name.name]; |
+ if (getter == null) { |
+ //Look for an inherited getter. |
+ ExecutableElement getter = |
+ manager.lookupMember(node.element, setter.name.name); |
+ if (getter is PropertyAccessorElement) { |
+ if (getter.documentationComment != null) { |
+ continue; |
+ } |
+ } |
+ check(setter); |
+ } else if (missingDocs.contains(getter)) { |
+ check(setter); |
+ } |
+ } |
+ |
+ // Check remaining methods. |
+ methods.forEach(check); |
} |
@override |
@@ -115,6 +173,50 @@ class Visitor extends GeneralizingAstVisitor { |
visitCompilationUnit(CompilationUnit node) { |
LibraryElement library = node?.element?.library; |
manager = library == null ? null : new InheritanceManager(library); |
+ |
+ Map<String, FunctionDeclaration> getters = <String, FunctionDeclaration>{}; |
+ Map<String, FunctionDeclaration> setters = <String, FunctionDeclaration>{}; |
pquitslund
2016/05/18 17:21:16
Note that I did play with a few approaches to avoi
|
+ |
+ // Check functions. |
+ |
+ // Non-getters/setters. |
+ List<FunctionDeclaration> functions = <FunctionDeclaration>[]; |
+ |
+ // Identify getter/setter pairs. |
+ for (CompilationUnitMember member in node.declarations) { |
+ if (member is FunctionDeclaration) { |
+ Identifier name = member.name; |
+ if (!isPrivate(name) && name.name != 'main') { |
+ if (member.isGetter) { |
+ getters[member.name.name] = member; |
+ } else if (member.isSetter) { |
+ setters[member.name.name] = member; |
+ } else { |
+ functions.add(member); |
+ } |
+ } |
+ } |
+ } |
+ |
+ // Check all getters, and collect offenders along the way. |
+ List<FunctionDeclaration> missingDocs = <FunctionDeclaration>[]; |
+ for (FunctionDeclaration getter in getters.values) { |
+ if (check(getter)) { |
+ missingDocs.add(getter); |
+ } |
+ } |
+ |
+ // But only setters whose getter is missing a doc. |
+ for (FunctionDeclaration setter in setters.values) { |
+ FunctionDeclaration getter = getters[setter.name.name]; |
+ if (getter != null && missingDocs.contains(getter)) { |
+ check(setter); |
+ } |
+ } |
+ |
+ // Check remaining functions. |
+ functions.forEach(check); |
+ |
super.visitCompilationUnit(node); |
} |
@@ -151,16 +253,6 @@ class Visitor extends GeneralizingAstVisitor { |
} |
@override |
- visitFunctionDeclaration(FunctionDeclaration node) { |
- if (node.parent is! CompilationUnit) { |
- return; // Skip inner functions. |
- } |
- if (!isPrivate(node.name) && node.name.name != 'main') { |
- check(node); |
- } |
- } |
- |
- @override |
visitFunctionTypeAlias(FunctionTypeAlias node) { |
if (!isPrivate(node.name)) { |
check(node); |
@@ -168,13 +260,6 @@ class Visitor extends GeneralizingAstVisitor { |
} |
@override |
- visitMethodDeclaration(MethodDeclaration node) { |
- if (!inPrivateMember(node) && !isPrivate(node.name)) { |
- check(node); |
- } |
- } |
- |
- @override |
visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { |
for (VariableDeclaration decl in node.variables.variables) { |
if (!isPrivate(decl.name)) { |