Don't record references to the name of this node or the name of the enclosing class.

R=brianwilkerson@google.com

Change-Id: Iaf66c2995cb39039f508f55e8920c59b2afec04c
Reviewed-on: https://dart-review.googlesource.com/c/86825
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2018-12-11 02:38:23 +00:00 committed by commit-bot@chromium.org
parent f6b5f9ce2e
commit f0d85bb914
3 changed files with 213 additions and 29 deletions

View file

@ -142,6 +142,9 @@ class _LibraryBuilder {
/// are different.
List<int> uriSignature;
/// The name of the enclosing class name, or `null` if outside a class.
String enclosingClassName;
/// The precomputed signature of the enclosing class name, or `null` if
/// outside a class.
///
@ -158,10 +161,6 @@ class _LibraryBuilder {
_addImports();
_addExports();
// TODO(scheglov) import prefixes are shadowed by class members
// TODO(scheglov) top-level declarations shadow external names
for (var unit in units) {
_addUnit(unit);
}
@ -171,19 +170,24 @@ class _LibraryBuilder {
}
void _addClassOrMixin(ClassOrMixinDeclaration node) {
enclosingClassName = node.name.name;
enclosingClassNameSignature =
(ApiSignature()..addString(node.name.name)).toByteList();
(ApiSignature()..addString(enclosingClassName)).toByteList();
var hasConstConstructor = node.members.any(
(m) => m is ConstructorDeclaration && m.constKeyword != null,
);
// TODO(scheglov) do we need type parameters at all?
List<Node> classTypeParameters;
if (node.typeParameters != null) {
classTypeParameters = <Node>[];
for (var typeParameter in node.typeParameters.typeParameters) {
var api = referenceCollector.collect(
_computeNodeTokenSignature(typeParameter),
enclosingClassName: enclosingClassName,
thisNodeName: typeParameter.name.name,
type: typeParameter.bound,
);
classTypeParameters.add(Node(
@ -234,6 +238,7 @@ class _LibraryBuilder {
if (node is ClassDeclaration) {
api = referenceCollector.collect(
apiTokenSignature,
thisNodeName: enclosingClassName,
typeParameters: node.typeParameters,
extendsClause: node.extendsClause,
withClause: node.withClause,
@ -242,6 +247,7 @@ class _LibraryBuilder {
} else if (node is MixinDeclaration) {
api = referenceCollector.collect(
apiTokenSignature,
thisNodeName: enclosingClassName,
typeParameters: node.typeParameters,
onClause: node.onClause,
implementsClause: node.implementsClause,
@ -251,7 +257,7 @@ class _LibraryBuilder {
}
var classNode = Node(
LibraryQualifiedName(uri, node.name.name),
LibraryQualifiedName(uri, enclosingClassName),
node is MixinDeclaration ? NodeKind.MIXIN : NodeKind.CLASS,
api,
Dependencies.none,
@ -262,6 +268,7 @@ class _LibraryBuilder {
classNode.setClassMembers(classMembers);
declaredNodes.add(classNode);
enclosingClassName = null;
enclosingClassNameSignature = null;
}
@ -291,13 +298,16 @@ class _LibraryBuilder {
var api = referenceCollector.collect(
apiTokenSignature,
enclosingClassName: enclosingClassName,
formalParameters: node.parameters,
);
// TODO(scheglov) constructor initializers
// TODO(scheglov) constructor redirection
var implTokenSignature = _computeNodeTokenSignature(node.body);
var impl = referenceCollector.collect(
implTokenSignature,
enclosingClassName: enclosingClassName,
formalParametersForDefaultValues: node.parameters,
functionBody: node.body,
);
@ -394,6 +404,7 @@ class _LibraryBuilder {
var api = referenceCollector.collect(
apiTokenSignature,
thisNodeName: node.name.name,
typeParameters: functionExpression.typeParameters,
formalParameters: functionExpression.parameters,
returnType: node.returnType,
@ -403,6 +414,7 @@ class _LibraryBuilder {
var implTokenSignature = _computeNodeTokenSignature(body);
var impl = referenceCollector.collect(
implTokenSignature,
thisNodeName: node.name.name,
formalParametersForDefaultValues: functionExpression.parameters,
functionBody: body,
);
@ -420,6 +432,7 @@ class _LibraryBuilder {
var api = referenceCollector.collect(
apiTokenSignature,
thisNodeName: node.name.name,
typeParameters: node.typeParameters,
formalParameters: node.parameters,
returnType: node.returnType,
@ -507,6 +520,8 @@ class _LibraryBuilder {
// TODO(scheglov) metadata, here and everywhere
var api = referenceCollector.collect(
apiTokenSignature,
enclosingClassName: enclosingClassName,
thisNodeName: node.name.name,
typeParameters: node.typeParameters,
formalParameters: node.parameters,
returnType: node.returnType,
@ -515,6 +530,8 @@ class _LibraryBuilder {
var implTokenSignature = _computeNodeTokenSignature(node.body);
var impl = referenceCollector.collect(
implTokenSignature,
enclosingClassName: enclosingClassName,
thisNodeName: node.name.name,
formalParametersForDefaultValues: node.parameters,
functionBody: node.body,
);
@ -570,13 +587,19 @@ class _LibraryBuilder {
var apiTokenSignature = builder.toByteList();
var api = referenceCollector.collect(
apiTokenSignature,
enclosingClassName: enclosingClassName,
thisNodeName: variable.name.name,
type: variables.type,
expression: appendInitializerToApi ? initializer : null,
);
var implTokenSignature = _computeNodeTokenSignature(initializer);
var impl = referenceCollector.collect(implTokenSignature,
expression: initializer);
var impl = referenceCollector.collect(
implTokenSignature,
enclosingClassName: enclosingClassName,
thisNodeName: variable.name.name,
expression: initializer,
);
var rawName = variable.name.name;
variableNodes.add(Node(

View file

@ -55,7 +55,9 @@ class ReferenceCollector {
/// Construct and return a new [Dependencies] with the given [tokenSignature]
/// and all recorded references to external nodes in the given AST nodes.
Dependencies collect(List<int> tokenSignature,
{Expression expression,
{String enclosingClassName,
String thisNodeName,
Expression expression,
ExtendsClause extendsClause,
FormalParameterList formalParameters,
FormalParameterList formalParametersForDefaultValues,
@ -70,6 +72,14 @@ class ReferenceCollector {
WithClause withClause}) {
_localScopes.enter();
// The name of the node shadows any external names.
if (enclosingClassName != null) {
_localScopes.add(enclosingClassName);
}
if (thisNodeName != null) {
_localScopes.add(thisNodeName);
}
// Add type parameters first, they might be referenced later.
_visitTypeParameterList(typeParameters);
_visitTypeParameterList(typeParameters2);
@ -82,8 +92,8 @@ class ReferenceCollector {
_visitTypeAnnotations(implementsClause?.interfaces);
// Parts of executables.
_visitFormalParameterList(formalParameters, false);
_visitFormalParameterList(formalParametersForDefaultValues, true);
_visitFormalParameterList(formalParameters);
_visitFormalParameterListDefaults(formalParametersForDefaultValues);
_visitTypeAnnotation(returnType);
_visitFunctionBody(functionBody);
@ -96,13 +106,26 @@ class ReferenceCollector {
var unprefixedReferencedNames = _unprefixedReferences.toList();
_unprefixedReferences = _NameSet();
var numberOfPrefixes = _importPrefixedReferences.length;
var importPrefixes = List<String>(numberOfPrefixes);
var importPrefixedReferencedNames = List<List<String>>(numberOfPrefixes);
for (var i = 0; i < numberOfPrefixes; i++) {
var importPrefixCount = 0;
for (var i = 0; i < _importPrefixedReferences.length; i++) {
var import = _importPrefixedReferences[i];
importPrefixes[i] = import.prefix;
importPrefixedReferencedNames[i] = import.names.toList();
if (import.names.isNotEmpty) {
importPrefixCount++;
}
}
var importPrefixes = List<String>(importPrefixCount);
var importPrefixedReferencedNames = List<List<String>>(importPrefixCount);
var importIndex = 0;
for (var i = 0; i < _importPrefixedReferences.length; i++) {
var import = _importPrefixedReferences[i];
if (import.names.isNotEmpty) {
importPrefixes[importIndex] = import.prefix;
importPrefixedReferencedNames[importIndex] = import.names.toList();
importIndex++;
}
import.clear();
}
@ -315,8 +338,7 @@ class ReferenceCollector {
_localScopes.exit();
}
void _visitFormalParameterList(
FormalParameterList node, bool withDefaultValues) {
void _visitFormalParameterList(FormalParameterList node) {
if (node == null) return;
var parameters = node.parameters;
@ -325,16 +347,13 @@ class ReferenceCollector {
if (parameter is DefaultFormalParameter) {
DefaultFormalParameter defaultParameter = parameter;
parameter = defaultParameter.parameter;
if (withDefaultValues) {
_visitExpression(defaultParameter.defaultValue);
}
}
if (parameter.identifier != null) {
_localScopes.add(parameter.identifier.name);
}
if (parameter is FunctionTypedFormalParameter) {
_visitTypeAnnotation(parameter.returnType);
_visitFormalParameterList(parameter.parameters, withDefaultValues);
_visitFormalParameterList(parameter.parameters);
} else if (parameter is SimpleFormalParameter) {
_visitTypeAnnotation(parameter.type);
} else {
@ -344,6 +363,18 @@ class ReferenceCollector {
}
}
void _visitFormalParameterListDefaults(FormalParameterList node) {
if (node == null) return;
var parameters = node.parameters;
for (var i = 0; i < parameters.length; i++) {
FormalParameter parameter = parameters[i];
if (parameter is DefaultFormalParameter) {
_visitExpression(parameter.defaultValue);
}
}
}
void _visitForStatement(ForStatement node) {
_localScopes.enter();
@ -384,7 +415,8 @@ class ReferenceCollector {
void _visitFunctionExpression(FunctionExpression node) {
_localScopes.enter();
_visitTypeParameterList(node.typeParameters);
_visitFormalParameterList(node.parameters, true);
_visitFormalParameterList(node.parameters);
_visitFormalParameterListDefaults(node.parameters);
_visitFunctionBody(node.body);
_localScopes.exit();
}
@ -692,7 +724,7 @@ class ReferenceCollector {
}
_visitTypeAnnotation(node.returnType);
_visitFormalParameterList(node.parameters, true);
_visitFormalParameterList(node.parameters);
_localScopes.exit();
} else if (node is TypeName) {
@ -809,6 +841,8 @@ class _LocalScopes {
class _NameSet {
final List<String> names = [];
bool get isNotEmpty => names.isNotEmpty;
void add(String name) {
// TODO(scheglov) consider just adding, but toList() sort and unique
if (!contains(name)) {

View file

@ -18,6 +18,7 @@ main() {
defineReflectiveTests(ExpressionReferenceCollectorTest);
defineReflectiveTests(ExpressionReferenceCollectorTest_SetLiterals);
defineReflectiveTests(ImplReferenceCollectorTest);
defineReflectiveTests(ShadowReferenceCollectorTest);
defineReflectiveTests(StatementReferenceCollectorTest);
defineReflectiveTests(TypeReferenceCollectorTest);
});
@ -242,7 +243,6 @@ class X<T extends A<B, C>> {}
''');
_assertApi(library, 'T', NodeKind.TYPE_PARAMETER,
typeParameterOf: 'X', unprefixed: ['A', 'B', 'C']);
// TODO(scheglov) test for type parameter referencing the enclosing class
}
test_unit_class() async {
@ -1381,7 +1381,7 @@ class ImplReferenceCollectorTest extends _Base {
test_class_constructor() async {
var library = await buildTestLibrary(a, r'''
class C {
C.test({a: x}) {
C.test(A a, {b: x}) {
y;
}
}
@ -1393,7 +1393,7 @@ class C {
test_class_method() async {
var library = await buildTestLibrary(a, r'''
class C {
void test({a: x}) {
void test(A a, {b: x}) {
y;
}
}
@ -1443,7 +1443,7 @@ class Test<T extends V, U extends T> = A<T> with B<U, W>;
test_unit_function() async {
var library = await buildTestLibrary(a, r'''
void test({a: x}) {
void test(A a, {b: x}) {
y;
}
''');
@ -1478,6 +1478,133 @@ int test;
}
}
@reflectiveTest
class ShadowReferenceCollectorTest extends _Base {
test_importPrefix_with_classMember_getter_field() async {
var library = await buildTestLibrary(a, r'''
import 'b.dart' as p;
class X {
p.A<B> test() {}
int p;
}
''');
_assertApi(library, 'test', NodeKind.METHOD,
memberOf: 'X', unprefixed: ['B', 'p']);
}
test_importPrefix_with_classMember_method() async {
var library = await buildTestLibrary(a, r'''
import 'b.dart' as p;
class X {
p.A<B> test() {}
p() {}
}
''');
_assertApi(library, 'test', NodeKind.METHOD,
memberOf: 'X', unprefixed: ['B', 'p']);
}
test_importPrefix_with_function() async {
var library = await buildTestLibrary(a, r'''
import 'b.dart' as p;
p() {} // this is a compilation error
class X extends p.A<B> {}
''');
_assertApi(library, 'X', NodeKind.CLASS, unprefixed: [
'B'
], prefixed: {
'p': ['A']
});
}
test_syntacticScope_class_constructor() async {
var library = await buildTestLibrary(a, r'''
class X {
X.test(A a, X b) {
X;
}
}
''');
_assertApi(library, 'test', NodeKind.CONSTRUCTOR,
memberOf: 'X', unprefixed: ['A']);
_assertImpl(library, 'test', NodeKind.CONSTRUCTOR, memberOf: 'X');
}
test_syntacticScope_class_field() async {
var library = await buildTestLibrary(a, r'''
class X {
var test = x + X + test;
}
''');
_assertApi(library, 'test', NodeKind.GETTER,
memberOf: 'X', unprefixed: ['x']);
_assertImpl(library, 'test', NodeKind.GETTER,
memberOf: 'X', unprefixed: ['x']);
}
test_syntacticScope_class_method() async {
var library = await buildTestLibrary(a, r'''
class X {
test(A a, X b, test c) {
X;
test;
B;
}
}
''');
_assertApi(library, 'test', NodeKind.METHOD,
memberOf: 'X', unprefixed: ['A']);
_assertImpl(library, 'test', NodeKind.METHOD,
memberOf: 'X', unprefixed: ['B']);
}
test_syntacticScope_class_typeParameter_ofClass() async {
var library = await buildTestLibrary(a, r'''
class X<T extends A<B, X, T>> {}
''');
_assertApi(library, 'T', NodeKind.TYPE_PARAMETER,
typeParameterOf: 'X', unprefixed: ['A', 'B']);
}
test_syntacticScope_unit_class() async {
var library = await buildTestLibrary(a, r'''
class X extends A<B, X> {}
''');
_assertApi(library, 'X', NodeKind.CLASS, unprefixed: ['A', 'B']);
}
test_syntacticScope_unit_function() async {
var library = await buildTestLibrary(a, r'''
test(A a, test b) {
test;
B;
}
''');
_assertApi(library, 'test', NodeKind.FUNCTION, unprefixed: ['A']);
_assertImpl(library, 'test', NodeKind.FUNCTION, unprefixed: ['B']);
}
test_syntacticScope_unit_functionTypeAlias() async {
var library = await buildTestLibrary(a, r'''
typedef X(A a, X b);
''');
_assertApi(library, 'X', NodeKind.FUNCTION_TYPE_ALIAS, unprefixed: ['A']);
}
test_syntacticScope_unit_mixin() async {
var library = await buildTestLibrary(a, r'''
mixin X on A<B, X> {}
''');
_assertApi(library, 'X', NodeKind.MIXIN, unprefixed: ['A', 'B']);
}
}
@reflectiveTest
class StatementReferenceCollectorTest extends _Base {
test_assertStatement() async {