Skip to content

Commit

Permalink
Version 2.10.0-80.0.dev
Browse files Browse the repository at this point in the history
Merge commit 'f5a0e185d20b46dbfe112070bb2128a99e93a400' into 'dev'
  • Loading branch information
Dart CI committed Sep 1, 2020
2 parents 6eab35f + f5a0e18 commit 2a5f37d
Show file tree
Hide file tree
Showing 12 changed files with 284 additions and 19 deletions.
1 change: 1 addition & 0 deletions pkg/analyzer/lib/error/error.dart
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ const List<ErrorCode> errorCodeValues = [
FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_EXTENDS,
FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_IMPLEMENTS,
FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_WITH,
HintCode.ASSIGNMENT_OF_DO_NOT_STORE,
HintCode.CAN_BE_NULL_AFTER_NULL_AWARE,
HintCode.DEAD_CODE,
HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH,
Expand Down
20 changes: 20 additions & 0 deletions pkg/analyzer/lib/src/dart/element/extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,26 @@ import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';

extension ElementExtension on Element {
/// Return `true` if this element, the enclosing class (if there is one), or
/// the enclosing library, has been annotated with the `@doNotStore`
/// annotation.
bool get hasOrInheritsDoNotStore {
if (hasDoNotStore) {
return true;
}
var ancestor = enclosingElement;
if (ancestor is ClassElement || ancestor is ExtensionElement) {
if (ancestor.hasDoNotStore) {
return true;
}
ancestor = ancestor.enclosingElement;
}
return ancestor is CompilationUnitElement &&
ancestor.enclosingElement.hasDoNotStore;
}
}

extension ParameterElementExtensions on ParameterElement {
/// Return [ParameterElement] with the specified properties replaced.
ParameterElement copyWith({DartType type, ParameterKind kind}) {
Expand Down
8 changes: 8 additions & 0 deletions pkg/analyzer/lib/src/dart/error/hint_codes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ import 'package:analyzer/src/error/analyzer_error_code.dart';
* mentioned in the Dart Language Specification.
*/
class HintCode extends AnalyzerErrorCode {
/**
* Users should not assign values marked `@doNotStore`.
*/
static const HintCode ASSIGNMENT_OF_DO_NOT_STORE = HintCode(
'ASSIGNMENT_OF_DO_NOT_STORE',
"'{0}' is marked 'doNotStore' and shouldn't be assigned to a field.",
correction: "Try removing the assignment.");

/**
* When the target expression uses '?.' operator, it can be `null`, so all the
* subsequent invocations should also use '?.' operator.
Expand Down
32 changes: 32 additions & 0 deletions pkg/analyzer/lib/src/error/best_practices_verifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/type_provider.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/extensions.dart';
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
import 'package:analyzer/src/dart/element/member.dart' show ExecutableMember;
import 'package:analyzer/src/dart/element/type.dart';
Expand Down Expand Up @@ -359,6 +360,37 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
field.name,
[field.name, overriddenElement.enclosingElement.name]);
}

var expression = field.initializer;

Element element;
if (expression is PropertyAccess) {
element = expression.propertyName.staticElement;
// Tear-off.
if (element is FunctionElement || element is MethodElement) {
element = null;
}
} else if (expression is MethodInvocation) {
element = expression.methodName.staticElement;
} else if (expression is Identifier) {
element = expression.staticElement;
// Tear-off.
if (element is FunctionElement || element is MethodElement) {
element = null;
}
}
if (element != null) {
if (element is PropertyAccessorElement && element.isSynthetic) {
element = (element as PropertyAccessorElement).variable;
}
if (element.hasOrInheritsDoNotStore) {
_errorReporter.reportErrorForNode(
HintCode.ASSIGNMENT_OF_DO_NOT_STORE,
expression,
[element.name],
);
}
}
}
} finally {
_inDeprecatedMember = wasInDeprecatedMember;
Expand Down
12 changes: 8 additions & 4 deletions pkg/analyzer/lib/src/test_utilities/mock_packages.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class JS {
library meta;
const _AlwaysThrows alwaysThrows = const _AlwaysThrows();
const _DoNotStore doNotStore = _DoNotStore();
const _Factory factory = const _Factory();
const Immutable immutable = const Immutable();
const _Literal literal = const _Literal();
Expand All @@ -36,16 +37,19 @@ const Required required = const Required();
const _Sealed sealed = const _Sealed();
const _VisibleForTesting visibleForTesting = const _VisibleForTesting();
class Immutable {
final String reason;
const Immutable([this.reason]);
}
class _AlwaysThrows {
const _AlwaysThrows();
}
class _DoNotStore {
const _DoNotStore();
}
class _Factory {
const _Factory();
}
class Immutable {
final String reason;
const Immutable([this.reason]);
}
class _Literal {
const _Literal();
}
Expand Down
179 changes: 179 additions & 0 deletions pkg/analyzer/test/src/diagnostics/assignment_of_do_not_store_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// Copyright (c) 2020, 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/src/error/codes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';

import '../dart/resolution/context_collection_resolution.dart';

main() {
defineReflectiveSuite(() {
defineReflectiveTests(AssignmentOfDoNotStoreTest);
});
}

@reflectiveTest
class AssignmentOfDoNotStoreTest extends PubPackageResolutionTest {
@override
void setUp() {
super.setUp();
writeTestPackageConfigWithMeta();
}

test_classMemberGetter() async {
await assertErrorsInCode('''
import 'package:meta/meta.dart';
class A {
@doNotStore
String get v => '';
}
class B {
String f = A().v;
}
''', [
error(HintCode.ASSIGNMENT_OF_DO_NOT_STORE, 106, 5),
]);
}

test_classMemberVariable() async {
await assertErrorsInCode('''
import 'package:meta/meta.dart';
class A{
@doNotStore
final f = '';
}
class B {
String f = A().f;
}
''', [
error(HintCode.ASSIGNMENT_OF_DO_NOT_STORE, 99, 5),
]);
}

test_classStaticGetter() async {
await assertErrorsInCode('''
import 'package:meta/meta.dart';
class A {
@doNotStore
static String get v => '';
}
class B {
String f = A.v;
}
''', [
error(HintCode.ASSIGNMENT_OF_DO_NOT_STORE, 113, 3),
]);
}

test_classStaticVariable() async {
await assertErrorsInCode('''
import 'package:meta/meta.dart';
class A{
@doNotStore
static final f = '';
}
class B {
String f = A.f;
}
''', [
error(HintCode.ASSIGNMENT_OF_DO_NOT_STORE, 106, 3),
]);
}

test_functionAssignment() async {
await assertNoErrorsInCode('''
import 'package:meta/meta.dart';
@doNotStore
String g(int i) => '';
class C {
String Function(int) f = g;
}
''');
}

test_functionReturnValue() async {
await assertErrorsInCode('''
import 'package:meta/meta.dart';
@doNotStore
String getV() => '';
class A {
final f = getV();
}
''', [
error(HintCode.ASSIGNMENT_OF_DO_NOT_STORE, 90, 6),
]);
}

test_methodReturnValue() async {
await assertErrorsInCode('''
import 'package:meta/meta.dart';
class A {
@doNotStore
String getV() => '';
}
class B {
final f = A().getV();
}
''', [
error(HintCode.ASSIGNMENT_OF_DO_NOT_STORE, 106, 10),
]);
}

test_tearOff() async {
await assertNoErrorsInCode('''
import 'package:meta/meta.dart';
@doNotStore
String getV() => '';
class A {
final f = getV;
}
''');
}

test_topLevelGetter() async {
await assertErrorsInCode('''
import 'package:meta/meta.dart';
@doNotStore
String get v => '';
class A {
final f = v;
}
''', [
error(HintCode.ASSIGNMENT_OF_DO_NOT_STORE, 89, 1),
]);
}

test_topLevelVariable() async {
await assertErrorsInCode('''
import 'package:meta/meta.dart';
@doNotStore
final v = '';
class A {
final f = v;
}
''', [
error(HintCode.ASSIGNMENT_OF_DO_NOT_STORE, 83, 1),
]);
}
}
2 changes: 2 additions & 0 deletions pkg/analyzer/test/src/diagnostics/test_all.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import 'annotation_with_non_class_test.dart' as annotation_with_non_class;
import 'argument_type_not_assignable_test.dart' as argument_type_not_assignable;
import 'assert_in_redirecting_constructor_test.dart'
as assert_in_redirecting_constructor;
import 'assignment_of_do_not_store_test.dart' as assignment_of_do_not_store;
import 'assignment_to_const_test.dart' as assignment_to_const;
import 'assignment_to_final_local_test.dart' as assignment_to_final_local;
import 'assignment_to_final_no_setter_test.dart'
Expand Down Expand Up @@ -653,6 +654,7 @@ main() {
annotation_with_non_class.main();
argument_type_not_assignable.main();
assert_in_redirecting_constructor.main();
assignment_of_do_not_store.main();
assignment_to_const.main();
assignment_to_final_local.main();
assignment_to_final_no_setter.main();
Expand Down
14 changes: 7 additions & 7 deletions pkg/dartdev/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@ A command-line utility for Dart development.
Usage: dart [<vm-flags>] <command|dart-file> [<arguments>]
Global options:
-h, --help Print this usage information.
-v, --verbose Show additional command output.
--version Print the Dart SDK version.
--enable-analytics Enable anonymous analytics.
--disable-analytics Disable anonymous analytics.
--enable-experiment=<experiment> Enable one or more experimental features (see dart.dev/go/experiments).
-h, --help Print this usage information.
-v, --verbose Show additional command output.
--version Print the Dart SDK version.
--enable-analytics Enable anonymous analytics.
--disable-analytics Disable anonymous analytics.
Available commands:
analyze Analyze the project's Dart code.
compile Compile Dart to various formats.
create Create a new project.
format Idiomatically formats Dart source code.
format Idiomatically format Dart source code.
pub Work with packages.
run Run a Dart program.
test Run tests in this package.
Run "dart help <command>" for more information about a command.
See https://dart.dev/tools/dart-tool for detailed documentation.
```

## Contributing
Expand Down
13 changes: 8 additions & 5 deletions pkg/dartdev/lib/dartdev.dart
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,12 @@ class DartdevRunner<int> extends CommandRunner {
// A hidden flag to disable analytics on this run, this constructor can be
// called with this flag, but should be removed before run() is called as
// the flag has not been added to all sub-commands.
argParser.addFlag('disable-dartdev-analytics',
negatable: false,
help: 'Disable anonymous analytics for this `dart *` run',
hide: true);
argParser.addFlag(
'disable-dartdev-analytics',
negatable: false,
help: 'Disable anonymous analytics for this `dart *` run',
hide: true,
);

// Another hidden flag used by the VM to indicate that DDS should be
// launched. Should be removed for all commands other than `run`.
Expand All @@ -220,7 +222,7 @@ class DartdevRunner<int> extends CommandRunner {
addCommand(CreateCommand(verbose: verbose));
addCommand(CompileCommand());
addCommand(FixCommand());
addCommand(FormatCommand());
addCommand(FormatCommand(verbose: verbose));
addCommand(MigrateCommand(
verbose: verbose,
hidden: Runtime.runtime.stableChannel,
Expand Down Expand Up @@ -254,6 +256,7 @@ class DartdevRunner<int> extends CommandRunner {
allowedHelp: verbose ? allowedHelp : null,
help: 'Enable one or more experimental features '
'(see dart.dev/go/experiments).',
hide: !verbose,
);
}

Expand Down
Loading

0 comments on commit 2a5f37d

Please sign in to comment.