| Index: pkg/compiler/lib/src/resolution/resolution_strategy.dart
|
| diff --git a/pkg/compiler/lib/src/resolution/resolution_strategy.dart b/pkg/compiler/lib/src/resolution/resolution_strategy.dart
|
| index d9eb53f5bf92f319fc095e9cfb567e1b8eb2e5f8..6fadb4e2bb6f1c989707e34d3a2492a99133073d 100644
|
| --- a/pkg/compiler/lib/src/resolution/resolution_strategy.dart
|
| +++ b/pkg/compiler/lib/src/resolution/resolution_strategy.dart
|
| @@ -4,6 +4,8 @@
|
|
|
| library dart2js.resolution_strategy;
|
|
|
| +import 'package:front_end/src/fasta/scanner.dart' show Token;
|
| +
|
| import '../common.dart';
|
| import '../common_elements.dart';
|
| import '../common/backend_api.dart';
|
| @@ -31,6 +33,7 @@ import '../js_backend/native_data.dart';
|
| import '../js_backend/no_such_method_registry.dart';
|
| import '../library_loader.dart';
|
| import '../native/resolver.dart';
|
| +import '../tree/tree.dart' show Node;
|
| import '../serialization/task.dart';
|
| import '../patch_parser.dart';
|
| import '../resolved_uri_translator.dart';
|
| @@ -212,6 +215,155 @@ class ResolutionFrontEndStrategy implements FrontEndStrategy {
|
| }
|
| return mainMethod;
|
| }
|
| +
|
| + SourceSpan spanFromToken(Element currentElement, Token token) =>
|
| + _spanFromTokens(currentElement, token, token);
|
| +
|
| + SourceSpan _spanFromTokens(Element currentElement, Token begin, Token end,
|
| + [Uri uri]) {
|
| + if (begin == null || end == null) {
|
| + // TODO(ahe): We can almost always do better. Often it is only
|
| + // end that is null. Otherwise, we probably know the current
|
| + // URI.
|
| + throw 'Cannot find tokens to produce error message.';
|
| + }
|
| + if (uri == null && currentElement != null) {
|
| + if (currentElement is! Element) {
|
| + throw 'Can only find tokens from an Element.';
|
| + }
|
| + Element element = currentElement;
|
| + uri = element.compilationUnit.script.resourceUri;
|
| + assert(invariant(currentElement, () {
|
| + bool sameToken(Token token, Token sought) {
|
| + if (token == sought) return true;
|
| + if (token.stringValue == '>>') {
|
| + // `>>` is converted to `>` in the parser when needed.
|
| + return sought.stringValue == '>' &&
|
| + token.charOffset <= sought.charOffset &&
|
| + sought.charOffset < token.charEnd;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + /// Check that [begin] and [end] can be found between [from] and [to].
|
| + validateToken(Token from, Token to) {
|
| + if (from == null || to == null) return true;
|
| + bool foundBegin = false;
|
| + bool foundEnd = false;
|
| + Token token = from;
|
| + while (true) {
|
| + if (sameToken(token, begin)) {
|
| + foundBegin = true;
|
| + }
|
| + if (sameToken(token, end)) {
|
| + foundEnd = true;
|
| + }
|
| + if (foundBegin && foundEnd) {
|
| + return true;
|
| + }
|
| + if (token == to || token == token.next || token.next == null) {
|
| + break;
|
| + }
|
| + token = token.next;
|
| + }
|
| +
|
| + // Create a good message for when the tokens were not found.
|
| + StringBuffer sb = new StringBuffer();
|
| + sb.write('Invalid current element: $element. ');
|
| + sb.write('Looking for ');
|
| + sb.write('[${begin} (${begin.hashCode}),');
|
| + sb.write('${end} (${end.hashCode})] in');
|
| +
|
| + token = from;
|
| + while (true) {
|
| + sb.write('\n ${token} (${token.hashCode})');
|
| + if (token == to || token == token.next || token.next == null) {
|
| + break;
|
| + }
|
| + token = token.next;
|
| + }
|
| + return sb.toString();
|
| + }
|
| +
|
| + if (element.enclosingClass != null &&
|
| + element.enclosingClass.isEnumClass) {
|
| + // Enums ASTs are synthesized (and give messed up messages).
|
| + return true;
|
| + }
|
| +
|
| + if (element is AstElement) {
|
| + AstElement astElement = element;
|
| + if (astElement.hasNode) {
|
| + Token from = astElement.node.getBeginToken();
|
| + Token to = astElement.node.getEndToken();
|
| + if (astElement.metadata.isNotEmpty) {
|
| + if (!astElement.metadata.first.hasNode) {
|
| + // We might try to report an error while parsing the metadata
|
| + // itself.
|
| + return true;
|
| + }
|
| + from = astElement.metadata.first.node.getBeginToken();
|
| + }
|
| + return validateToken(from, to);
|
| + }
|
| + }
|
| + return true;
|
| + }, message: "Invalid current element: $element [$begin,$end]."));
|
| + }
|
| + return new SourceSpan.fromTokens(uri, begin, end);
|
| + }
|
| +
|
| + SourceSpan _spanFromNode(Element currentElement, Node node) {
|
| + return _spanFromTokens(
|
| + currentElement, node.getBeginToken(), node.getPrefixEndToken());
|
| + }
|
| +
|
| + SourceSpan _spanFromElement(Element currentElement, Element element) {
|
| + if (element != null && element.sourcePosition != null) {
|
| + return element.sourcePosition;
|
| + }
|
| + while (element != null && element.isSynthesized) {
|
| + element = element.enclosingElement;
|
| + }
|
| + if (element != null &&
|
| + element.sourcePosition == null &&
|
| + !element.isLibrary &&
|
| + !element.isCompilationUnit) {
|
| + // Sometimes, the backend fakes up elements that have no
|
| + // position. So we use the enclosing element instead. It is
|
| + // not a good error location, but cancel really is "internal
|
| + // error" or "not implemented yet", so the vicinity is good
|
| + // enough for now.
|
| + element = element.enclosingElement;
|
| + // TODO(ahe): I plan to overhaul this infrastructure anyways.
|
| + }
|
| + if (element == null) {
|
| + element = currentElement;
|
| + }
|
| + if (element == null) {
|
| + return null;
|
| + }
|
| +
|
| + if (element.sourcePosition != null) {
|
| + return element.sourcePosition;
|
| + }
|
| + Token position = element.position;
|
| + Uri uri = element.compilationUnit.script.resourceUri;
|
| + return (position == null)
|
| + ? new SourceSpan(uri, 0, 0)
|
| + : _spanFromTokens(currentElement, position, position, uri);
|
| + }
|
| +
|
| + SourceSpan spanFromSpannable(Spannable node, Entity currentElement) {
|
| + if (node is Node) {
|
| + return _spanFromNode(currentElement, node);
|
| + } else if (node is Element) {
|
| + return _spanFromElement(currentElement, node);
|
| + } else if (node is MetadataAnnotation) {
|
| + return node.sourcePosition;
|
| + }
|
| + return null;
|
| + }
|
| }
|
|
|
| /// An element environment base on a [Compiler].
|
|
|