Include 'invokesSuperSelf' flag into unlinked API signature.

We will add this flag as a property of MethodElement. So, it will
affect the semantics, and should be a part of unlinked signature.

Change-Id: If24b09fcd000364a2ddb3737baa69af3d1c6fbd5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/240641
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2022-04-08 05:28:58 +00:00 committed by Commit Bot
parent 7f8bf79ad8
commit 6b6e6da943
6 changed files with 156 additions and 53 deletions

View file

@ -83,7 +83,7 @@ import 'package:meta/meta.dart';
/// TODO(scheglov) Clean up the list of implicitly analyzed files.
class AnalysisDriver implements AnalysisDriverGeneric {
/// The version of data format, should be incremented on every format change.
static const int DATA_VERSION = 212;
static const int DATA_VERSION = 213;
/// The number of exception contexts allowed to write. Once this field is
/// zero, we stop writing any new exception contexts in this process.

View file

@ -6,6 +6,7 @@ import 'dart:typed_data';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/src/dart/ast/invokes_super_self.dart';
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/summary/api_signature.dart';
import 'package:collection/collection.dart';
@ -140,6 +141,7 @@ class _UnitApiSignatureComputer {
);
signature.addBool(node.body is EmptyFunctionBody);
_addFunctionBodyModifiers(node.body);
signature.addBool(node.invokesSuperSelf);
}
void _addNode(AstNode? node) {

View file

@ -0,0 +1,62 @@
// Copyright (c) 2022, 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';
class _SuperVisitor extends RecursiveAstVisitor<void> {
final String name;
/// Set to `true` if a super invocation with the [name] is found.
bool hasSuperInvocation = false;
_SuperVisitor(this.name);
@override
void visitAssignmentExpression(AssignmentExpression node) {
var left = node.leftHandSide;
if (left is PropertyAccess) {
if (left.target is SuperExpression && left.propertyName.name == name) {
hasSuperInvocation = true;
return;
}
}
super.visitAssignmentExpression(node);
}
@override
void visitBinaryExpression(BinaryExpression node) {
if (node.leftOperand is SuperExpression && node.operator.lexeme == name) {
hasSuperInvocation = true;
return;
}
super.visitBinaryExpression(node);
}
@override
void visitMethodInvocation(MethodInvocation node) {
if (node.target is SuperExpression && node.methodName.name == name) {
hasSuperInvocation = true;
return;
}
super.visitMethodInvocation(node);
}
@override
void visitPropertyAccess(PropertyAccess node) {
if (node.target is SuperExpression && node.propertyName.name == name) {
hasSuperInvocation = true;
return;
}
super.visitPropertyAccess(node);
}
}
extension MethodDeclarationExtension on MethodDeclaration {
bool get invokesSuperSelf {
var visitor = _SuperVisitor(name.name);
body.accept(visitor);
return visitor.hasSuperInvocation;
}
}

View file

@ -1,3 +1,7 @@
// 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/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';

View file

@ -5,9 +5,9 @@
import 'dart:collection';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/ast/invokes_super_self.dart';
import 'package:analyzer/src/dart/error/hint_codes.dart';
class MustCallSuperVerifier {
@ -133,9 +133,7 @@ class MustCallSuperVerifier {
void _verifySuperIsCalled(MethodDeclaration node, String methodName,
String? overriddenEnclosingName) {
_SuperCallVerifier verifier = _SuperCallVerifier(methodName);
node.accept(verifier);
if (!verifier.superIsCalled) {
if (!node.invokesSuperSelf) {
// Overridable elements are always enclosed in named elements, so it is
// safe to assume [overriddenEnclosingName] is non-`null`.
_errorReporter.reportErrorForNode(
@ -144,51 +142,3 @@ class MustCallSuperVerifier {
return;
}
}
/// Recursively visits an AST, looking for method invocations.
class _SuperCallVerifier extends RecursiveAstVisitor<void> {
bool superIsCalled = false;
final String name;
_SuperCallVerifier(this.name);
@override
void visitAssignmentExpression(AssignmentExpression node) {
var lhs = node.leftHandSide;
if (lhs is PropertyAccess) {
if (lhs.target is SuperExpression && lhs.propertyName.name == name) {
superIsCalled = true;
return;
}
}
super.visitAssignmentExpression(node);
}
@override
void visitBinaryExpression(BinaryExpression node) {
if (node.leftOperand is SuperExpression && node.operator.lexeme == name) {
superIsCalled = true;
return;
}
super.visitBinaryExpression(node);
}
@override
void visitMethodInvocation(MethodInvocation node) {
if (node.target is SuperExpression && node.methodName.name == name) {
superIsCalled = true;
return;
}
super.visitMethodInvocation(node);
}
@override
void visitPropertyAccess(PropertyAccess node) {
if (node.target is SuperExpression && node.propertyName.name == name) {
superIsCalled = true;
return;
}
super.visitPropertyAccess(node);
}
}

View file

@ -457,6 +457,83 @@ static const int a = 2;
''');
}
test_classLike_method_body_block_invokesSuperSelf_false_differentName() {
_assertSameSignature_classLike(r'''
void foo() {
super.bar();
}
''', r'''
void foo() {
super.bar2();
}
''');
}
test_classLike_method_body_block_invokesSuperSelf_falseToTrue() {
_assertNotSameSignature_classLike(r'''
void foo() {}
''', r'''
void foo() {
super.foo();
}
''');
}
test_classLike_method_body_block_invokesSuperSelf_trueToFalse_assignmentExpression() {
_assertNotSameSignature_classLike(r'''
void foo() {
super.foo = 0;
}
''', r'''
void foo() {}
''');
}
test_classLike_method_body_block_invokesSuperSelf_trueToFalse_binaryExpression() {
_assertNotSameSignature_classLike(r'''
int operator +() {
super + 2;
return 0;
}
''', r'''
int operator +() {
return 0;
}
''');
}
test_classLike_method_body_block_invokesSuperSelf_trueToFalse_differentName() {
_assertNotSameSignature_classLike(r'''
void foo() {
super.foo();
}
''', r'''
void foo() {
super.bar();
}
''');
}
test_classLike_method_body_block_invokesSuperSelf_trueToFalse_methodInvocation() {
_assertNotSameSignature_classLike(r'''
void foo() {
super.foo();
}
''', r'''
void foo() {}
''');
}
test_classLike_method_body_block_invokesSuperSelf_trueToFalse_propertyAccess() {
_assertNotSameSignature_classLike(r'''
void foo() {
super.foo;
}
''', r'''
void foo() {}
''');
}
test_classLike_method_body_block_to_empty() {
_assertNotSameSignature_classLike(r'''
void foo() {}
@ -481,6 +558,14 @@ int foo() => 0;
''');
}
test_classLike_method_body_expression_invokesSuperSelf_trueToFalse_methodInvocation() {
_assertNotSameSignature_classLike(r'''
void foo() => super.foo();
''', r'''
void foo() => 0;
''');
}
test_classLike_method_getter_body_block_to_empty() {
_assertNotSameSignature_classLike(r'''
int get foo {