refactor(dart/transform): Run `ReflectionRemover` after codegen phases

Move the `ReflectionRemover` phase to execute after the codegen phases.
This commit is contained in:
Tim Blasi 2015-10-23 09:54:11 -07:00
parent eba70736f1
commit 6b40293c0a
6 changed files with 66 additions and 63 deletions

View File

@ -1,16 +1,27 @@
library angular2.transform.common.code.import_export_code; library angular2.transform.common.code.import_export_code;
import 'package:analyzer/analyzer.dart'; import 'package:analyzer/analyzer.dart';
import 'package:angular2/src/transform/common/mirror_matcher.dart';
import 'package:angular2/src/transform/common/model/import_export_model.pb.dart'; import 'package:angular2/src/transform/common/model/import_export_model.pb.dart';
const _mirrorMatcher = const MirrorMatcher();
/// Visitor responsible for parsing [ImportDirective]s into [ImportModel]s. /// Visitor responsible for parsing [ImportDirective]s into [ImportModel]s.
class ImportVisitor extends SimpleAstVisitor<ImportModel> { class ImportVisitor extends SimpleAstVisitor<ImportModel> {
@override @override
ImportModel visitImportDirective(ImportDirective node) { ImportModel visitImportDirective(ImportDirective node) {
if (node.isSynthetic) return null; if (node.isSynthetic) return null;
/// We skip this, as it transitively imports 'dart:mirrors'
if (_mirrorMatcher.hasReflectionCapabilitiesUri(node)) return null;
String uri = stringLiteralToString(node.uri);
// The bootstrap code also transitively imports 'dart:mirrors'
if (_mirrorMatcher.hasBootstrapUri(node)) {
uri = BOOTSTRAP_STATIC_URI;
}
var model = new ImportModel() var model = new ImportModel()
..uri = stringLiteralToString(node.uri) ..uri = uri
..isDeferred = node.deferredKeyword != null; ..isDeferred = node.deferredKeyword != null;
if (node.prefix != null) { if (node.prefix != null) {
model.prefix = node.prefix.name; model.prefix = node.prefix.name;
@ -26,7 +37,15 @@ class ExportVisitor extends SimpleAstVisitor<ExportModel> {
ExportModel visitExportDirective(ExportDirective node) { ExportModel visitExportDirective(ExportDirective node) {
if (node.isSynthetic) return null; if (node.isSynthetic) return null;
var model = new ExportModel()..uri = stringLiteralToString(node.uri); /// We skip this, as it transitively imports 'dart:mirrors'
if (_mirrorMatcher.hasReflectionCapabilitiesUri(node)) return null;
String uri = stringLiteralToString(node.uri);
// The bootstrap code also transitively imports 'dart:mirrors'
if (_mirrorMatcher.hasBootstrapUri(node)) {
uri = BOOTSTRAP_STATIC_URI;
}
var model = new ExportModel()..uri = uri;
_populateCombinators(node, model); _populateCombinators(node, model);
return model; return model;
} }

View File

@ -0,0 +1,29 @@
library angular2.transform.common.mirror_matcher;
import 'package:analyzer/src/generated/ast.dart';
import 'package:angular2/src/transform/common/names.dart';
const BOOTSTRAP_STATIC_URI = 'package:angular2/bootstrap_static.dart';
const BOOTSTRAP_URI = 'package:angular2/bootstrap.dart';
const REFLECTION_CAPABILITIES_URI =
'package:angular2/src/core/reflection/reflection_capabilities.dart';
/// Syntactially checks for code related to the use of `dart:mirrors`.
///
/// Checks various [AstNode]s to determine if they are
/// - Libraries that transitively import `dart:mirrors`
/// - Instantiations of [ReflectionCapabilities]
class MirrorMatcher {
const MirrorMatcher();
bool isNewReflectionCapabilities(InstanceCreationExpression node) =>
'${node.constructorName.type.name}' == REFLECTION_CAPABILITIES_NAME;
bool hasReflectionCapabilitiesUri(UriBasedDirective node) {
return node.uri.stringValue == REFLECTION_CAPABILITIES_URI;
}
bool hasBootstrapUri(UriBasedDirective node) {
return node.uri.stringValue == BOOTSTRAP_URI;
}
}

View File

@ -1,44 +0,0 @@
library angular2.transform.reflection_remover.ast_tester;
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:angular2/src/transform/common/names.dart';
/// An object that checks for {@link ReflectionCapabilities} syntactically, that is,
/// without resolution information.
class AstTester {
const AstTester();
bool isNewReflectionCapabilities(InstanceCreationExpression node) =>
'${node.constructorName.type.name}' == REFLECTION_CAPABILITIES_NAME;
bool isReflectionCapabilitiesImport(ImportDirective node) {
return node.uri.stringValue ==
"package:angular2/src/core/reflection/reflection_capabilities.dart";
}
bool isBootstrapImport(ImportDirective node) {
return node.uri.stringValue == "package:angular2/bootstrap.dart";
}
}
/// An object that checks for {@link ReflectionCapabilities} using a fully resolved
/// Ast.
class ResolvedTester implements AstTester {
final ClassElement _forbiddenClass;
ResolvedTester(this._forbiddenClass);
bool isNewReflectionCapabilities(InstanceCreationExpression node) {
var typeElement = node.constructorName.type.name.bestElement;
return typeElement != null && typeElement == _forbiddenClass;
}
bool isReflectionCapabilitiesImport(ImportDirective node) {
return node.uriElement == _forbiddenClass.library;
}
bool isBootstrapImport(ImportDirective node) {
throw 'Not implemented';
}
}

View File

@ -2,32 +2,33 @@ library angular2.transform.reflection_remover.rewriter;
import 'package:analyzer/src/generated/ast.dart'; import 'package:analyzer/src/generated/ast.dart';
import 'package:angular2/src/transform/common/logging.dart'; import 'package:angular2/src/transform/common/logging.dart';
import 'package:angular2/src/transform/common/mirror_matcher.dart';
import 'package:angular2/src/transform/common/mirror_mode.dart'; import 'package:angular2/src/transform/common/mirror_mode.dart';
import 'package:angular2/src/transform/common/names.dart'; import 'package:angular2/src/transform/common/names.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'ast_tester.dart';
import 'codegen.dart'; import 'codegen.dart';
class Rewriter { class Rewriter {
final String _code; final String _code;
final Codegen _codegen; final Codegen _codegen;
final AstTester _tester; final MirrorMatcher _mirrorMatcher;
final MirrorMode _mirrorMode; final MirrorMode _mirrorMode;
final bool _writeStaticInit; final bool _writeStaticInit;
Rewriter(this._code, this._codegen, Rewriter(this._code, this._codegen,
{AstTester tester, {MirrorMatcher mirrorMatcher,
MirrorMode mirrorMode: MirrorMode.none, MirrorMode mirrorMode: MirrorMode.none,
bool writeStaticInit: true}) bool writeStaticInit: true})
: _mirrorMode = mirrorMode, : _mirrorMode = mirrorMode,
_writeStaticInit = writeStaticInit, _writeStaticInit = writeStaticInit,
_tester = tester == null ? const AstTester() : tester; _mirrorMatcher =
mirrorMatcher == null ? const MirrorMatcher() : mirrorMatcher;
/// Rewrites the provided code removing imports of the /// Rewrites the provided code removing imports of the
/// {@link ReflectionCapabilities} library and instantiations of /// {@link ReflectionCapabilities} library and instantiations of
/// {@link ReflectionCapabilities}, as detected by the (potentially) provided /// {@link ReflectionCapabilities}, as detected by the (potentially) provided
/// {@link AstTester}. /// {@link MirrorMatcher}.
/// ///
/// To the extent possible, this method does not change line numbers or /// To the extent possible, this method does not change line numbers or
/// offsets in the provided code to facilitate debugging via source maps. /// offsets in the provided code to facilitate debugging via source maps.
@ -62,9 +63,9 @@ class _RewriterVisitor extends Object with RecursiveAstVisitor<Object> {
Object visitImportDirective(ImportDirective node) { Object visitImportDirective(ImportDirective node) {
buf.write(_rewriter._code.substring(_currentIndex, node.offset)); buf.write(_rewriter._code.substring(_currentIndex, node.offset));
_currentIndex = node.offset; _currentIndex = node.offset;
if (_rewriter._tester.isReflectionCapabilitiesImport(node)) { if (_rewriter._mirrorMatcher.hasReflectionCapabilitiesUri(node)) {
_rewriteReflectionCapabilitiesImport(node); _rewriteReflectionCapabilitiesImport(node);
} else if (_rewriter._tester.isBootstrapImport(node)) { } else if (_rewriter._mirrorMatcher.hasBootstrapUri(node)) {
_rewriteBootstrapImportToStatic(node); _rewriteBootstrapImportToStatic(node);
} }
if (!_importAdded && _rewriter._writeStaticInit) { if (!_importAdded && _rewriter._writeStaticInit) {
@ -78,7 +79,8 @@ class _RewriterVisitor extends Object with RecursiveAstVisitor<Object> {
@override @override
Object visitAssignmentExpression(AssignmentExpression node) { Object visitAssignmentExpression(AssignmentExpression node) {
if (node.rightHandSide is InstanceCreationExpression && if (node.rightHandSide is InstanceCreationExpression &&
_rewriter._tester.isNewReflectionCapabilities(node.rightHandSide)) { _rewriter._mirrorMatcher
.isNewReflectionCapabilities(node.rightHandSide)) {
reflectionCapabilityAssignments.add(node); reflectionCapabilityAssignments.add(node);
_rewriteReflectionCapabilitiesAssignment(node); _rewriteReflectionCapabilitiesAssignment(node);
} }
@ -87,7 +89,7 @@ class _RewriterVisitor extends Object with RecursiveAstVisitor<Object> {
@override @override
Object visitInstanceCreationExpression(InstanceCreationExpression node) { Object visitInstanceCreationExpression(InstanceCreationExpression node) {
if (_rewriter._tester.isNewReflectionCapabilities(node) && if (_rewriter._mirrorMatcher.isNewReflectionCapabilities(node) &&
!reflectionCapabilityAssignments.contains(node.parent)) { !reflectionCapabilityAssignments.contains(node.parent)) {
logger.error('Unexpected format in creation of ' logger.error('Unexpected format in creation of '
'${REFLECTION_CAPABILITIES_NAME}'); '${REFLECTION_CAPABILITIES_NAME}');
@ -112,10 +114,10 @@ class _RewriterVisitor extends Object with RecursiveAstVisitor<Object> {
_rewriteBootstrapImportToStatic(ImportDirective node) { _rewriteBootstrapImportToStatic(ImportDirective node) {
if (_rewriter._writeStaticInit) { if (_rewriter._writeStaticInit) {
// rewrite `bootstrap.dart` to `bootstrap_static.dart` // rewrite bootstrap import to its static version.
buf.write(_rewriter._code.substring(_currentIndex, node.offset)); buf.write(_rewriter._code.substring(_currentIndex, node.offset));
// TODO(yjbanov): handle import "..." show/hide ... // TODO(yjbanov): handle import "..." show/hide ...
buf.write("import 'package:angular2/bootstrap_static.dart';"); buf.write("import '$BOOTSTRAP_STATIC_URI';");
} else { } else {
// leave it as is // leave it as is
buf.write(_rewriter._code.substring(_currentIndex, node.end)); buf.write(_rewriter._code.substring(_currentIndex, node.end));

View File

@ -32,9 +32,9 @@ class AngularTransformerGroup extends TransformerGroup {
]; ];
} else { } else {
phases = [ phases = [
[new ReflectionRemover(options)],
[new DirectiveProcessor(options)], [new DirectiveProcessor(options)],
[new DirectiveMetadataLinker()], [new DirectiveMetadataLinker()],
[new ReflectionRemover(options)],
[ [
new DeferredRewriter(options), new DeferredRewriter(options),
new StylesheetCompiler(), new StylesheetCompiler(),

View File

@ -3,17 +3,14 @@ library web_foo.ng_deps.dart;
import 'index.dart'; import 'index.dart';
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
import 'package:angular2/bootstrap_static.dart'; import 'package:angular2/bootstrap_static.dart';
import 'index.ng_deps.dart' as ngStaticInit;
import 'index.ng_deps.dart' as i1;
import 'package:angular2/src/core/reflection/reflection.dart'; import 'package:angular2/src/core/reflection/reflection.dart';
import 'bar.dart'; import 'bar.dart';
import 'bar.ng_deps.dart' as i3; import 'bar.ng_deps.dart' as i2;
export 'index.dart'; export 'index.dart';
var _visited = false; var _visited = false;
void initReflector() { void initReflector() {
if (_visited) return; if (_visited) return;
_visited = true; _visited = true;
i1.initReflector(); i2.initReflector();
i3.initReflector();
} }