This repository has been archived by the owner on Nov 20, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 170
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add 3 lints for always specify types
- Loading branch information
Showing
8 changed files
with
455 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// Copyright (c) 2018, 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. | ||
|
||
import 'package:analyzer/dart/ast/ast.dart'; | ||
import 'package:analyzer/dart/ast/visitor.dart'; | ||
import 'package:linter/src/analyzer.dart'; | ||
import 'package:linter/src/utils.dart'; | ||
|
||
const _desc = r'Specify type annotations.'; | ||
|
||
const _details = r''' | ||
**DO** specify type annotations. | ||
**GOOD:** | ||
``` | ||
int foo = 10; | ||
final Bar bar = new Bar(); | ||
String baz = 'hello'; | ||
const int quux = 20; | ||
``` | ||
**BAD:** | ||
``` | ||
var foo = 10; | ||
final bar = new Bar(); | ||
const quux = 20; | ||
``` | ||
'''; | ||
|
||
class AlwaysSpecifyTypeAnnotations extends LintRule implements NodeLintRule { | ||
AlwaysSpecifyTypeAnnotations() | ||
: super( | ||
name: 'always_specify_type_annotations', | ||
description: _desc, | ||
details: _details, | ||
group: Group.style); | ||
|
||
@override | ||
void registerNodeProcessors(NodeLintRegistry registry) { | ||
final visitor = new _Visitor(this); | ||
registry.addDeclaredIdentifier(this, visitor); | ||
registry.addSimpleFormalParameter(this, visitor); | ||
registry.addVariableDeclarationList(this, visitor); | ||
} | ||
} | ||
|
||
class _Visitor extends SimpleAstVisitor<void> { | ||
final LintRule rule; | ||
|
||
_Visitor(this.rule); | ||
|
||
@override | ||
void visitDeclaredIdentifier(DeclaredIdentifier node) { | ||
if (node.type == null) { | ||
rule.reportLintForToken(node.keyword); | ||
} | ||
} | ||
|
||
@override | ||
void visitSimpleFormalParameter(SimpleFormalParameter param) { | ||
if (param.type == null && | ||
param.identifier != null && | ||
!isJustUnderscores(param.identifier.name)) { | ||
if (param.keyword != null) { | ||
rule.reportLintForToken(param.keyword); | ||
} else { | ||
rule.reportLint(param); | ||
} | ||
} | ||
} | ||
|
||
@override | ||
void visitVariableDeclarationList(VariableDeclarationList list) { | ||
if (list.type == null) { | ||
rule.reportLintForToken(list.keyword); | ||
} | ||
} | ||
} |
131 changes: 131 additions & 0 deletions
131
lib/src/rules/always_specify_type_arguments_for_classes.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
// Copyright (c) 2018, 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. | ||
|
||
import 'package:analyzer/dart/ast/ast.dart'; | ||
import 'package:analyzer/dart/ast/visitor.dart'; | ||
import 'package:analyzer/dart/element/element.dart'; | ||
import 'package:analyzer/dart/element/type.dart'; | ||
import 'package:linter/src/analyzer.dart'; | ||
|
||
const _desc = r'Specify type arguments for classes.'; | ||
|
||
const _details = r''' | ||
**DO** specify type arguments for classes. | ||
**GOOD:** | ||
``` | ||
final a = <int>[]; | ||
final b = new List<int>(); | ||
final c = <int, String>{}; | ||
final d = new Map<int, String>(); | ||
``` | ||
**BAD:** | ||
``` | ||
final a = []; | ||
final b = new List(); | ||
final c = {}; | ||
final d = new Map(); | ||
``` | ||
NOTE: Using the the `@optionalTypeArgs` annotation in the `meta` package, API | ||
authors can special-case type variables whose type needs to by dynamic but whose | ||
declaration should be treated as optional. For example, suppose you have a | ||
`Key` object whose type parameter you'd like to treat as optional. Using the | ||
`@optionalTypeArgs` would look like this: | ||
``` | ||
import 'package:meta/meta.dart'; | ||
@optionalTypeArgs | ||
class Key<T> { | ||
... | ||
} | ||
main() { | ||
Key s = new Key(); // OK! | ||
} | ||
``` | ||
'''; | ||
|
||
/// The name of `meta` library, used to define analysis annotations. | ||
String _META_LIB_NAME = 'meta'; | ||
|
||
/// The name of the top-level variable used to mark a Class as having optional | ||
/// type args. | ||
String _OPTIONAL_TYPE_ARGS_VAR_NAME = 'optionalTypeArgs'; | ||
|
||
bool _isOptionallyParameterized(ParameterizedType type) { | ||
List<ElementAnnotation> metadata = type.element?.metadata; | ||
if (metadata != null) { | ||
return metadata | ||
.any((ElementAnnotation a) => _isOptionalTypeArgs(a.element)); | ||
} | ||
return false; | ||
} | ||
|
||
bool _isOptionalTypeArgs(Element element) => | ||
element is PropertyAccessorElement && | ||
element.name == _OPTIONAL_TYPE_ARGS_VAR_NAME && | ||
element.library?.name == _META_LIB_NAME; | ||
|
||
class AlwaysSpecifyTypeArgumentsForClasses extends LintRule | ||
implements NodeLintRule { | ||
AlwaysSpecifyTypeArgumentsForClasses() | ||
: super( | ||
name: 'always_specify_type_arguments_for_classes', | ||
description: _desc, | ||
details: _details, | ||
group: Group.style); | ||
|
||
@override | ||
void registerNodeProcessors(NodeLintRegistry registry) { | ||
final visitor = new _Visitor(this); | ||
registry.addListLiteral(this, visitor); | ||
registry.addMapLiteral(this, visitor); | ||
registry.addTypeName(this, visitor); | ||
} | ||
} | ||
|
||
class _Visitor extends SimpleAstVisitor<void> { | ||
final LintRule rule; | ||
|
||
_Visitor(this.rule); | ||
|
||
@override | ||
void visitListLiteral(ListLiteral literal) { | ||
_checkLiteral(literal); | ||
} | ||
|
||
@override | ||
void visitMapLiteral(MapLiteral literal) { | ||
_checkLiteral(literal); | ||
} | ||
|
||
void _checkLiteral(TypedLiteral literal) { | ||
if (literal.typeArguments == null) { | ||
rule.reportLintForToken(literal.beginToken); | ||
} | ||
} | ||
|
||
// Future kernel API. | ||
void visitNamedType(NamedType namedType) { | ||
DartType type = namedType.type; | ||
if (type is ParameterizedType) { | ||
if (type.typeParameters.isNotEmpty && | ||
namedType.typeArguments == null && | ||
namedType.parent is! IsExpression && | ||
!_isOptionallyParameterized(type)) { | ||
rule.reportLint(namedType); | ||
} | ||
} | ||
} | ||
|
||
@override | ||
void visitTypeName(NamedType typeName) { | ||
visitNamedType(typeName); | ||
} | ||
} |
91 changes: 91 additions & 0 deletions
91
lib/src/rules/always_specify_type_arguments_for_methods.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// 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. | ||
|
||
import 'package:analyzer/dart/ast/ast.dart'; | ||
import 'package:analyzer/dart/ast/visitor.dart'; | ||
import 'package:analyzer/dart/element/element.dart'; | ||
import 'package:linter/src/analyzer.dart'; | ||
|
||
const _desc = r'Specify type arguments for methods.'; | ||
|
||
const _details = r''' | ||
**DO** specify type arguments for methods. | ||
**GOOD:** | ||
``` | ||
void m<T>(T t1, T t2) {} | ||
m<int>(1, 2); | ||
``` | ||
**BAD:** | ||
``` | ||
void m<T>(T t1, T t2) {} | ||
m(1, 2); | ||
``` | ||
NOTE: Using the the `@optionalTypeArgs` annotation in the `meta` package, API | ||
authors can special-case type variables whose type needs to by dynamic but whose | ||
declaration should be treated as optional. For example, suppose you have a | ||
`m` function whose type parameter you'd like to treat as optional. Using the | ||
`@optionalTypeArgs` would look like this: | ||
``` | ||
import 'package:meta/meta.dart'; | ||
@optionalTypeArgs | ||
void m<T>(T t1, T t2) {} | ||
main() { | ||
m(1, 2); // OK! | ||
} | ||
``` | ||
'''; | ||
|
||
/// The name of `meta` library, used to define analysis annotations. | ||
String _META_LIB_NAME = 'meta'; | ||
|
||
/// The name of the top-level variable used to mark a Class as having optional | ||
/// type args. | ||
String _OPTIONAL_TYPE_ARGS_VAR_NAME = 'optionalTypeArgs'; | ||
|
||
bool _isOptionalTypeArgs(Element element) => | ||
element is PropertyAccessorElement && | ||
element.name == _OPTIONAL_TYPE_ARGS_VAR_NAME && | ||
element.library?.name == _META_LIB_NAME; | ||
|
||
class AlwaysSpecifyTypeArgumentsForMethods extends LintRule | ||
implements NodeLintRule { | ||
AlwaysSpecifyTypeArgumentsForMethods() | ||
: super( | ||
name: 'always_specify_type_arguments_for_methods', | ||
description: _desc, | ||
details: _details, | ||
group: Group.style); | ||
|
||
@override | ||
void registerNodeProcessors(NodeLintRegistry registry) { | ||
final visitor = new _Visitor(this); | ||
registry.addMethodInvocation(this, visitor); | ||
} | ||
} | ||
|
||
class _Visitor extends SimpleAstVisitor<void> { | ||
final LintRule rule; | ||
|
||
_Visitor(this.rule); | ||
|
||
@override | ||
void visitMethodInvocation(MethodInvocation node) { | ||
if (node.typeArguments == null) { | ||
final element = node.methodName.bestElement; | ||
if (element is FunctionTypedElement && | ||
element.typeParameters.isNotEmpty && | ||
!element.metadata.any((a) => _isOptionalTypeArgs(a.element))) { | ||
rule.reportLint(node.methodName); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// Copyright (c) 2018, 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. | ||
|
||
// test w/ `pub run test -N always_specify_type_annotations` | ||
|
||
final x = 1; //LINT [1:5] | ||
final int xx = 3; | ||
const y = 2; //LINT | ||
const int yy = 3; | ||
|
||
a(var x) {} //LINT | ||
b(s) {} //LINT [3:1] | ||
c(int x) {} | ||
d(final x) {} //LINT | ||
e(final int x) {} | ||
|
||
main() { | ||
var x = ''; //LINT [3:3] | ||
for (var i = 0; i < 10; ++i) { //LINT [8:3] | ||
print(i); | ||
} | ||
List<String> ls = <String>[]; | ||
ls.forEach((s) => print(s)); //LINT [15:1] | ||
for (var l in ls) { //LINT [8:3] | ||
print(l); | ||
} | ||
try { | ||
for (final l in ls) { // LINT [10:5] | ||
print(l); | ||
} | ||
} on Exception catch (ex) { | ||
print(ex); | ||
} catch (e) { // NO warning (https://codereview.chromium.org/1427223002/) | ||
print(e); | ||
} | ||
|
||
var __; // LINT | ||
|
||
listen((_) { // OK! | ||
// ... | ||
}); | ||
} | ||
|
||
listen(void onData(Object event)) {} | ||
|
||
var z; //LINT | ||
|
||
class Foo { | ||
static var bar; //LINT | ||
static final baz = 1; //LINT | ||
static final int bazz = 42; | ||
var foo; //LINT | ||
Foo(var bar); //LINT [7:3] | ||
} |
Oops, something went wrong.