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

Side by Side Diff: pkg/analyzer/lib/src/dart/analysis/search.dart

Issue 2522503004: Start implementing search support in AnalysisDriver. (Closed)
Patch Set: Created 4 years 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 import 'dart:async';
6
7 import 'package:analyzer/dart/ast/ast.dart';
8 import 'package:analyzer/dart/ast/visitor.dart';
9 import 'package:analyzer/dart/element/element.dart';
10 import 'package:analyzer/dart/element/visitor.dart';
11 import 'package:analyzer/src/dart/analysis/driver.dart';
12 import 'package:analyzer/src/dart/ast/utilities.dart';
13 import 'package:analyzer/src/dart/element/element.dart';
14
15 /**
16 * Search support for an [AnalysisDriver].
17 */
18 class Search {
19 final AnalysisDriver _driver;
20
21 Search(this._driver);
22
23 /**
24 * Returns references to the element at the given [offset] in the file with
25 * the given [path].
26 */
27 Future<List<SearchResult>> references(String path, int offset) async {
28 // Search only in added files.
29 if (!_driver.addedFiles.contains(path)) {
30 return const <SearchResult>[];
31 }
32
33 AnalysisResult analysisResult = await _driver.getResult(path);
34 CompilationUnit unit = analysisResult.unit;
35
36 // Prepare the node.
37 AstNode node = new NodeLocator(offset).searchWithin(unit);
38 if (node == null) {
39 return const <SearchResult>[];
40 }
41
42 // Prepare the element.
43 Element element = ElementLocator.locate(node);
44 if (element == null) {
45 return const <SearchResult>[];
46 }
47
48 ElementKind kind = element.kind;
49 if (kind == ElementKind.LABEL || kind == ElementKind.LOCAL_VARIABLE) {
50 Block block = node.getAncestor((n) => n is Block);
51 return _searchReferences_Local(element, unit.element, block);
52 }
53 // TODO(scheglov) support other kinds
54 return [];
55 }
56
57 Future<List<SearchResult>> _searchReferences_Local(
58 Element element,
59 CompilationUnitElement enclosingUnitElement,
60 AstNode enclosingNode) async {
61 _LocalReferencesVisitor visitor =
62 new _LocalReferencesVisitor(element, enclosingUnitElement);
63 enclosingNode?.accept(visitor);
64 return visitor.matches;
65 }
66 }
67
68 /**
69 * A single search result.
70 */
71 class SearchResult {
72 /**
73 * The element that is used at this result.
74 */
75 final Element element;
76
77 /**
78 * The deep most element that contains this result.
79 */
80 final Element enclosingElement;
81
82 /**
83 * The kind of the [element] usage.
84 */
85 final SearchResultKind kind;
86
87 /**
88 * The offset relative to the beginning of the containing file.
89 */
90 final int offset;
91
92 /**
93 * The length of the usage in the containing file context.
94 */
95 final int length;
96
97 /**
98 * Is `true` if a field or a method is using with a qualifier.
99 */
100 final bool isResolved;
101
102 /**
103 * Is `true` if the result is a resolved reference to [element].
104 */
105 final bool isQualified;
106
107 SearchResult._(this.element, this.enclosingElement, this.kind, this.offset,
108 this.length, this.isResolved, this.isQualified);
109
110 @override
111 String toString() {
112 StringBuffer buffer = new StringBuffer();
113 buffer.write("SearchResult(kind=");
114 buffer.write(kind);
115 buffer.write(", offset=");
116 buffer.write(offset);
117 buffer.write(", length=");
118 buffer.write(length);
119 buffer.write(", isResolved=");
120 buffer.write(isResolved);
121 buffer.write(", isQualified=");
122 buffer.write(isQualified);
123 buffer.write(", enclosingElement=");
124 buffer.write(enclosingElement);
125 buffer.write(")");
126 return buffer.toString();
127 }
128 }
129
130 /**
131 * The kind of reference in a [SearchResult].
132 */
133 enum SearchResultKind { READ, READ_WRITE, WRITE, INVOCATION, REFERENCE }
134
135 /**
136 * A visitor that finds the deep-most [Element] that contains the [offset].
137 */
138 class _ContainingElementFinder extends GeneralizingElementVisitor {
139 final int offset;
140 Element containingElement;
141
142 _ContainingElementFinder(this.offset);
143
144 visitElement(Element element) {
145 if (element is ElementImpl) {
146 if (element.codeOffset != null &&
147 element.codeOffset <= offset &&
148 offset <= element.codeOffset + element.codeLength) {
149 containingElement = element;
150 super.visitElement(element);
151 }
152 }
153 }
154 }
155
156 /**
157 * Visitor that adds [SearchResult]s for local elements of a block, method,
158 * class or a library - labels, local functions, local variables and parameters,
159 * type parameters, import prefixes.
160 */
161 class _LocalReferencesVisitor extends RecursiveAstVisitor {
162 final List<SearchResult> matches = <SearchResult>[];
163
164 final Element element;
165 final CompilationUnitElement enclosingUnitElement;
166
167 _LocalReferencesVisitor(this.element, this.enclosingUnitElement);
168
169 @override
170 visitSimpleIdentifier(SimpleIdentifier node) {
171 if (node.inDeclarationContext()) {
172 return;
173 }
174 if (node.staticElement == element) {
175 AstNode parent = node.parent;
176 SearchResultKind kind = SearchResultKind.REFERENCE;
177 if (element is FunctionElement) {
178 if (parent is MethodInvocation && parent.methodName == node) {
179 kind = SearchResultKind.INVOCATION;
180 }
181 } else if (element is VariableElement) {
182 bool isGet = node.inGetterContext();
183 bool isSet = node.inSetterContext();
184 if (isGet && isSet) {
185 kind = SearchResultKind.READ_WRITE;
186 } else if (isGet) {
187 if (parent is MethodInvocation && parent.methodName == node) {
188 kind = SearchResultKind.INVOCATION;
189 } else {
190 kind = SearchResultKind.READ;
191 }
192 } else if (isSet) {
193 kind = SearchResultKind.WRITE;
194 }
195 }
196 _addMatch(node, kind);
197 }
198 }
199
200 void _addMatch(AstNode node, SearchResultKind kind) {
201 bool isQualified = node.parent is Label;
202 var finder = new _ContainingElementFinder(node.offset);
203 enclosingUnitElement.accept(finder);
204 matches.add(new SearchResult._(element, finder.containingElement, kind,
205 node.offset, node.length, true, isQualified));
206 }
207 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698