From d91c69493f3cf07884ef88f572ff42635961b215 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Sat, 28 Sep 2019 22:24:40 +0200 Subject: [PATCH] Plugin: Navigation for column references in queries --- .../backends/plugin/services/navigation.dart | 43 +++++++++++++++---- .../backends/plugin/services/requests.dart | 1 + .../plugin/utils/ast_to_location.dart | 27 +++++++++--- 3 files changed, 58 insertions(+), 13 deletions(-) diff --git a/moor_generator/lib/src/backends/plugin/services/navigation.dart b/moor_generator/lib/src/backends/plugin/services/navigation.dart index 5788aafe..3a2e1ef5 100644 --- a/moor_generator/lib/src/backends/plugin/services/navigation.dart +++ b/moor_generator/lib/src/backends/plugin/services/navigation.dart @@ -1,6 +1,9 @@ import 'package:analyzer_plugin/protocol/protocol_common.dart'; import 'package:analyzer_plugin/utilities/navigation/navigation.dart'; +import 'package:moor_generator/src/analyzer/sql_queries/meta/column_declaration.dart'; import 'package:moor_generator/src/backends/plugin/services/requests.dart'; +import 'package:moor_generator/src/backends/plugin/utils/ast_to_location.dart'; +import 'package:source_span/source_span.dart'; import 'package:sqlparser/sqlparser.dart'; class MoorNavigationContributor implements NavigationContributor { @@ -24,6 +27,13 @@ class _NavigationVisitor extends RecursiveVisitor { _NavigationVisitor(this.request, this.collector); + void _reportForSpan(SourceSpan span, ElementKind kind, Location target) { + final offset = span.start.offset; + final length = span.end.offset - offset; + + collector.addRegion(offset, length, kind, target); + } + @override void visitMoorImportStatement(ImportStatement e) { if (request.isMoorAndParsed) { @@ -32,15 +42,32 @@ class _NavigationVisitor extends RecursiveVisitor { if (resolved != null) { final span = e.importString.span; - final offset = span.start.offset; - final length = span.end.offset - offset; + _reportForSpan( + span, ElementKind.FILE, Location(resolved.uri.path, 0, 0, 1, 1)); + } + } - collector.addRegion( - offset, - length, - ElementKind.FILE, - Location(resolved.uri.path, 0, 0, 1, 1), - ); + super.visitChildren(e); + } + + @override + void visitReference(Reference e) { + if (request.isMoorAndAnalyzed) { + final resolved = e.resolved; + + if (resolved is Column) { + // if we know the declaration because the file was analyzed - use that + final declaration = resolved.meta(); + if (declaration != null) { + final location = locationOfDeclaration(declaration); + _reportForSpan(e.span, ElementKind.FIELD, location); + } else if (declaration is ExpressionColumn) { + // expression references don't have an explicit declaration, but they + // reference an expression that we can target + final expr = (declaration as ExpressionColumn).expression; + final target = locationOfNode(request.file, expr); + _reportForSpan(e.span, ElementKind.LOCAL_VARIABLE, target); + } } } diff --git a/moor_generator/lib/src/backends/plugin/services/requests.dart b/moor_generator/lib/src/backends/plugin/services/requests.dart index 1b77f3e1..1c3b178d 100644 --- a/moor_generator/lib/src/backends/plugin/services/requests.dart +++ b/moor_generator/lib/src/backends/plugin/services/requests.dart @@ -13,6 +13,7 @@ mixin _MoorBaseRequest { bool get isMoor => file.type == FileType.moor; bool get isMoorAndParsed => isMoor && file.isParsed; + bool get isMoorAndAnalyzed => isMoor && file.isAnalyzed; String get path => file.uri.path; diff --git a/moor_generator/lib/src/backends/plugin/utils/ast_to_location.dart b/moor_generator/lib/src/backends/plugin/utils/ast_to_location.dart index bf1f8fbf..a2e209c8 100644 --- a/moor_generator/lib/src/backends/plugin/utils/ast_to_location.dart +++ b/moor_generator/lib/src/backends/plugin/utils/ast_to_location.dart @@ -1,12 +1,13 @@ import 'package:analyzer_plugin/protocol/protocol_common.dart'; import 'package:moor_generator/src/analyzer/runner/file_graph.dart'; +import 'package:moor_generator/src/analyzer/sql_queries/meta/column_declaration.dart'; +import 'package:source_gen/source_gen.dart' show spanForElement; +import 'package:source_span/source_span.dart'; import 'package:sqlparser/sqlparser.dart'; -Location locationOfNode(FoundFile file, AstNode node) { - if (!node.hasSpan) return null; - - final first = node.first.span.start; - final last = node.last.span.end; +Location _locationForSpan(SourceSpan span, FoundFile file) { + final first = span.start; + final last = span.end; // in [Location], lines and columns are one-indexed, but in [SourceLocation] // they're 0-based. @@ -18,3 +19,19 @@ Location locationOfNode(FoundFile file, AstNode node) { first.column + 1, ); } + +Location locationOfNode(FoundFile file, AstNode node) { + if (!node.hasSpan) return null; + return _locationForSpan(node.span, file); +} + +Location locationOfDeclaration(ColumnDeclaration declaration) { + if (declaration.dartDeclaration != null) { + final span = spanForElement(declaration.dartDeclaration); + return _locationForSpan(span, declaration.declarationFile); + } else if (declaration.moorDeclaration != null) { + return locationOfNode( + declaration.declarationFile, declaration.moorDeclaration); + } + return null; +}