Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(176)

Unified Diff: pkg/analyzer/lib/src/dart/analysis/search.dart

Issue 2522503004: Start implementing search support in AnalysisDriver. (Closed)
Patch Set: Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/analyzer/lib/src/dart/analysis/search.dart
diff --git a/pkg/analyzer/lib/src/dart/analysis/search.dart b/pkg/analyzer/lib/src/dart/analysis/search.dart
new file mode 100644
index 0000000000000000000000000000000000000000..e28a5b6dd5ba76d02ecf69aa933232c975b15938
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/analysis/search.dart
@@ -0,0 +1,207 @@
+// Copyright (c) 2016, 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 'dart:async';
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/visitor.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+
+/**
+ * Search support for an [AnalysisDriver].
+ */
+class Search {
+ final AnalysisDriver _driver;
+
+ Search(this._driver);
+
+ /**
+ * Returns references to the element at the given [offset] in the file with
+ * the given [path].
+ */
+ Future<List<SearchResult>> references(String path, int offset) async {
+ // Search only in added files.
+ if (!_driver.addedFiles.contains(path)) {
+ return const <SearchResult>[];
+ }
+
+ AnalysisResult analysisResult = await _driver.getResult(path);
+ CompilationUnit unit = analysisResult.unit;
+
+ // Prepare the node.
+ AstNode node = new NodeLocator(offset).searchWithin(unit);
+ if (node == null) {
+ return const <SearchResult>[];
+ }
+
+ // Prepare the element.
+ Element element = ElementLocator.locate(node);
+ if (element == null) {
+ return const <SearchResult>[];
+ }
+
+ ElementKind kind = element.kind;
+ if (kind == ElementKind.LABEL || kind == ElementKind.LOCAL_VARIABLE) {
+ Block block = node.getAncestor((n) => n is Block);
+ return _searchReferences_Local(element, unit.element, block);
+ }
+ // TODO(scheglov) support other kinds
+ return [];
+ }
+
+ Future<List<SearchResult>> _searchReferences_Local(
+ Element element,
+ CompilationUnitElement enclosingUnitElement,
+ AstNode enclosingNode) async {
+ _LocalReferencesVisitor visitor =
+ new _LocalReferencesVisitor(element, enclosingUnitElement);
+ enclosingNode?.accept(visitor);
+ return visitor.matches;
+ }
+}
+
+/**
+ * A single search result.
+ */
+class SearchResult {
+ /**
+ * The element that is used at this result.
+ */
+ final Element element;
+
+ /**
+ * The deep most element that contains this result.
+ */
+ final Element enclosingElement;
+
+ /**
+ * The kind of the [element] usage.
+ */
+ final SearchResultKind kind;
+
+ /**
+ * The offset relative to the beginning of the containing file.
+ */
+ final int offset;
+
+ /**
+ * The length of the usage in the containing file context.
+ */
+ final int length;
+
+ /**
+ * Is `true` if a field or a method is using with a qualifier.
+ */
+ final bool isResolved;
+
+ /**
+ * Is `true` if the result is a resolved reference to [element].
+ */
+ final bool isQualified;
+
+ SearchResult._(this.element, this.enclosingElement, this.kind, this.offset,
+ this.length, this.isResolved, this.isQualified);
+
+ @override
+ String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.write("SearchResult(kind=");
+ buffer.write(kind);
+ buffer.write(", offset=");
+ buffer.write(offset);
+ buffer.write(", length=");
+ buffer.write(length);
+ buffer.write(", isResolved=");
+ buffer.write(isResolved);
+ buffer.write(", isQualified=");
+ buffer.write(isQualified);
+ buffer.write(", enclosingElement=");
+ buffer.write(enclosingElement);
+ buffer.write(")");
+ return buffer.toString();
+ }
+}
+
+/**
+ * The kind of reference in a [SearchResult].
+ */
+enum SearchResultKind { READ, READ_WRITE, WRITE, INVOCATION, REFERENCE }
+
+/**
+ * A visitor that finds the deep-most [Element] that contains the [offset].
+ */
+class _ContainingElementFinder extends GeneralizingElementVisitor {
+ final int offset;
+ Element containingElement;
+
+ _ContainingElementFinder(this.offset);
+
+ visitElement(Element element) {
+ if (element is ElementImpl) {
+ if (element.codeOffset != null &&
+ element.codeOffset <= offset &&
+ offset <= element.codeOffset + element.codeLength) {
+ containingElement = element;
+ super.visitElement(element);
+ }
+ }
+ }
+}
+
+/**
+ * Visitor that adds [SearchResult]s for local elements of a block, method,
+ * class or a library - labels, local functions, local variables and parameters,
+ * type parameters, import prefixes.
+ */
+class _LocalReferencesVisitor extends RecursiveAstVisitor {
+ final List<SearchResult> matches = <SearchResult>[];
+
+ final Element element;
+ final CompilationUnitElement enclosingUnitElement;
+
+ _LocalReferencesVisitor(this.element, this.enclosingUnitElement);
+
+ @override
+ visitSimpleIdentifier(SimpleIdentifier node) {
+ if (node.inDeclarationContext()) {
+ return;
+ }
+ if (node.staticElement == element) {
+ AstNode parent = node.parent;
+ SearchResultKind kind = SearchResultKind.REFERENCE;
+ if (element is FunctionElement) {
+ if (parent is MethodInvocation && parent.methodName == node) {
+ kind = SearchResultKind.INVOCATION;
+ }
+ } else if (element is VariableElement) {
+ bool isGet = node.inGetterContext();
+ bool isSet = node.inSetterContext();
+ if (isGet && isSet) {
+ kind = SearchResultKind.READ_WRITE;
+ } else if (isGet) {
+ if (parent is MethodInvocation && parent.methodName == node) {
+ kind = SearchResultKind.INVOCATION;
+ } else {
+ kind = SearchResultKind.READ;
+ }
+ } else if (isSet) {
+ kind = SearchResultKind.WRITE;
+ }
+ }
+ _addMatch(node, kind);
+ }
+ }
+
+ void _addMatch(AstNode node, SearchResultKind kind) {
+ bool isQualified = node.parent is Label;
+ var finder = new _ContainingElementFinder(node.offset);
+ enclosingUnitElement.accept(finder);
+ matches.add(new SearchResult._(element, finder.containingElement, kind,
+ node.offset, node.length, true, isQualified));
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698