Skip to content

Commit 77b31ab

Browse files
author
Tim Blasi
committed
feat(dart/transform): Add debug transform parameters
Add two transform parameters to aid in debugging the transformer - `mirror_mode`, with values {`debug`, `none`, and `verbose`} - `init_reflector`, with values {`true`, `false`} `mirror_mode`: - `debug`: Allow reflective access, but log a message if it is used - `none`: Remove reflective access, `throw` if it is used. Default value - `verbose`: Allow reflective access, log a stack trace if it is used `init_reflector`: Whether to generate calls to our generated `initReflector` code. These will be useful to reveal areas where the transformer is not generating appropriate code and to quickly see where reflective accesses occur. When the pub mode is `transform_dynamic`, we run in MirrorMode.debug with `init_reflector = false`. This is used for testing purposes.
1 parent 5b4eb0c commit 77b31ab

22 files changed

Lines changed: 343 additions & 22 deletions

File tree

modules/angular2/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ dependencies:
1414
code_transformers: '^0.2.5'
1515
dart_style: '^0.1.3'
1616
html: '^0.12.0'
17+
logging: '>=0.9.0 <0.11.0'
1718
source_span: '^1.0.0'
1819
stack_trace: '^1.1.1'
1920
transformers:
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
library reflection.debug_reflection_capabilities;
2+
3+
import 'package:logging/logging.dart';
4+
import 'package:stack_trace/stack_trace.dart';
5+
import 'types.dart';
6+
import 'reflection_capabilities.dart' as standard;
7+
8+
class ReflectionCapabilities extends standard.ReflectionCapabilities {
9+
final bool _verbose;
10+
final Logger _log = new Logger('ReflectionCapabilities');
11+
12+
ReflectionCapabilities({bool verbose: false})
13+
: _verbose = verbose,
14+
super() {
15+
Logger.root.level = _verbose ? Level.ALL : Level.INFO;
16+
Logger.root.onRecord.listen((LogRecord rec) {
17+
print('[${rec.loggerName}(${rec.level.name})]: ${rec.message}');
18+
});
19+
}
20+
21+
void _notify(String methodName, param) {
22+
var trace = _verbose ? ' ${Trace.format(new Trace.current())}' : '';
23+
_log.info('"$methodName" requested for "$param".$trace');
24+
}
25+
26+
Function factory(Type type) {
27+
_notify('factory', type);
28+
return super.factory(type);
29+
}
30+
31+
List<List> parameters(typeOrFunc) {
32+
_notify('parameters', typeOrFunc);
33+
return super.parameters(typeOrFunc);
34+
}
35+
36+
List annotations(typeOrFunc) {
37+
_notify('annotations', typeOrFunc);
38+
return super.annotations(typeOrFunc);
39+
}
40+
41+
GetterFn getter(String name) {
42+
_notify('getter', name);
43+
return super.getter(name);
44+
}
45+
46+
SetterFn setter(String name) {
47+
_notify('setter', name);
48+
return super.setter(name);
49+
}
50+
51+
MethodFn method(String name) {
52+
_notify('method', name);
53+
return super.method(name);
54+
}
55+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
library angular2.transform.common.mirror_mode;
2+
3+
/// Modes for mirror use.
4+
/// `none` is the default value and signifies that mirror use should be
5+
/// removed.
6+
/// `debug` allows the use of mirrors and logs a notice whenever they are
7+
/// accessed.
8+
/// `verbose` allows the use of mirrors and logs a stack trace whenever they
9+
/// are accessed.
10+
enum MirrorMode { debug, none, verbose }

modules/angular2/src/transform/common/names.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ library angular2.transform.common.names;
22

33
const SETUP_METHOD_NAME = 'initReflector';
44
const REFLECTOR_VAR_NAME = 'reflector';
5+
const TRANSFORM_DYNAMIC_MODE = 'transform_dynamic';
56
const DEPS_EXTENSION = '.ng_deps.dart';
67
const REFLECTION_CAPABILITIES_NAME = 'ReflectionCapabilities';
78
const REGISTER_TYPE_METHOD_NAME = 'registerType';
89
const REGISTER_GETTERS_METHOD_NAME = 'registerGetters';
910
const REGISTER_SETTERS_METHOD_NAME = 'registerSetters';
1011
const REGISTER_METHODS_METHOD_NAME = 'registerMethods';
11-
const TRANSFORM_MODE = 'ngstatic';

modules/angular2/src/transform/common/options.dart

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
library angular2.transform.common.options;
22

3+
import 'mirror_mode.dart';
4+
35
const ENTRY_POINT_PARAM = 'entry_points';
46
const REFLECTION_ENTRY_POINT_PARAM = 'reflection_entry_points';
57

@@ -15,15 +17,22 @@ class TransformerOptions {
1517
/// The `BarbackMode#name` we are running in.
1618
final String modeName;
1719

18-
TransformerOptions._internal(
19-
this.entryPoints, this.reflectionEntryPoints, this.modeName);
20+
/// The [MirrorMode] to use for the transformation.
21+
final MirrorMode mirrorMode;
22+
23+
/// Whether to generate calls to our generated `initReflector` code
24+
final bool initReflector;
25+
26+
TransformerOptions._internal(this.entryPoints, this.reflectionEntryPoints,
27+
this.modeName, this.mirrorMode, this.initReflector);
2028

2129
factory TransformerOptions(List<String> entryPoints,
22-
{List<String> reflectionEntryPoints, String modeName: 'release'}) {
30+
{List<String> reflectionEntryPoints, String modeName: 'release',
31+
MirrorMode mirrorMode: MirrorMode.none, bool initReflector: true}) {
2332
if (reflectionEntryPoints == null || reflectionEntryPoints.isEmpty) {
2433
reflectionEntryPoints = entryPoints;
2534
}
26-
return new TransformerOptions._internal(
27-
entryPoints, reflectionEntryPoints, modeName);
35+
return new TransformerOptions._internal(entryPoints, reflectionEntryPoints,
36+
modeName, mirrorMode, initReflector);
2837
}
2938
}

modules/angular2/src/transform/common/options_reader.dart

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,35 @@
11
library angular2.transform.common.options_reader;
22

33
import 'package:barback/barback.dart';
4+
import 'mirror_mode.dart';
45
import 'options.dart';
56

67
TransformerOptions parseBarbackSettings(BarbackSettings settings) {
78
var config = settings.configuration;
89
var entryPoints = _readFileList(config, ENTRY_POINT_PARAM);
910
var reflectionEntryPoints =
1011
_readFileList(config, REFLECTION_ENTRY_POINT_PARAM);
12+
var initReflector = !config.containsKey('init_reflector') ||
13+
config['init_reflector'] != false;
14+
String mirrorModeVal =
15+
config.containsKey('mirror_mode') ? config['mirror_mode'] : '';
16+
var mirrorMode = MirrorMode.none;
17+
switch (mirrorModeVal) {
18+
case 'debug':
19+
mirrorMode = MirrorMode.debug;
20+
break;
21+
case 'verbose':
22+
mirrorMode = MirrorMode.verbose;
23+
break;
24+
default:
25+
mirrorMode = MirrorMode.none;
26+
break;
27+
}
1128
return new TransformerOptions(entryPoints,
1229
reflectionEntryPoints: reflectionEntryPoints,
13-
modeName: settings.mode.name);
30+
modeName: settings.mode.name,
31+
mirrorMode: mirrorMode,
32+
initReflector: initReflector);
1433
}
1534

