Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(450)

Side by Side Diff: pkg/checked_mirrors/lib/src/checker.dart

Issue 111643015: Preliminary checked mirrors (not ready for review yet) (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/checked_mirrors/lib/control.dart ('k') | pkg/checked_mirrors/lib/src/utils.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013, 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 /// Defines rules and a chacker to determine if MirrorsUsed was used correctly.
6 library checked_mirrors.src.checker;
7
8 import "dart:mirrors";
9 import "dart:async";
10
11 import 'package:checked_mirrors/control.dart';
12 import 'package:logging/logging.dart';
13
14 import 'utils.dart';
15
16 /// Controller used to log warnings detected by this checker.
17 var _warnings = new StreamController<MirrorsUsedWarning>.broadcast(sync: true);
18 var _logger = new Logger('checked_mirrors');
19
20 /// Stream of warnings detected by this checker.
21 Stream<MirrorsUsedWarning> get onWarning => _warnings.stream;
22
23 /// A singleton checker used by the checked_mirrors system.
24 MirrorsUsedChecker checker = new MirrorsUsedChecker();
25
26 /// Symbol used to search for the MirrorUsed annotation. One dartbug.com/10360
27 /// is fixed, we can just put the annotation directly in the checked_mirrors
28 /// import.
29 const _MIRROR_USED_LOCATION = #checked_mirrors_workaround_for_issue_10360;
30
31
32 /// A warning generated by the checked_mirrors system.
33 class MirrorsUsedWarning {
34
35 /// The kind of warning (undeclared symbol, target not marked).
36 final MirrorsUsedWarningKind kind;
37
38 /// The target of the mirror system that was not marked correctly. Or the
39 /// object containing the target (if symbol is not null).
40 final object;
41
42 final symbol;
43
44 MirrorsUsedWarning(this.kind, this.object, this.symbol);
45 }
46
47 /// Enumeration of warning kinds.
48 class MirrorsUsedWarningKind {
49 final int _value;
50 const MirrorsUsedWarningKind(this._value);
51
52 /// Warning when reading a symbol that was not declared via
53 /// @MirrorUsed(symbols: ...)
54 static const UNDECLARED_SYMBOL = const MirrorsUsedWarningKind(1);
55
56 /// Warning when accesing a target that was not declared via
57 /// @MirrorUsed(targets: ...) or @MirrorUsed(metaTargets: ...)
58 static const TARGET_NOT_MARKED = const MirrorsUsedWarningKind(2);
59 }
60
61 /// Contains rules to check when mirrors are used, but they are not annotated
62 /// appropriately.
63 class MirrorsUsedChecker {
64 bool isInitialized = false;
65 bool _throwOnWarning = false;
66
67 Set symbols = new Set();
68 List globalRules = [];
69
70 Map<Uri, List> libraryRules = new Map<Uri, List>();
71
72 void init({throwOnWarning}) {
73 if (isInitialized) return;
74 _throwOnWarning = throwOnWarning;
75 var system = currentMirrorSystem();
76 system.libraries.forEach((uri, lib) {
77 if (uri.scheme == 'dart') return;
78 // TODO(sigmund): this should lookup the import instead. dartbug.com/10360
79 var target = lib.declarations[_MIRROR_USED_LOCATION];
80 if (target == null) return;
81 for (var metaMirror in target.metadata) {
82 var meta = metaMirror.reflectee;
83 if (meta is MirrorsUsed) {
84 addRule(uri, meta);
85 }
86 }
87 });
88 isInitialized = true;
89 }
90
91 /// Add a [rule] that was seen in [location].
92 void addRule(Uri location, MirrorsUsed annotation) {
93
94 // Symbols are handled separately since they are always global.
95 _loadSymbols(annotation.symbols);
96
97 // Direct target rules to specific libraries, if that's how they are
98 // declared.
99 var rule = new _Rule(annotation);
100 if (annotation.override == '*') {
101 globalRules.add(rule);
102 return;
103 }
104
105 if (annotation.override == null) {
106 _addToLibrary(location, rule);
107 return;
108 }
109
110 for (var name in annotation.override.split(',')) {
111 var symbol = MirrorSystem.getSymbol(name);
112 for (var lib in currentMirrorSystem().libraries.values) {
113 if (lib.simpleName == symbol) _addToLibrary(lib.uri, rule);
114 }
115 }
116 }
117
118 void _loadSymbols(value) {
119 if (value == null) return;
120 if (value is String) {
121 for (var s in value.split(',')) {
122 symbols.add(MirrorSystem.getSymbol(s));
123 }
124 } else if (value is Symbol) {
125 symbols.add(value);
126 } else if (value is List) {
127 for (var s in value) _loadSymbols(s);
128 } else {
129 _logger.warning('MirrorsUsed symbol not understood: $value');
130 }
131 }
132
133
134 void _addToLibrary(uri, rule) {
135 var rules = libraryRules[uri];
136 if (rules == null) {
137 rules = [];
138 libraryRules[uri] = rules;
139 }
140 rules.add(rule);
141 }
142
143 void useSymbol(Symbol symbol) {
144 if (!isInitialized || symbols.contains(symbol)) return;
145 var warning = new MirrorsUsedWarning(
146 MirrorsUsedWarningKind.UNDECLARED_SYMBOL, null, symbol);
147 _warnings.add(warning);
148 if (_throwOnWarning) throw warning;
149 }
150
151 void access(Mirror object, Symbol symbol) {
152 if (!isInitialized) return;
153
154 for (var rule in globalRules) {
155 if (rule.access(object, symbol)) return;
156 }
157
158 var uri = getLibraryUriOf(object);
159 var rules = libraryRules[uri];
160 if (rules != null) {
161 for (var rule in rules) {
162 if (rule.access(object, symbol)) return;
163 }
164 }
165
166 // No rule determined that it's ok to access [symbol]. Report an error.
167 var warning = new MirrorsUsedWarning(
168 MirrorsUsedWarningKind.TARGET_NOT_MARKED, object, symbol);
169 _warnings.add(warning);
170 if (_throwOnWarning) throw warning;
171 }
172 }
173
174 /// Contains a single rule, which is derived from a [MirrorsUsed] annotation.
175 /// The information here is very similar to that of [MirrorsUsed] except it's
176 /// normalized to make it easy to use and apply in the checker logic.
177 class _Rule {
178 List<Mirror> targets = [];
179 List<Type> metaTargets = [];
180
181 _Rule(MirrorsUsed annotation) {
182 _loadTargets(annotation.targets);
183 _loadMetaTargets(annotation.metaTargets);
184 }
185
186 void _loadTargets(value) {
187 if (value == null) return;
188 if (value is Type) {
189 targets.add(value);
190 } else if (value is List) {
191 for (var t in value) _loadTargets(t);
192 } else {
193 _logger.warning('MirrorsUsed target not understood: $value');
194 }
195 }
196 void _loadMetaTargets(value) {
197 if (value == null) return;
198 if (value is Type) {
199 metaTargets.add(value);
200 } else if (value is List) {
201 for (var t in value) _loadMetaTargets(t);
202 } else {
203 _logger.warning('MirrorsUsed metaTarget not understood: $value');
204 }
205 }
206
207 bool access(object, Symbol symbol) {
208 // Explicitly declared targets/types
209 var declaration = getDeclarationOf(object);
210 if (declaration == null) return false;
211 if (targets.contains(declaration.reflectedType)) return true;
212
213 // Meta-targets on classes
214 for (var meta in declaration.metadata) {
215 var type = meta.type.reflectedType;
216 if (metaTargets.contains(type)) return true;
217 }
218
219 if (symbol == null) return false;
220
221 // Meta-targets on fields
222 var symbolDeclaration = declaration.declarations[symbol];
223 if (symbolDeclaration == null) return false;
224 for (var meta in symbolDeclaration.metadata) {
225 var type = meta.type.reflectedType;
226 if (metaTargets.contains(type)) return true;
227 }
228 }
229 }
OLDNEW
« no previous file with comments | « pkg/checked_mirrors/lib/control.dart ('k') | pkg/checked_mirrors/lib/src/utils.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698