blob: bea49f128d7f2917bd4c019fdcdd052dafbd3727 [file] [log] [blame]
// Copyright (c) 2018, 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.
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
/**
* A computer for [CompilationUnit] folding.
*/
class DartUnitFoldingComputer {
final LineInfo _lineInfo;
final CompilationUnit _unit;
Directive _firstDirective, _lastDirective;
final List<FoldingRegion> _foldingRegions = [];
DartUnitFoldingComputer(this._lineInfo, this._unit);
/**
* Returns a list of folding regions, not `null`.
*/
List<FoldingRegion> compute() {
_unit.accept(new _DartUnitFoldingComputerVisitor(this));
if (_firstDirective != null &&
_lastDirective != null &&
_firstDirective != _lastDirective) {
_foldingRegions.add(new FoldingRegion(
FoldingKind.DIRECTIVES,
_firstDirective.keyword.end,
_lastDirective.end - _firstDirective.keyword.end));
}
return _foldingRegions;
}
}
/**
* An AST visitor for [DartUnitFoldingComputer].
*/
class _DartUnitFoldingComputerVisitor extends RecursiveAstVisitor<Object> {
final DartUnitFoldingComputer _computer;
_DartUnitFoldingComputerVisitor(this._computer);
@override
Object visitBlockFunctionBody(BlockFunctionBody node) {
final FoldingKind kind = node.parent is ConstructorDeclaration ||
node.parent is MethodDeclaration
? FoldingKind.CLASS_MEMBER
: FoldingKind.TOP_LEVEL_DECLARATION;
_addRegion(
node.block.leftBracket.end, node.block.rightBracket.offset, kind);
return super.visitBlockFunctionBody(node);
}
@override
Object visitClassDeclaration(ClassDeclaration node) {
_addRegion(node.leftBracket.end, node.rightBracket.offset,
FoldingKind.TOP_LEVEL_DECLARATION);
return super.visitClassDeclaration(node);
}
@override
Object visitAnnotation(Annotation node) {
if (node.arguments != null &&
node.arguments.leftParenthesis != null &&
node.arguments.rightParenthesis != null) {
_addRegion(
node.arguments.leftParenthesis.end,
node.arguments.rightParenthesis.offset,
FoldingKind.TOP_LEVEL_DECLARATION);
}
return super.visitAnnotation(node);
}
@override
Object visitComment(Comment node) {
final FoldingKind kind = node.isDocumentation
? FoldingKind.DOCUMENTATION_COMMENT
: FoldingKind.COMMENT;
_addRegion(node.offset, node.end, kind);
return super.visitComment(node);
}
@override
Object visitExportDirective(ExportDirective node) {
_recordDirective(node);
return super.visitExportDirective(node);
}
@override
visitImportDirective(ImportDirective node) {
_recordDirective(node);
return super.visitImportDirective(node);
}
@override
Object visitLibraryDirective(LibraryDirective node) {
_recordDirective(node);
return super.visitLibraryDirective(node);
}
@override
Object visitPartDirective(PartDirective node) {
_recordDirective(node);
return super.visitPartDirective(node);
}
@override
Object visitPartOfDirective(PartOfDirective node) {
_recordDirective(node);
return super.visitPartOfDirective(node);
}
_addRegion(int startOffset, int endOffset, FoldingKind kind) {
// TODO(dantup): This class is marked deprecated; find out what to change it to.
final LineInfo_Location start =
_computer._lineInfo.getLocation(startOffset);
final LineInfo_Location end = _computer._lineInfo.getLocation(endOffset);
if (start.lineNumber != end.lineNumber) {
_computer._foldingRegions
.add(new FoldingRegion(kind, startOffset, endOffset - startOffset));
}
}
_recordDirective(Directive node) {
_computer._firstDirective ??= node;
_computer._lastDirective = node;
}
}