| Index: pkg/analysis_server/lib/src/computer/computer_navigation.dart
|
| diff --git a/pkg/analysis_server/lib/src/computer/computer_navigation.dart b/pkg/analysis_server/lib/src/computer/computer_navigation.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..905996bf81d3eca66fa7283758b3f9d8f999ddc7
|
| --- /dev/null
|
| +++ b/pkg/analysis_server/lib/src/computer/computer_navigation.dart
|
| @@ -0,0 +1,208 @@
|
| +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +library computer.navigation;
|
| +
|
| +import 'package:analyzer/src/generated/ast.dart';
|
| +import 'package:analyzer/src/generated/element.dart';
|
| +import 'package:analyzer/src/generated/scanner.dart';
|
| +import 'package:analyzer/src/generated/source.dart';
|
| +
|
| +
|
| +/**
|
| + * A computer for navigation regions in a Dart [CompilationUnit].
|
| + */
|
| +class DartUnitNavigationComputer {
|
| + final CompilationUnit _unit;
|
| +
|
| + List<Map<String, Object>> _regions = [];
|
| +
|
| + DartUnitNavigationComputer(this._unit);
|
| +
|
| + /**
|
| + * Returns the computed navigation regions, not `null`.
|
| + */
|
| + List<Map<String, Object>> compute() {
|
| + _unit.accept(new _DartUnitNavigationComputerVisitor(this));
|
| + return new List.from(_regions);
|
| + }
|
| +
|
| + void _addRegion(int offset, int length, Element element) {
|
| + Map<String, Object> target = _createTarget(element);
|
| + if (target == null) {
|
| + return;
|
| + }
|
| + _regions.add({
|
| + 'offset': offset,
|
| + 'length': length,
|
| + 'targets': [target]
|
| + });
|
| + }
|
| +
|
| + void _addRegion_nodeStart_nodeEnd(AstNode a, AstNode b, Element element) {
|
| + int offset = a.offset;
|
| + int length = b.end - offset;
|
| + _addRegion(offset, length, element);
|
| + }
|
| +
|
| + void _addRegion_nodeStart_nodeStart(AstNode a, AstNode b, Element element) {
|
| + int offset = a.offset;
|
| + int length = b.offset - offset;
|
| + _addRegion(offset, length, element);
|
| + }
|
| +
|
| + void _addRegion_tokenStart_nodeEnd(Token a, AstNode b, Element element) {
|
| + int offset = a.offset;
|
| + int length = b.end - offset;
|
| + _addRegion(offset, length, element);
|
| + }
|
| +
|
| + void _addRegionForNode(AstNode node, Element element) {
|
| + int offset = node.offset;
|
| + int length = node.length;
|
| + _addRegion(offset, length, element);
|
| + }
|
| +
|
| + void _addRegionForToken(Token token, Element element) {
|
| + int offset = token.offset;
|
| + int length = token.length;
|
| + _addRegion(offset, length, element);
|
| + }
|
| +
|
| + /**
|
| + * Returns the JSON for the given [Element], maybe `null` if `null` was given.
|
| + */
|
| + Map<String, Object> _createTarget(Element element) {
|
| + if (element == null) {
|
| + return null;
|
| + }
|
| + if (element is FieldFormalParameterElement) {
|
| + element = (element as FieldFormalParameterElement).field;
|
| + }
|
| + // prepare Source
|
| + Source source = element.source;
|
| + if (source == null) {
|
| + return null;
|
| + }
|
| + // prepare location
|
| + int offset = element.nameOffset;
|
| + int length = element.displayName.length;
|
| + if (element is CompilationUnitElement) {
|
| + offset = 0;
|
| + length = 0;
|
| + }
|
| + // return as JSON
|
| + return {
|
| + 'file': source.fullName,
|
| + 'offset': offset,
|
| + 'length': length,
|
| + 'elementId': element.location.encoding
|
| + };
|
| + }
|
| +}
|
| +
|
| +
|
| +
|
| +class _DartUnitNavigationComputerVisitor extends RecursiveAstVisitor {
|
| + final DartUnitNavigationComputer computer;
|
| +
|
| + _DartUnitNavigationComputerVisitor(this.computer);
|
| +
|
| + @override
|
| + visitAssignmentExpression(AssignmentExpression node) {
|
| + computer._addRegionForToken(node.operator, node.bestElement);
|
| + return super.visitAssignmentExpression(node);
|
| + }
|
| +
|
| + @override
|
| + visitBinaryExpression(BinaryExpression node) {
|
| + computer._addRegionForToken(node.operator, node.bestElement);
|
| + return super.visitBinaryExpression(node);
|
| + }
|
| +
|
| + @override
|
| + visitConstructorDeclaration(ConstructorDeclaration node) {
|
| + // associate constructor with "T" or "T.name"
|
| + {
|
| + AstNode firstNode = node.returnType;
|
| + AstNode lastNode = node.name;
|
| + if (lastNode == null) {
|
| + lastNode = firstNode;
|
| + }
|
| + if (firstNode != null && lastNode != null) {
|
| + computer._addRegion_nodeStart_nodeEnd(firstNode, lastNode, node.element);
|
| + }
|
| + }
|
| + return super.visitConstructorDeclaration(node);
|
| + }
|
| +
|
| + @override
|
| + visitExportDirective(ExportDirective node) {
|
| + ExportElement exportElement = node.element;
|
| + if (exportElement != null) {
|
| + Element element = exportElement.exportedLibrary;
|
| + computer._addRegion_tokenStart_nodeEnd(node.keyword, node.uri, element);
|
| + }
|
| + return super.visitExportDirective(node);
|
| + }
|
| +
|
| + @override
|
| + visitImportDirective(ImportDirective node) {
|
| + ImportElement importElement = node.element;
|
| + if (importElement != null) {
|
| + Element element = importElement.importedLibrary;
|
| + computer._addRegion_tokenStart_nodeEnd(node.keyword, node.uri, element);
|
| + }
|
| + return super.visitImportDirective(node);
|
| + }
|
| +
|
| + @override
|
| + visitIndexExpression(IndexExpression node) {
|
| + computer._addRegionForToken(node.rightBracket, node.bestElement);
|
| + return super.visitIndexExpression(node);
|
| + }
|
| +
|
| + @override
|
| + visitInstanceCreationExpression(InstanceCreationExpression node) {
|
| + Element element = node.staticElement;
|
| + if (element != null && element.isSynthetic) {
|
| + element = element.enclosingElement;
|
| + }
|
| + computer._addRegion_nodeStart_nodeStart(node, node.argumentList, element);
|
| + return super.visitInstanceCreationExpression(node);
|
| + }
|
| +
|
| + @override
|
| + visitPartDirective(PartDirective node) {
|
| + computer._addRegion_tokenStart_nodeEnd(node.keyword, node.uri, node.element);
|
| + return super.visitPartDirective(node);
|
| + }
|
| +
|
| + @override
|
| + visitPartOfDirective(PartOfDirective node) {
|
| + computer._addRegion_tokenStart_nodeEnd(node.keyword, node.libraryName, node.element);
|
| + return super.visitPartOfDirective(node);
|
| + }
|
| +
|
| + @override
|
| + visitPostfixExpression(PostfixExpression node) {
|
| + computer._addRegionForToken(node.operator, node.bestElement);
|
| + return super.visitPostfixExpression(node);
|
| + }
|
| +
|
| + @override
|
| + visitPrefixExpression(PrefixExpression node) {
|
| + computer._addRegionForToken(node.operator, node.bestElement);
|
| + return super.visitPrefixExpression(node);
|
| + }
|
| +
|
| + @override
|
| + visitSimpleIdentifier(SimpleIdentifier node) {
|
| + if (node.parent is ConstructorDeclaration) {
|
| + } else {
|
| + computer._addRegionForNode(node, node.bestElement);
|
| + }
|
| + return super.visitSimpleIdentifier(node);
|
| + }
|
| +}
|
|
|