| 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 computer.navigation; | 5 library domains.analysis.navigation_dart; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'package:analysis_server/analysis/navigation/navigation_core.dart'; |
| 8 | |
| 9 import 'package:analysis_server/src/protocol_server.dart' as protocol; | 8 import 'package:analysis_server/src/protocol_server.dart' as protocol; |
| 10 import 'package:analyzer/src/generated/ast.dart'; | 9 import 'package:analyzer/src/generated/ast.dart'; |
| 11 import 'package:analyzer/src/generated/element.dart'; | 10 import 'package:analyzer/src/generated/element.dart'; |
| 11 import 'package:analyzer/src/generated/engine.dart'; |
| 12 import 'package:analyzer/src/generated/scanner.dart'; | 12 import 'package:analyzer/src/generated/scanner.dart'; |
| 13 import 'package:analyzer/src/generated/source.dart'; | 13 import 'package:analyzer/src/generated/source.dart'; |
| 14 | 14 |
| 15 /** | 15 /** |
| 16 * A computer for navigation regions in a Dart [CompilationUnit]. | 16 * A computer for navigation regions in a Dart [CompilationUnit]. |
| 17 */ | 17 */ |
| 18 class DartUnitNavigationComputer { | 18 class DartNavigationComputer implements NavigationContributor { |
| 19 final List<String> files = <String>[]; | 19 @override |
| 20 final Map<String, int> fileMap = new HashMap<String, int>(); | 20 void computeNavigation(NavigationHolder holder, AnalysisContext context, |
| 21 final List<protocol.NavigationTarget> targets = <protocol.NavigationTarget>[]; | 21 Source source, int offset, int length) { |
| 22 final Map<Element, int> targetMap = new HashMap<Element, int>(); | 22 List<Source> libraries = context.getLibrariesContaining(source); |
| 23 final List<protocol.NavigationRegion> regions = <protocol.NavigationRegion>[]; | 23 if (libraries.isNotEmpty) { |
| 24 | 24 CompilationUnit unit = |
| 25 /** | 25 context.getResolvedCompilationUnit2(source, libraries.first); |
| 26 * Computes [regions], [targets] and [files]. | 26 if (unit != null) { |
| 27 */ | 27 _DartNavigationHolder dartHolder = new _DartNavigationHolder(holder); |
| 28 void compute(AstNode node) { | 28 _DartNavigationComputerVisitor visitor = |
| 29 node.accept(new _DartUnitNavigationComputerVisitor(this)); | 29 new _DartNavigationComputerVisitor(dartHolder); |
| 30 } | 30 if (offset == null || length == null) { |
| 31 | 31 unit.accept(visitor); |
| 32 int _addFile(String file) { | 32 } else { |
| 33 int index = fileMap[file]; | 33 _DartRangeAstVisitor partVisitor = |
| 34 if (index == null) { | 34 new _DartRangeAstVisitor(offset, offset + length, visitor); |
| 35 index = files.length; | 35 unit.accept(partVisitor); |
| 36 files.add(file); | 36 } |
| 37 fileMap[file] = index; | 37 } |
| 38 } | 38 } |
| 39 return index; | |
| 40 } | |
| 41 | |
| 42 void _addRegion(int offset, int length, Element element) { | |
| 43 if (element is FieldFormalParameterElement) { | |
| 44 element = (element as FieldFormalParameterElement).field; | |
| 45 } | |
| 46 if (element == null || element == DynamicElementImpl.instance) { | |
| 47 return; | |
| 48 } | |
| 49 if (element.location == null) { | |
| 50 return; | |
| 51 } | |
| 52 int targetIndex = _addTarget(element); | |
| 53 regions | |
| 54 .add(new protocol.NavigationRegion(offset, length, <int>[targetIndex])); | |
| 55 } | |
| 56 | |
| 57 void _addRegion_nodeStart_nodeEnd(AstNode a, AstNode b, Element element) { | |
| 58 int offset = a.offset; | |
| 59 int length = b.end - offset; | |
| 60 _addRegion(offset, length, element); | |
| 61 } | |
| 62 | |
| 63 void _addRegion_tokenStart_nodeEnd(Token a, AstNode b, Element element) { | |
| 64 int offset = a.offset; | |
| 65 int length = b.end - offset; | |
| 66 _addRegion(offset, length, element); | |
| 67 } | |
| 68 | |
| 69 void _addRegionForNode(AstNode node, Element element) { | |
| 70 int offset = node.offset; | |
| 71 int length = node.length; | |
| 72 _addRegion(offset, length, element); | |
| 73 } | |
| 74 | |
| 75 void _addRegionForToken(Token token, Element element) { | |
| 76 int offset = token.offset; | |
| 77 int length = token.length; | |
| 78 _addRegion(offset, length, element); | |
| 79 } | |
| 80 | |
| 81 int _addTarget(Element element) { | |
| 82 int index = targetMap[element]; | |
| 83 if (index == null) { | |
| 84 index = targets.length; | |
| 85 protocol.NavigationTarget target = | |
| 86 protocol.newNavigationTarget_fromElement(element, _addFile); | |
| 87 targets.add(target); | |
| 88 targetMap[element] = index; | |
| 89 } | |
| 90 return index; | |
| 91 } | 39 } |
| 92 } | 40 } |
| 93 | 41 |
| 94 class _DartUnitNavigationComputerVisitor extends RecursiveAstVisitor { | 42 class _DartNavigationComputerVisitor extends RecursiveAstVisitor { |
| 95 final DartUnitNavigationComputer computer; | 43 final _DartNavigationHolder computer; |
| 96 | 44 |
| 97 _DartUnitNavigationComputerVisitor(this.computer); | 45 _DartNavigationComputerVisitor(this.computer); |
| 98 | 46 |
| 99 @override | 47 @override |
| 100 visitAssignmentExpression(AssignmentExpression node) { | 48 visitAssignmentExpression(AssignmentExpression node) { |
| 101 _safelyVisit(node.leftHandSide); | 49 _safelyVisit(node.leftHandSide); |
| 102 computer._addRegionForToken(node.operator, node.bestElement); | 50 computer._addRegionForToken(node.operator, node.bestElement); |
| 103 _safelyVisit(node.rightHandSide); | 51 _safelyVisit(node.rightHandSide); |
| 104 } | 52 } |
| 105 | 53 |
| 106 @override | 54 @override |
| 107 visitBinaryExpression(BinaryExpression node) { | 55 visitBinaryExpression(BinaryExpression node) { |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 } | 214 } |
| 267 } | 215 } |
| 268 } | 216 } |
| 269 | 217 |
| 270 void _safelyVisit(AstNode node) { | 218 void _safelyVisit(AstNode node) { |
| 271 if (node != null) { | 219 if (node != null) { |
| 272 node.accept(this); | 220 node.accept(this); |
| 273 } | 221 } |
| 274 } | 222 } |
| 275 } | 223 } |
| 224 |
| 225 /** |
| 226 * A Dart specific wrapper around [NavigationHolder]. |
| 227 */ |
| 228 class _DartNavigationHolder { |
| 229 final NavigationHolder holder; |
| 230 |
| 231 _DartNavigationHolder(this.holder); |
| 232 |
| 233 void _addRegion(int offset, int length, Element element) { |
| 234 if (element is FieldFormalParameterElement) { |
| 235 element = (element as FieldFormalParameterElement).field; |
| 236 } |
| 237 if (element == null || element == DynamicElementImpl.instance) { |
| 238 return; |
| 239 } |
| 240 if (element.location == null) { |
| 241 return; |
| 242 } |
| 243 protocol.ElementKind kind = |
| 244 protocol.newElementKind_fromEngine(element.kind); |
| 245 protocol.Location location = protocol.newLocation_fromElement(element); |
| 246 if (location == null) { |
| 247 return; |
| 248 } |
| 249 holder.addRegion(offset, length, kind, location); |
| 250 } |
| 251 |
| 252 void _addRegion_nodeStart_nodeEnd(AstNode a, AstNode b, Element element) { |
| 253 int offset = a.offset; |
| 254 int length = b.end - offset; |
| 255 _addRegion(offset, length, element); |
| 256 } |
| 257 |
| 258 void _addRegion_tokenStart_nodeEnd(Token a, AstNode b, Element element) { |
| 259 int offset = a.offset; |
| 260 int length = b.end - offset; |
| 261 _addRegion(offset, length, element); |
| 262 } |
| 263 |
| 264 void _addRegionForNode(AstNode node, Element element) { |
| 265 int offset = node.offset; |
| 266 int length = node.length; |
| 267 _addRegion(offset, length, element); |
| 268 } |
| 269 |
| 270 void _addRegionForToken(Token token, Element element) { |
| 271 int offset = token.offset; |
| 272 int length = token.length; |
| 273 _addRegion(offset, length, element); |
| 274 } |
| 275 } |
| 276 |
| 277 /** |
| 278 * An AST visitor that forwards nodes intersecting with the range from |
| 279 * [start] to [end] to the given [visitor]. |
| 280 */ |
| 281 class _DartRangeAstVisitor extends UnifyingAstVisitor { |
| 282 final int start; |
| 283 final int end; |
| 284 final AstVisitor visitor; |
| 285 |
| 286 _DartRangeAstVisitor(this.start, this.end, this.visitor); |
| 287 |
| 288 bool isInRange(int offset) { |
| 289 return start <= offset && offset <= end; |
| 290 } |
| 291 |
| 292 @override |
| 293 visitNode(AstNode node) { |
| 294 // The node ends before the range starts. |
| 295 if (node.end < start) { |
| 296 return; |
| 297 } |
| 298 // The node starts after the range ends. |
| 299 if (node.offset > end) { |
| 300 return; |
| 301 } |
| 302 // The node starts or ends in the range. |
| 303 if (isInRange(node.offset) || isInRange(node.end)) { |
| 304 node.accept(visitor); |
| 305 return; |
| 306 } |
| 307 // Go deeper. |
| 308 super.visitNode(node); |
| 309 } |
| 310 } |
| OLD | NEW |