1635
/// Cribbed from the polymer project.

modules/angular2/src/transform/reflection_remover/remove_reflection_capabilities.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'dart:async';
44
import 'package:analyzer/analyzer.dart';
55
import 'package:barback/barback.dart';
66
import 'package:angular2/src/transform/common/asset_reader.dart';
7+
import 'package:angular2/src/transform/common/mirror_mode.dart';
78

89
import 'codegen.dart';
910
import 'rewriter.dart';
@@ -15,12 +16,15 @@ import 'rewriter.dart';
1516
/// This only searches the code in `reflectionEntryPoint`, not `part`s,
1617
/// `import`s, `export`s, etc.
1718
Future<String> removeReflectionCapabilities(AssetReader reader,
18-
AssetId reflectionEntryPoint, Iterable<AssetId> newEntryPoints) async {
19+
AssetId reflectionEntryPoint, Iterable<AssetId> newEntryPoints,
20+
{MirrorMode mirrorMode: MirrorMode.none,
21+
bool writeStaticInit: true}) async {
1922
var code = await reader.readAsString(reflectionEntryPoint);
2023
var reflectionEntryPointPath = reflectionEntryPoint.path;
2124
var newEntryPointPaths = newEntryPoints.map((id) => id.path);
2225

2326
var codegen = new Codegen(reflectionEntryPointPath, newEntryPointPaths);
24-
return new Rewriter(code, codegen)
27+
return new Rewriter(code, codegen,
28+
mirrorMode: mirrorMode, writeStaticInit: writeStaticInit)
2529
.rewrite(parseCompilationUnit(code, name: reflectionEntryPointPath));
2630
}

modules/angular2/src/transform/reflection_remover/rewriter.dart

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ library angular2.transform.reflection_remover.rewriter;
22

33
import 'package:analyzer/src/generated/ast.dart';
44
import 'package:angular2/src/transform/common/logging.dart';
5+
import 'package:angular2/src/transform/common/mirror_mode.dart';
56
import 'package:angular2/src/transform/common/names.dart';
7+
import 'package:path/path.dart' as path;
68

