Implement basic functionality of the analyzer plugin

This commit is contained in:
Simon Binder 2019-09-07 18:49:11 +02:00
parent 10dca6a8a9
commit 1fcc6facee
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
13 changed files with 183 additions and 55 deletions

View File

@ -1,4 +1,3 @@
import 'package:analyzer/analyzer.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:build/build.dart' hide log;

View File

@ -88,19 +88,20 @@ class MoorDriver implements AnalysisDriverGeneric {
String absolutePath(Uri reference, {Uri base}) {
final factory = dartDriver.sourceFactory;
final baseSource = base == null ? null : factory.forUri2(base);
final source =
dartDriver.sourceFactory.resolveUri(baseSource, reference.toString());
return source.fullName;
}
PluginTask _createTask(String path) {
final uri = Uri.parse(path);
final uri = Uri.parse(path).replace(scheme: 'file');
return PluginTask(uri, this);
}
@override
set priorityFiles(List<String> priorityPaths) {
_tracker.setPriorityFiles(priorityPaths);
_tracker.setPriorityFiles(priorityPaths.where(_ownsFile));
}
@override

View File

@ -46,7 +46,7 @@ class FileTracker {
_putInQueue(addFile(path));
}
void setPriorityFiles(List<String> priority) {
void setPriorityFiles(Iterable<String> priority) {
// remove prioritized flag from existing files
for (var file in _currentPriority) {
_updateFile(file, (f) => f._prioritized = false);

View File

@ -13,9 +13,9 @@ void setupLogger(MoorPlugin plugin) {
Logger.root.level = Level.ALL;
Logger.root.onRecord.listen((LogRecord rec) {
if (rec.level >= Level.INFO) {
final isFatal = rec.level >= Level.WARNING;
final isFatal = rec.level > Level.WARNING;
final error =
PluginErrorParams(isFatal, rec.message, rec.stackTrace?.toString());
PluginErrorParams(isFatal, rec.message, rec.stackTrace.toString());
plugin.channel.sendNotification(error.toNotification());
}

View File

@ -1,15 +1,25 @@
import 'package:analyzer/context/context_root.dart';
// ignore: implementation_imports
import 'package:analyzer/src/context/builder.dart';
import 'package:analyzer/src/context/context_root.dart'; // ignore: implementation_imports
import 'package:analyzer/src/context/builder.dart'; // ignore: implementation_imports
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer_plugin/plugin/folding_mixin.dart';
import 'package:analyzer_plugin/plugin/highlights_mixin.dart';
import 'package:analyzer_plugin/plugin/outline_mixin.dart';
import 'package:analyzer_plugin/plugin/plugin.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
import 'package:analyzer_plugin/utilities/folding/folding.dart';
import 'package:analyzer_plugin/utilities/highlights/highlights.dart';
import 'package:analyzer_plugin/utilities/outline/outline.dart';
import 'package:moor_generator/src/backends/plugin/backend/file_tracker.dart';
import 'package:moor_generator/src/backends/plugin/services/folding.dart';
import 'package:moor_generator/src/backends/plugin/services/highlights.dart';
import 'package:moor_generator/src/backends/plugin/services/outline.dart';
import 'package:moor_generator/src/backends/plugin/services/requests.dart';
import 'backend/driver.dart';
import 'backend/logger.dart';
class MoorPlugin extends ServerPlugin {
class MoorPlugin extends ServerPlugin
with OutlineMixin, HighlightsMixin, FoldingMixin {
MoorPlugin(ResourceProvider provider) : super(provider) {
setupLogger(this);
}
@ -61,4 +71,38 @@ class MoorPlugin extends ServerPlugin {
if (driver is! MoorDriver) return null;
return driver as MoorDriver;
}
Future<MoorRequest> _createMoorRequest(String path) async {
final driver = _moorDriverForPath(path);
final task = await driver.parseMoorFile(path);
return MoorRequest(task, resourceProvider);
}
@override
List<OutlineContributor> getOutlineContributors(String path) {
return const [MoorOutlineContributor()];
}
@override
Future<OutlineRequest> getOutlineRequest(String path) =>
_createMoorRequest(path);
@override
List<HighlightsContributor> getHighlightsContributors(String path) {
return const [MoorHighlightContributor()];
}
@override
Future<HighlightsRequest> getHighlightsRequest(String path) =>
_createMoorRequest(path);
@override
List<FoldingContributor> getFoldingContributors(String path) {
return const [MoorFoldingContributor()];
}
@override
Future<FoldingRequest> getFoldingRequest(String path) =>
_createMoorRequest(path);
}

View File

@ -0,0 +1,38 @@
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/utilities/folding/folding.dart';
import 'package:moor_generator/src/backends/plugin/services/requests.dart';
import 'package:sqlparser/sqlparser.dart';
class MoorFoldingContributor implements FoldingContributor {
const MoorFoldingContributor();
@override
void computeFolding(FoldingRequest request, FoldingCollector collector) {
final moorRequest = request as MoorRequest;
final visitor = _FoldingVisitor(collector);
for (var stmt in moorRequest.resolvedTask.lastResult.statements) {
stmt.accept(visitor);
}
}
}
class _FoldingVisitor extends RecursiveVisitor<void> {
final FoldingCollector collector;
_FoldingVisitor(this.collector);
@override
void visitCreateTableStatement(CreateTableStatement e) {
final startBody = e.openingBracket;
final endBody = e.closingBracket;
// report everything between the two brackets as class body
final first = startBody.span.end.offset + 1;
final last = endBody.span.start.offset - 1;
if (last - first < 0) return; // empty body, e.g. CREATE TABLE ()
collector.addRegion(first, last - first, FoldingKind.CLASS_BODY);
}
}

View File

@ -1,50 +1,29 @@
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/utilities/highlights/highlights.dart';
import 'package:moor_generator/src/backends/plugin/services/highlights/request.dart';
import 'package:moor_generator/src/backends/plugin/services/requests.dart';
import 'package:sqlparser/sqlparser.dart';
const _notBuiltIn = {
TokenType.numberLiteral,
TokenType.stringLiteral,
TokenType.identifier,
TokenType.leftParen,
TokenType.rightParen,
TokenType.comma,
TokenType.star,
TokenType.less,
TokenType.lessEqual,
TokenType.lessMore,
TokenType.equal,
TokenType.more,
TokenType.moreEqual,
TokenType.shiftRight,
TokenType.shiftLeft,
TokenType.exclamationEqual,
TokenType.plus,
TokenType.minus,
};
class SqlHighlighter implements HighlightsContributor {
const SqlHighlighter();
class MoorHighlightContributor implements HighlightsContributor {
const MoorHighlightContributor();
@override
void computeHighlights(
HighlightsRequest request, HighlightsCollector collector) {
if (request is! MoorHighlightingRequest) {
if (request is! MoorRequest) {
return;
}
final typedRequest = request as MoorHighlightingRequest;
final typedRequest = request as MoorRequest;
final visitor = _HighlightingVisitor(collector);
final result = typedRequest.task.lastResult;
final result = typedRequest.resolvedTask.lastResult;
for (var stmt in result.statements) {
stmt.accept(visitor);
}
for (var token in result.tokens) {
if (!_notBuiltIn.contains(token.type)) {
if (token is KeywordToken) {
final start = token.span.start.offset;
final length = token.span.length;
collector.addRegion(start, length, HighlightRegionType.BUILT_IN);

View File

@ -1,13 +0,0 @@
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer_plugin/utilities/highlights/highlights.dart';
import 'package:moor_generator/src/analyzer/session.dart';
class MoorHighlightingRequest extends HighlightsRequest {
@override
final String path;
@override
final ResourceProvider resourceProvider;
final MoorTask task;
MoorHighlightingRequest(this.task, this.path, this.resourceProvider);
}

View File

@ -0,0 +1,57 @@
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/utilities/outline/outline.dart';
import 'package:moor_generator/src/backends/plugin/services/requests.dart';
import 'package:sqlparser/sqlparser.dart';
const _defaultFlags = 0;
class MoorOutlineContributor implements OutlineContributor {
const MoorOutlineContributor();
@override
void computeOutline(OutlineRequest request, OutlineCollector collector) {
final moorRequest = request as MoorRequest;
final file = moorRequest.path;
final libraryElement = Element(ElementKind.FILE, file, _defaultFlags);
collector.startElement(
libraryElement, 0, moorRequest.resolvedTask.content.length);
final visitor = _OutlineVisitor(collector);
for (var stmt in moorRequest.resolvedTask.lastResult.statements) {
stmt.accept(visitor);
}
collector.endElement();
}
}
class _OutlineVisitor extends RecursiveVisitor<void> {
final OutlineCollector collector;
_OutlineVisitor(this.collector);
Element _startElement(ElementKind kind, String name, AstNode e) {
final element = Element(kind, name, _defaultFlags);
final offset = e.firstPosition;
final length = e.lastPosition - offset;
collector.startElement(element, offset, length);
return element;
}
@override
void visitCreateTableStatement(CreateTableStatement e) {
_startElement(ElementKind.CLASS, e.tableName, e);
super.visitChildren(e);
collector.endElement();
}
@override
void visitColumnDefinition(ColumnDefinition e) {
_startElement(ElementKind.FIELD, e.columnName, e);
super.visitChildren(e);
collector.endElement();
}
}

View File

@ -0,0 +1,16 @@
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer_plugin/utilities/folding/folding.dart';
import 'package:analyzer_plugin/utilities/highlights/highlights.dart';
import 'package:analyzer_plugin/utilities/outline/outline.dart';
import 'package:moor_generator/src/analyzer/session.dart';
class MoorRequest implements OutlineRequest, HighlightsRequest, FoldingRequest {
final MoorTask resolvedTask;
@override
final ResourceProvider resourceProvider;
MoorRequest(this.resolvedTask, this.resourceProvider);
@override
String get path => resolvedTask.backendTask.entrypoint.toFilePath();
}

View File

@ -8,7 +8,7 @@ class ImportStatement extends Statement {
ImportStatement(this.importedFile);
@override
T accept<T>(AstVisitor<T> visitor) {}
T accept<T>(AstVisitor<T> visitor) => visitor.visitMoorImportStatement(this);
@override
final Iterable<AstNode> childNodes = const [];

View File

@ -9,6 +9,9 @@ class CreateTableStatement extends Statement with SchemaStatement {
final List<TableConstraint> tableConstraints;
final bool withoutRowId;
Token openingBracket;
Token closingBracket;
CreateTableStatement(
{this.ifNotExists = false,
@required this.tableName,

View File

@ -19,7 +19,7 @@ mixin SchemaParser on ParserBase {
_consumeIdentifier('Expected a table name', lenient: true);
// we don't currently support CREATE TABLE x AS SELECT ... statements
_consume(
final leftParen = _consume(
TokenType.leftParen, 'Expected opening parenthesis to list columns');
final columns = <ColumnDefinition>[];
@ -42,7 +42,8 @@ mixin SchemaParser on ParserBase {
}
} while (_matchOne(TokenType.comma));
_consume(TokenType.rightParen, 'Expected closing parenthesis');
final rightParen =
_consume(TokenType.rightParen, 'Expected closing parenthesis');
var withoutRowId = false;
if (_matchOne(TokenType.without)) {
@ -57,7 +58,10 @@ mixin SchemaParser on ParserBase {
withoutRowId: withoutRowId,
columns: columns,
tableConstraints: tableConstraints,
)..setSpan(first, _previous);
)
..setSpan(first, _previous)
..openingBracket = leftParen
..closingBracket = rightParen;
}
ColumnDefinition _columnDefinition() {