Use single unit/node/element.

R=brianwilkerson@google.com
BUG=

Review URL: https://codereview.chromium.org/2525693002 .
This commit is contained in:
Konstantin Shcheglov 2016-11-22 09:13:31 -08:00
parent 21b6f8904c
commit ab0a8e775f
7 changed files with 114 additions and 186 deletions

View file

@ -706,41 +706,36 @@ class AnalysisServer {
}
/**
* Returns [Element]s at the given [offset] of the given [file].
*
* May be empty if cannot be resolved, but not `null`.
* Return the [Element] at the given [offset] of the given [file], or `null`
* if there is no node at the [offset] or the node does not have an element.
*/
List<Element> getElementsAtOffset(String file, int offset) {
List<AstNode> nodes = getNodesAtOffset(file, offset);
return getElementsOfNodes(nodes);
Element getElementAtOffset(String file, int offset) {
AstNode node = getNodeAtOffset(file, offset);
return getElementOfNode(node);
}
/**
* Returns [Element]s of the given [nodes].
*
* May be empty if not resolved, but not `null`.
* Return the [Element] of the given [node], or `null` if [node] is `null` or
* does not have an element.
*/
List<Element> getElementsOfNodes(List<AstNode> nodes) {
List<Element> elements = <Element>[];
for (AstNode node in nodes) {
if (node is SimpleIdentifier && node.parent is LibraryIdentifier) {
node = node.parent;
}
if (node is LibraryIdentifier) {
node = node.parent;
}
if (node is StringLiteral && node.parent is UriBasedDirective) {
continue;
}
Element element = ElementLocator.locate(node);
if (node is SimpleIdentifier && element is PrefixElement) {
element = getImportElement(node);
}
if (element != null) {
elements.add(element);
}
Element getElementOfNode(AstNode node) {
if (node == null) {
return null;
}
return elements;
if (node is SimpleIdentifier && node.parent is LibraryIdentifier) {
node = node.parent;
}
if (node is LibraryIdentifier) {
node = node.parent;
}
if (node is StringLiteral && node.parent is UriBasedDirective) {
return null;
}
Element element = ElementLocator.locate(node);
if (node is SimpleIdentifier && element is PrefixElement) {
element = getImportElement(node);
}
return element;
}
/**
@ -770,49 +765,35 @@ class AnalysisServer {
}
/**
* Returns resolved [AstNode]s at the given [offset] of the given [file].
*
* May be empty, but not `null`.
* Return the resolved [AstNode]s at the given [offset] of the given [file],
* or `null` if there is no node as the [offset].
*/
List<AstNode> getNodesAtOffset(String file, int offset) {
List<CompilationUnit> units = getResolvedCompilationUnits(file);
List<AstNode> nodes = <AstNode>[];
for (CompilationUnit unit in units) {
AstNode node = new NodeLocator(offset).searchWithin(unit);
if (node != null) {
nodes.add(node);
}
AstNode getNodeAtOffset(String file, int offset) {
CompilationUnit unit = getResolvedCompilationUnit(file);
if (unit != null) {
return new NodeLocator(offset).searchWithin(unit);
}
return nodes;
return null;
}
/**
* Returns resolved [CompilationUnit]s of the Dart file with the given [path].
*
* May be empty, but not `null`.
* Return the resolved [CompilationUnit] for the Dart file with the given
* [path], or `null` if the file is not a Dart file or cannot be resolved.
*/
List<CompilationUnit> getResolvedCompilationUnits(String path) {
List<CompilationUnit> units = <CompilationUnit>[];
CompilationUnit getResolvedCompilationUnit(String path) {
ContextSourcePair contextSource = getContextSourcePair(path);
// prepare AnalysisContext
AnalysisContext context = contextSource.context;
if (context == null) {
return units;
return null;
}
// add a unit for each unit/library combination
runWithActiveContext(context, () {
return runWithActiveContext(context, () {
Source unitSource = contextSource.source;
List<Source> librarySources = context.getLibrariesContaining(unitSource);
for (Source librarySource in librarySources) {
CompilationUnit unit =
context.resolveCompilationUnit2(unitSource, librarySource);
if (unit != null) {
units.add(unit);
}
return context.resolveCompilationUnit2(unitSource, librarySource);
}
return null;
});
// done
return units;
}
// TODO(brianwilkerson) Add the following method after 'prioritySources' has

View file

@ -90,17 +90,17 @@ class AnalysisDomainHandler implements RequestHandler {
var params = new AnalysisGetHoverParams.fromRequest(request);
// Prepare the resolved units.
List<CompilationUnit> units;
CompilationUnit unit;
if (server.options.enableNewAnalysisDriver) {
AnalysisResult result = await server.getAnalysisResult(params.file);
units = result != null ? [result.unit] : null;
unit = result?.unit;
} else {
units = server.getResolvedCompilationUnits(params.file);
unit = server.getResolvedCompilationUnit(params.file);
}
// Prepare the hovers.
List<HoverInformation> hovers = <HoverInformation>[];
for (CompilationUnit unit in units) {
if (unit != null) {
HoverInformation hoverInformation =
new DartUnitHoverComputer(unit, params.offset).compute();
if (hoverInformation != null) {
@ -147,12 +147,11 @@ class AnalysisDomainHandler implements RequestHandler {
analysisFuture.then((AnalysisDoneReason reason) {
switch (reason) {
case AnalysisDoneReason.COMPLETE:
List<CompilationUnit> units =
server.getResolvedCompilationUnits(file);
if (units.isEmpty) {
CompilationUnit unit = server.getResolvedCompilationUnit(file);
if (unit == null) {
server.sendResponse(new Response.getNavigationInvalidFile(request));
} else {
CompilationUnitElement unitElement = units.first.element;
CompilationUnitElement unitElement = unit.element;
NavigationCollectorImpl collector = computeNavigation(
server,
unitElement.context,

View file

@ -201,27 +201,25 @@ class EditDomainHandler implements RequestHandler {
}
}
} else {
List<CompilationUnit> units = server.getResolvedCompilationUnits(file);
for (CompilationUnit unit in units) {
engine.AnalysisErrorInfo errorInfo = server.getErrors(file);
if (errorInfo != null) {
LineInfo lineInfo = errorInfo.lineInfo;
int requestLine = lineInfo.getLocation(offset).lineNumber;
for (engine.AnalysisError error in errorInfo.errors) {
int errorLine = lineInfo.getLocation(error.offset).lineNumber;
if (errorLine == requestLine) {
List<Fix> fixes = await computeFixes(server.serverPlugin,
server.resourceProvider, unit.element.context, error);
if (fixes.isNotEmpty) {
AnalysisError serverError =
newAnalysisError_fromEngine(lineInfo, error);
AnalysisErrorFixes errorFixes =
new AnalysisErrorFixes(serverError);
errorFixesList.add(errorFixes);
fixes.forEach((fix) {
errorFixes.fixes.add(fix.change);
});
}
CompilationUnit unit = server.getResolvedCompilationUnit(file);
engine.AnalysisErrorInfo errorInfo = server.getErrors(file);
if (errorInfo != null) {
LineInfo lineInfo = errorInfo.lineInfo;
int requestLine = lineInfo.getLocation(offset).lineNumber;
for (engine.AnalysisError error in errorInfo.errors) {
int errorLine = lineInfo.getLocation(error.offset).lineNumber;
if (errorLine == requestLine) {
List<Fix> fixes = await computeFixes(server.serverPlugin,
server.resourceProvider, unit.element.context, error);
if (fixes.isNotEmpty) {
AnalysisError serverError =
newAnalysisError_fromEngine(lineInfo, error);
AnalysisErrorFixes errorFixes =
new AnalysisErrorFixes(serverError);
errorFixesList.add(errorFixes);
fixes.forEach((fix) {
errorFixes.fixes.add(fix.change);
});
}
}
}
@ -286,14 +284,13 @@ class EditDomainHandler implements RequestHandler {
unit = result.unit;
errors = result.errors;
} else {
// prepare resolved units
List<CompilationUnit> units = server.getResolvedCompilationUnits(file);
if (units.isEmpty) {
// prepare resolved unit
unit = server.getResolvedCompilationUnit(file);
if (unit == null) {
server.sendResponse(new Response.fileNotAnalyzed(request, file));
return;
}
// prepare context
unit = units.first;
engine.AnalysisContext context = unit.element.context;
Source source = unit.element.source;
errors = context.computeErrors(source);
@ -400,9 +397,8 @@ class EditDomainHandler implements RequestHandler {
}
// check elements
{
List<Element> elements = server.getElementsAtOffset(file, offset);
if (elements.isNotEmpty) {
Element element = elements[0];
Element element = server.getElementAtOffset(file, offset);
if (element != null) {
// try CONVERT_METHOD_TO_GETTER
if (element is ExecutableElement) {
Refactoring refactoring =
@ -708,9 +704,8 @@ class _RefactoringManager {
}
// create a new Refactoring instance
if (kind == RefactoringKind.CONVERT_GETTER_TO_METHOD) {
List<Element> elements = server.getElementsAtOffset(file, offset);
if (elements.isNotEmpty) {
Element element = elements[0];
Element element = server.getElementAtOffset(file, offset);
if (element != null) {
if (element is ExecutableElement) {
_resetOnAnalysisStarted();
refactoring =
@ -719,9 +714,8 @@ class _RefactoringManager {
}
}
if (kind == RefactoringKind.CONVERT_METHOD_TO_GETTER) {
List<Element> elements = server.getElementsAtOffset(file, offset);
if (elements.isNotEmpty) {
Element element = elements[0];
Element element = server.getElementAtOffset(file, offset);
if (element != null) {
if (element is ExecutableElement) {
_resetOnAnalysisStarted();
refactoring =
@ -730,10 +724,10 @@ class _RefactoringManager {
}
}
if (kind == RefactoringKind.EXTRACT_LOCAL_VARIABLE) {
List<CompilationUnit> units = server.getResolvedCompilationUnits(file);
if (units.isNotEmpty) {
CompilationUnit unit = server.getResolvedCompilationUnit(file);
if (unit != null) {
_resetOnFileResolutionChanged(file);
refactoring = new ExtractLocalRefactoring(units[0], offset, length);
refactoring = new ExtractLocalRefactoring(unit, offset, length);
feedback = new ExtractLocalVariableFeedback(
<String>[], <int>[], <int>[],
coveringExpressionOffsets: <int>[],
@ -741,29 +735,27 @@ class _RefactoringManager {
}
}
if (kind == RefactoringKind.EXTRACT_METHOD) {
List<CompilationUnit> units = server.getResolvedCompilationUnits(file);
if (units.isNotEmpty) {
CompilationUnit unit = server.getResolvedCompilationUnit(file);
if (unit != null) {
_resetOnAnalysisStarted();
refactoring = new ExtractMethodRefactoring(
searchEngine, units[0], offset, length);
refactoring =
new ExtractMethodRefactoring(searchEngine, unit, offset, length);
feedback = new ExtractMethodFeedback(offset, length, '', <String>[],
false, <RefactoringMethodParameter>[], <int>[], <int>[]);
}
}
if (kind == RefactoringKind.INLINE_LOCAL_VARIABLE) {
List<CompilationUnit> units = server.getResolvedCompilationUnits(file);
if (units.isNotEmpty) {
CompilationUnit unit = server.getResolvedCompilationUnit(file);
if (unit != null) {
_resetOnFileResolutionChanged(file);
refactoring =
new InlineLocalRefactoring(searchEngine, units[0], offset);
refactoring = new InlineLocalRefactoring(searchEngine, unit, offset);
}
}
if (kind == RefactoringKind.INLINE_METHOD) {
List<CompilationUnit> units = server.getResolvedCompilationUnits(file);
if (units.isNotEmpty) {
CompilationUnit unit = server.getResolvedCompilationUnit(file);
if (unit != null) {
_resetOnAnalysisStarted();
refactoring =
new InlineMethodRefactoring(searchEngine, units[0], offset);
refactoring = new InlineMethodRefactoring(searchEngine, unit, offset);
}
}
if (kind == RefactoringKind.MOVE_FILE) {
@ -775,11 +767,9 @@ class _RefactoringManager {
server.resourceProvider, searchEngine, context, source, file);
}
if (kind == RefactoringKind.RENAME) {
List<AstNode> nodes = server.getNodesAtOffset(file, offset);
List<Element> elements = server.getElementsOfNodes(nodes);
if (nodes.isNotEmpty && elements.isNotEmpty) {
AstNode node = nodes[0];
Element element = elements[0];
AstNode node = server.getNodeAtOffset(file, offset);
Element element = server.getElementOfNode(node);
if (node != null && element != null) {
if (element is FieldFormalParameterElement) {
element = (element as FieldFormalParameterElement).field;
}

View file

@ -35,7 +35,7 @@ runWithActiveContext(AnalysisContext context, f()) {
context.isActive = false;
}
} else {
f();
return f();
}
}

View file

@ -61,39 +61,30 @@ class SearchDomainHandler implements protocol.RequestHandler {
var params =
new protocol.SearchFindElementReferencesParams.fromRequest(request);
await server.onAnalysisComplete;
// prepare elements
List<Element> elements =
server.getElementsAtOffset(params.file, params.offset);
elements = elements.map((Element element) {
if (element is ImportElement) {
return element.prefix;
}
if (element is FieldFormalParameterElement) {
return element.field;
}
if (element is PropertyAccessorElement) {
return element.variable;
}
return element;
}).where((Element element) {
return element != null;
}).toList();
// prepare element
Element element = server.getElementAtOffset(params.file, params.offset);
if (element is ImportElement) {
element = (element as ImportElement).prefix;
}
if (element is FieldFormalParameterElement) {
element = (element as FieldFormalParameterElement).field;
}
if (element is PropertyAccessorElement) {
element = (element as PropertyAccessorElement).variable;
}
// respond
String searchId = (_nextSearchId++).toString();
var result = new protocol.SearchFindElementReferencesResult();
if (elements.isNotEmpty) {
if (element != null) {
result.id = searchId;
result.element = protocol.convertElement(elements.first);
result.element = protocol.convertElement(element);
}
_sendSearchResult(request, result);
// search elements
elements.forEach((Element element) async {
var computer = new ElementReferencesComputer(searchEngine);
List<protocol.SearchResult> results =
await computer.compute(element, params.includePotential);
bool isLast = identical(element, elements.last);
_sendSearchNotification(searchId, isLast, results);
});
var computer = new ElementReferencesComputer(searchEngine);
List<protocol.SearchResult> results =
await computer.compute(element, params.includePotential);
_sendSearchNotification(searchId, true, results);
}
Future findMemberDeclarations(protocol.Request request) async {
@ -171,12 +162,11 @@ class SearchDomainHandler implements protocol.RequestHandler {
await server.onAnalysisComplete;
}
// prepare element
List<Element> elements = server.getElementsAtOffset(file, params.offset);
if (elements.isEmpty) {
Element element = server.getElementAtOffset(file, params.offset);
if (element == null) {
_sendTypeHierarchyNull(request);
return;
}
Element element = elements.first;
// maybe supertype hierarchy only
if (params.superOnly == true) {
TypeHierarchyComputer computer =

View file

@ -116,8 +116,8 @@ main() {
// unit "a" is resolved eventually
// unit "b" is not resolved
return server.onAnalysisComplete.then((_) {
expect(serverRef.getResolvedCompilationUnits(fileA), hasLength(1));
expect(serverRef.getResolvedCompilationUnits(fileB), isEmpty);
expect(serverRef.getResolvedCompilationUnit(fileA), isNotNull);
expect(serverRef.getResolvedCompilationUnit(fileB), isNull);
});
});
@ -148,8 +148,8 @@ main() {
expect(response, isResponseSuccess('0'));
// verify that unit is resolved eventually
return server.onAnalysisComplete.then((_) {
var units = serverRef.getResolvedCompilationUnits(file);
expect(units, hasLength(1));
var unit = serverRef.getResolvedCompilationUnit(file);
expect(unit, isNotNull);
});
});
@ -162,7 +162,7 @@ main() {
// Non-existence of /project_a should not prevent files in /project_b
// from being analyzed.
await server.onAnalysisComplete;
expect(serverRef.getResolvedCompilationUnits(fileB), hasLength(1));
expect(serverRef.getResolvedCompilationUnit(fileB), isNotNull);
});
test('not absolute', () async {

View file

@ -403,38 +403,6 @@ main() {
expect(searchId, isNull);
}
test_oneUnit_twoLibraries() async {
var pathA = '/project/bin/libA.dart';
var pathB = '/project/bin/libB.dart';
var codeA = '''
library lib;
part 'test.dart';
main() {
fff(1);
}
''';
var codeB = '''
library lib;
part 'test.dart';
main() {
fff(2);
}
''';
addFile(pathA, codeA);
addFile(pathB, codeB);
addTestFile('''
part of lib;
fff(p) {}
''');
await findElementReferences('fff(p) {}', false);
expect(searchElement.kind, ElementKind.FUNCTION);
expect(results, hasLength(2));
findResult(
SearchResultKind.INVOCATION, pathA, codeA.indexOf('fff(1)'), 3, true);
findResult(
SearchResultKind.INVOCATION, pathB, codeB.indexOf('fff(2)'), 3, true);
}
test_oneUnit_zeroLibraries() async {
addTestFile('''
part of lib;