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

Side by Side Diff: pkg/analysis_server/lib/src/protocol2.dart

Issue 506433002: Finish modifying analysis server to make use of code generation. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 4 months 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
OLDNEW
(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 protocol2;
6
7 import 'dart:convert';
8
9 import 'package:analysis_server/src/computer/element.dart' show
10 elementFromEngine;
11 import 'package:analysis_server/src/services/correction/fix.dart' show Fix;
12 import 'package:analysis_server/src/search/search_result.dart' show
13 searchResultFromMatch;
14 import 'package:analysis_server/src/services/json.dart';
15 import 'package:analysis_server/src/services/search/search_engine.dart' as
16 engine;
17 import 'package:analyzer/src/generated/ast.dart' as engine;
18 import 'package:analyzer/src/generated/element.dart' as engine;
19 import 'package:analyzer/src/generated/engine.dart' as engine;
20 import 'package:analyzer/src/generated/error.dart' as engine;
21 import 'package:analyzer/src/generated/source.dart' as engine;
22
23 import 'protocol.dart';
24
25 part 'generated_protocol.dart';
26
27 /**
28 * Translate the input [map], applying [keyCallback] to all its keys, and
29 * [valueCallback] to all its values.
30 */
31 mapMap(Map map, {dynamic keyCallback(key), dynamic valueCallback(value)}) {
32 Map result = {};
33 map.forEach((key, value) {
34 if (keyCallback != null) {
35 key = keyCallback(key);
36 }
37 if (valueCallback != null) {
38 value = valueCallback(value);
39 }
40 result[key] = value;
41 });
42 return result;
43 }
44
45 /**
46 * Adds the given [sourceEdits] to the list in [sourceFileEdit].
47 */
48 void _addAllEditsForSource(SourceFileEdit sourceFileEdit,
49 Iterable<SourceEdit> edits) {
50 edits.forEach(sourceFileEdit.add);
51 }
52
53 /**
54 * Adds the given [sourceEdit] to the list in [sourceFileEdit].
55 */
56 void _addEditForSource(SourceFileEdit sourceFileEdit, SourceEdit sourceEdit) {
57 List<SourceEdit> edits = sourceFileEdit.edits;
58 int index = 0;
59 while (index < edits.length && edits[index].offset > sourceEdit.offset) {
60 index++;
61 }
62 edits.insert(index, sourceEdit);
63 }
64
65 /**
66 * Adds [edit] to the [FileEdit] for the given [file].
67 */
68 void _addEditToSourceChange(SourceChange change, String file, SourceEdit edit) {
69 SourceFileEdit fileEdit = change.getFileEdit(file);
70 if (fileEdit == null) {
71 fileEdit = new SourceFileEdit(file);
72 change.addFileEdit(fileEdit);
73 }
74 fileEdit.add(edit);
75 }
76
77 /**
78 * Returns the [FileEdit] for the given [file], maybe `null`.
79 */
80 SourceFileEdit _getChangeFileEdit(SourceChange change, String file) {
81 for (SourceFileEdit fileEdit in change.edits) {
82 if (fileEdit.file == file) {
83 return fileEdit;
84 }
85 }
86 return null;
87 }
88
89 /**
90 * Create an AnalysisError based on error information from the analyzer
91 * engine. Access via AnalysisError.fromEngine().
92 */
93 AnalysisError _analysisErrorFromEngine(engine.LineInfo lineInfo,
94 engine.AnalysisError error) {
95 engine.ErrorCode errorCode = error.errorCode;
96 // prepare location
97 Location location;
98 {
99 String file = error.source.fullName;
100 int offset = error.offset;
101 int length = error.length;
102 int startLine = -1;
103 int startColumn = -1;
104 if (lineInfo != null) {
105 engine.LineInfo_Location lineLocation = lineInfo.getLocation(offset);
106 if (lineLocation != null) {
107 startLine = lineLocation.lineNumber;
108 startColumn = lineLocation.columnNumber;
109 }
110 }
111 location = new Location(file, offset, length, startLine, startColumn);
112 }
113 // done
114 var severity = new ErrorSeverity(errorCode.errorSeverity.name);
115 var type = new ErrorType(errorCode.type.name);
116 String message = error.message;
117 String correction = error.correction;
118 return new AnalysisError(
119 severity,
120 type,
121 location,
122 message,
123 correction: correction);
124 }
125
126 /**
127 * Returns a list of AnalysisErrors correponding to the given list of Engine
128 * errors. Access via AnalysisError.listFromEngine().
129 */
130 List<AnalysisError> _analysisErrorListFromEngine(engine.LineInfo lineInfo,
131 List<engine.AnalysisError> errors) {
132 return errors.map((engine.AnalysisError error) {
133 return new AnalysisError.fromEngine(lineInfo, error);
134 }).toList();
135 }
136
137 /**
138 * Get the result of applying the edit to the given [code]. Access via
139 * SourceEdit.apply().
140 */
141 String _applyEdit(String code, SourceEdit edit) {
142 return code.substring(0, edit.offset) +
143 edit.replacement +
144 code.substring(edit.end);
145 }
146
147 /**
148 * Get the result of applying a set of [edits] to the given [code]. Edits
149 * are applied in the order they appear in [edits]. Access via
150 * SourceEdit.applySequence().
151 */
152 String _applySequence(String code, Iterable<SourceEdit> edits) {
153 edits.forEach((SourceEdit edit) {
154 code = edit.apply(code);
155 });
156 return code;
157 }
158
159 /**
160 * Map an element kind from the analyzer engine to a [CompletionSuggestionKind].
161 */
162 CompletionSuggestionKind _completionSuggestionKindFromElementKind(engine.Element Kind kind) {
163 // ElementKind.ANGULAR_FORMATTER,
164 // ElementKind.ANGULAR_COMPONENT,
165 // ElementKind.ANGULAR_CONTROLLER,
166 // ElementKind.ANGULAR_DIRECTIVE,
167 // ElementKind.ANGULAR_PROPERTY,
168 // ElementKind.ANGULAR_SCOPE_PROPERTY,
169 // ElementKind.ANGULAR_SELECTOR,
170 // ElementKind.ANGULAR_VIEW,
171 if (kind == engine.ElementKind.CLASS) return CompletionSuggestionKind.CLASS;
172 // ElementKind.COMPILATION_UNIT,
173 if (kind == engine.ElementKind.CONSTRUCTOR) return CompletionSuggestionKind.CO NSTRUCTOR;
174 // ElementKind.DYNAMIC,
175 // ElementKind.EMBEDDED_HTML_SCRIPT,
176 // ElementKind.ERROR,
177 // ElementKind.EXPORT,
178 // ElementKind.EXTERNAL_HTML_SCRIPT,
179 if (kind == engine.ElementKind.FIELD) return CompletionSuggestionKind.FIELD;
180 if (kind == engine.ElementKind.FUNCTION) return CompletionSuggestionKind.FUNCT ION;
181 if (kind == engine.ElementKind.FUNCTION_TYPE_ALIAS) return CompletionSuggestio nKind.FUNCTION_TYPE_ALIAS;
182 if (kind == engine.ElementKind.GETTER) return CompletionSuggestionKind.GETTER;
183 // ElementKind.HTML,
184 if (kind == engine.ElementKind.IMPORT) return CompletionSuggestionKind.IMPORT;
185 // ElementKind.LABEL,
186 // ElementKind.LIBRARY,
187 if (kind == engine.ElementKind.LOCAL_VARIABLE) return CompletionSuggestionKind .LOCAL_VARIABLE;
188 if (kind == engine.ElementKind.METHOD) return CompletionSuggestionKind.METHOD;
189 // ElementKind.NAME,
190 if (kind == engine.ElementKind.PARAMETER) return CompletionSuggestionKind.PARA METER;
191 // ElementKind.POLYMER_ATTRIBUTE,
192 // ElementKind.POLYMER_TAG_DART,
193 // ElementKind.POLYMER_TAG_HTML,
194 // ElementKind.PREFIX,
195 if (kind == engine.ElementKind.SETTER) return CompletionSuggestionKind.SETTER;
196 if (kind == engine.ElementKind.TOP_LEVEL_VARIABLE) return CompletionSuggestion Kind.TOP_LEVEL_VARIABLE;
197 // ElementKind.TYPE_PARAMETER,
198 // ElementKind.UNIVERSE
199 throw new ArgumentError('Unknown CompletionSuggestionKind for: $kind');
200 }
201
202 /**
203 * Create an ElementKind based on a value from the analyzer engine. Access
204 * this function via new ElementKind.fromEngine().
205 */
206 ElementKind _elementKindFromEngine(engine.ElementKind kind) {
207 if (kind == engine.ElementKind.CLASS) {
208 return ElementKind.CLASS;
209 }
210 if (kind == engine.ElementKind.COMPILATION_UNIT) {
211 return ElementKind.COMPILATION_UNIT;
212 }
213 if (kind == engine.ElementKind.CONSTRUCTOR) {
214 return ElementKind.CONSTRUCTOR;
215 }
216 if (kind == engine.ElementKind.FIELD) {
217 return ElementKind.FIELD;
218 }
219 if (kind == engine.ElementKind.FUNCTION) {
220 return ElementKind.FUNCTION;
221 }
222 if (kind == engine.ElementKind.FUNCTION_TYPE_ALIAS) {
223 return ElementKind.FUNCTION_TYPE_ALIAS;
224 }
225 if (kind == engine.ElementKind.GETTER) {
226 return ElementKind.GETTER;
227 }
228 if (kind == engine.ElementKind.LIBRARY) {
229 return ElementKind.LIBRARY;
230 }
231 if (kind == engine.ElementKind.LOCAL_VARIABLE) {
232 return ElementKind.LOCAL_VARIABLE;
233 }
234 if (kind == engine.ElementKind.METHOD) {
235 return ElementKind.METHOD;
236 }
237 if (kind == engine.ElementKind.PARAMETER) {
238 return ElementKind.PARAMETER;
239 }
240 if (kind == engine.ElementKind.SETTER) {
241 return ElementKind.SETTER;
242 }
243 if (kind == engine.ElementKind.TOP_LEVEL_VARIABLE) {
244 return ElementKind.TOP_LEVEL_VARIABLE;
245 }
246 if (kind == engine.ElementKind.TYPE_PARAMETER) {
247 return ElementKind.TYPE_PARAMETER;
248 }
249 return ElementKind.UNKNOWN;
250 }
251
252 /**
253 * Compare the lists [listA] and [listB], using [itemEqual] to compare
254 * list elements.
255 */
256 bool _listEqual(List listA, List listB, bool itemEqual(a, b)) {
257 if (listA.length != listB.length) {
258 return false;
259 }
260 for (int i = 0; i < listA.length; i++) {
261 if (!itemEqual(listA[i], listB[i])) {
262 return false;
263 }
264 }
265 return true;
266 }
267
268 /**
269 * Creates a new [Location].
270 */
271 Location _locationForArgs(engine.AnalysisContext context, engine.Source source,
272 engine.SourceRange range) {
273 int startLine = 0;
274 int startColumn = 0;
275 {
276 engine.LineInfo lineInfo = context.getLineInfo(source);
277 if (lineInfo != null) {
278 engine.LineInfo_Location offsetLocation =
279 lineInfo.getLocation(range.offset);
280 startLine = offsetLocation.lineNumber;
281 startColumn = offsetLocation.columnNumber;
282 }
283 }
284 return new Location(
285 source.fullName,
286 range.offset,
287 range.length,
288 startLine,
289 startColumn);
290 }
291
292 /**
293 * Creates a new [Location] for the given [engine.Element].
294 */
295 Location _locationFromElement(engine.Element element) {
296 engine.AnalysisContext context = element.context;
297 engine.Source source = element.source;
298 String name = element.displayName;
299 int offset = element.nameOffset;
300 int length = name != null ? name.length : 0;
301 if (element is engine.CompilationUnitElement) {
302 offset = 0;
303 length = 0;
304 }
305 engine.SourceRange range = new engine.SourceRange(offset, length);
306 return _locationForArgs(context, source, range);
307 }
308
309
310 /**
311 * Creates a new [Location] for the given [engine.SearchMatch].
312 */
313 Location _locationFromMatch(engine.SearchMatch match) {
314 engine.Element enclosingElement = match.element;
315 return _locationForArgs(
316 enclosingElement.context,
317 enclosingElement.source,
318 match.sourceRange);
319 }
320
321
322 /**
323 * Creates a new [Location] for the given [engine.AstNode].
324 */
325 Location _locationFromNode(engine.AstNode node) {
326 engine.CompilationUnit unit =
327 node.getAncestor((node) => node is engine.CompilationUnit);
328 engine.CompilationUnitElement unitElement = unit.element;
329 engine.AnalysisContext context = unitElement.context;
330 engine.Source source = unitElement.source;
331 engine.SourceRange range = new engine.SourceRange(node.offset, node.length);
332 return _locationForArgs(context, source, range);
333 }
334
335 /**
336 * Creates a new [Location] for the given [engine.CompilationUnit].
337 */
338 Location _locationFromUnit(engine.CompilationUnit unit,
339 engine.SourceRange range) {
340 engine.CompilationUnitElement unitElement = unit.element;
341 engine.AnalysisContext context = unitElement.context;
342 engine.Source source = unitElement.source;
343 return _locationForArgs(context, source, range);
344 }
345
346
347 /**
348 * Compare the maps [mapA] and [mapB], using [valueEqual] to compare map
349 * values.
350 */
351 bool _mapEqual(Map mapA, Map mapB, bool valueEqual(a, b)) {
352 if (mapA.length != mapB.length) {
353 return false;
354 }
355 for (var key in mapA.keys) {
356 if (!mapB.containsKey(key)) {
357 return false;
358 }
359 if (!valueEqual(mapA[key], mapB[key])) {
360 return false;
361 }
362 }
363 return true;
364 }
365
366
367 RefactoringProblemSeverity
368 _maxRefactoringProblemSeverity(RefactoringProblemSeverity a,
369 RefactoringProblemSeverity b) {
370 if (b == null) {
371 return a;
372 }
373 if (a == null) {
374 return b;
375 } else if (a == RefactoringProblemSeverity.INFO) {
376 return b;
377 } else if (a == RefactoringProblemSeverity.WARNING) {
378 if (b == RefactoringProblemSeverity.ERROR ||
379 b == RefactoringProblemSeverity.FATAL) {
380 return b;
381 }
382 } else if (a == RefactoringProblemSeverity.ERROR) {
383 if (b == RefactoringProblemSeverity.FATAL) {
384 return b;
385 }
386 }
387 return a;
388 }
389
390 /**
391 * Create an OverriddenMember based on an element from the analyzer engine.
392 */
393 OverriddenMember _overriddenMemberFromEngine(engine.Element member) {
394 Element element = elementFromEngine(member);
395 String className = member.enclosingElement.displayName;
396 return new OverriddenMember(element, className);
397 }
398
399 /**
400 * Create a SearchResultKind based on a value from the search engine.
401 */
402 SearchResultKind _searchResultKindFromEngine(engine.MatchKind kind) {
403 if (kind == engine.MatchKind.DECLARATION) {
404 return SearchResultKind.DECLARATION;
405 }
406 if (kind == engine.MatchKind.READ) {
407 return SearchResultKind.READ;
408 }
409 if (kind == engine.MatchKind.READ_WRITE) {
410 return SearchResultKind.READ_WRITE;
411 }
412 if (kind == engine.MatchKind.WRITE) {
413 return SearchResultKind.WRITE;
414 }
415 if (kind == engine.MatchKind.INVOCATION) {
416 return SearchResultKind.INVOCATION;
417 }
418 if (kind == engine.MatchKind.REFERENCE) {
419 return SearchResultKind.REFERENCE;
420 }
421 return SearchResultKind.UNKNOWN;
422 }
423
424
425 /**
426 * Type of callbacks used to decode parts of JSON objects. [jsonPath] is a
427 * string describing the part of the JSON object being decoded, and [value] is
428 * the part to decode.
429 */
430 typedef Object JsonDecoderCallback(String jsonPath, Object value);
431
432 /**
433 * Base class for decoding JSON objects. The derived class must implement
434 * error reporting logic.
435 */
436 abstract class JsonDecoder {
437 /**
438 * Create an exception to throw if the JSON object at [jsonPath] fails to
439 * match the API definition of [expected].
440 */
441 dynamic mismatch(String jsonPath, String expected);
442
443 /**
444 * Create an exception to throw if the JSON object at [jsonPath] is missing
445 * the key [key].
446 */
447 dynamic missingKey(String jsonPath, String key);
448
449 /**
450 * Decode a JSON object that is expected to be a boolean. The strings "true"
451 * and "false" are also accepted.
452 */
453 bool _decodeBool(String jsonPath, Object json) {
454 if (json is bool) {
455 return json;
456 } else if (json == 'true') {
457 return true;
458 } else if (json == 'false') {
459 return false;
460 }
461 throw mismatch(jsonPath, 'bool');
462 }
463
464 /**
465 * Decode a JSON object that is expected to be an integer. A string
466 * representation of an integer is also accepted.
467 */
468 int _decodeInt(String jsonPath, Object json) {
469 if (json is int) {
470 return json;
471 } else if (json is String) {
472 return int.parse(json, onError: (String value) {
473 throw mismatch(jsonPath, 'int');
474 });
475 }
476 throw mismatch(jsonPath, 'int');
477 }
478
479 /**
480 * Decode a JSON object that is expected to be a List. [decoder] is used to
481 * decode the items in the list.
482 */
483 List _decodeList(String jsonPath, Object json,
484 [JsonDecoderCallback decoder]) {
485 if (json == null) {
486 return [];
487 } else if (json is List) {
488 List result = [];
489 for (int i = 0; i < json.length; i++) {
490 result.add(decoder('$jsonPath[$i]', json[i]));
491 }
492 return result;
493 } else {
494 throw mismatch(jsonPath, 'List');
495 }
496 }
497
498 /**
499 * Decode a JSON object that is expected to be a Map. [keyDecoder] is used
500 * to decode the keys, and [valueDecoder] is used to decode the values.
501 */
502 Map _decodeMap(String jsonPath, Object json, {JsonDecoderCallback keyDecoder,
503 JsonDecoderCallback valueDecoder}) {
504 if (json == null) {
505 return {};
506 } else if (json is Map) {
507 Map result = {};
508 json.forEach((String key, value) {
509 Object decodedKey;
510 if (keyDecoder != null) {
511 decodedKey = keyDecoder('$jsonPath.key', key);
512 } else {
513 decodedKey = key;
514 }
515 if (valueDecoder != null) {
516 value = valueDecoder('$jsonPath[${JSON.encode(key)}]', value);
517 }
518 result[decodedKey] = value;
519 });
520 return result;
521 } else {
522 throw mismatch(jsonPath, 'Map');
523 }
524 }
525
526 /**
527 * Decode a JSON object that is expected to be a string.
528 */
529 String _decodeString(String jsonPath, Object json) {
530 if (json is String) {
531 return json;
532 } else {
533 throw mismatch(jsonPath, 'String');
534 }
535 }
536
537 /**
538 * Decode a JSON object that is expected to be one of several choices,
539 * where the choices are disambiguated by the contents of the field [field].
540 * [decoders] is a map from each possible string in the field to the decoder
541 * that should be used to decode the JSON object.
542 */
543 Object _decodeUnion(String jsonPath, Map json, String field, Map<String,
544 JsonDecoderCallback> decoders) {
545 if (json is Map) {
546 if (!json.containsKey(field)) {
547 throw missingKey(jsonPath, field);
548 }
549 var disambiguatorPath = '$jsonPath[${JSON.encode(field)}]';
550 String disambiguator = _decodeString(disambiguatorPath, json[field]);
551 if (!decoders.containsKey(disambiguator)) {
552 throw mismatch(disambiguatorPath, 'One of: ${decoders.keys.toList()}');
553 }
554 return decoders[disambiguator](jsonPath, json);
555 } else {
556 throw mismatch(jsonPath, 'Map');
557 }
558 }
559 }
560
561 /**
562 * JsonDecoder for decoding requests. Errors are reporting by throwing a
563 * [RequestFailure].
564 */
565 class RequestDecoder extends JsonDecoder {
566 /**
567 * The request being deserialized.
568 */
569 final Request _request;
570
571 RequestDecoder(this._request);
572
573 @override
574 dynamic mismatch(String jsonPath, String expected) {
575 return new RequestFailure(
576 new Response.invalidParameter(_request, jsonPath, 'be $expected'));
577 }
578
579 @override
580 dynamic missingKey(String jsonPath, String key) {
581 return new RequestFailure(
582 new Response.invalidParameter(
583 _request,
584 jsonPath,
585 'contain key ${JSON.encode(key)}'));
586 }
587 }
588
589 /**
590 * JsonDecoder for decoding responses from the server. This is intended to be
591 * used only for testing. Errors are reported using bare [Exception] objects.
592 */
593 class ResponseDecoder extends JsonDecoder {
594 @override
595 dynamic mismatch(String jsonPath, String expected) {
596 return new Exception('Expected $expected at $jsonPath');
597 }
598
599 @override
600 dynamic missingKey(String jsonPath, String key) {
601 return new Exception('Missing key $key at $jsonPath');
602 }
603 }
604
605 /**
606 * Jenkins hash function, optimized for small integers. Borrowed from
607 * sdk/lib/math/jenkins_smi_hash.dart.
608 *
609 * TODO(paulberry): Move to somewhere that can be shared with other code.
610 */
611 class _JenkinsSmiHash {
612 static int combine(int hash, int value) {
613 hash = 0x1fffffff & (hash + value);
614 hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
615 return hash ^ (hash >> 6);
616 }
617
618 static int finish(int hash) {
619 hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
620 hash = hash ^ (hash >> 11);
621 return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
622 }
623
624 static int hash2(a, b) => finish(combine(combine(0, a), b));
625
626 static int hash4(a, b, c, d) =>
627 finish(combine(combine(combine(combine(0, a), b), c), d));
628 }
OLDNEW
« no previous file with comments | « pkg/analysis_server/lib/src/protocol.dart ('k') | pkg/analysis_server/lib/src/search/element_references.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698