mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 08:11:05 +00:00
Deoptimize Search - request a new resolved unit for local search.
It seems to me that it would be easier to integrate if we keep the same search technique - search for Element references. I think any saving can be only for local elements search. If it turns out to be expensive, we could add priority results caching in the driver. R=brianwilkerson@google.com BUG= Review URL: https://codereview.chromium.org/2521913004 .
This commit is contained in:
parent
3a6972095f
commit
4fea218f77
|
@ -21,47 +21,46 @@ class Search {
|
|||
Search(this._driver);
|
||||
|
||||
/**
|
||||
* Returns references to the element at the given [offset] in the file with
|
||||
* the given [path].
|
||||
* Returns references to the [element].
|
||||
*/
|
||||
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);
|
||||
Future<List<SearchResult>> references(Element element) async {
|
||||
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);
|
||||
return _searchReferences_Local(element, (n) => n is Block);
|
||||
}
|
||||
// TODO(scheglov) support other kinds
|
||||
return [];
|
||||
return const <SearchResult>[];
|
||||
}
|
||||
|
||||
Future<List<SearchResult>> _searchReferences_Local(
|
||||
Element element,
|
||||
CompilationUnitElement enclosingUnitElement,
|
||||
AstNode enclosingNode) async {
|
||||
Element element, bool isRootNode(AstNode n)) async {
|
||||
String path = element.source.fullName;
|
||||
|
||||
// Prepare the unit.
|
||||
AnalysisResult analysisResult = await _driver.getResult(path);
|
||||
CompilationUnit unit = analysisResult.unit;
|
||||
if (unit == null) {
|
||||
return const <SearchResult>[];
|
||||
}
|
||||
|
||||
// Prepare the node.
|
||||
AstNode node = new NodeLocator(element.nameOffset).searchWithin(unit);
|
||||
if (node == null) {
|
||||
return const <SearchResult>[];
|
||||
}
|
||||
|
||||
// Prepare the enclosing node.
|
||||
AstNode enclosingNode = node.getAncestor(isRootNode);
|
||||
|
||||
// Find the matches.
|
||||
_LocalReferencesVisitor visitor =
|
||||
new _LocalReferencesVisitor(element, enclosingUnitElement);
|
||||
enclosingNode?.accept(visitor);
|
||||
return visitor.matches;
|
||||
new _LocalReferencesVisitor(element, unit.element);
|
||||
enclosingNode.accept(visitor);
|
||||
return visitor.results;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,7 +158,7 @@ class _ContainingElementFinder extends GeneralizingElementVisitor {
|
|||
* type parameters, import prefixes.
|
||||
*/
|
||||
class _LocalReferencesVisitor extends RecursiveAstVisitor {
|
||||
final List<SearchResult> matches = <SearchResult>[];
|
||||
final List<SearchResult> results = <SearchResult>[];
|
||||
|
||||
final Element element;
|
||||
final CompilationUnitElement enclosingUnitElement;
|
||||
|
@ -193,15 +192,15 @@ class _LocalReferencesVisitor extends RecursiveAstVisitor {
|
|||
kind = SearchResultKind.WRITE;
|
||||
}
|
||||
}
|
||||
_addMatch(node, kind);
|
||||
_addResult(node, kind);
|
||||
}
|
||||
}
|
||||
|
||||
void _addMatch(AstNode node, SearchResultKind kind) {
|
||||
void _addResult(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,
|
||||
results.add(new SearchResult._(element, finder.containingElement, kind,
|
||||
node.offset, node.length, true, isQualified));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/dart/element/visitor.dart';
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/file_system/memory_file_system.dart';
|
||||
import 'package:analyzer/source/package_map_resolver.dart';
|
||||
|
@ -17,6 +19,30 @@ import 'package:test/test.dart';
|
|||
|
||||
import '../../context/mock_sdk.dart';
|
||||
|
||||
/**
|
||||
* Finds an [Element] with the given [name].
|
||||
*/
|
||||
Element findChildElement(Element root, String name, [ElementKind kind]) {
|
||||
Element result = null;
|
||||
root.accept(new _ElementVisitorFunctionWrapper((Element element) {
|
||||
if (element.name != name) {
|
||||
return;
|
||||
}
|
||||
if (kind != null && element.kind != kind) {
|
||||
return;
|
||||
}
|
||||
result = element;
|
||||
}));
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef bool Predicate<E>(E argument);
|
||||
|
||||
/**
|
||||
* A function to be called for every [Element].
|
||||
*/
|
||||
typedef void _ElementVisitorFunction(Element element);
|
||||
|
||||
class BaseAnalysisDriverTest {
|
||||
static final MockSdk sdk = new MockSdk();
|
||||
|
||||
|
@ -108,6 +134,20 @@ class BaseAnalysisDriverTest {
|
|||
String _p(String path) => provider.convertPath(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps an [_ElementVisitorFunction] into a [GeneralizingElementVisitor].
|
||||
*/
|
||||
class _ElementVisitorFunctionWrapper extends GeneralizingElementVisitor {
|
||||
final _ElementVisitorFunction function;
|
||||
|
||||
_ElementVisitorFunctionWrapper(this.function);
|
||||
|
||||
visitElement(Element element) {
|
||||
function(element);
|
||||
super.visitElement(element);
|
||||
}
|
||||
}
|
||||
|
||||
class _Monitor {
|
||||
Completer<Null> _completer = new Completer<Null>();
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import 'dart:convert';
|
|||
|
||||
import 'package:analyzer/dart/ast/ast.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/analysis/index.dart';
|
||||
import 'package:analyzer/src/summary/format.dart';
|
||||
|
@ -23,28 +22,6 @@ main() {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an [Element] with the given [name].
|
||||
*/
|
||||
Element findChildElement(Element root, String name, [ElementKind kind]) {
|
||||
Element result = null;
|
||||
root.accept(new _ElementVisitorFunctionWrapper((Element element) {
|
||||
if (element.name != name) {
|
||||
return;
|
||||
}
|
||||
if (kind != null && element.kind != kind) {
|
||||
return;
|
||||
}
|
||||
result = element;
|
||||
}));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* A function to be called for every [Element].
|
||||
*/
|
||||
typedef void _ElementVisitorFunction(Element element);
|
||||
|
||||
class ExpectedLocation {
|
||||
final CompilationUnitElement unitElement;
|
||||
final int offset;
|
||||
|
@ -1210,20 +1187,6 @@ class _ElementIndexAssert {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps an [_ElementVisitorFunction] into a [GeneralizingElementVisitor].
|
||||
*/
|
||||
class _ElementVisitorFunctionWrapper extends GeneralizingElementVisitor {
|
||||
final _ElementVisitorFunction function;
|
||||
|
||||
_ElementVisitorFunctionWrapper(this.function);
|
||||
|
||||
visitElement(Element element) {
|
||||
function(element);
|
||||
super.visitElement(element);
|
||||
}
|
||||
}
|
||||
|
||||
class _NameIndexAssert {
|
||||
final IndexTest test;
|
||||
final String name;
|
||||
|
|
|
@ -4,8 +4,11 @@
|
|||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/analysis/driver.dart';
|
||||
import 'package:analyzer/src/dart/analysis/search.dart';
|
||||
import 'package:analyzer/src/dart/ast/utilities.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
|
@ -90,13 +93,13 @@ label:
|
|||
}
|
||||
}
|
||||
''');
|
||||
int offset = findOffset('label:');
|
||||
Element element = await _findElementAtString('label:');
|
||||
List<String> main = [testUri, 'main'];
|
||||
var expected = [
|
||||
_expectId(main, SearchResultKind.REFERENCE, 'label; // 1'),
|
||||
_expectId(main, SearchResultKind.REFERENCE, 'label; // 2')
|
||||
];
|
||||
await _verifyReferences(offset, expected);
|
||||
await _verifyReferences(element, expected);
|
||||
}
|
||||
|
||||
test_searchReferences_localVariable() async {
|
||||
|
@ -109,7 +112,7 @@ main() {
|
|||
v();
|
||||
}
|
||||
''');
|
||||
int offset = findOffset('v;');
|
||||
Element element = await _findElementAtString('v;');
|
||||
List<String> main = [testUri, 'main'];
|
||||
var expected = [
|
||||
_expectId(main, SearchResultKind.WRITE, 'v = 1;'),
|
||||
|
@ -117,7 +120,7 @@ main() {
|
|||
_expectId(main, SearchResultKind.READ, 'v);'),
|
||||
_expectId(main, SearchResultKind.INVOCATION, 'v();')
|
||||
];
|
||||
await _verifyReferences(offset, expected);
|
||||
await _verifyReferences(element, expected);
|
||||
}
|
||||
|
||||
test_searchReferences_localVariable_inForEachLoop() async {
|
||||
|
@ -131,7 +134,7 @@ main() {
|
|||
}
|
||||
}
|
||||
''');
|
||||
int offset = findOffset('v in []');
|
||||
Element element = await _findElementAtString('v in []');
|
||||
List<String> main = [testUri, 'main'];
|
||||
var expected = [
|
||||
_expectId(main, SearchResultKind.WRITE, 'v = 1;'),
|
||||
|
@ -139,7 +142,7 @@ main() {
|
|||
_expectId(main, SearchResultKind.READ, 'v);'),
|
||||
_expectId(main, SearchResultKind.INVOCATION, 'v();')
|
||||
];
|
||||
await _verifyReferences(offset, expected);
|
||||
await _verifyReferences(element, expected);
|
||||
}
|
||||
|
||||
ExpectedResult _expectId(
|
||||
|
@ -153,10 +156,16 @@ main() {
|
|||
isResolved: isResolved, isQualified: isQualified);
|
||||
}
|
||||
|
||||
Future<Element> _findElementAtString(String search) async {
|
||||
AnalysisResult result = await driver.getResult(testFile);
|
||||
int offset = findOffset(search);
|
||||
AstNode node = new NodeLocator(offset).searchWithin(result.unit);
|
||||
return ElementLocator.locate(node);
|
||||
}
|
||||
|
||||
Future _verifyReferences(
|
||||
int offset, List<ExpectedResult> expectedMatches) async {
|
||||
List<SearchResult> results =
|
||||
await driver.search.references(testFile, offset);
|
||||
Element element, List<ExpectedResult> expectedMatches) async {
|
||||
List<SearchResult> results = await driver.search.references(element);
|
||||
_assertResults(results, expectedMatches);
|
||||
expect(results, hasLength(expectedMatches.length));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue