New NodeLocator which uses positions of characters, not between them.

R=brianwilkerson@google.com
BUG=

Review URL: https://codereview.chromium.org/1490933002 .
This commit is contained in:
Konstantin Shcheglov
2015-12-01 13:59:11 -08:00
parent 6fc5018282
commit 1b9c263b56
3 changed files with 135 additions and 9 deletions
+89
View File
@@ -12945,6 +12945,95 @@ class NodeLocator extends UnifyingAstVisitor<Object> {
}
}
/**
* An object used to locate the [AstNode] associated with a source range.
* More specifically, they will return the deepest [AstNode] which completely
* encompasses the specified range.
*/
class NodeLocator2 extends UnifyingAstVisitor<Object> {
/**
* The inclusive start offset of the range used to identify the node.
*/
int _startOffset = 0;
/**
* The inclusive end offset of the range used to identify the node.
*/
int _endOffset = 0;
/**
* The found node or `null` if there is no such node.
*/
AstNode _foundNode;
/**
* Initialize a newly created locator to locate the deepest [AstNode] for
* which `node.offset <= [startOffset]` and `[endOffset] < node.end`.
*
* If [endOffset] is not provided, then it is considered the same as the
* given [startOffset].
*/
NodeLocator2(int startOffset, [int endOffset])
: this._startOffset = startOffset,
this._endOffset = endOffset == null ? startOffset : endOffset;
/**
* Search within the given AST [node] and return the node that was found,
* or `null` if no node was found.
*/
AstNode searchWithin(AstNode node) {
if (node == null) {
return null;
}
try {
node.accept(this);
} on NodeLocator_NodeFoundException {} catch (exception, stackTrace) {
AnalysisEngine.instance.logger.logInformation(
"Unable to locate element at offset ($_startOffset - $_endOffset)",
new CaughtException(exception, stackTrace));
return null;
}
return _foundNode;
}
@override
Object visitNode(AstNode node) {
Token beginToken = node.beginToken;
Token endToken = node.endToken;
// Don't include synthetic tokens.
while (endToken != beginToken) {
if (endToken.type == TokenType.EOF || !endToken.isSynthetic) {
break;
}
endToken = endToken.previous;
}
int end = endToken.end;
int start = node.offset;
if (end <= _startOffset) {
return null;
}
if (start > _endOffset) {
return null;
}
try {
node.visitChildren(this);
} on NodeLocator_NodeFoundException {
rethrow;
} catch (exception, stackTrace) {
// Ignore the exception and proceed in order to visit the rest of the
// structure.
AnalysisEngine.instance.logger.logInformation(
"Exception caught while traversing an AST structure.",
new CaughtException(exception, stackTrace));
}
if (start <= _startOffset && _endOffset < end) {
_foundNode = node;
throw new NodeLocator_NodeFoundException();
}
return null;
}
}
/**
* An exception used by [NodeLocator] to cancel visiting after a node has been
* found.
+1 -9
View File
@@ -2953,15 +2953,7 @@ abstract class InferStaticVariableTask extends ConstantEvaluationAnalysisTask {
*/
VariableDeclaration getDeclaration(CompilationUnit unit) {
VariableElement variable = target;
// Usually: Type ^name = ...
// Sometimes there is no space after the type: List<Type>^name = ...
// So, we need to use an offset within (or right after) the name:
// Type n^ame =
// List<Type>n^ame =
// Type x^=
int searchOffset = variable.nameOffset + 1;
NodeLocator locator = new NodeLocator(searchOffset);
AstNode node = locator.searchWithin(unit);
AstNode node = new NodeLocator2(variable.nameOffset).searchWithin(unit);
VariableDeclaration declaration =
node.getAncestor((AstNode ancestor) => ancestor is VariableDeclaration);
if (declaration == null || declaration.name != node) {
+45
View File
@@ -29,6 +29,7 @@ main() {
runReflectiveTests(IndexExpressionTest);
runReflectiveTests(NodeListTest);
runReflectiveTests(NodeLocatorTest);
runReflectiveTests(NodeLocator2Test);
runReflectiveTests(SimpleIdentifierTest);
runReflectiveTests(SimpleStringLiteralTest);
runReflectiveTests(StringInterpolationTest);
@@ -944,6 +945,50 @@ class NodeListTest extends EngineTestCase {
}
}
@reflectiveTest
class NodeLocator2Test extends ParserTestCase {
void test_onlyStartOffset() {
String code = ' int vv; ';
// 012345678
CompilationUnit unit = ParserTestCase.parseCompilationUnit(code);
TopLevelVariableDeclaration declaration = unit.declarations[0];
VariableDeclarationList variableList = declaration.variables;
Identifier typeName = variableList.type.name;
SimpleIdentifier varName = variableList.variables[0].name;
expect(new NodeLocator2(0).searchWithin(unit), same(unit));
expect(new NodeLocator2(1).searchWithin(unit), same(typeName));
expect(new NodeLocator2(2).searchWithin(unit), same(typeName));
expect(new NodeLocator2(3).searchWithin(unit), same(typeName));
expect(new NodeLocator2(4).searchWithin(unit), same(variableList));
expect(new NodeLocator2(5).searchWithin(unit), same(varName));
expect(new NodeLocator2(6).searchWithin(unit), same(varName));
expect(new NodeLocator2(7).searchWithin(unit), same(declaration));
expect(new NodeLocator2(8).searchWithin(unit), same(unit));
expect(new NodeLocator2(9).searchWithin(unit), isNull);
expect(new NodeLocator2(100).searchWithin(unit), isNull);
}
void test_startEndOffset() {
String code = ' int vv; ';
// 012345678
CompilationUnit unit = ParserTestCase.parseCompilationUnit(code);
TopLevelVariableDeclaration declaration = unit.declarations[0];
VariableDeclarationList variableList = declaration.variables;
Identifier typeName = variableList.type.name;
SimpleIdentifier varName = variableList.variables[0].name;
expect(new NodeLocator2(-1, 2).searchWithin(unit), isNull);
expect(new NodeLocator2(0, 2).searchWithin(unit), same(unit));
expect(new NodeLocator2(1, 2).searchWithin(unit), same(typeName));
expect(new NodeLocator2(1, 3).searchWithin(unit), same(typeName));
expect(new NodeLocator2(1, 4).searchWithin(unit), same(variableList));
expect(new NodeLocator2(5, 6).searchWithin(unit), same(varName));
expect(new NodeLocator2(5, 7).searchWithin(unit), same(declaration));
expect(new NodeLocator2(5, 8).searchWithin(unit), same(unit));
expect(new NodeLocator2(5, 100).searchWithin(unit), isNull);
expect(new NodeLocator2(100, 200).searchWithin(unit), isNull);
}
}
@reflectiveTest
class NodeLocatorTest extends ParserTestCase {
void test_range() {