-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new lints {omit_,specify_non}obvious_property_types
See https://github.com/dart-lang/linter/issues/5101 for some background information. Change-Id: I51b6988f08585b7b4863ae8858d44de831615177 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/387960 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Erik Ernst <[email protected]>
- Loading branch information
Showing
16 changed files
with
1,486 additions
and
2 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
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
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,66 @@ | ||
// Copyright (c) 2024, 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 '../analyzer.dart'; | ||
import '../util/obvious_types.dart'; | ||
|
||
const _desc = | ||
r'Omit obvious type annotations for top-level and static variables.'; | ||
|
||
class OmitObviousPropertyTypes extends LintRule { | ||
OmitObviousPropertyTypes() | ||
: super( | ||
name: 'omit_obvious_property_types', | ||
description: _desc, | ||
state: State.experimental(), | ||
); | ||
|
||
@override | ||
List<String> get incompatibleRules => const ['always_specify_types']; | ||
|
||
@override | ||
LintCode get lintCode => LinterLintCode.omit_obvious_property_types; | ||
|
||
@override | ||
void registerNodeProcessors( | ||
NodeLintRegistry registry, LinterContext context) { | ||
var visitor = _Visitor(this); | ||
registry.addFieldDeclaration(this, visitor); | ||
registry.addTopLevelVariableDeclaration(this, visitor); | ||
} | ||
} | ||
|
||
class _Visitor extends SimpleAstVisitor<void> { | ||
final LintRule rule; | ||
|
||
_Visitor(this.rule); | ||
|
||
@override | ||
void visitFieldDeclaration(FieldDeclaration node) => | ||
_visitVariableDeclarationList(node.fields); | ||
|
||
@override | ||
void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) => | ||
_visitVariableDeclarationList(node.variables); | ||
|
||
void _visitVariableDeclarationList(VariableDeclarationList node) { | ||
var staticType = node.type?.type; | ||
if (staticType == null || staticType.isDartCoreNull) { | ||
return; | ||
} | ||
for (var child in node.variables) { | ||
var initializer = child.initializer; | ||
if (initializer != null && !initializer.hasObviousType) { | ||
return; | ||
} | ||
if (initializer?.staticType != staticType) { | ||
return; | ||
} | ||
} | ||
rule.reportLint(node.type); | ||
} | ||
} |
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
107 changes: 107 additions & 0 deletions
107
pkg/linter/lib/src/rules/specify_nonobvious_property_types.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,107 @@ | ||
// Copyright (c) 2024, 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 '../analyzer.dart'; | ||
import '../util/obvious_types.dart'; | ||
|
||
const _desc = r'Specify non-obvious type annotations for local variables.'; | ||
|
||
class SpecifyNonObviousPropertyTypes extends LintRule { | ||
SpecifyNonObviousPropertyTypes() | ||
: super( | ||
name: 'specify_nonobvious_property_types', | ||
description: _desc, | ||
state: State.experimental(), | ||
); | ||
|
||
@override | ||
List<String> get incompatibleRules => const ['omit_local_variable_types']; | ||
|
||
@override | ||
LintCode get lintCode => LinterLintCode.specify_nonobvious_property_types; | ||
|
||
@override | ||
void registerNodeProcessors( | ||
NodeLintRegistry registry, LinterContext context) { | ||
var visitor = _Visitor(this); | ||
registry.addFieldDeclaration(this, visitor); | ||
registry.addTopLevelVariableDeclaration(this, visitor); | ||
} | ||
} | ||
|
||
class _Visitor extends SimpleAstVisitor<void> { | ||
final LintRule rule; | ||
|
||
_Visitor(this.rule); | ||
|
||
@override | ||
void visitFieldDeclaration(FieldDeclaration node) => | ||
_visitVariableDeclarationList(node.fields, | ||
isInstanceVariable: !node.isStatic); | ||
|
||
@override | ||
void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) => | ||
_visitVariableDeclarationList(node.variables, isInstanceVariable: false); | ||
|
||
void _visitVariableDeclarationList(VariableDeclarationList node, | ||
{required bool isInstanceVariable}) { | ||
var staticType = node.type?.type; | ||
if (staticType != null && !staticType.isDartCoreNull) { | ||
return; | ||
} | ||
bool aDeclaredTypeIsNeeded = false; | ||
var variablesThatNeedAType = <VariableDeclaration>[]; | ||
for (var child in node.variables) { | ||
var initializer = child.initializer; | ||
if (isInstanceVariable) { | ||
// Ignore this variable if the type comes from override inference. | ||
bool ignoreThisVariable = false; | ||
AstNode? owningDeclaration = node; | ||
while (owningDeclaration != null) { | ||
InterfaceElement? owningElement = switch (owningDeclaration) { | ||
ClassDeclaration(:var declaredElement) => declaredElement, | ||
MixinDeclaration(:var declaredElement) => declaredElement, | ||
EnumDeclaration(:var declaredElement) => declaredElement, | ||
ExtensionTypeDeclaration(:var declaredElement) => declaredElement, | ||
_ => null, | ||
}; | ||
if (owningElement != null) { | ||
var variableName = child.name.lexeme; | ||
for (var superInterface in owningElement.allSupertypes) { | ||
if (superInterface.getGetter(variableName) != null) { | ||
ignoreThisVariable = true; | ||
} | ||
if (superInterface.getSetter(variableName) != null) { | ||
ignoreThisVariable = true; | ||
} | ||
} | ||
} | ||
owningDeclaration = owningDeclaration.parent; | ||
} | ||
if (ignoreThisVariable) continue; | ||
} | ||
if (initializer == null) { | ||
aDeclaredTypeIsNeeded = true; | ||
variablesThatNeedAType.add(child); | ||
} else { | ||
if (!initializer.hasObviousType) { | ||
aDeclaredTypeIsNeeded = true; | ||
variablesThatNeedAType.add(child); | ||
} | ||
} | ||
} | ||
if (aDeclaredTypeIsNeeded) { | ||
if (node.variables.length == 1) { | ||
rule.reportLint(node); | ||
} else { | ||
// Multiple variables, report each of them separately. No fix. | ||
variablesThatNeedAType.forEach(rule.reportLint); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.