Skip to content

Commit 388c983

Browse files
scheglovcommit-bot@chromium.org
authored andcommitted
Add higher level non-API for angular_analyzer_plugin.
Change-Id: I7eb5a3c7e90b9d86c296dafc95b9f9c750c0095a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/154200 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 39f39c0 commit 388c983

File tree

5 files changed

+254
-0
lines changed

5 files changed

+254
-0
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// This library provides additional APIs for the corresponding client.
6+
///
7+
/// By providing such higher level APIs we simplify the clients, and reduce
8+
/// dependencies on analyzer internal, so can make otherwise breaking
9+
/// changes easily.
10+
library angular_analyzer_plugin;
11+
12+
import 'package:analyzer/dart/ast/ast.dart';
13+
import 'package:analyzer/dart/element/element.dart';
14+
import 'package:analyzer/dart/element/type_provider.dart';
15+
import 'package:analyzer/error/listener.dart';
16+
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
17+
import 'package:analyzer/src/dart/resolver/resolution_visitor.dart';
18+
import 'package:analyzer/src/dart/resolver/scope.dart';
19+
import 'package:analyzer/src/generated/error_verifier.dart';
20+
import 'package:analyzer/src/generated/resolver.dart';
21+
import 'package:analyzer/src/generated/source.dart';
22+
import 'package:meta/meta.dart';
23+
24+
/// Resolve the given [node] in the specified context.
25+
///
26+
/// The [componentClass] is the component class.
27+
///
28+
/// The [templateSource] is the file with the template.
29+
///
30+
/// The template might declare [localVariables], which might be referenced
31+
/// in the node being resolved.
32+
///
33+
/// The [overrideAsExpression] is invoked during [AsExpression] to support
34+
/// custom resolution behavior.
35+
void resolveTemplateNode({
36+
@required ClassElement componentClass,
37+
@required Source templateSource,
38+
@required Iterable<LocalVariableElement> localVariables,
39+
@required AstNode node,
40+
@required AnalysisErrorListener errorListener,
41+
@required ErrorReporter errorReporter,
42+
OverrideAsExpression overrideAsExpression,
43+
}) {
44+
final unitElement = componentClass.enclosingElement;
45+
final library = componentClass.library;
46+
47+
final libraryScope = LibraryScope(library);
48+
node.accept(
49+
ResolutionVisitor(
50+
unitElement: unitElement,
51+
errorListener: errorListener,
52+
featureSet: library.context.analysisOptions.contextFeatures,
53+
nameScope: libraryScope,
54+
),
55+
);
56+
57+
final inheritanceManager = InheritanceManager3();
58+
final resolver = _AngularTemplateResolver(inheritanceManager, library,
59+
templateSource, library.typeProvider, errorListener,
60+
overrideAsExpression: overrideAsExpression);
61+
// fill the name scope
62+
final classScope = ClassScope(resolver.nameScope, componentClass);
63+
final localScope = EnclosedScope(classScope);
64+
resolver
65+
..nameScope = localScope
66+
..enclosingClass = componentClass;
67+
localVariables.forEach(localScope.define);
68+
// do resolve
69+
node.accept(resolver);
70+
// verify
71+
final verifier = ErrorVerifier(
72+
errorReporter, library, library.typeProvider, inheritanceManager)
73+
..enclosingClass = componentClass;
74+
node.accept(verifier);
75+
}
76+
77+
typedef OverrideAsExpression = void Function({
78+
@required AsExpression node,
79+
@required void Function(AsExpression) invokeSuper,
80+
});
81+
82+
class _AngularTemplateResolver extends ResolverVisitor {
83+
final OverrideAsExpression overrideAsExpression;
84+
85+
_AngularTemplateResolver(
86+
InheritanceManager3 inheritanceManager,
87+
LibraryElement library,
88+
Source source,
89+
TypeProvider typeProvider,
90+
AnalysisErrorListener errorListener, {
91+
@required this.overrideAsExpression,
92+
}) : super(inheritanceManager, library, source, typeProvider, errorListener);
93+
94+
@override
95+
void visitAsExpression(AsExpression node) {
96+
if (overrideAsExpression != null) {
97+
overrideAsExpression(
98+
node: node,
99+
invokeSuper: (node) {
100+
super.visitAsExpression(node);
101+
},
102+
);
103+
} else {
104+
super.visitAsExpression(node);
105+
}
106+
}
107+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:analyzer/dart/analysis/utilities.dart';
6+
import 'package:analyzer/dart/ast/ast.dart';
7+
import 'package:analyzer/error/listener.dart';
8+
import 'package:analyzer/src/clients/angular_analyzer_plugin/angular_analyzer_plugin.dart';
9+
import 'package:analyzer/src/test_utilities/find_node.dart';
10+
import 'package:meta/meta.dart';
11+
import 'package:test/test.dart';
12+
import 'package:test_reflective_loader/test_reflective_loader.dart';
13+
14+
import '../../dart/resolution/driver_resolution.dart';
15+
16+
main() {
17+
defineReflectiveSuite(() {
18+
defineReflectiveTests(ResolveTemplateNodeTest);
19+
});
20+
}
21+
22+
@reflectiveTest
23+
class ResolveTemplateNodeTest extends DriverResolutionTest {
24+
test_asExpression() async {
25+
await assertNoErrorsInCode(r'''
26+
class MyComponent {}
27+
''');
28+
29+
var source = findElement.unitElement.source;
30+
var errorListener = RecordingErrorListener();
31+
32+
var template = _parseTemplate('var x = 0 as int;');
33+
var node = template.findNode.variableDeclaration('x = ').initializer;
34+
35+
var overrideAsExpressionInvoked = false;
36+
37+
resolveTemplateNode(
38+
componentClass: findElement.class_('MyComponent'),
39+
templateSource: source,
40+
localVariables: [],
41+
node: node,
42+
errorListener: errorListener,
43+
errorReporter: ErrorReporter(errorListener, source),
44+
overrideAsExpression: ({node, invokeSuper}) {
45+
overrideAsExpressionInvoked = true;
46+
expect(invokeSuper, isNotNull);
47+
},
48+
);
49+
50+
expect(overrideAsExpressionInvoked, isTrue);
51+
}
52+
53+
test_references() async {
54+
await assertNoErrorsInCode(r'''
55+
class MyComponent {
56+
void someContext() {
57+
// ignore:unused_local_variable
58+
var foo = 0;
59+
}
60+
61+
void bar(int a) {}
62+
}
63+
''');
64+
65+
var source = findElement.unitElement.source;
66+
var errorListener = RecordingErrorListener();
67+
68+
var template = _parseTemplate('var x = bar(foo);');
69+
var node = template.findNode.variableDeclaration('x = ').initializer;
70+
assertElementNull(template.findNode.simple('foo'));
71+
assertElementNull(template.findNode.methodInvocation('bar'));
72+
73+
resolveTemplateNode(
74+
componentClass: findElement.class_('MyComponent'),
75+
templateSource: source,
76+
localVariables: [
77+
findElement.localVar('foo'),
78+
],
79+
node: node,
80+
errorListener: errorListener,
81+
errorReporter: ErrorReporter(errorListener, source),
82+
);
83+
84+
assertElement(
85+
template.findNode.simple('foo'),
86+
findElement.localVar('foo'),
87+
);
88+
89+
assertElement(
90+
template.findNode.methodInvocation('bar'),
91+
findElement.method('bar'),
92+
);
93+
}
94+
95+
_ParsedTemplate _parseTemplate(String templateCode) {
96+
var templateUnit = parseString(
97+
content: templateCode,
98+
featureSet: result.unit.featureSet,
99+
).unit;
100+
101+
return _ParsedTemplate(
102+
content: templateCode,
103+
unit: templateUnit,
104+
findNode: FindNode(templateCode, templateUnit),
105+
);
106+
}
107+
}
108+
109+
class _ParsedTemplate {
110+
final String content;
111+
final CompilationUnit unit;
112+
final FindNode findNode;
113+
114+
_ParsedTemplate({
115+
@required this.content,
116+
@required this.unit,
117+
@required this.findNode,
118+
});
119+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:test_reflective_loader/test_reflective_loader.dart';
6+
7+
import 'resolve_template_node_test.dart' as resolve_template_node;
8+
9+
main() {
10+
defineReflectiveSuite(() {
11+
resolve_template_node.main();
12+
}, name: 'angular_analyzer_plugin');
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:test_reflective_loader/test_reflective_loader.dart';
6+
7+
import 'angular_analyzer_plugin/test_all.dart' as angular_analyzer_plugin;
8+
9+
main() {
10+
defineReflectiveSuite(() {
11+
angular_analyzer_plugin.main();
12+
}, name: 'clients');
13+
}

pkg/analyzer/test/src/test_all.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import 'package:test_reflective_loader/test_reflective_loader.dart';
66

7+
import 'clients/test_all.dart' as clients;
78
import 'command_line/test_all.dart' as command_line;
89
import 'context/test_all.dart' as context;
910
import 'dart/test_all.dart' as dart;
@@ -25,6 +26,7 @@ import 'workspace/test_all.dart' as workspace;
2526

2627
main() {
2728
defineReflectiveSuite(() {
29+
clients.main();
2830
command_line.main();
2931
context.main();
3032
dart.main();

0 commit comments

Comments
 (0)