79
import 'ast_tester.dart';
810
import 'codegen.dart';
@@ -11,9 +13,14 @@ class Rewriter {
1113
final String _code;
1214
final Codegen _codegen;
1315
final AstTester _tester;
16+
final MirrorMode _mirrorMode;
17+
final bool _writeStaticInit;
1418

15-
Rewriter(this._code, this._codegen, {AstTester tester})
16-
: _tester = tester == null ? const AstTester() : tester;
19+
Rewriter(this._code, this._codegen, {AstTester tester,
20+
MirrorMode mirrorMode: MirrorMode.none, bool writeStaticInit: true})
21+
: _mirrorMode = mirrorMode,
22+
_writeStaticInit = writeStaticInit,
23+
_tester = tester == null ? const AstTester() : tester;
1724

1825
/// Rewrites the provided code removing imports of the
1926
/// {@link ReflectionCapabilities} library and instantiations of
@@ -51,8 +58,12 @@ class Rewriter {
5158
'Found import prefix "${_codegen.prefix}" in source file.'
5259
' Transform may not succeed.');
5360
}
54-
buf.write(_commentedNode(node));
55-
if (!importAdded) {
61+
if (_mirrorMode != MirrorMode.none) {
62+
buf.write(_importDebugReflectionCapabilities(node));
63+
} else {
64+
buf.write(_commentedNode(node));
65+
}
66+
if (!importAdded && _writeStaticInit) {
5667
buf.write(_codegen.codegenImport());
5768
importAdded = true;
5869
}
@@ -67,8 +78,19 @@ class Rewriter {
6778
node = node.parent;
6879
}
6980
buf.write(_code.substring(lastIdx, node.offset));
70-
buf.write(_commentedNode(node));
71-
if (!setupAdded) {
81+
switch (_mirrorMode) {
82+
case MirrorMode.debug:
83+
buf.write(node);
84+
break;
85+
case MirrorMode.verbose:
86+
buf.write(_instantiateVerboseReflectionCapabilities(assignNode));
87+
break;
88+
case MirrorMode.none:
89+
default:
90+
buf.write(_commentedNode(node));
91+
break;
92+
}
93+
if (!setupAdded && _writeStaticInit) {
7294
buf.write(_codegen.codegenSetupReflectionCall(
7395
reflectorAssignment: assignNode));
7496
setupAdded = true;
@@ -79,8 +101,24 @@ class Rewriter {
79101
return buf.toString();
80102
}
81103

104+
String _instantiateVerboseReflectionCapabilities(
105+
AssignmentExpression assignNode) {
106+
if (assignNode.rightHandSide is! InstanceCreationExpression) {
107+
return '$assignNode;';
108+
}
109+
var rhs = (assignNode.rightHandSide as InstanceCreationExpression);
110+
return '${assignNode.leftHandSide} ${assignNode.operator} '
111+
'new ${rhs.constructorName}(verbose: true);';
112+
}
113+
114+
String _importDebugReflectionCapabilities(ImportDirective node) {
115+
var uri = '${node.uri}';
116+
uri = path.join(path.dirname(uri), 'debug_${path.basename(uri)}');
117+
var asClause = node.prefix != null ? ' as ${node.prefix}' : '';
118+
return 'import $uri$asClause;';
119+
}
120+
82121
String _commentedNode(AstNode node) {
83-
// TODO(kegluneq): Return commented code once we generate all needed code.
84122
return '/*${_code.substring(node.offset, node.end)}*/';
85123
}
86124
}

modules/angular2/src/transform/reflection_remover/transformer.dart

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ library angular2.transform.reflection_remover.transformer;
33
import 'dart:async';
44
import 'package:angular2/src/transform/common/asset_reader.dart';
55
import 'package:angular2/src/transform/common/logging.dart' as log;
6+
import 'package:angular2/src/transform/common/mirror_mode.dart';
67
import 'package:angular2/src/transform/common/names.dart';
78
import 'package:angular2/src/transform/common/options.dart';
89
import 'package:barback/barback.dart';
@@ -38,8 +39,19 @@ class ReflectionRemover extends Transformer {
3839
});
3940
var reader = new AssetReader.fromTransform(transform);
4041

42+
var mirrorMode = options.mirrorMode;
43+
var writeStaticInit = options.initReflector;
44+
if (options.modeName == TRANSFORM_DYNAMIC_MODE) {
45+
mirrorMode = MirrorMode.debug;
46+
writeStaticInit = false;
47+
log.logger.info('Running in "${options.modeName}", '
48+
'mirrorMode: ${mirrorMode}, '
49+
'writeStaticInit: ${writeStaticInit}.');
50+
}
51+
4152
var transformedCode = await removeReflectionCapabilities(
42-
reader, transform.primaryInput.id, newEntryPoints);
53+
reader, transform.primaryInput.id, newEntryPoints,
54+
mirrorMode: mirrorMode, writeStaticInit: writeStaticInit);
4355
transform.addOutput(
4456
new Asset.fromString(transform.primaryInput.id, transformedCode));
4557
} catch (ex, stackTrace) {

modules/angular2/test/transform/integration/all_tests.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ main() {
1414

1515
var formatter = new DartFormatter();
1616
var transform = new AngularTransformerGroup(new TransformerOptions(
17-
['web/index.dart'],
18-
reflectionEntryPoints: ['web/index.dart'], modeName: TRANSFORM_MODE));
17+
['web/index.dart'], reflectionEntryPoints: ['web/index.dart']));
1918

2019
class IntegrationTestConfig {
2120
final String name;

0 commit comments

Comments
 (0)