OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library services.status; | |
6 | |
7 import 'package:analysis_services/search/search_engine.dart'; | |
8 import 'package:analysis_services/src/correction/source_range.dart'; | |
9 import 'package:analyzer/src/generated/ast.dart'; | |
10 import 'package:analyzer/src/generated/element.dart'; | |
11 import 'package:analyzer/src/generated/engine.dart'; | |
12 import 'package:analyzer/src/generated/java_core.dart'; | |
13 import 'package:analyzer/src/generated/source.dart'; | |
14 | |
15 | |
16 /** | |
17 * An outcome of a condition checking operation. | |
18 */ | |
19 class RefactoringStatus { | |
20 /** | |
21 * The current severity of this [RefactoringStatus] - the maximum of the | |
22 * severities of its [entries]. | |
23 */ | |
24 RefactoringStatusSeverity _severity = RefactoringStatusSeverity.OK; | |
25 | |
26 /** | |
27 * A list of [RefactoringStatusEntry]s. | |
28 */ | |
29 final List<RefactoringStatusEntry> entries = []; | |
30 | |
31 /** | |
32 * Creates a new OK [RefactoringStatus]. | |
33 */ | |
34 RefactoringStatus(); | |
35 | |
36 /** | |
37 * Creates a new [RefactoringStatus] with the ERROR severity. | |
38 */ | |
39 factory RefactoringStatus.error(String msg, | |
40 [RefactoringStatusContext context]) { | |
41 RefactoringStatus status = new RefactoringStatus(); | |
42 status.addError(msg, context); | |
43 return status; | |
44 } | |
45 | |
46 /** | |
47 * Creates a new [RefactoringStatus] with the FATAL severity. | |
48 */ | |
49 factory RefactoringStatus.fatal(String msg, | |
50 [RefactoringStatusContext context]) { | |
51 RefactoringStatus status = new RefactoringStatus(); | |
52 status.addFatalError(msg, context); | |
53 return status; | |
54 } | |
55 | |
56 /** | |
57 * Creates a new [RefactoringStatus] with the WARNING severity. | |
58 */ | |
59 factory RefactoringStatus.warning(String msg, | |
60 [RefactoringStatusContext context]) { | |
61 RefactoringStatus status = new RefactoringStatus(); | |
62 status.addWarning(msg, context); | |
63 return status; | |
64 } | |
65 | |
66 /** | |
67 * Returns the first [RefactoringStatusEntry] with the highest severity. | |
68 * | |
69 * If there is more than one entry with the highest severity then there is no | |
70 * guarantee as to which will be returned. | |
71 * | |
72 * Returns `null` if no entries. | |
73 */ | |
74 RefactoringStatusEntry get entryWithHighestSeverity { | |
75 for (RefactoringStatusEntry entry in entries) { | |
76 if (entry.severity == _severity) { | |
77 return entry; | |
78 } | |
79 } | |
80 return null; | |
81 } | |
82 | |
83 /** | |
84 * Returns `true` if the severity is FATAL or ERROR. | |
85 */ | |
86 bool get hasError => | |
87 _severity == RefactoringStatusSeverity.FATAL || | |
88 _severity == RefactoringStatusSeverity.ERROR; | |
89 | |
90 /** | |
91 * Returns `true` if the severity is FATAL. | |
92 */ | |
93 bool get hasFatalError => _severity == RefactoringStatusSeverity.FATAL; | |
94 | |
95 /** | |
96 * Returns `true` if the severity is WARNING. | |
97 */ | |
98 bool get hasWarning => _severity == RefactoringStatusSeverity.WARNING; | |
99 | |
100 /** | |
101 * Return `true` if the severity is `OK`. | |
102 */ | |
103 bool get isOK => _severity == RefactoringStatusSeverity.OK; | |
104 | |
105 /** | |
106 * Returns the message of the [RefactoringStatusEntry] with highest severity; | |
107 * may be `null` if no entries. | |
108 */ | |
109 String get message { | |
110 RefactoringStatusEntry entry = entryWithHighestSeverity; | |
111 if (entry == null) { | |
112 return null; | |
113 } | |
114 return entry.message; | |
115 } | |
116 | |
117 /** | |
118 * Returns the current severity of this [RefactoringStatus]. | |
119 */ | |
120 RefactoringStatusSeverity get severity => _severity; | |
121 | |
122 /** | |
123 * Adds an ERROR entry with the given message and status. | |
124 */ | |
125 void addError(String msg, [RefactoringStatusContext context]) { | |
126 _addEntry( | |
127 new RefactoringStatusEntry(RefactoringStatusSeverity.ERROR, msg, context
)); | |
128 } | |
129 | |
130 /** | |
131 * Adds a FATAL entry with the given message and status. | |
132 */ | |
133 void addFatalError(String msg, [RefactoringStatusContext context]) { | |
134 _addEntry( | |
135 new RefactoringStatusEntry(RefactoringStatusSeverity.FATAL, msg, context
)); | |
136 } | |
137 | |
138 /** | |
139 * Merges [other] into this [RefactoringStatus]. | |
140 * | |
141 * The [other]'s entries are added to this. | |
142 * | |
143 * The resulting severity is the more severe of this and [other] severities. | |
144 * | |
145 * Merging with `null` is allowed - it has no effect. | |
146 */ | |
147 void addStatus(RefactoringStatus other) { | |
148 if (other == null) { | |
149 return; | |
150 } | |
151 entries.addAll(other.entries); | |
152 _severity = RefactoringStatusSeverity._max(_severity, other.severity); | |
153 } | |
154 | |
155 /** | |
156 * Adds a WARNING entry with the given message and status. | |
157 */ | |
158 void addWarning(String msg, [RefactoringStatusContext context]) { | |
159 _addEntry( | |
160 new RefactoringStatusEntry(RefactoringStatusSeverity.WARNING, msg, conte
xt)); | |
161 } | |
162 | |
163 /** | |
164 * Returns a copy of this [RefactoringStatus] with ERROR replaced with FATAL. | |
165 */ | |
166 RefactoringStatus escalateErrorToFatal() { | |
167 RefactoringStatus result = new RefactoringStatus(); | |
168 for (RefactoringStatusEntry entry in entries) { | |
169 if (entry.severity == RefactoringStatusSeverity.ERROR) { | |
170 entry = new RefactoringStatusEntry( | |
171 RefactoringStatusSeverity.FATAL, | |
172 entry.message, | |
173 entry.context); | |
174 } | |
175 result._addEntry(entry); | |
176 } | |
177 return result; | |
178 } | |
179 | |
180 @override | |
181 String toString() { | |
182 StringBuffer sb = new StringBuffer(); | |
183 sb.write("<"); | |
184 sb.write(_severity.name); | |
185 if (!isOK) { | |
186 sb.write("\n"); | |
187 for (RefactoringStatusEntry entry in entries) { | |
188 sb.write("\t"); | |
189 sb.write(entry); | |
190 sb.write("\n"); | |
191 } | |
192 } | |
193 sb.write(">"); | |
194 return sb.toString(); | |
195 } | |
196 | |
197 /** | |
198 * Adds the given [RefactoringStatusEntry] and updates [severity]. | |
199 */ | |
200 void _addEntry(RefactoringStatusEntry entry) { | |
201 entries.add(entry); | |
202 _severity = RefactoringStatusSeverity._max(_severity, entry.severity); | |
203 } | |
204 } | |
205 | |
206 | |
207 /** | |
208 * [RefactoringStatusContext] can be used to annotate [RefactoringStatusEntry]s | |
209 * with additional information typically presented in the user interface. | |
210 */ | |
211 class RefactoringStatusContext { | |
212 /** | |
213 * The [AnalysisContext] in which this status occurs. | |
214 */ | |
215 final AnalysisContext context; | |
216 | |
217 /** | |
218 * The [Source] in which this status occurs. | |
219 */ | |
220 final Source source; | |
221 | |
222 /** | |
223 * The [SourceRange] with specific location where this status occurs. | |
224 */ | |
225 final SourceRange range; | |
226 | |
227 /** | |
228 * Creates a new [RefactoringStatusContext]. | |
229 */ | |
230 RefactoringStatusContext(this.context, this.source, this.range); | |
231 | |
232 /** | |
233 * Creates a new [RefactoringStatusContext] for the given [Element]. | |
234 */ | |
235 factory RefactoringStatusContext.forElement(Element element) { | |
236 AnalysisContext context = element.context; | |
237 Source source = element.source; | |
238 SourceRange range = rangeElementName(element); | |
239 return new RefactoringStatusContext(context, source, range); | |
240 } | |
241 | |
242 /** | |
243 * Creates a new [RefactoringStatusContext] for the given [SearchMatch]. | |
244 */ | |
245 factory RefactoringStatusContext.forMatch(SearchMatch match) { | |
246 Element enclosingElement = match.element; | |
247 return new RefactoringStatusContext( | |
248 enclosingElement.context, | |
249 enclosingElement.source, | |
250 match.sourceRange); | |
251 } | |
252 | |
253 /** | |
254 * Creates a new [RefactoringStatusContext] for the given [AstNode]. | |
255 */ | |
256 factory RefactoringStatusContext.forNode(AstNode node) { | |
257 CompilationUnit unit = node.getAncestor((node) => node is CompilationUnit); | |
258 CompilationUnitElement unitElement = unit.element; | |
259 AnalysisContext context = unitElement.context; | |
260 Source source = unitElement.source; | |
261 SourceRange range = rangeNode(node); | |
262 return new RefactoringStatusContext(context, source, range); | |
263 } | |
264 | |
265 /** | |
266 * Creates a new [RefactoringStatusContext] for the given [CompilationUnit]. | |
267 */ | |
268 factory RefactoringStatusContext.forUnit(CompilationUnit unit, | |
269 SourceRange range) { | |
270 CompilationUnitElement unitElement = unit.element; | |
271 AnalysisContext context = unitElement.context; | |
272 Source source = unitElement.source; | |
273 return new RefactoringStatusContext(context, source, range); | |
274 } | |
275 | |
276 @override | |
277 String toString() { | |
278 JavaStringBuilder builder = new JavaStringBuilder(); | |
279 builder.append("[source="); | |
280 builder.append(source); | |
281 builder.append(", range="); | |
282 builder.append(range); | |
283 builder.append("]"); | |
284 return builder.toString(); | |
285 } | |
286 } | |
287 | |
288 | |
289 /** | |
290 * An immutable object representing an entry in a [RefactoringStatus]. | |
291 * | |
292 * A [RefactoringStatusEntry] consists of a severity, a message and a context. | |
293 */ | |
294 class RefactoringStatusEntry { | |
295 /** | |
296 * The severity level. | |
297 */ | |
298 final RefactoringStatusSeverity severity; | |
299 | |
300 /** | |
301 * The message of the status entry. | |
302 */ | |
303 final String message; | |
304 | |
305 /** | |
306 * The [RefactoringStatusContext] which can be used to show more detailed | |
307 * information regarding this status entry in the UI. | |
308 * | |
309 * May be `null` indicating that no context is available. | |
310 */ | |
311 final RefactoringStatusContext context; | |
312 | |
313 RefactoringStatusEntry(this.severity, this.message, [this.context]); | |
314 | |
315 /** | |
316 * Returns whether the entry represents an error or not. | |
317 */ | |
318 bool get isError => severity == RefactoringStatusSeverity.ERROR; | |
319 | |
320 /** | |
321 * Returns whether the entry represents a fatal error or not. | |
322 */ | |
323 bool get isFatalError => severity == RefactoringStatusSeverity.FATAL; | |
324 | |
325 /** | |
326 * Returns whether the entry represents a warning or not. | |
327 */ | |
328 bool get isWarning => severity == RefactoringStatusSeverity.WARNING; | |
329 | |
330 @override | |
331 String toString() { | |
332 if (context != null) { | |
333 return "${severity}: ${message}; Context: ${context}"; | |
334 } else { | |
335 return "${severity}: ${message}"; | |
336 } | |
337 } | |
338 } | |
339 | |
340 | |
341 /** | |
342 * Severity of [RefactoringStatus]. | |
343 */ | |
344 class RefactoringStatusSeverity { | |
345 /** | |
346 * The severity indicating the nominal case. | |
347 */ | |
348 static const OK = const RefactoringStatusSeverity('OK', 0); | |
349 | |
350 /** | |
351 * The severity indicating a warning. | |
352 * | |
353 * Use this severity if the refactoring can be performed, but you assume that | |
354 * the user could not be aware of problems or confusions resulting from the | |
355 * execution. | |
356 */ | |
357 static const WARNING = const RefactoringStatusSeverity('WARNING', 2); | |
358 | |
359 /** | |
360 * The severity indicating an error. | |
361 * | |
362 * Use this severity if the refactoring can be performed, but the refactoring | |
363 * will not be behavior preserving and/or the partial execution will lead to | |
364 * an inconsistent state (e.g. compile errors). | |
365 */ | |
366 static const ERROR = const RefactoringStatusSeverity('ERROR', 3); | |
367 | |
368 /** | |
369 * The severity indicating a fatal error. | |
370 * | |
371 * Use this severity if the refactoring cannot be performed, and execution | |
372 * would lead to major problems. Note that this completely blocks the user | |
373 * from performing this refactoring. | |
374 * | |
375 * It is often preferable to use an [ERROR] status and allow a partial | |
376 * execution (e.g. if just one reference to a refactored element cannot be | |
377 * updated). | |
378 */ | |
379 static const FATAL = const RefactoringStatusSeverity('FATAL', 4); | |
380 | |
381 final String name; | |
382 final int ordinal; | |
383 | |
384 const RefactoringStatusSeverity(this.name, this.ordinal); | |
385 | |
386 @override | |
387 String toString() => name; | |
388 | |
389 /** | |
390 * Returns the most severe [RefactoringStatusSeverity]. | |
391 */ | |
392 static RefactoringStatusSeverity _max(RefactoringStatusSeverity a, | |
393 RefactoringStatusSeverity b) { | |
394 if (b.ordinal > a.ordinal) { | |
395 return b; | |
396 } | |
397 return a; | |
398 } | |
399 } | |
OLD | NEW |