Chromium Code Reviews| Index: compiler/java/com/google/dart/compiler/type/ExternalTypeAnalyzers.java | 
| diff --git a/compiler/java/com/google/dart/compiler/type/ExternalTypeAnalyzers.java b/compiler/java/com/google/dart/compiler/type/ExternalTypeAnalyzers.java | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..cd4ce8cd488900318ddbc2639da2529c1e3a4f24 | 
| --- /dev/null | 
| +++ b/compiler/java/com/google/dart/compiler/type/ExternalTypeAnalyzers.java | 
| @@ -0,0 +1,175 @@ | 
| +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 
| +// for details. All rights reserved. Use of this source code is governed by a | 
| +// BSD-style license that can be found in the LICENSE file. | 
| + | 
| +package com.google.dart.compiler.type; | 
| + | 
| +import com.google.common.collect.Maps; | 
| +import com.google.dart.compiler.ast.DartExpression; | 
| +import com.google.dart.compiler.ast.DartMethodInvocation; | 
| +import com.google.dart.compiler.ast.DartStringLiteral; | 
| +import com.google.dart.compiler.ast.DartUnqualifiedInvocation; | 
| +import com.google.dart.compiler.resolver.Element; | 
| +import com.google.dart.compiler.resolver.ElementKind; | 
| +import com.google.dart.compiler.resolver.Elements; | 
| +import com.google.dart.compiler.resolver.EnclosingElement; | 
| +import com.google.dart.compiler.resolver.LibraryElement; | 
| +import com.google.dart.compiler.util.apache.StringUtils; | 
| + | 
| +import java.util.List; | 
| +import java.util.Map; | 
| + | 
| +/** | 
| + * Provides type information which can not be inferred from source itself. | 
| 
 
Brian Wilkerson
2012/08/01 17:45:46
nit: "can not" --> "cannot", here and below
 
 | 
| + */ | 
| +public class ExternalTypeAnalyzers { | 
| + private static final Map<String, String> tagToElementType = Maps.newHashMap(); | 
| + static { | 
| + tagToElementType.put("A", "AnchorElement"); | 
| + tagToElementType.put("AREA", "AreaElement"); | 
| + tagToElementType.put("BR", "BRElement"); | 
| + tagToElementType.put("BASE", "BaseElement"); | 
| + tagToElementType.put("BODY", "BodyElement"); | 
| + tagToElementType.put("BUTTON", "ButtonElement"); | 
| + tagToElementType.put("CANVAS", "CanvasElement"); | 
| + tagToElementType.put("DL", "DListElement"); | 
| + tagToElementType.put("DETAILS", "DetailsElement"); | 
| + tagToElementType.put("DIV", "DivElement"); | 
| + tagToElementType.put("EMBED", "EmbedElement"); | 
| + tagToElementType.put("FIELDSET", "FieldSetElement"); | 
| + tagToElementType.put("FORM", "FormElement"); | 
| + tagToElementType.put("HR", "HRElement"); | 
| + tagToElementType.put("HEAD", "HeadElement"); | 
| + tagToElementType.put("H1", "HeadingElement"); | 
| + tagToElementType.put("H2", "HeadingElement"); | 
| + tagToElementType.put("H3", "HeadingElement"); | 
| + tagToElementType.put("H4", "HeadingElement"); | 
| + tagToElementType.put("H5", "HeadingElement"); | 
| + tagToElementType.put("H6", "HeadingElement"); | 
| + tagToElementType.put("HTML", "HtmlElement"); | 
| + tagToElementType.put("IFRAME", "IFrameElement"); | 
| + tagToElementType.put("IMG", "ImageElement"); | 
| + tagToElementType.put("INPUT", "InputElement"); | 
| + tagToElementType.put("KEYGEN", "KeygenElement"); | 
| + tagToElementType.put("LI", "LIElement"); | 
| + tagToElementType.put("LABEL", "LabelElement"); | 
| + tagToElementType.put("LEGEND", "LegendElement"); | 
| + tagToElementType.put("LINK", "LinkElement"); | 
| + tagToElementType.put("MAP", "MapElement"); | 
| + tagToElementType.put("MENU", "MenuElement"); | 
| + tagToElementType.put("METER", "MeterElement"); | 
| + tagToElementType.put("OL", "OListElement"); | 
| + tagToElementType.put("OBJECT", "ObjectElement"); | 
| + tagToElementType.put("OPTGROUP", "OptGroupElement"); | 
| + tagToElementType.put("OUTPUT", "OutputElement"); | 
| + tagToElementType.put("P", "ParagraphElement"); | 
| + tagToElementType.put("PARAM", "ParamElement"); | 
| + tagToElementType.put("PRE", "PreElement"); | 
| + tagToElementType.put("PROGRESS", "ProgressElement"); | 
| + tagToElementType.put("SCRIPT", "ScriptElement"); | 
| + tagToElementType.put("SOURCE", "SourceElement"); | 
| + tagToElementType.put("SPAN", "SpanElement"); | 
| + tagToElementType.put("STYLE", "StyleElement"); | 
| + tagToElementType.put("CAPTION", "TableCaptionElement"); | 
| + tagToElementType.put("TD", "TableCellElement"); | 
| + tagToElementType.put("COL", "TableColElement"); | 
| + tagToElementType.put("TABLE", "TableElement"); | 
| + tagToElementType.put("TR", "TableRowElement"); | 
| + tagToElementType.put("TEXTAREA", "TextAreaElement"); | 
| + tagToElementType.put("TITLE", "TitleElement"); | 
| + tagToElementType.put("TRACK", "TrackElement"); | 
| + tagToElementType.put("UL", "UListElement"); | 
| + tagToElementType.put("VIDEO", "VideoElement"); | 
| + tagToElementType.put("DART_EDITOR_NO_SUCH_TYPE", "DartEditorNoSuchElement"); | 
| + } | 
| + | 
| + /** | 
| + * Attempts to make better guess about return type of invocation. | 
| + * | 
| + * @return the better {@link Type} guess, may be "defaultType" if can not make better guess. | 
| + */ | 
| + public static Type resolve(Types types, DartUnqualifiedInvocation invocation, Element element, | 
| + Type defaultType) { | 
| + if (element == null) { | 
| + return defaultType; | 
| + } | 
| + String name = element.getName(); | 
| + List<DartExpression> arguments = invocation.getArguments(); | 
| + LibraryElement libraryElement = Elements.getDeclaringLibrary(element); | 
| + // html.query(String) | 
| + if ("query".equals(name) && isHtmlLibraryFunction(element)) { | 
| + return analyzeQuery(arguments, libraryElement, defaultType); | 
| + } | 
| + // no guess | 
| + return defaultType; | 
| + } | 
| + | 
| + /** | 
| + * Attempts to make better guess about return type of invocation. | 
| + * | 
| + * @return the better {@link Type} guess, may be "defaultType" if can not make better guess. | 
| + */ | 
| + public static Type resolve(Types types, DartMethodInvocation invocation, Element element, | 
| + Type defaultType) { | 
| + if (element == null) { | 
| + return defaultType; | 
| + } | 
| + String name = element.getName(); | 
| + List<DartExpression> arguments = invocation.getArguments(); | 
| + LibraryElement libraryElement = Elements.getDeclaringLibrary(element); | 
| + // NodeSelector.query(String) | 
| + EnclosingElement enclosingElement = element.getEnclosingElement(); | 
| + if ("query".equals(name) && isDeclaredInHtmlLibrary(element) | 
| + && ElementKind.of(enclosingElement) == ElementKind.CLASS | 
| + && "NodeSelector".equals(enclosingElement.getName())) { | 
| + return analyzeQuery(arguments, libraryElement, defaultType); | 
| + } | 
| + // no guess | 
| + return defaultType; | 
| + } | 
| + | 
| + private static Type analyzeQuery(List<DartExpression> arguments, LibraryElement libraryElement, | 
| + Type defaultType) { | 
| + if (arguments.size() == 1 && arguments.get(0) instanceof DartStringLiteral) { | 
| + String selectors = ((DartStringLiteral) arguments.get(0)).getValue(); | 
| + // if has spaces, full parsing required, because may be: E[text='warning text'] | 
| + if (selectors.contains(" ")) { | 
| + return defaultType; | 
| + } | 
| + // try to extract tag | 
| + // http://www.w3.org/TR/CSS2/selector.html | 
| + String tag = selectors; | 
| + tag = StringUtils.substringBefore(tag, ":"); | 
| + tag = StringUtils.substringBefore(tag, "["); | 
| + tag = StringUtils.substringBefore(tag, "."); | 
| + tag = StringUtils.substringBefore(tag, "#"); | 
| + tag = tag.toUpperCase(); | 
| + // prepare Element type name | 
| + String tagTypeName = tagToElementType.get(tag); | 
| + if (tagTypeName == null) { | 
| + return defaultType; | 
| + } | 
| + // lookup tag Element | 
| + Element tagTypeElement = libraryElement.lookupLocalElement(tagTypeName); | 
| + if (tagTypeElement == null) { | 
| + return defaultType; | 
| + } | 
| + // OK, we know more specific return type | 
| + Type tagType = tagTypeElement.getType(); | 
| + if (tagType != null) { | 
| + return tagType; | 
| + } | 
| + } | 
| + // no guess | 
| + return defaultType; | 
| + } | 
| + | 
| + private static boolean isHtmlLibraryFunction(Element element) { | 
| + return ElementKind.of(element) == ElementKind.METHOD && isDeclaredInHtmlLibrary(element); | 
| + } | 
| + | 
| + private static boolean isDeclaredInHtmlLibrary(Element element) { | 
| + LibraryElement libraryElement = Elements.getDeclaringLibrary(element); | 
| + return StringUtils.startsWith(libraryElement.getName(), "dart://html"); | 
| + } | 
| +} |