mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 04:06:59 +00:00
Implement Search.declarations().
R=brianwilkerson@google.com Change-Id: Id14cf6c1f4cbf51fa8398d257515b96ee3b0d4a6 Reviewed-on: https://dart-review.googlesource.com/42181 Commit-Queue: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
2d851eb444
commit
00225dedfe
|
@ -25,6 +25,40 @@ Element _getEnclosingElement(CompilationUnitElement unitElement, int offset) {
|
|||
return finder.containingElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* An element declaration.
|
||||
*/
|
||||
class Declaration {
|
||||
final int fileIndex;
|
||||
final String name;
|
||||
final DeclarationKind kind;
|
||||
final int offset;
|
||||
final int line;
|
||||
final int column;
|
||||
final String className;
|
||||
|
||||
Declaration(this.fileIndex, this.name, this.kind, this.offset, this.line,
|
||||
this.column, this.className);
|
||||
}
|
||||
|
||||
/**
|
||||
* The kind of a [Declaration].
|
||||
*/
|
||||
enum DeclarationKind {
|
||||
CLASS,
|
||||
CLASS_TYPE_ALIAS,
|
||||
CONSTRUCTOR,
|
||||
ENUM,
|
||||
ENUM_CONSTANT,
|
||||
FIELD,
|
||||
FUNCTION,
|
||||
FUNCTION_TYPE_ALIAS,
|
||||
GETTER,
|
||||
METHOD,
|
||||
SETTER,
|
||||
VARIABLE
|
||||
}
|
||||
|
||||
/**
|
||||
* Search support for an [AnalysisDriver].
|
||||
*/
|
||||
|
@ -59,6 +93,104 @@ class Search {
|
|||
return elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return top-level and class member declarations.
|
||||
*
|
||||
* The path of each file with at least one declaration is added to [files].
|
||||
* The list is for searched, there might be duplicates, but this is OK,
|
||||
* we just want reduce amount of data, not to make it absolute minimum.
|
||||
*/
|
||||
Future<List<Declaration>> declarations(List<String> files) async {
|
||||
List<Declaration> declarations = <Declaration>[];
|
||||
|
||||
DeclarationKind getExecutableKind(
|
||||
UnlinkedExecutable executable, bool topLevel) {
|
||||
switch (executable.kind) {
|
||||
case UnlinkedExecutableKind.constructor:
|
||||
return DeclarationKind.CONSTRUCTOR;
|
||||
case UnlinkedExecutableKind.functionOrMethod:
|
||||
if (topLevel) {
|
||||
return DeclarationKind.FUNCTION;
|
||||
}
|
||||
return DeclarationKind.METHOD;
|
||||
case UnlinkedExecutableKind.getter:
|
||||
return DeclarationKind.GETTER;
|
||||
break;
|
||||
default:
|
||||
return DeclarationKind.SETTER;
|
||||
}
|
||||
}
|
||||
|
||||
for (String path in _driver.addedFiles) {
|
||||
FileState file = _driver.fsState.getFileForPath(path);
|
||||
int fileIndex;
|
||||
|
||||
void addDeclaration(String name, DeclarationKind kind, int offset,
|
||||
[String className]) {
|
||||
if (fileIndex == null) {
|
||||
fileIndex = files.length;
|
||||
files.add(file.path);
|
||||
}
|
||||
if (name.endsWith('=')) {
|
||||
name = name.substring(0, name.length - 1);
|
||||
}
|
||||
var location = file.lineInfo.getLocation(offset);
|
||||
declarations.add(new Declaration(fileIndex, name, kind, offset,
|
||||
location.lineNumber, location.columnNumber, className));
|
||||
}
|
||||
|
||||
for (var class_ in file.unlinked.classes) {
|
||||
String className = class_.name;
|
||||
addDeclaration(
|
||||
className,
|
||||
class_.isMixinApplication
|
||||
? DeclarationKind.CLASS_TYPE_ALIAS
|
||||
: DeclarationKind.CLASS,
|
||||
class_.nameOffset);
|
||||
|
||||
for (var field in class_.fields) {
|
||||
addDeclaration(
|
||||
field.name, DeclarationKind.FIELD, field.nameOffset, className);
|
||||
}
|
||||
|
||||
for (var executable in class_.executables) {
|
||||
if (executable.name.isNotEmpty) {
|
||||
addDeclaration(
|
||||
executable.name,
|
||||
getExecutableKind(executable, false),
|
||||
executable.nameOffset,
|
||||
className);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var enum_ in file.unlinked.enums) {
|
||||
addDeclaration(enum_.name, DeclarationKind.ENUM, enum_.nameOffset);
|
||||
for (var value in enum_.values) {
|
||||
addDeclaration(
|
||||
value.name, DeclarationKind.ENUM_CONSTANT, value.nameOffset);
|
||||
}
|
||||
}
|
||||
|
||||
for (var executable in file.unlinked.executables) {
|
||||
addDeclaration(executable.name, getExecutableKind(executable, true),
|
||||
executable.nameOffset);
|
||||
}
|
||||
|
||||
for (var typedef_ in file.unlinked.typedefs) {
|
||||
addDeclaration(typedef_.name, DeclarationKind.FUNCTION_TYPE_ALIAS,
|
||||
typedef_.nameOffset);
|
||||
}
|
||||
|
||||
for (var variable in file.unlinked.variables) {
|
||||
addDeclaration(
|
||||
variable.name, DeclarationKind.VARIABLE, variable.nameOffset);
|
||||
}
|
||||
}
|
||||
|
||||
return declarations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns references to the [element].
|
||||
*/
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart' hide Declaration;
|
||||
import 'package:analyzer/dart/ast/standard_resolution_map.dart';
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/analysis/driver.dart';
|
||||
|
@ -98,6 +98,71 @@ import 'not-dart.txt';
|
|||
expect(await driver.search.classMembers('test'), isEmpty);
|
||||
}
|
||||
|
||||
test_declarations_class() async {
|
||||
await _resolveTestUnit('''
|
||||
class C {
|
||||
int f;
|
||||
C();
|
||||
C.named();
|
||||
int get g => 0;
|
||||
void set s(_) {}
|
||||
void m() {}
|
||||
}
|
||||
''');
|
||||
var files = <String>[];
|
||||
List<Declaration> declarations = await driver.search.declarations(files);
|
||||
_assertHasDeclaration(declarations, 'C', DeclarationKind.CLASS, 6);
|
||||
_assertHasDeclaration(declarations, 'f', DeclarationKind.FIELD, 16, 'C');
|
||||
_assertHasDeclaration(
|
||||
declarations, 'named', DeclarationKind.CONSTRUCTOR, 30, 'C');
|
||||
_assertHasDeclaration(declarations, 'g', DeclarationKind.GETTER, 49, 'C');
|
||||
_assertHasDeclaration(declarations, 's', DeclarationKind.SETTER, 68, 'C');
|
||||
_assertHasDeclaration(declarations, 'm', DeclarationKind.METHOD, 83, 'C');
|
||||
}
|
||||
|
||||
test_declarations_enum() async {
|
||||
await _resolveTestUnit('''
|
||||
enum E {
|
||||
a, b, c
|
||||
}
|
||||
''');
|
||||
var files = <String>[];
|
||||
List<Declaration> declarations = await driver.search.declarations(files);
|
||||
_assertHasDeclaration(declarations, 'E', DeclarationKind.ENUM, 5);
|
||||
_assertHasDeclaration(declarations, 'a', DeclarationKind.ENUM_CONSTANT, 11);
|
||||
_assertHasDeclaration(declarations, 'b', DeclarationKind.ENUM_CONSTANT, 14);
|
||||
_assertHasDeclaration(declarations, 'c', DeclarationKind.ENUM_CONSTANT, 17);
|
||||
}
|
||||
|
||||
test_declarations_top() async {
|
||||
await _resolveTestUnit('''
|
||||
int get g => 0;
|
||||
void set s(_) {}
|
||||
void f(int p) {}
|
||||
int v;
|
||||
typedef void tf1();
|
||||
typedef tf2<T> = int Function<S>(T tp, S sp);
|
||||
''');
|
||||
var files = <String>[];
|
||||
List<Declaration> declarations = await driver.search.declarations(files);
|
||||
_assertHasDeclaration(declarations, 'g', DeclarationKind.GETTER, 8);
|
||||
_assertHasDeclaration(declarations, 's', DeclarationKind.SETTER, 25);
|
||||
_assertHasDeclaration(declarations, 'f', DeclarationKind.FUNCTION, 38);
|
||||
_assertHasDeclaration(declarations, 'v', DeclarationKind.VARIABLE, 54);
|
||||
_assertHasDeclaration(
|
||||
declarations, 'tf1', DeclarationKind.FUNCTION_TYPE_ALIAS, 70);
|
||||
_assertHasDeclaration(
|
||||
declarations, 'tf2', DeclarationKind.FUNCTION_TYPE_ALIAS, 85);
|
||||
// No declaration for type variables.
|
||||
_assertNoDeclaration(declarations, 'T');
|
||||
_assertNoDeclaration(declarations, 'S');
|
||||
// No declarations for parameters.
|
||||
_assertNoDeclaration(declarations, '_');
|
||||
_assertNoDeclaration(declarations, 'p');
|
||||
_assertNoDeclaration(declarations, 'tp');
|
||||
_assertNoDeclaration(declarations, 'sp');
|
||||
}
|
||||
|
||||
test_searchMemberReferences_qualified_resolved() async {
|
||||
await _resolveTestUnit('''
|
||||
class C {
|
||||
|
@ -1183,6 +1248,32 @@ class NoMatchABCDE {}
|
|||
unorderedEquals([a, b, c, d, e]));
|
||||
}
|
||||
|
||||
void _assertHasDeclaration(List<Declaration> declarations, String name,
|
||||
DeclarationKind kind, int offset,
|
||||
[String className]) {
|
||||
for (var declaration in declarations) {
|
||||
if (declaration.name == name &&
|
||||
declaration.kind == kind &&
|
||||
declaration.offset == offset &&
|
||||
declaration.className == className) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var actual = declarations
|
||||
.map((d) => '(name=${d.name}, kind=${d.kind}, offset=${d.offset})')
|
||||
.join('\n');
|
||||
fail(
|
||||
'Exected to find (name=$name, kind=$kind, offset=$offset) in\n$actual');
|
||||
}
|
||||
|
||||
void _assertNoDeclaration(List<Declaration> declarations, String name) {
|
||||
for (var declaration in declarations) {
|
||||
if (declaration.name == name) {
|
||||
fail('Unexpected declaration $name');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExpectedResult _expectId(
|
||||
Element enclosingElement, SearchResultKind kind, String search,
|
||||
{int length, bool isResolved: true, bool isQualified: false}) {
|
||||
|
|
Loading…
Reference in a new issue