Index: lib/src/rules/type_annotate_public_apis.dart |
diff --git a/lib/src/rules/type_annotate_public_apis.dart b/lib/src/rules/type_annotate_public_apis.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1db683ceba0dda2bbcfba0e8726ac1f18f8b85ed |
--- /dev/null |
+++ b/lib/src/rules/type_annotate_public_apis.dart |
@@ -0,0 +1,133 @@ |
+// Copyright (c) 2015, 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. |
+ |
+library linter.src.rules.type_annotate_public_apis; |
+ |
+import 'package:analyzer/src/generated/ast.dart'; |
+import 'package:linter/src/linter.dart'; |
+import 'package:linter/src/ast.dart'; |
+ |
+const desc = r'Type annotate public APIs.'; |
+ |
+const details = r''' |
+From [effective dart] (https://www.dartlang.org/effective-dart/design/#do-type-annotate-public-apis): |
+ |
+**DO** type annotate public APIs. |
+ |
+Type annotations are important documentation for how a library should be used. |
+Annotating the parameter and return types of public methods and functions helps |
+users understand what the API expects and what it provides. |
+ |
+Note that if a public API accepts a range of values that Dart's type system |
+cannot express, then it is acceptable to leave that untyped. In that case, the |
+implicit `dynamic` is the correct type for the API. |
+ |
+For code internal to a library (either private, or things like nested functions) |
+annotate where you feel it helps, but don't feel that you *must* provide them. |
+ |
+**BAD:** |
+``` |
+install(id, destination) { |
+ // ... |
+} |
+``` |
+ |
+Here, it's unclear what `id` is. A string? And what is `destination`? A string |
+or a `File` object? Is this method synchronous or asynchronous? |
+ |
+ |
+**GOOD:** |
+ |
+``` |
+Future<bool> install(PackageId id, String destination) { |
+ // ... |
+} |
+``` |
+ |
+With types, all of this is clarified. |
+'''; |
+ |
+class TypeAnnotatePublicApis extends LintRule { |
+ TypeAnnotatePublicApis() |
+ : super( |
+ name: 'type_annotate_public_apis', |
+ description: desc, |
+ details: details, |
+ group: Group.style); |
+ |
+ @override |
+ AstVisitor getVisitor() => new Visitor(this); |
+} |
+ |
+class Visitor extends SimpleAstVisitor { |
+ final LintRule rule; |
+ _VisitoHelper v; |
+ Visitor(this.rule) { |
+ v = new _VisitoHelper(rule); |
+ } |
+ |
+ @override |
+ visitFieldDeclaration(FieldDeclaration node) { |
+ if (node.fields.type == null) { |
+ node.fields.accept(v); |
+ } |
+ } |
+ |
+ @override |
+ visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { |
+ if (node.variables.type == null) { |
+ node.variables.accept(v); |
+ } |
+ } |
+ |
+ @override |
+ visitFunctionDeclaration(FunctionDeclaration node) { |
+ if (!isPrivate(node.name)) { |
+ if (node.returnType == null) { |
+ rule.reportLint(node.name); |
+ } else { |
+ node.functionExpression.parameters.accept(v); |
+ } |
+ } |
+ } |
+ |
+ @override |
+ visitMethodDeclaration(MethodDeclaration node) { |
+ if (!isPrivate(node.name)) { |
+ if (node.returnType == null) { |
+ rule.reportLint(node.name); |
+ } else { |
+ node.parameters.accept(v); |
+ } |
+ } |
+ } |
+ |
+ @override |
+ visitFunctionTypeAlias(FunctionTypeAlias node) { |
+ if (node.returnType == null) { |
+ rule.reportLint(node.name); |
+ } else { |
+ node.parameters.accept(v); |
+ } |
+ } |
+} |
+ |
+class _VisitoHelper extends RecursiveAstVisitor { |
+ final LintRule rule; |
+ _VisitoHelper(this.rule); |
+ |
+ @override |
+ visitVariableDeclaration(VariableDeclaration node) { |
+ if (!isPrivate(node.name)) { |
+ rule.reportLint(node.name); |
+ } |
+ } |
+ |
+ @override |
+ visitSimpleFormalParameter(SimpleFormalParameter param) { |
+ if (param.type == null) { |
+ rule.reportLint(param); |
+ } |
+ } |
+} |