OLD | NEW |
---|---|
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library trydart.poi; | 5 library trydart.poi; |
6 | 6 |
7 import 'dart:async' show | 7 import 'dart:async' show |
8 Future; | 8 Future; |
9 | 9 |
10 import 'dart:io' show | 10 import 'dart:io' show |
11 Platform; | 11 Platform; |
12 | 12 |
13 import 'package:dart2js_incremental/dart2js_incremental.dart' show | 13 import 'package:dart2js_incremental/dart2js_incremental.dart' show |
14 reuseCompiler; | 14 reuseCompiler; |
15 | 15 |
16 import 'package:compiler/implementation/source_file_provider.dart' show | 16 import 'package:compiler/implementation/source_file_provider.dart' show |
17 FormattingDiagnosticHandler, | 17 FormattingDiagnosticHandler, |
18 SourceFileProvider; | 18 SourceFileProvider; |
19 | 19 |
20 import 'package:compiler/compiler.dart' as api show | 20 import 'package:compiler/compiler.dart' as api; |
21 Diagnostic; | |
22 | 21 |
23 import 'package:compiler/implementation/dart2jslib.dart' show | 22 import 'package:compiler/implementation/dart2jslib.dart' show |
24 Compiler, | 23 Compiler, |
25 Enqueuer, | 24 Enqueuer, |
26 QueueFilter, | 25 QueueFilter, |
27 WorkItem; | 26 WorkItem; |
28 | 27 |
29 import 'package:compiler/implementation/elements/visitor.dart' show | 28 import 'package:compiler/implementation/elements/visitor.dart' show |
30 ElementVisitor; | 29 ElementVisitor; |
31 | 30 |
32 import 'package:compiler/implementation/elements/elements.dart' show | 31 import 'package:compiler/implementation/elements/elements.dart' show |
33 ClassElement, | 32 ClassElement, |
33 CompilationUnitElement, | |
34 Element, | 34 Element, |
35 LibraryElement, | |
35 ScopeContainerElement; | 36 ScopeContainerElement; |
36 | 37 |
37 import 'package:compiler/implementation/scanner/scannerlib.dart' show | 38 import 'package:compiler/implementation/scanner/scannerlib.dart' show |
38 PartialClassElement, | 39 PartialClassElement, |
39 PartialElement; | 40 PartialElement; |
40 | 41 |
42 import 'package:compiler/implementation/util/uri_extras.dart' show | |
43 relativize; | |
44 | |
41 main(List<String> arguments) { | 45 main(List<String> arguments) { |
42 Uri script = Uri.base.resolve(arguments.first); | 46 Uri script = Uri.base.resolve(arguments.first); |
43 int position = int.parse(arguments[1]); | 47 int position = int.parse(arguments[1]); |
44 return runPoi(script, position).then((Element element) { | |
45 print('Found $element.'); | |
46 }); | |
47 } | |
48 | 48 |
49 Future<Element> runPoi(Uri script, int position) { | |
50 FormattingDiagnosticHandler handler = new FormattingDiagnosticHandler(); | 49 FormattingDiagnosticHandler handler = new FormattingDiagnosticHandler(); |
51 handler | 50 handler |
52 ..verbose = true | 51 ..verbose = true |
53 ..enableColors = true; | 52 ..enableColors = true; |
53 api.CompilerInputProvider inputProvider = handler.provider; | |
54 | |
55 inputProvider(script); | |
56 handler( | |
57 script, position, position + 1, | |
58 'Point of interest.', api.Diagnostic.HINT); | |
59 | |
60 Future future = runPoi(script, position, inputProvider, handler); | |
61 return future.then((Element element) { | |
62 print(scopeInformation(element, position)); | |
63 }); | |
64 } | |
65 | |
66 Future<Element> runPoi( | |
67 Uri script, int position, | |
68 api.CompilerInputProvider inputProvider, | |
69 api.DiagnosticHandler handler) { | |
54 | 70 |
55 Uri libraryRoot = Uri.base.resolve('sdk/'); | 71 Uri libraryRoot = Uri.base.resolve('sdk/'); |
56 Uri packageRoot = Uri.base.resolveUri( | 72 Uri packageRoot = Uri.base.resolveUri( |
57 new Uri.file('${Platform.packageRoot}/')); | 73 new Uri.file('${Platform.packageRoot}/')); |
58 | 74 |
59 var options = [ | 75 var options = [ |
60 '--analyze-main', | 76 '--analyze-main', |
61 '--analyze-only', | 77 '--analyze-only', |
62 '--no-source-maps', | 78 '--no-source-maps', |
63 '--verbose', | 79 '--verbose', |
64 '--categories=Client,Server', | 80 '--categories=Client,Server', |
65 ]; | 81 ]; |
66 | 82 |
67 Compiler cachedCompiler = null; | 83 Compiler cachedCompiler = null; |
68 cachedCompiler = reuseCompiler( | 84 cachedCompiler = reuseCompiler( |
69 diagnosticHandler: handler, | 85 diagnosticHandler: handler, |
70 inputProvider: handler.provider, | 86 inputProvider: inputProvider, |
71 options: options, | 87 options: options, |
72 cachedCompiler: cachedCompiler, | 88 cachedCompiler: cachedCompiler, |
73 libraryRoot: libraryRoot, | 89 libraryRoot: libraryRoot, |
74 packageRoot: packageRoot, | 90 packageRoot: packageRoot, |
75 packagesAreImmutable: true); | 91 packagesAreImmutable: true); |
76 | 92 |
77 cachedCompiler.enqueuerFilter = new ScriptOnlyFilter(script); | 93 cachedCompiler.enqueuerFilter = new ScriptOnlyFilter(script); |
78 | 94 |
79 return cachedCompiler.run(script).then((success) { | 95 return cachedCompiler.run(script).then((success) { |
80 if (success != true) { | 96 if (success != true) { |
81 throw 'Compilation failed'; | 97 throw 'Compilation failed'; |
82 } | 98 } |
83 return poi(cachedCompiler, script, position); | 99 return findPosition(position, cachedCompiler.mainApp); |
84 }); | 100 }); |
85 } | 101 } |
86 | 102 |
87 Element poi(Compiler compiler, Uri script, int offset) { | |
88 compiler.handler( | |
89 script, offset, offset + 1, | |
90 'Point of interest.', api.Diagnostic.HINT); | |
91 | |
92 Element element = findPosition(offset, compiler.mainApp); | |
93 | |
94 return element; | |
95 } | |
96 | |
97 Element findPosition(int position, Element element) { | 103 Element findPosition(int position, Element element) { |
98 FindPositionVisitor visitor = new FindPositionVisitor(position, element); | 104 FindPositionVisitor visitor = new FindPositionVisitor(position, element); |
99 element.accept(visitor); | 105 element.accept(visitor); |
100 return visitor.element; | 106 return visitor.element; |
101 } | 107 } |
102 | 108 |
109 String scopeInformation(Element element, int position) { | |
110 ScopeInformationVisitor vistor = | |
Johnni Winther
2014/07/14 10:35:36
'vistor' -> 'visitor'.
ahe
2014/07/14 13:06:07
Done.
| |
111 new ScopeInformationVisitor(element, position); | |
112 element.accept(vistor); | |
113 return '${vistor.buffer}'; | |
114 } | |
115 | |
103 class FindPositionVisitor extends ElementVisitor { | 116 class FindPositionVisitor extends ElementVisitor { |
104 final int position; | 117 final int position; |
105 Element element; | 118 Element element; |
106 | 119 |
107 FindPositionVisitor(this.position, this.element); | 120 FindPositionVisitor(this.position, this.element); |
108 | 121 |
109 visitElement(Element e) { | 122 visitElement(Element e) { |
110 if (e is! PartialElement) return; | 123 if (e is PartialElement) { |
111 if (e.beginToken.charOffset <= position && | 124 if (e.beginToken.charOffset <= position && |
112 position < e.endToken.next.charOffset) { | 125 position < e.endToken.next.charOffset) { |
113 element = e; | 126 element = e; |
127 } | |
114 } | 128 } |
115 } | 129 } |
116 | 130 |
117 visitClassElement(ClassElement e) { | 131 visitClassElement(ClassElement e) { |
118 if (e is! PartialClassElement) return; | 132 if (e is PartialClassElement) { |
119 if (e.beginToken.charOffset <= position && | 133 if (e.beginToken.charOffset <= position && |
120 position < e.endToken.next.charOffset) { | 134 position < e.endToken.next.charOffset) { |
121 element = e; | 135 element = e; |
122 visitScopeContainerElement(e); | 136 visitScopeContainerElement(e); |
137 } | |
123 } | 138 } |
124 } | 139 } |
125 | 140 |
126 visitScopeContainerElement(ScopeContainerElement e) { | 141 visitScopeContainerElement(ScopeContainerElement e) { |
127 e.forEachLocalMember((Element element) => element.accept(this)); | 142 e.forEachLocalMember((Element element) => element.accept(this)); |
128 } | 143 } |
129 } | 144 } |
130 | 145 |
131 class ScriptOnlyFilter implements QueueFilter { | 146 class ScriptOnlyFilter implements QueueFilter { |
132 final Uri script; | 147 final Uri script; |
133 | 148 |
134 ScriptOnlyFilter(this.script); | 149 ScriptOnlyFilter(this.script); |
135 | 150 |
136 bool checkNoEnqueuedInvokedInstanceMethods(Enqueuer enqueuer) => true; | 151 bool checkNoEnqueuedInvokedInstanceMethods(Enqueuer enqueuer) => true; |
137 | 152 |
138 void processWorkItem(void f(WorkItem work), WorkItem work) { | 153 void processWorkItem(void f(WorkItem work), WorkItem work) { |
139 if (work.element.library.canonicalUri == script) { | 154 if (work.element.library.canonicalUri == script) { |
140 f(work); | 155 f(work); |
141 } | 156 } |
142 } | 157 } |
143 } | 158 } |
159 | |
160 class ScopeInformationVisitor extends ElementVisitor/* <void> */ { | |
161 // TODO(ahe): Include function paramters and local variables. | |
Johnni Winther
2014/07/14 10:35:36
'paramters' -> 'parameters'
ahe
2014/07/14 13:06:07
Done.
| |
162 | |
163 final Element element; | |
164 final int position; | |
165 final StringBuffer buffer = new StringBuffer(); | |
166 int indentationLevel = 0; | |
167 | |
168 ScopeInformationVisitor(this.element, this.position); | |
169 | |
170 String get indentation => ' ' * indentationLevel; | |
171 | |
172 StringBuffer get indented => buffer..write(indentation); | |
173 | |
174 void visitElement(Element e) { | |
175 serialize(e, omitEnclosing: false); | |
176 } | |
177 | |
178 void visitLibraryElement(LibraryElement e) { | |
179 bool isFirst = true; | |
180 serialize( | |
181 e, omitEnclosing: true, | |
182 name: relativize(Uri.base, e.canonicalUri, false), | |
183 serializeMembers: () { | |
184 // TODO(ahe): Include imported elements in libraries. | |
185 e.forEachLocalMember((Element member) { | |
186 if (!isFirst) { | |
187 buffer.write(','); | |
188 } | |
189 buffer.write('\n'); | |
190 indented; | |
191 serialize(member); | |
192 isFirst = false; | |
193 }); | |
194 }); | |
195 } | |
196 | |
197 void visitScopeContainerElement(ScopeContainerElement e) { | |
198 bool isFirst = true; | |
199 serialize(e, omitEnclosing: false, serializeMembers: () { | |
200 // TODO(ahe): Include inherited members in classes. | |
201 e.forEachLocalMember((Element member) { | |
202 if (!isFirst) { | |
203 buffer.write(','); | |
204 } | |
205 buffer.write('\n'); | |
206 indented; | |
207 serialize(member); | |
208 isFirst = false; | |
209 }); | |
210 }); | |
211 } | |
212 | |
213 void visitCompilationUnitElement(CompilationUnitElement e) { | |
214 e.enclosingElement.accept(this); | |
215 } | |
216 | |
217 void serialize( | |
218 Element element, | |
219 {bool omitEnclosing: true, | |
220 void serializeMembers(), | |
221 String name}) { | |
222 if (name == null) { | |
223 name = element.name; | |
224 } | |
225 buffer.write('{\n'); | |
226 indentationLevel++; | |
227 indented | |
228 ..write('"name": "') | |
229 ..write(name) | |
230 ..write('",\n'); | |
231 indented | |
232 ..write('"kind": "') | |
233 ..write(element.kind) | |
234 ..write('"'); | |
235 // TODO(ahe): Add a type/signature field. | |
236 if (serializeMembers != null) { | |
237 buffer.write(',\n'); | |
238 indented.write('"members": ['); | |
239 indentationLevel++; | |
240 serializeMembers(); | |
241 indentationLevel--; | |
242 buffer.write('\n'); | |
243 indented.write(']'); | |
244 } | |
245 if (!omitEnclosing) { | |
246 buffer.write(',\n'); | |
247 indented.write('"enclosing": '); | |
248 element.enclosingElement.accept(this); | |
249 } | |
250 indentationLevel--; | |
251 buffer.write('\n'); | |
252 indented.write('}'); | |
253 } | |
254 } | |
OLD | NEW |