| Index: pkg/analysis_server/lib/src/computer/computer_outline.dart
|
| diff --git a/pkg/analysis_server/lib/src/computer/computer_outline.dart b/pkg/analysis_server/lib/src/computer/computer_outline.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..92d528694723a8f8e5f7f4eed16cb919bb370436
|
| --- /dev/null
|
| +++ b/pkg/analysis_server/lib/src/computer/computer_outline.dart
|
| @@ -0,0 +1,366 @@
|
| +// 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.outline;
|
| +
|
| +import 'package:analysis_server/src/constants.dart';
|
| +import 'package:analyzer/src/generated/ast.dart';
|
| +
|
| +
|
| +/**
|
| + * A computer for [Outline]s in a Dart [CompilationUnit].
|
| + */
|
| +class DartUnitOutlineComputer {
|
| + static String _UNITTEST_LIBRARY = "unittest";
|
| +
|
| + final CompilationUnit _unit;
|
| +
|
| + List<Map<String, Object>> _regions = <Map<String, Object>>[];
|
| +
|
| + DartUnitOutlineComputer(this._unit);
|
| +
|
| + /**
|
| + * Returns the computed outlines, not `null`.
|
| + */
|
| + Map<String, Object> compute() {
|
| + _Outline unitOutline = _newUnitOutline();
|
| + for (CompilationUnitMember unitMember in _unit.declarations) {
|
| + if (unitMember is ClassDeclaration) {
|
| + ClassDeclaration classDeclartion = unitMember;
|
| + _Outline classOutline = _newClassOutline(unitOutline, classDeclartion);
|
| + for (ClassMember classMember in classDeclartion.members) {
|
| + if (classMember is ConstructorDeclaration) {
|
| + ConstructorDeclaration constructorDeclaration = classMember;
|
| + _newConstructorOutline(classOutline, constructorDeclaration);
|
| + }
|
| + if (classMember is FieldDeclaration) {
|
| + FieldDeclaration fieldDeclaration = classMember;
|
| + VariableDeclarationList fields = fieldDeclaration.fields;
|
| + if (fields != null) {
|
| + TypeName fieldType = fields.type;
|
| + String fieldTypeName = fieldType != null ? fieldType.toSource() : "";
|
| + for (VariableDeclaration field in fields.variables) {
|
| + _newVariableOutline(classOutline, fieldTypeName, _OutlineKind.FIELD, field, fieldDeclaration.isStatic);
|
| + }
|
| + }
|
| + }
|
| + if (classMember is MethodDeclaration) {
|
| + MethodDeclaration methodDeclaration = classMember;
|
| + _newMethodOutline(classOutline, methodDeclaration);
|
| + }
|
| + }
|
| + }
|
| + if (unitMember is TopLevelVariableDeclaration) {
|
| + TopLevelVariableDeclaration fieldDeclaration = unitMember;
|
| + VariableDeclarationList fields = fieldDeclaration.variables;
|
| + if (fields != null) {
|
| + TypeName fieldType = fields.type;
|
| + String fieldTypeName = fieldType != null ? fieldType.toSource() : "";
|
| + for (VariableDeclaration field in fields.variables) {
|
| + _newVariableOutline(unitOutline, fieldTypeName, _OutlineKind.TOP_LEVEL_VARIABLE, field, false);
|
| + }
|
| + }
|
| + }
|
| + if (unitMember is FunctionDeclaration) {
|
| + FunctionDeclaration functionDeclaration = unitMember;
|
| + _newFunctionOutline(unitOutline, functionDeclaration);
|
| + }
|
| + if (unitMember is ClassTypeAlias) {
|
| + ClassTypeAlias alias = unitMember;
|
| + _newClassTypeAlias(unitOutline, alias);
|
| + }
|
| + if (unitMember is FunctionTypeAlias) {
|
| + FunctionTypeAlias alias = unitMember;
|
| + _newFunctionTypeAliasOutline(unitOutline, alias);
|
| + }
|
| + }
|
| + return unitOutline.toJson();
|
| + }
|
| +
|
| + void _addLocalFunctionOutlines(_Outline parent, FunctionBody body) {
|
| + body.accept(new _LocalFunctionOutlinesVisitor(this, parent));
|
| + }
|
| +
|
| + /**
|
| + * Returns the [AstNode]'s source region.
|
| + */
|
| + _SourceRegion _getSourceRegion(AstNode node) {
|
| + int endOffset = node.end;
|
| + // prepare position of the node among its siblings
|
| + int firstOffset;
|
| + List<AstNode> siblings;
|
| + AstNode parent = node.parent;
|
| + // field
|
| + if (parent is VariableDeclarationList) {
|
| + VariableDeclarationList variableList = parent as VariableDeclarationList;
|
| + List<VariableDeclaration> variables = variableList.variables;
|
| + int variableIndex = variables.indexOf(node);
|
| + if (variableIndex == variables.length - 1) {
|
| + endOffset = variableList.parent.end;
|
| + }
|
| + if (variableIndex == 0) {
|
| + node = parent.parent;
|
| + parent = node.parent;
|
| + } else if (variableIndex >= 1) {
|
| + firstOffset = variables[variableIndex - 1].end;
|
| + return new _SourceRegion(firstOffset, endOffset - firstOffset);
|
| + }
|
| + }
|
| + // unit or class member
|
| + if (parent is CompilationUnit) {
|
| + firstOffset = 0;
|
| + siblings = (parent as CompilationUnit).declarations;
|
| + } else if (parent is ClassDeclaration) {
|
| + ClassDeclaration classDeclaration = parent as ClassDeclaration;
|
| + firstOffset = classDeclaration.leftBracket.end;
|
| + siblings = classDeclaration.members;
|
| + } else {
|
| + int offset = node.offset;
|
| + return new _SourceRegion(offset, endOffset - offset);
|
| + }
|
| + // first child: [endOfParent, endOfNode]
|
| + int index = siblings.indexOf(node);
|
| + if (index == 0) {
|
| + return new _SourceRegion(firstOffset, endOffset - firstOffset);
|
| + }
|
| + // not first child: [endOfPreviousSibling, endOfNode]
|
| + int prevSiblingEnd = siblings[index - 1].end;
|
| + return new _SourceRegion(prevSiblingEnd, endOffset - prevSiblingEnd);
|
| + }
|
| +
|
| + _Outline _newClassOutline(_Outline parent, ClassDeclaration classDeclaration) {
|
| + SimpleIdentifier nameNode = classDeclaration.name;
|
| + String name = nameNode.name;
|
| + _SourceRegion sourceRegion = _getSourceRegion(classDeclaration);
|
| + _Outline outline = new _Outline(
|
| + _OutlineKind.CLASS, name,
|
| + nameNode.offset, nameNode.length,
|
| + sourceRegion.offset, sourceRegion.length,
|
| + classDeclaration.isAbstract, false,
|
| + null, null);
|
| + parent.children.add(outline);
|
| + return outline;
|
| + }
|
| +
|
| + void _newClassTypeAlias(_Outline parent, ClassTypeAlias alias) {
|
| + SimpleIdentifier nameNode = alias.name;
|
| + String name = nameNode.name;
|
| + _SourceRegion sourceRegion = _getSourceRegion(alias);
|
| + _Outline outline = new _Outline(
|
| + _OutlineKind.CLASS_TYPE_ALIAS, name,
|
| + nameNode.offset, nameNode.length,
|
| + sourceRegion.offset, sourceRegion.length,
|
| + alias.isAbstract, false,
|
| + null, null);
|
| + parent.children.add(outline);
|
| + }
|
| +
|
| + void _newConstructorOutline(_Outline parent, ConstructorDeclaration constructor) {
|
| + Identifier returnType = constructor.returnType;
|
| + String name = returnType.name;
|
| + int offset = returnType.offset;
|
| + int length = returnType.length;
|
| + SimpleIdentifier constructorNameNode = constructor.name;
|
| + if (constructorNameNode != null) {
|
| + String constructorName = constructorNameNode.name;
|
| + name += ".${constructorName}";
|
| + offset = constructorNameNode.offset;
|
| + length = constructorNameNode.length;
|
| + }
|
| + _SourceRegion sourceRegion = _getSourceRegion(constructor);
|
| + FormalParameterList parameters = constructor.parameters;
|
| + String parametersStr = parameters != null ? parameters.toSource() : "";
|
| + _Outline outline = new _Outline(
|
| + _OutlineKind.CONSTRUCTOR, name,
|
| + offset, length,
|
| + sourceRegion.offset, sourceRegion.length,
|
| + false, false,
|
| + parametersStr, null);
|
| + parent.children.add(outline);
|
| + _addLocalFunctionOutlines(outline, constructor.body);
|
| + }
|
| +
|
| + void _newFunctionOutline(_Outline parent, FunctionDeclaration function) {
|
| + TypeName returnType = function.returnType;
|
| + SimpleIdentifier nameNode = function.name;
|
| + String name = nameNode.name;
|
| + FunctionExpression functionExpression = function.functionExpression;
|
| + FormalParameterList parameters = functionExpression.parameters;
|
| + _OutlineKind kind;
|
| + if (function.isGetter) {
|
| + kind = _OutlineKind.GETTER;
|
| + } else if (function.isSetter) {
|
| + kind = _OutlineKind.SETTER;
|
| + } else {
|
| + kind = _OutlineKind.FUNCTION;
|
| + }
|
| + _SourceRegion sourceRegion = _getSourceRegion(function);
|
| + String parametersStr = parameters != null ? parameters.toSource() : "";
|
| + String returnTypeStr = returnType != null ? returnType.toSource() : "";
|
| + _Outline outline = new _Outline(
|
| + kind, name,
|
| + nameNode.offset, nameNode.length,
|
| + sourceRegion.offset, sourceRegion.length,
|
| + false, false,
|
| + parametersStr, returnTypeStr);
|
| + parent.children.add(outline);
|
| + _addLocalFunctionOutlines(outline, functionExpression.body);
|
| + }
|
| +
|
| + void _newFunctionTypeAliasOutline(_Outline parent, FunctionTypeAlias alias) {
|
| + TypeName returnType = alias.returnType;
|
| + SimpleIdentifier nameNode = alias.name;
|
| + String name = nameNode.name;
|
| + _SourceRegion sourceRegion = _getSourceRegion(alias);
|
| + FormalParameterList parameters = alias.parameters;
|
| + String parametersStr = parameters != null ? parameters.toSource() : "";
|
| + String returnTypeStr = returnType != null ? returnType.toSource() : "";
|
| + _Outline outline = new _Outline(
|
| + _OutlineKind.FUNCTION_TYPE_ALIAS, name,
|
| + nameNode.offset, nameNode.length,
|
| + sourceRegion.offset, sourceRegion.length,
|
| + false, false,
|
| + parametersStr, returnTypeStr);
|
| + parent.children.add(outline);
|
| + }
|
| +
|
| + void _newMethodOutline(_Outline parent, MethodDeclaration method) {
|
| + TypeName returnType = method.returnType;
|
| + SimpleIdentifier nameNode = method.name;
|
| + String name = nameNode.name;
|
| + FormalParameterList parameters = method.parameters;
|
| + _OutlineKind kind;
|
| + if (method.isGetter) {
|
| + kind = _OutlineKind.GETTER;
|
| + } else if (method.isSetter) {
|
| + kind = _OutlineKind.SETTER;
|
| + } else {
|
| + kind = _OutlineKind.METHOD;
|
| + }
|
| + _SourceRegion sourceRegion = _getSourceRegion(method);
|
| + String parametersStr = parameters != null ? parameters.toSource() : "";
|
| + String returnTypeStr = returnType != null ? returnType.toSource() : "";
|
| + _Outline outline = new _Outline(
|
| + kind, name,
|
| + nameNode.offset, nameNode.length,
|
| + sourceRegion.offset, sourceRegion.length,
|
| + method.isAbstract, method.isStatic,
|
| + parametersStr, returnTypeStr);
|
| + parent.children.add(outline);
|
| + _addLocalFunctionOutlines(outline, method.body);
|
| + }
|
| +
|
| + _Outline _newUnitOutline() {
|
| + return new _Outline(
|
| + _OutlineKind.COMPILATION_UNIT, null,
|
| + _unit.offset, _unit.length,
|
| + _unit.offset, _unit.length,
|
| + false, false,
|
| + null, null);
|
| + }
|
| +
|
| + void _newVariableOutline(_Outline parent, String typeName, _OutlineKind kind, VariableDeclaration variable, bool isStatic) {
|
| + SimpleIdentifier nameNode = variable.name;
|
| + String name = nameNode.name;
|
| + _SourceRegion sourceRegion = _getSourceRegion(variable);
|
| + _Outline outline = new _Outline(
|
| + kind, name,
|
| + nameNode.offset, nameNode.length,
|
| + sourceRegion.offset, sourceRegion.length,
|
| + false, isStatic,
|
| + null, typeName);
|
| + parent.children.add(outline);
|
| + }
|
| +}
|
| +
|
| +
|
| +class _LocalFunctionOutlinesVisitor extends RecursiveAstVisitor {
|
| + final DartUnitOutlineComputer outlineComputer;
|
| +
|
| + _Outline parent;
|
| +
|
| + _LocalFunctionOutlinesVisitor(this.outlineComputer, this.parent);
|
| +
|
| + @override
|
| + visitFunctionDeclaration(FunctionDeclaration node) {
|
| + outlineComputer._newFunctionOutline(parent, node);
|
| + }
|
| +}
|
| +
|
| +
|
| +
|
| +/**
|
| + * A range of characters.
|
| + */
|
| +class _SourceRegion {
|
| + final int offset;
|
| + final int length;
|
| + _SourceRegion(this.offset, this.length);
|
| +}
|
| +
|
| +
|
| +/**
|
| + * Element outline kinds.
|
| + */
|
| +class _OutlineKind {
|
| + static const _OutlineKind CLASS = const _OutlineKind('CLASS');
|
| + static const _OutlineKind CLASS_TYPE_ALIAS = const _OutlineKind('CLASS_TYPE_ALIAS');
|
| + static const _OutlineKind COMPILATION_UNIT = const _OutlineKind('COMPILATION_UNIT');
|
| + static const _OutlineKind CONSTRUCTOR = const _OutlineKind('CONSTRUCTOR');
|
| + static const _OutlineKind GETTER = const _OutlineKind('GETTER');
|
| + static const _OutlineKind FIELD = const _OutlineKind('FIELD');
|
| + static const _OutlineKind FUNCTION = const _OutlineKind('FUNCTION');
|
| + static const _OutlineKind FUNCTION_TYPE_ALIAS = const _OutlineKind('FUNCTION_TYPE_ALIAS');
|
| + static const _OutlineKind LIBRARY = const _OutlineKind('LIBRARY');
|
| + static const _OutlineKind METHOD = const _OutlineKind('METHOD');
|
| + static const _OutlineKind SETTER = const _OutlineKind('SETTER');
|
| + static const _OutlineKind TOP_LEVEL_VARIABLE = const _OutlineKind('TOP_LEVEL_VARIABLE');
|
| + static const _OutlineKind UNKNOWN = const _OutlineKind('UNKNOWN');
|
| + static const _OutlineKind UNIT_TEST_CASE = const _OutlineKind('UNIT_TEST_CASE');
|
| + static const _OutlineKind UNIT_TEST_GROUP = const _OutlineKind('UNIT_TEST_GROUP');
|
| +
|
| + final String name;
|
| +
|
| + const _OutlineKind(this.name);
|
| +}
|
| +
|
| +
|
| +class _Outline {
|
| + static const List<_Outline> EMPTY_ARRAY = const <_Outline>[];
|
| +
|
| + _Outline parent;
|
| + final _OutlineKind kind;
|
| + final String name;
|
| + final int nameOffset;
|
| + final int nameLength;
|
| + final int elementOffset;
|
| + final int elementLength;
|
| + final bool isAbstract;
|
| + final bool isStatic;
|
| + final String arguments;
|
| + final String returnType;
|
| + final List<_Outline> children = <_Outline>[];
|
| +
|
| + _Outline(this.kind, this.name,
|
| + this.nameOffset, this.nameLength,
|
| + this.elementOffset, this.elementLength,
|
| + this.isAbstract, this.isStatic,
|
| + this.arguments, this.returnType);
|
| +
|
| + Map<String, Object> toJson() {
|
| + return {
|
| + KIND: kind.name,
|
| + NAME: name,
|
| + NAME_OFFSET: nameOffset,
|
| + NAME_LENGTH: nameLength,
|
| + ELEMENT_OFFSET: elementOffset,
|
| + ELEMENT_LENGTH: elementLength,
|
| + IS_ABSTRACT: isAbstract,
|
| + IS_STATIC: isStatic,
|
| + ARGUMENTS: arguments,
|
| + RETURN_TYPE: returnType,
|
| + CHILDREN: children.map((child) => child.toJson()).toList(growable: false)
|
| + };
|
| + }
|
| +}
|
|
|