| 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/computer/element.dart' show | 9 import 'package:analysis_server/src/computer/element.dart' show |
| 10 elementFromEngine; | 10 elementFromEngine; |
| 11 import 'package:analysis_server/src/search/search_result.dart' show | 11 import 'package:analysis_server/src/search/search_result.dart' show |
| 12 searchResultFromMatch; | 12 searchResultFromMatch; |
| 13 import 'package:analysis_server/src/services/json.dart'; | 13 import 'package:analysis_server/src/services/json.dart'; |
| 14 import 'package:analysis_server/src/services/search/search_engine.dart' as | 14 import 'package:analysis_server/src/services/search/search_engine.dart' as |
| 15 engine; | 15 engine; |
| 16 import 'package:analyzer/src/generated/ast.dart' as engine; |
| 16 import 'package:analyzer/src/generated/element.dart' as engine; | 17 import 'package:analyzer/src/generated/element.dart' as engine; |
| 17 import 'package:analyzer/src/generated/engine.dart' as engine; | 18 import 'package:analyzer/src/generated/engine.dart' as engine; |
| 18 import 'package:analyzer/src/generated/error.dart' as engine; | 19 import 'package:analyzer/src/generated/error.dart' as engine; |
| 19 import 'package:analyzer/src/generated/source.dart' as engine; | 20 import 'package:analyzer/src/generated/source.dart' as engine; |
| 20 | 21 |
| 21 import 'protocol.dart'; | 22 import 'protocol.dart'; |
| 22 | 23 |
| 23 part 'generated_protocol.dart'; | 24 part 'generated_protocol.dart'; |
| 24 | 25 |
| 25 /** | 26 /** |
| 26 * Translate the input [map], applying [keyCallback] to all its keys, and | 27 * Translate the input [map], applying [keyCallback] to all its keys, and |
| 27 * [valueCallback] to all its values. | 28 * [valueCallback] to all its values. |
| 28 */ | 29 */ |
| 29 mapMap(Map map, {dynamic keyCallback(key), dynamic valueCallback(value)}) { | 30 mapMap(Map map, {dynamic keyCallback(key), dynamic valueCallback(value)}) { |
| 30 Map result = {}; | 31 Map result = {}; |
| 31 map.forEach((key, value) { | 32 map.forEach((key, value) { |
| 32 if (keyCallback != null) { | 33 if (keyCallback != null) { |
| 33 key = keyCallback(key); | 34 key = keyCallback(key); |
| 34 } | 35 } |
| 35 if (valueCallback != null) { | 36 if (valueCallback != null) { |
| 36 value = valueCallback(value); | 37 value = valueCallback(value); |
| 37 } | 38 } |
| 38 result[key] = value; | 39 result[key] = value; |
| 39 }); | 40 }); |
| 40 return result; | 41 return result; |
| 41 } | 42 } |
| 42 | 43 |
| 43 /** | 44 /** |
| 45 * Adds the given [sourceEdits] to the list in [sourceFileEdit]. |
| 46 */ |
| 47 void _addAllEditsForSource(SourceFileEdit sourceFileEdit, |
| 48 Iterable<SourceEdit> edits) { |
| 49 edits.forEach(sourceFileEdit.add); |
| 50 } |
| 51 |
| 52 /** |
| 44 * Adds the given [sourceEdit] to the list in [sourceFileEdit]. | 53 * Adds the given [sourceEdit] to the list in [sourceFileEdit]. |
| 45 */ | 54 */ |
| 46 void _addEditForSource(SourceFileEdit sourceFileEdit, SourceEdit sourceEdit) { | 55 void _addEditForSource(SourceFileEdit sourceFileEdit, SourceEdit sourceEdit) { |
| 47 List<SourceEdit> edits = sourceFileEdit.edits; | 56 List<SourceEdit> edits = sourceFileEdit.edits; |
| 48 int index = 0; | 57 int index = 0; |
| 49 while (index < edits.length && edits[index].offset > sourceEdit.offset) { | 58 while (index < edits.length && edits[index].offset > sourceEdit.offset) { |
| 50 index++; | 59 index++; |
| 51 } | 60 } |
| 52 edits.insert(index, sourceEdit); | 61 edits.insert(index, sourceEdit); |
| 53 } | 62 } |
| 54 | 63 |
| 55 /** | 64 /** |
| 56 * Adds the given [sourceEdits] to the list in [sourceFileEdit]. | |
| 57 */ | |
| 58 void _addAllEditsForSource(SourceFileEdit sourceFileEdit, | |
| 59 Iterable<SourceEdit> edits) { | |
| 60 edits.forEach(sourceFileEdit.add); | |
| 61 } | |
| 62 | |
| 63 /** | |
| 64 * Create an AnalysisError based on error information from the analyzer | 65 * Create an AnalysisError based on error information from the analyzer |
| 65 * engine. Access via AnalysisError.fromEngine(). | 66 * engine. Access via AnalysisError.fromEngine(). |
| 66 */ | 67 */ |
| 67 AnalysisError _analysisErrorFromEngine(engine.LineInfo | 68 AnalysisError _analysisErrorFromEngine(engine.LineInfo lineInfo, |
| 68 lineInfo, engine.AnalysisError error) { | 69 engine.AnalysisError error) { |
| 69 engine.ErrorCode errorCode = error.errorCode; | 70 engine.ErrorCode errorCode = error.errorCode; |
| 70 // prepare location | 71 // prepare location |
| 71 Location location; | 72 Location location; |
| 72 { | 73 { |
| 73 String file = error.source.fullName; | 74 String file = error.source.fullName; |
| 74 int offset = error.offset; | 75 int offset = error.offset; |
| 75 int length = error.length; | 76 int length = error.length; |
| 76 int startLine = -1; | 77 int startLine = -1; |
| 77 int startColumn = -1; | 78 int startColumn = -1; |
| 78 if (lineInfo != null) { | 79 if (lineInfo != null) { |
| 79 engine.LineInfo_Location lineLocation = lineInfo.getLocation(offset); | 80 engine.LineInfo_Location lineLocation = lineInfo.getLocation(offset); |
| 80 if (lineLocation != null) { | 81 if (lineLocation != null) { |
| 81 startLine = lineLocation.lineNumber; | 82 startLine = lineLocation.lineNumber; |
| 82 startColumn = lineLocation.columnNumber; | 83 startColumn = lineLocation.columnNumber; |
| 83 } | 84 } |
| 84 } | 85 } |
| 85 location = new Location(file, offset, length, startLine, startColumn); | 86 location = new Location(file, offset, length, startLine, startColumn); |
| 86 } | 87 } |
| 87 // done | 88 // done |
| 88 var severity = new ErrorSeverity(errorCode.errorSeverity.name); | 89 var severity = new ErrorSeverity(errorCode.errorSeverity.name); |
| 89 var type = new ErrorType(errorCode.type.name); | 90 var type = new ErrorType(errorCode.type.name); |
| 90 String message = error.message; | 91 String message = error.message; |
| 91 String correction = error.correction; | 92 String correction = error.correction; |
| 92 return new AnalysisError(severity, type, location, message, correction: | 93 return new AnalysisError( |
| 93 correction); | 94 severity, |
| 95 type, |
| 96 location, |
| 97 message, |
| 98 correction: correction); |
| 94 } | 99 } |
| 95 | 100 |
| 96 /** | 101 /** |
| 97 * Get the result of applying the edit to the given [code]. Access via | 102 * Get the result of applying the edit to the given [code]. Access via |
| 98 * SourceEdit.apply(). | 103 * SourceEdit.apply(). |
| 99 */ | 104 */ |
| 100 String _applyEdit(String code, SourceEdit edit) { | 105 String _applyEdit(String code, SourceEdit edit) { |
| 101 return code.substring(0, edit.offset) + edit.replacement + code.substring( | 106 return code.substring(0, edit.offset) + |
| 102 edit.end); | 107 edit.replacement + |
| 108 code.substring(edit.end); |
| 103 } | 109 } |
| 104 | 110 |
| 105 /** | 111 /** |
| 106 * Get the result of applying a set of [edits] to the given [code]. Edits | 112 * Get the result of applying a set of [edits] to the given [code]. Edits |
| 107 * are applied in the order they appear in [edits]. Access via | 113 * are applied in the order they appear in [edits]. Access via |
| 108 * SourceEdit.applySequence(). | 114 * SourceEdit.applySequence(). |
| 109 */ | 115 */ |
| 110 String _applySequence(String code, Iterable<SourceEdit> edits) { | 116 String _applySequence(String code, Iterable<SourceEdit> edits) { |
| 111 edits.forEach((SourceEdit edit) { | 117 edits.forEach((SourceEdit edit) { |
| 112 code = edit.apply(code); | 118 code = edit.apply(code); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 174 } | 180 } |
| 175 for (int i = 0; i < listA.length; i++) { | 181 for (int i = 0; i < listA.length; i++) { |
| 176 if (!itemEqual(listA[i], listB[i])) { | 182 if (!itemEqual(listA[i], listB[i])) { |
| 177 return false; | 183 return false; |
| 178 } | 184 } |
| 179 } | 185 } |
| 180 return true; | 186 return true; |
| 181 } | 187 } |
| 182 | 188 |
| 183 /** | 189 /** |
| 184 * Create a Location based on an element from the analyzer engine. | 190 * Creates a new [Location]. |
| 185 */ | 191 */ |
| 186 Location _locationFromElement(engine.Element element) { | 192 Location _locationForArgs(engine.AnalysisContext context, engine.Source source, |
| 187 engine.Source source = element.source; | 193 engine.SourceRange range) { |
| 188 engine.LineInfo lineInfo = element.context.getLineInfo(source); | 194 int startLine = 0; |
| 189 String name = element.displayName; | 195 int startColumn = 0; |
| 190 // prepare location | 196 { |
| 191 int offset = element.nameOffset; | 197 engine.LineInfo lineInfo = context.getLineInfo(source); |
| 192 int length = name != null ? name.length : 0; | 198 if (lineInfo != null) { |
| 193 engine.LineInfo_Location lineLocation = lineInfo.getLocation(offset); | 199 engine.LineInfo_Location offsetLocation = |
| 194 int startLine = lineLocation.lineNumber; | 200 lineInfo.getLocation(range.offset); |
| 195 int startColumn = lineLocation.columnNumber; | 201 startLine = offsetLocation.lineNumber; |
| 196 if (element is engine.CompilationUnitElement) { | 202 startColumn = offsetLocation.columnNumber; |
| 197 offset = 0; | 203 } |
| 198 length = 0; | |
| 199 startLine = 1; | |
| 200 startColumn = 1; | |
| 201 } | 204 } |
| 202 // done | |
| 203 return new Location( | 205 return new Location( |
| 204 source.fullName, | 206 source.fullName, |
| 205 offset, | 207 range.offset, |
| 206 length, | 208 range.length, |
| 207 startLine, | 209 startLine, |
| 208 startColumn); | 210 startColumn); |
| 209 } | 211 } |
| 210 | 212 |
| 211 /** | 213 /** |
| 212 * Create a Location based on an element and offset from the analyzer engine. | 214 * Creates a new [Location] for the given [engine.Element]. |
| 213 */ | 215 */ |
| 214 Location _locationFromOffset(engine.Element element, int offset, int length) { | 216 Location _locationForElement(engine.Element element) { |
| 217 engine.AnalysisContext context = element.context; |
| 215 engine.Source source = element.source; | 218 engine.Source source = element.source; |
| 216 engine.LineInfo lineInfo = element.context.getLineInfo(source); | 219 String name = element.displayName; |
| 217 // prepare location | 220 int offset = element.nameOffset; |
| 218 engine.LineInfo_Location lineLocation = lineInfo.getLocation(offset); | 221 int length = name != null ? name.length : 0; |
| 219 int startLine = lineLocation.lineNumber; | 222 if (element is engine.CompilationUnitElement) { |
| 220 int startColumn = lineLocation.columnNumber; | 223 offset = 0; |
| 221 // done | 224 length = 0; |
| 222 return new Location( | 225 } |
| 223 source.fullName, | 226 engine.SourceRange range = new engine.SourceRange(offset, length); |
| 224 offset, | 227 return _locationForArgs(context, source, range); |
| 225 length, | |
| 226 startLine, | |
| 227 startColumn); | |
| 228 } | 228 } |
| 229 | 229 |
| 230 |
| 231 /** |
| 232 * Creates a new [Location] for the given [engine.SearchMatch]. |
| 233 */ |
| 234 Location _locationForMatch(engine.SearchMatch match) { |
| 235 engine.Element enclosingElement = match.element; |
| 236 return _locationForArgs( |
| 237 enclosingElement.context, |
| 238 enclosingElement.source, |
| 239 match.sourceRange); |
| 240 } |
| 241 |
| 242 |
| 243 /** |
| 244 * Creates a new [Location] for the given [engine.AstNode]. |
| 245 */ |
| 246 Location _locationForNode(engine.AstNode node) { |
| 247 engine.CompilationUnit unit = |
| 248 node.getAncestor((node) => node is engine.CompilationUnit); |
| 249 engine.CompilationUnitElement unitElement = unit.element; |
| 250 engine.AnalysisContext context = unitElement.context; |
| 251 engine.Source source = unitElement.source; |
| 252 engine.SourceRange range = new engine.SourceRange(node.offset, node.length); |
| 253 return _locationForArgs(context, source, range); |
| 254 } |
| 255 |
| 256 /** |
| 257 * Creates a new [Location] for the given [engine.CompilationUnit]. |
| 258 */ |
| 259 Location _locationForUnit(engine.CompilationUnit unit, engine.SourceRange range) |
| 260 { |
| 261 engine.CompilationUnitElement unitElement = unit.element; |
| 262 engine.AnalysisContext context = unitElement.context; |
| 263 engine.Source source = unitElement.source; |
| 264 return _locationForArgs(context, source, range); |
| 265 } |
| 266 |
| 267 |
| 230 /** | 268 /** |
| 231 * Compare the maps [mapA] and [mapB], using [valueEqual] to compare map | 269 * Compare the maps [mapA] and [mapB], using [valueEqual] to compare map |
| 232 * values. | 270 * values. |
| 233 */ | 271 */ |
| 234 bool _mapEqual(Map mapA, Map mapB, bool valueEqual(a, b)) { | 272 bool _mapEqual(Map mapA, Map mapB, bool valueEqual(a, b)) { |
| 235 if (mapA.length != mapB.length) { | 273 if (mapA.length != mapB.length) { |
| 236 return false; | 274 return false; |
| 237 } | 275 } |
| 238 for (var key in mapA.keys) { | 276 for (var key in mapA.keys) { |
| 239 if (!mapB.containsKey(key)) { | 277 if (!mapB.containsKey(key)) { |
| 240 return false; | 278 return false; |
| 241 } | 279 } |
| 242 if (!valueEqual(mapA[key], mapB[key])) { | 280 if (!valueEqual(mapA[key], mapB[key])) { |
| 243 return false; | 281 return false; |
| 244 } | 282 } |
| 245 } | 283 } |
| 246 return true; | 284 return true; |
| 247 } | 285 } |
| 248 | 286 |
| 287 |
| 288 RefactoringProblemSeverity |
| 289 _maxRefactoringProblemSeverity(RefactoringProblemSeverity a, |
| 290 RefactoringProblemSeverity b) { |
| 291 if (b == null) { |
| 292 return a; |
| 293 } |
| 294 if (a == null) { |
| 295 return b; |
| 296 } else if (a == RefactoringProblemSeverity.INFO) { |
| 297 return b; |
| 298 } else if (a == RefactoringProblemSeverity.WARNING) { |
| 299 if (b == RefactoringProblemSeverity.ERROR || |
| 300 b == RefactoringProblemSeverity.FATAL) { |
| 301 return b; |
| 302 } |
| 303 } else if (a == RefactoringProblemSeverity.ERROR) { |
| 304 if (b == RefactoringProblemSeverity.FATAL) { |
| 305 return b; |
| 306 } |
| 307 } |
| 308 return a; |
| 309 } |
| 310 |
| 249 /** | 311 /** |
| 250 * Create an OverriddenMember based on an element from the analyzer engine. | 312 * Create an OverriddenMember based on an element from the analyzer engine. |
| 251 */ | 313 */ |
| 252 OverriddenMember _overriddenMemberFromEngine(engine.Element member) { | 314 OverriddenMember _overriddenMemberFromEngine(engine.Element member) { |
| 253 Element element = elementFromEngine(member); | 315 Element element = elementFromEngine(member); |
| 254 String className = member.enclosingElement.displayName; | 316 String className = member.enclosingElement.displayName; |
| 255 return new OverriddenMember(element, className); | 317 return new OverriddenMember(element, className); |
| 256 } | 318 } |
| 257 | 319 |
| 258 /** | 320 /** |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 332 throw mismatch(jsonPath, 'int'); | 394 throw mismatch(jsonPath, 'int'); |
| 333 }); | 395 }); |
| 334 } | 396 } |
| 335 throw mismatch(jsonPath, 'int'); | 397 throw mismatch(jsonPath, 'int'); |
| 336 } | 398 } |
| 337 | 399 |
| 338 /** | 400 /** |
| 339 * Decode a JSON object that is expected to be a List. [decoder] is used to | 401 * Decode a JSON object that is expected to be a List. [decoder] is used to |
| 340 * decode the items in the list. | 402 * decode the items in the list. |
| 341 */ | 403 */ |
| 342 List _decodeList(String jsonPath, Object json, [JsonDecoderCallback decoder]) | 404 List _decodeList(String jsonPath, Object json, |
| 343 { | 405 [JsonDecoderCallback decoder]) { |
| 344 if (json == null) { | 406 if (json == null) { |
| 345 return []; | 407 return []; |
| 346 } else if (json is List) { | 408 } else if (json is List) { |
| 347 List result = []; | 409 List result = []; |
| 348 for (int i = 0; i < json.length; i++) { | 410 for (int i = 0; i < json.length; i++) { |
| 349 result.add(decoder('$jsonPath[$i]', json[i])); | 411 result.add(decoder('$jsonPath[$i]', json[i])); |
| 350 } | 412 } |
| 351 return result; | 413 return result; |
| 352 } else { | 414 } else { |
| 353 throw mismatch(jsonPath, 'List'); | 415 throw mismatch(jsonPath, 'List'); |
| 354 } | 416 } |
| 355 } | 417 } |
| 356 | 418 |
| 357 /** | 419 /** |
| 358 * Decode a JSON object that is expected to be a Map. [keyDecoder] is used | 420 * Decode a JSON object that is expected to be a Map. [keyDecoder] is used |
| 359 * to decode the keys, and [valueDecoder] is used to decode the values. | 421 * to decode the keys, and [valueDecoder] is used to decode the values. |
| 360 */ | 422 */ |
| 361 Map _decodeMap(String jsonPath, Object json, {JsonDecoderCallback | 423 Map _decodeMap(String jsonPath, Object json, {JsonDecoderCallback keyDecoder, |
| 362 keyDecoder, JsonDecoderCallback valueDecoder}) { | 424 JsonDecoderCallback valueDecoder}) { |
| 363 if (json == null) { | 425 if (json == null) { |
| 364 return {}; | 426 return {}; |
| 365 } else if (json is Map) { | 427 } else if (json is Map) { |
| 366 Map result = {}; | 428 Map result = {}; |
| 367 json.forEach((String key, value) { | 429 json.forEach((String key, value) { |
| 368 Object decodedKey; | 430 Object decodedKey; |
| 369 if (keyDecoder != null) { | 431 if (keyDecoder != null) { |
| 370 decodedKey = keyDecoder('$jsonPath.key', key); | 432 decodedKey = keyDecoder('$jsonPath.key', key); |
| 371 } else { | 433 } else { |
| 372 decodedKey = key; | 434 decodedKey = key; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 424 class RequestDecoder extends JsonDecoder { | 486 class RequestDecoder extends JsonDecoder { |
| 425 /** | 487 /** |
| 426 * The request being deserialized. | 488 * The request being deserialized. |
| 427 */ | 489 */ |
| 428 final Request _request; | 490 final Request _request; |
| 429 | 491 |
| 430 RequestDecoder(this._request); | 492 RequestDecoder(this._request); |
| 431 | 493 |
| 432 @override | 494 @override |
| 433 dynamic mismatch(String jsonPath, String expected) { | 495 dynamic mismatch(String jsonPath, String expected) { |
| 434 return new RequestFailure(new Response.invalidParameter(_request, jsonPath, | 496 return new RequestFailure( |
| 435 'be $expected')); | 497 new Response.invalidParameter(_request, jsonPath, 'be $expected')); |
| 436 } | 498 } |
| 437 | 499 |
| 438 @override | 500 @override |
| 439 dynamic missingKey(String jsonPath, String key) { | 501 dynamic missingKey(String jsonPath, String key) { |
| 440 return new RequestFailure(new Response.invalidParameter(_request, jsonPath, | 502 return new RequestFailure( |
| 441 'contain key ${JSON.encode(key)}')); | 503 new Response.invalidParameter( |
| 504 _request, |
| 505 jsonPath, |
| 506 'contain key ${JSON.encode(key)}')); |
| 442 } | 507 } |
| 443 } | 508 } |
| 444 | 509 |
| 445 /** | 510 /** |
| 446 * JsonDecoder for decoding responses from the server. This is intended to be | 511 * JsonDecoder for decoding responses from the server. This is intended to be |
| 447 * used only for testing. Errors are reported using bare [Exception] objects. | 512 * used only for testing. Errors are reported using bare [Exception] objects. |
| 448 */ | 513 */ |
| 449 class ResponseDecoder extends JsonDecoder { | 514 class ResponseDecoder extends JsonDecoder { |
| 450 @override | 515 @override |
| 451 dynamic mismatch(String jsonPath, String expected) { | 516 dynamic mismatch(String jsonPath, String expected) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 472 } | 537 } |
| 473 | 538 |
| 474 static int finish(int hash) { | 539 static int finish(int hash) { |
| 475 hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); | 540 hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); |
| 476 hash = hash ^ (hash >> 11); | 541 hash = hash ^ (hash >> 11); |
| 477 return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); | 542 return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); |
| 478 } | 543 } |
| 479 | 544 |
| 480 static int hash2(a, b) => finish(combine(combine(0, a), b)); | 545 static int hash2(a, b) => finish(combine(combine(0, a), b)); |
| 481 | 546 |
| 482 static int hash4(a, b, c, d) => finish(combine(combine(combine(combine(0, a), | 547 static int hash4(a, b, c, d) => |
| 483 b), c), d)); | 548 finish(combine(combine(combine(combine(0, a), b), c), d)); |
| 484 } | 549 } |
| OLD | NEW |