Created
April 4, 2021 19:50
-
-
Save pedromassango/3ce08b936e39920a2e584ac2a94f8701 to your computer and use it in GitHub Desktop.
Lint rule: explicit_return for nullable types
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
// Copyright (c) 2021, 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 'dart:async'; | |
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/rules/always_declare_return_types.dart'; | |
import 'package:linter/src/rules/avoid_returning_this.dart'; | |
import '../analyzer.dart'; | |
import '../util/dart_type_utilities.dart'; | |
const _desc = r'Explicitly return null when a null would be inferred'; | |
const _details = r''' | |
**DO** Explicitly return null when a null would be inferred. | |
When declaring a method that returns a nullable type, | |
declare that it returns null explicitly. | |
**BAD:** | |
``` | |
String? f() {} | |
Future<String?> f2() async {} | |
``` | |
**GOOD:** | |
```dart | |
String? f() { | |
return null; | |
} | |
Future<String?> f2() async { | |
return null; | |
} | |
``` | |
'''; | |
class ExplicitReturn extends LintRule implements NodeLintRule { | |
ExplicitReturn() | |
: super( | |
name: 'explicit_return', | |
description: _desc, | |
details: _details, | |
group: Group.style); | |
@override | |
void registerNodeProcessors(NodeLintRegistry registry, LinterContext context) { | |
var visitor = _Visitor(context, this); | |
registry.addMethodDeclaration(this, visitor); | |
//registry.addFunctionDeclaration(this, visitor); | |
} | |
} | |
class _Visitor extends SimpleAstVisitor { | |
final LintRule rule; | |
final LinterContext linterContext; | |
_Visitor(this.linterContext, this.rule); | |
@override | |
void visitMethodDeclaration(MethodDeclaration node) { | |
if (node.returnType == null) return; | |
if (_hasVoidReturnType(node.returnType!)) return; | |
var returnType = node.returnType!; | |
if(_isNullableReturnStatement(returnType)) { | |
var returnStatements = DartTypeUtilities.traverseNodesInDFS(node.body) | |
.whereType<ReturnStatement>(); | |
var hasReturnStatement = returnStatements.any((element) => element.expression != null); | |
if (!hasReturnStatement) { | |
rule.reportLint(node); | |
} | |
} | |
} | |
bool _hasVoidReturnType(TypeAnnotation returnType) => returnType.type is VoidType; | |
bool _isNullableReturnStatement(TypeAnnotation returnType) { | |
if (_isAsync(returnType) && returnType.type is InterfaceType) { | |
var futureArgumentType = (returnType.type! as InterfaceType).typeArguments.first; | |
return !DartTypeUtilities.isNonNullable(linterContext, futureArgumentType); | |
} | |
return !DartTypeUtilities.isNonNullable(linterContext, returnType.type); | |
} | |
bool _isAsync(TypeAnnotation returnType) => | |
returnType.type!.isDartAsyncFuture || returnType.type!.isDartAsyncFutureOr; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment