OLD | NEW |
| (Empty) |
1 // Copyright (c) 2015, 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 /// Summary of error messages produced by a `SummaryReporter`. | |
6 | |
7 import 'dart:collection' show HashSet; | |
8 | |
9 import 'package:source_span/source_span.dart'; | |
10 | |
11 /// Summary information computed by the DDC checker. | |
12 abstract class Summary { | |
13 Map toJsonMap(); | |
14 | |
15 void accept(SummaryVisitor visitor); | |
16 } | |
17 | |
18 /// Summary for the entire program. | |
19 class GlobalSummary implements Summary { | |
20 /// Summary from the system libraries. | |
21 final Map<String, LibrarySummary> system = <String, LibrarySummary>{}; | |
22 | |
23 /// Summary for libraries in packages. | |
24 final Map<String, PackageSummary> packages = <String, PackageSummary>{}; | |
25 | |
26 /// Summary for loose files | |
27 // TODO(sigmund): consider inferring the package from the pubspec instead? | |
28 final Map<String, IndividualSummary> loose = <String, IndividualSummary>{}; | |
29 | |
30 GlobalSummary(); | |
31 | |
32 Map toJsonMap() => { | |
33 'system': system.values.map((l) => l.toJsonMap()).toList(), | |
34 'packages': packages.values.map((p) => p.toJsonMap()).toList(), | |
35 'loose': loose.values | |
36 .map((l) => ['${l.runtimeType}', l.toJsonMap()]) | |
37 .toList(), | |
38 }; | |
39 | |
40 void accept(SummaryVisitor visitor) => visitor.visitGlobal(this); | |
41 | |
42 static GlobalSummary parse(Map json) { | |
43 var res = new GlobalSummary(); | |
44 json['system'].map(LibrarySummary.parse).forEach((l) { | |
45 res.system[l.name] = l; | |
46 }); | |
47 json['packages'].map(PackageSummary.parse).forEach((p) { | |
48 res.packages[p.name] = p; | |
49 }); | |
50 json['loose'].forEach((e) { | |
51 var summary = e[0] == 'LibrarySummary' | |
52 ? LibrarySummary.parse(e[1]) | |
53 : HtmlSummary.parse(e[1]); | |
54 res.loose[summary.name] = summary; | |
55 }); | |
56 return res; | |
57 } | |
58 } | |
59 | |
60 /// A summary of a package. | |
61 class PackageSummary implements Summary { | |
62 final String name; | |
63 final Map<String, LibrarySummary> libraries = <String, LibrarySummary>{}; | |
64 | |
65 PackageSummary(this.name); | |
66 | |
67 Map toJsonMap() => { | |
68 'package_name': name, | |
69 'libraries': libraries.values.map((l) => l.toJsonMap()).toList(), | |
70 }; | |
71 | |
72 void accept(SummaryVisitor visitor) => visitor.visitPackage(this); | |
73 | |
74 static PackageSummary parse(Map json) { | |
75 var res = new PackageSummary(json['package_name']); | |
76 json['libraries'].map(LibrarySummary.parse).forEach((l) { | |
77 res.libraries[l.name] = l; | |
78 }); | |
79 return res; | |
80 } | |
81 } | |
82 | |
83 /// A summary for a library or an html file. | |
84 abstract class IndividualSummary extends Summary { | |
85 /// Unique name for this library. | |
86 String get name; | |
87 | |
88 List<MessageSummary> get messages; | |
89 } | |
90 | |
91 /// A summary at the level of a library. | |
92 class LibrarySummary implements IndividualSummary { | |
93 /// Unique name for this library. | |
94 final String name; | |
95 | |
96 /// All messages collected for the library. | |
97 final List<MessageSummary> messages; | |
98 | |
99 /// All parts of this library. Only used for computing _lines. | |
100 final _uris = new HashSet<Uri>(); | |
101 | |
102 int _lines; | |
103 | |
104 LibrarySummary(this.name, {List<MessageSummary> messages, lines}) | |
105 : messages = messages == null ? <MessageSummary>[] : messages, | |
106 _lines = lines != null ? lines : 0; | |
107 | |
108 void clear() { | |
109 _uris.clear(); | |
110 _lines = 0; | |
111 messages.clear(); | |
112 } | |
113 | |
114 /// Total lines of code (including all parts of the library). | |
115 int get lines => _lines; | |
116 | |
117 Map toJsonMap() => { | |
118 'library_name': name, | |
119 'messages': messages.map((m) => m.toJsonMap()).toList(), | |
120 'lines': lines, | |
121 }; | |
122 | |
123 void recordSourceLines(Uri uri, int computeLines()) { | |
124 if (_uris.add(uri)) { | |
125 _lines += computeLines(); | |
126 } | |
127 } | |
128 | |
129 void accept(SummaryVisitor visitor) => visitor.visitLibrary(this); | |
130 | |
131 static LibrarySummary parse(Map json) => | |
132 new LibrarySummary(json['library_name'], | |
133 messages: new List<MessageSummary>.from( | |
134 json['messages'].map(MessageSummary.parse)), | |
135 lines: json['lines']); | |
136 } | |
137 | |
138 /// A summary at the level of an HTML file. | |
139 class HtmlSummary implements IndividualSummary { | |
140 /// Unique name used to identify the HTML file. | |
141 final String name; | |
142 | |
143 /// All messages collected on the file. | |
144 final List<MessageSummary> messages; | |
145 | |
146 HtmlSummary(this.name, [List<MessageSummary> messages]) | |
147 : messages = messages == null ? <MessageSummary>[] : messages; | |
148 | |
149 Map toJsonMap() => | |
150 {'name': name, 'messages': messages.map((m) => m.toJsonMap()).toList()}; | |
151 | |
152 void accept(SummaryVisitor visitor) => visitor.visitHtml(this); | |
153 | |
154 static HtmlSummary parse(Map json) => new HtmlSummary( | |
155 json['name'], | |
156 new List<MessageSummary>.from( | |
157 json['messages'].map(MessageSummary.parse))); | |
158 } | |
159 | |
160 /// A single message produced by the checker. | |
161 class MessageSummary implements Summary { | |
162 /// The kind of message, currently the name of the StaticInfo type. | |
163 final String kind; | |
164 | |
165 /// Level (error, warning, etc). | |
166 final String level; | |
167 | |
168 /// Location where the error is reported. | |
169 final SourceSpan span; | |
170 final String message; | |
171 | |
172 MessageSummary(this.kind, this.level, this.span, this.message); | |
173 | |
174 Map toJsonMap() => { | |
175 'kind': kind, | |
176 'level': level, | |
177 'message': message, | |
178 'url': '${span.sourceUrl}', | |
179 'start': [span.start.offset, span.start.line, span.start.column], | |
180 'end': [span.end.offset, span.end.line, span.end.column], | |
181 'text': span.text, | |
182 'context': span is SourceSpanWithContext | |
183 ? (span as SourceSpanWithContext).context | |
184 : null, | |
185 }; | |
186 | |
187 void accept(SummaryVisitor visitor) => visitor.visitMessage(this); | |
188 | |
189 static MessageSummary parse(Map json) { | |
190 var start = new SourceLocation(json['start'][0], | |
191 sourceUrl: json['url'], | |
192 line: json['start'][1], | |
193 column: json['start'][2]); | |
194 var end = new SourceLocation(json['end'][0], | |
195 sourceUrl: json['url'], line: json['end'][1], column: json['end'][2]); | |
196 var context = json['context']; | |
197 var span = context != null | |
198 ? new SourceSpanWithContext(start, end, json['text'], context) | |
199 : new SourceSpan(start, end, json['text']); | |
200 return new MessageSummary( | |
201 json['kind'], json['level'], span, json['message']); | |
202 } | |
203 } | |
204 | |
205 /// A visitor of the [Summary] hierarchy. | |
206 abstract class SummaryVisitor { | |
207 void visitGlobal(GlobalSummary global); | |
208 void visitPackage(PackageSummary package); | |
209 void visitLibrary(LibrarySummary lib); | |
210 void visitHtml(HtmlSummary html); | |
211 void visitMessage(MessageSummary message); | |
212 } | |
213 | |
214 /// A recursive [SummaryVisitor] that visits summaries on a top-down fashion. | |
215 class RecursiveSummaryVisitor implements SummaryVisitor { | |
216 void visitGlobal(GlobalSummary global) { | |
217 for (var lib in global.system.values) { | |
218 lib.accept(this); | |
219 } | |
220 for (var package in global.packages.values) { | |
221 package.accept(this); | |
222 } | |
223 for (var libOrHtml in global.loose.values) { | |
224 libOrHtml.accept(this); | |
225 } | |
226 } | |
227 | |
228 void visitPackage(PackageSummary package) { | |
229 for (var lib in package.libraries.values) { | |
230 lib.accept(this); | |
231 } | |
232 } | |
233 | |
234 void visitLibrary(LibrarySummary lib) { | |
235 for (var msg in lib.messages) { | |
236 msg.accept(this); | |
237 } | |
238 } | |
239 | |
240 void visitHtml(HtmlSummary html) { | |
241 for (var msg in html.messages) { | |
242 msg.accept(this); | |
243 } | |
244 } | |
245 | |
246 void visitMessage(MessageSummary message) {} | |
247 } | |
OLD | NEW |