| 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 protocol2; | 5 library protocol2; |
| 6 | 6 |
| 7 import 'dart:convert'; | 7 import 'dart:convert'; |
| 8 | 8 |
| 9 import 'package:analysis_server/src/services/json.dart'; |
| 10 import 'package:analyzer/src/generated/element.dart' as engine; |
| 11 import 'package:analyzer/src/generated/engine.dart' as engine; |
| 12 import 'package:analyzer/src/generated/error.dart' as engine; |
| 13 import 'package:analyzer/src/generated/source.dart' as engine; |
| 14 |
| 9 import 'protocol.dart'; | 15 import 'protocol.dart'; |
| 10 | 16 |
| 11 import 'package:analysis_server/src/services/json.dart'; | 17 part 'generated_protocol.dart'; |
| 12 | 18 |
| 13 part 'generated_protocol.dart'; | 19 /** |
| 20 * Translate the input [map], applying [keyCallback] to all its keys, and |
| 21 * [valueCallback] to all its values. |
| 22 */ |
| 23 mapMap(Map map, {dynamic keyCallback(key), dynamic valueCallback(value)}) { |
| 24 Map result = {}; |
| 25 map.forEach((key, value) { |
| 26 if (keyCallback != null) { |
| 27 key = keyCallback(key); |
| 28 } |
| 29 if (valueCallback != null) { |
| 30 value = valueCallback(value); |
| 31 } |
| 32 result[key] = value; |
| 33 }); |
| 34 return result; |
| 35 } |
| 36 |
| 37 /** |
| 38 * Create an AnalysisError based on error information from the analyzer |
| 39 * engine. Access via AnalysisError.fromEngine(). |
| 40 */ |
| 41 AnalysisError _analysisErrorFromEngine(engine.LineInfo |
| 42 lineInfo, engine.AnalysisError error) { |
| 43 engine.ErrorCode errorCode = error.errorCode; |
| 44 // prepare location |
| 45 Location location; |
| 46 { |
| 47 String file = error.source.fullName; |
| 48 int offset = error.offset; |
| 49 int length = error.length; |
| 50 int startLine = -1; |
| 51 int startColumn = -1; |
| 52 if (lineInfo != null) { |
| 53 engine.LineInfo_Location lineLocation = lineInfo.getLocation(offset); |
| 54 if (lineLocation != null) { |
| 55 startLine = lineLocation.lineNumber; |
| 56 startColumn = lineLocation.columnNumber; |
| 57 } |
| 58 } |
| 59 location = new Location(file, offset, length, startLine, startColumn); |
| 60 } |
| 61 // done |
| 62 var severity = new ErrorSeverity(errorCode.errorSeverity.name); |
| 63 var type = new ErrorType(errorCode.type.name); |
| 64 String message = error.message; |
| 65 String correction = error.correction; |
| 66 return new AnalysisError(severity, type, location, message, correction: |
| 67 correction); |
| 68 } |
| 69 |
| 70 /** |
| 71 * Get the result of applying the edit to the given [code]. Access via |
| 72 * SourceEdit.apply(). |
| 73 */ |
| 74 String _applyEdit(String code, SourceEdit edit) { |
| 75 return code.substring(0, edit.offset) + edit.replacement + code.substring( |
| 76 edit.end); |
| 77 } |
| 78 |
| 79 /** |
| 80 * Get the result of applying a set of [edits] to the given [code]. Edits |
| 81 * are applied in the order they appear in [edits]. Access via |
| 82 * SourceEdit.applySequence(). |
| 83 */ |
| 84 String _applySequence(String code, Iterable<SourceEdit> edits) { |
| 85 edits.forEach((SourceEdit edit) { |
| 86 code = edit.apply(code); |
| 87 }); |
| 88 return code; |
| 89 } |
| 90 |
| 91 /** |
| 92 * Create an ElementKind based on a value from the analyzer engine. Access |
| 93 * this function via new ElementKind.fromEngine(). |
| 94 */ |
| 95 ElementKind _elementKindFromEngine(engine.ElementKind kind) { |
| 96 if (kind == engine.ElementKind.CLASS) { |
| 97 return ElementKind.CLASS; |
| 98 } |
| 99 if (kind == engine.ElementKind.COMPILATION_UNIT) { |
| 100 return ElementKind.COMPILATION_UNIT; |
| 101 } |
| 102 if (kind == engine.ElementKind.CONSTRUCTOR) { |
| 103 return ElementKind.CONSTRUCTOR; |
| 104 } |
| 105 if (kind == engine.ElementKind.FIELD) { |
| 106 return ElementKind.FIELD; |
| 107 } |
| 108 if (kind == engine.ElementKind.FUNCTION) { |
| 109 return ElementKind.FUNCTION; |
| 110 } |
| 111 if (kind == engine.ElementKind.FUNCTION_TYPE_ALIAS) { |
| 112 return ElementKind.FUNCTION_TYPE_ALIAS; |
| 113 } |
| 114 if (kind == engine.ElementKind.GETTER) { |
| 115 return ElementKind.GETTER; |
| 116 } |
| 117 if (kind == engine.ElementKind.LIBRARY) { |
| 118 return ElementKind.LIBRARY; |
| 119 } |
| 120 if (kind == engine.ElementKind.LOCAL_VARIABLE) { |
| 121 return ElementKind.LOCAL_VARIABLE; |
| 122 } |
| 123 if (kind == engine.ElementKind.METHOD) { |
| 124 return ElementKind.METHOD; |
| 125 } |
| 126 if (kind == engine.ElementKind.PARAMETER) { |
| 127 return ElementKind.PARAMETER; |
| 128 } |
| 129 if (kind == engine.ElementKind.SETTER) { |
| 130 return ElementKind.SETTER; |
| 131 } |
| 132 if (kind == engine.ElementKind.TOP_LEVEL_VARIABLE) { |
| 133 return ElementKind.TOP_LEVEL_VARIABLE; |
| 134 } |
| 135 if (kind == engine.ElementKind.TYPE_PARAMETER) { |
| 136 return ElementKind.TYPE_PARAMETER; |
| 137 } |
| 138 return ElementKind.UNKNOWN; |
| 139 } |
| 14 | 140 |
| 15 /** | 141 /** |
| 16 * Compare the lists [listA] and [listB], using [itemEqual] to compare | 142 * Compare the lists [listA] and [listB], using [itemEqual] to compare |
| 17 * list elements. | 143 * list elements. |
| 18 */ | 144 */ |
| 19 bool _listEqual(List listA, List listB, bool itemEqual(a, b)) { | 145 bool _listEqual(List listA, List listB, bool itemEqual(a, b)) { |
| 20 if (listA.length != listB.length) { | 146 if (listA.length != listB.length) { |
| 21 return false; | 147 return false; |
| 22 } | 148 } |
| 23 for (int i = 0; i < listA.length; i++) { | 149 for (int i = 0; i < listA.length; i++) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 40 if (!mapB.containsKey(key)) { | 166 if (!mapB.containsKey(key)) { |
| 41 return false; | 167 return false; |
| 42 } | 168 } |
| 43 if (!valueEqual(mapA[key], mapB[key])) { | 169 if (!valueEqual(mapA[key], mapB[key])) { |
| 44 return false; | 170 return false; |
| 45 } | 171 } |
| 46 } | 172 } |
| 47 return true; | 173 return true; |
| 48 } | 174 } |
| 49 | 175 |
| 50 /** | |
| 51 * Translate the input [map], applying [keyCallback] to all its keys, and | |
| 52 * [valueCallback] to all its values. | |
| 53 */ | |
| 54 mapMap(Map map, {dynamic keyCallback(key), dynamic valueCallback(value)}) { | |
| 55 Map result = {}; | |
| 56 map.forEach((key, value) { | |
| 57 if (keyCallback != null) { | |
| 58 key = keyCallback(key); | |
| 59 } | |
| 60 if (valueCallback != null) { | |
| 61 value = valueCallback(value); | |
| 62 } | |
| 63 result[key] = value; | |
| 64 }); | |
| 65 return result; | |
| 66 } | |
| 67 | 176 |
| 68 /** | 177 /** |
| 69 * Type of callbacks used to decode parts of JSON objects. [jsonPath] is a | 178 * Type of callbacks used to decode parts of JSON objects. [jsonPath] is a |
| 70 * string describing the part of the JSON object being decoded, and [value] is | 179 * string describing the part of the JSON object being decoded, and [value] is |
| 71 * the part to decode. | 180 * the part to decode. |
| 72 */ | 181 */ |
| 73 typedef Object JsonDecoderCallback(String jsonPath, Object value); | 182 typedef Object JsonDecoderCallback(String jsonPath, Object value); |
| 74 | 183 |
| 75 | |
| 76 /** | 184 /** |
| 77 * Base class for decoding JSON objects. The derived class must implement | 185 * Base class for decoding JSON objects. The derived class must implement |
| 78 * error reporting logic. | 186 * error reporting logic. |
| 79 */ | 187 */ |
| 80 abstract class JsonDecoder { | 188 abstract class JsonDecoder { |
| 81 /** | 189 /** |
| 82 * Create an exception to throw if the JSON object at [jsonPath] fails to | 190 * Create an exception to throw if the JSON object at [jsonPath] fails to |
| 83 * match the API definition of [expected]. | 191 * match the API definition of [expected]. |
| 84 */ | 192 */ |
| 85 dynamic mismatch(String jsonPath, String expected); | 193 dynamic mismatch(String jsonPath, String expected); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 throw mismatch(jsonPath, 'int'); | 225 throw mismatch(jsonPath, 'int'); |
| 118 }); | 226 }); |
| 119 } | 227 } |
| 120 throw mismatch(jsonPath, 'int'); | 228 throw mismatch(jsonPath, 'int'); |
| 121 } | 229 } |
| 122 | 230 |
| 123 /** | 231 /** |
| 124 * Decode a JSON object that is expected to be a List. [decoder] is used to | 232 * Decode a JSON object that is expected to be a List. [decoder] is used to |
| 125 * decode the items in the list. | 233 * decode the items in the list. |
| 126 */ | 234 */ |
| 127 List _decodeList(String jsonPath, Object json, [JsonDecoderCallback decoder])
{ | 235 List _decodeList(String jsonPath, Object json, [JsonDecoderCallback decoder]) |
| 236 { |
| 128 if (json == null) { | 237 if (json == null) { |
| 129 return []; | 238 return []; |
| 130 } else if (json is List) { | 239 } else if (json is List) { |
| 131 List result = []; | 240 List result = []; |
| 132 for (int i = 0; i < json.length; i++) { | 241 for (int i = 0; i < json.length; i++) { |
| 133 result.add(decoder('$jsonPath[$i]', json[i])); | 242 result.add(decoder('$jsonPath[$i]', json[i])); |
| 134 } | 243 } |
| 135 return result; | 244 return result; |
| 136 } else { | 245 } else { |
| 137 throw mismatch(jsonPath, 'List'); | 246 throw mismatch(jsonPath, 'List'); |
| 138 } | 247 } |
| 139 } | 248 } |
| 140 | 249 |
| 141 /** | 250 /** |
| 142 * Decode a JSON object that is expected to be a Map. [keyDecoder] is used | 251 * Decode a JSON object that is expected to be a Map. [keyDecoder] is used |
| 143 * to decode the keys, and [valueDecoder] is used to decode the values. | 252 * to decode the keys, and [valueDecoder] is used to decode the values. |
| 144 */ | 253 */ |
| 145 Map _decodeMap(String jsonPath, Object json, {JsonDecoderCallback keyDecoder, | 254 Map _decodeMap(String jsonPath, Object json, {JsonDecoderCallback |
| 146 JsonDecoderCallback valueDecoder}) { | 255 keyDecoder, JsonDecoderCallback valueDecoder}) { |
| 147 if (json == null) { | 256 if (json == null) { |
| 148 return {}; | 257 return {}; |
| 149 } else if (json is Map) { | 258 } else if (json is Map) { |
| 150 Map result = {}; | 259 Map result = {}; |
| 151 json.forEach((String key, value) { | 260 json.forEach((String key, value) { |
| 152 Object decodedKey; | 261 Object decodedKey; |
| 153 if (keyDecoder != null) { | 262 if (keyDecoder != null) { |
| 154 decodedKey = keyDecoder('$jsonPath.key', key); | 263 decodedKey = keyDecoder('$jsonPath.key', key); |
| 155 } else { | 264 } else { |
| 156 decodedKey = key; | 265 decodedKey = key; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 176 throw mismatch(jsonPath, 'String'); | 285 throw mismatch(jsonPath, 'String'); |
| 177 } | 286 } |
| 178 } | 287 } |
| 179 | 288 |
| 180 /** | 289 /** |
| 181 * Decode a JSON object that is expected to be one of several choices, | 290 * Decode a JSON object that is expected to be one of several choices, |
| 182 * where the choices are disambiguated by the contents of the field [field]. | 291 * where the choices are disambiguated by the contents of the field [field]. |
| 183 * [decoders] is a map from each possible string in the field to the decoder | 292 * [decoders] is a map from each possible string in the field to the decoder |
| 184 * that should be used to decode the JSON object. | 293 * that should be used to decode the JSON object. |
| 185 */ | 294 */ |
| 186 Object _decodeUnion(String jsonPath, Map json, String field, | 295 Object _decodeUnion(String jsonPath, Map json, String field, Map<String, |
| 187 Map<String, JsonDecoderCallback> decoders) { | 296 JsonDecoderCallback> decoders) { |
| 188 if (json is Map) { | 297 if (json is Map) { |
| 189 if (!json.containsKey(field)) { | 298 if (!json.containsKey(field)) { |
| 190 throw missingKey(jsonPath, field); | 299 throw missingKey(jsonPath, field); |
| 191 } | 300 } |
| 192 var disambiguatorPath = '$jsonPath[${JSON.encode(field)}]'; | 301 var disambiguatorPath = '$jsonPath[${JSON.encode(field)}]'; |
| 193 String disambiguator = _decodeString(disambiguatorPath, | 302 String disambiguator = _decodeString(disambiguatorPath, json[field]); |
| 194 json[field]); | |
| 195 if (!decoders.containsKey(disambiguator)) { | 303 if (!decoders.containsKey(disambiguator)) { |
| 196 throw mismatch(disambiguatorPath, 'One of: ${decoders.keys.toList()}'); | 304 throw mismatch(disambiguatorPath, 'One of: ${decoders.keys.toList()}'); |
| 197 } | 305 } |
| 198 return decoders[disambiguator](jsonPath, json); | 306 return decoders[disambiguator](jsonPath, json); |
| 199 } else { | 307 } else { |
| 200 throw mismatch(jsonPath, 'Map'); | 308 throw mismatch(jsonPath, 'Map'); |
| 201 } | 309 } |
| 202 } | 310 } |
| 203 } | 311 } |
| 204 | 312 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 250 * TODO(paulberry): Move to somewhere that can be shared with other code. | 358 * TODO(paulberry): Move to somewhere that can be shared with other code. |
| 251 */ | 359 */ |
| 252 class _JenkinsSmiHash { | 360 class _JenkinsSmiHash { |
| 253 static int combine(int hash, int value) { | 361 static int combine(int hash, int value) { |
| 254 hash = 0x1fffffff & (hash + value); | 362 hash = 0x1fffffff & (hash + value); |
| 255 hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); | 363 hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); |
| 256 return hash ^ (hash >> 6); | 364 return hash ^ (hash >> 6); |
| 257 } | 365 } |
| 258 | 366 |
| 259 static int finish(int hash) { | 367 static int finish(int hash) { |
| 260 hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); | 368 hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); |
| 261 hash = hash ^ (hash >> 11); | 369 hash = hash ^ (hash >> 11); |
| 262 return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); | 370 return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); |
| 263 } | 371 } |
| 264 | 372 |
| 265 static int hash2(a, b) => finish(combine(combine(0, a), b)); | 373 static int hash2(a, b) => finish(combine(combine(0, a), b)); |
| 266 | 374 |
| 267 static int hash4(a, b, c, d) => | 375 static int hash4(a, b, c, d) => finish(combine(combine(combine(combine(0, a), |
| 268 finish(combine(combine(combine(combine(0, a), b), c), d)); | 376 b), c), d)); |
| 269 } | 377 } |
| OLD | NEW |