Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(289)

Unified Diff: sdk/lib/_internal/compiler/implementation/native_handler.dart

Issue 11299220: Add @JSName annotation for native fields and methods. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/compiler/implementation/native_handler.dart
diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart
index ee8c27794ef7da39997b42f1e5275e55de82eb3c..124c173dd0ea642af88b82047b89608865fb6639 100644
--- a/sdk/lib/_internal/compiler/implementation/native_handler.dart
+++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart
@@ -35,15 +35,18 @@ class NativeEnqueuer {
/// Initial entry point to native enqueuer.
void processNativeClasses(Collection<LibraryElement> libraries) {}
+ /// Notification of a main Enqueuer worklist element. For methods, adds
+ /// information from metadata attributes, and computes types instantiated due
+ /// to calling the method.
void registerElement(Element element) {}
- /// Method is a member of a native class.
- void registerMethod(Element method) {}
+ /// Notification of native field. Adds information from metadata attributes.
+ void registerField(Element field) {}
- /// Compute types instantiated due to getting a native field.
+ /// Computes types instantiated due to getting a native field.
void registerFieldLoad(Element field) {}
- /// Compute types instantiated due to setting a native field.
+ /// Computes types instantiated due to setting a native field.
void registerFieldStore(Element field) {}
/**
@@ -93,6 +96,7 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer {
ClassElement _annotationCreatesClass;
ClassElement _annotationReturnsClass;
+ ClassElement _annotationJsNameClass;
/// Subclasses of [NativeEnqueuerBase] are constructed by the backend.
NativeEnqueuerBase(this.world, this.compiler, this.enableLiveTypeAnalysis);
@@ -122,16 +126,22 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer {
}
ClassElement get annotationCreatesClass {
- if (_annotationCreatesClass == null) findAnnotationClasses();
+ findAnnotationClasses();
return _annotationCreatesClass;
}
ClassElement get annotationReturnsClass {
- if (_annotationReturnsClass == null) findAnnotationClasses();
+ findAnnotationClasses();
return _annotationReturnsClass;
}
+ ClassElement get annotationJsNameClass {
+ findAnnotationClasses();
+ return _annotationJsNameClass;
+ }
+
void findAnnotationClasses() {
+ if (_annotationCreatesClass != null) return;
ClassElement find(name) {
Element e = compiler.findHelper(name);
if (e == null || e is! ClassElement) {
@@ -141,8 +151,41 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer {
}
_annotationCreatesClass = find(const SourceString('Creates'));
_annotationReturnsClass = find(const SourceString('Returns'));
+ _annotationJsNameClass = find(const SourceString('JSName'));
}
+ /// Returns the JSName annotation string or `null` if no JSName annotation is
+ /// present.
+ String findJsNameFromAnnotation(Element element) {
ahe 2012/11/29 09:19:26 This file should be deleted when we get rid of the
+ String name = null;
+ ClassElement annotationClass = annotationJsNameClass;
+ for (Link<MetadataAnnotation> link = element.metadata;
+ !link.isEmpty;
+ link = link.tail) {
+ MetadataAnnotation annotation = link.head.ensureResolved(compiler);
ahe 2012/11/29 09:19:26 I'm think we should make this an operation on elem
+ var value = annotation.value;
+ if (value is! ConstructedConstant) continue;
+ if (value.type is! InterfaceType) continue;
+ if (!identical(value.type.element, annotationClass)) continue;
+
+ var fields = value.fields;
+ // TODO(sra): Better validation of the constant.
ahe 2012/11/29 09:19:26 The constant will be validated in checked mode. W
+ if (fields.length != 1 || fields[0] is! StringConstant) {
+ PartialMetadataAnnotation partial = annotation;
+ compiler.cancel(
+ 'Annotations needs one string: ${partial.parseNode(compiler)}');
ahe 2012/11/29 09:19:26 This should be: compiler.internalError('Annotatio
sra1 2012/12/04 01:31:31 This would be sufficient for Issue 7007.
+ }
+ String specString = fields[0].toDartString().slowToString();
+ if (name == null) {
+ name = specString;
+ } else {
+ PartialMetadataAnnotation partial = annotation;
+ compiler.cancel(
+ 'Too many JSName annotations: ${partial.parseNode(compiler)}');
ahe 2012/11/29 09:19:26 Ditto.
+ }
+ }
+ return name;
+ }
enqueueClass(ClassElement classElement, cause) {
assert(unusedClasses.contains(classElement));
@@ -182,8 +225,15 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer {
if (element.isFunction()) return registerMethod(element);
}
+ registerField(Element element) {
+ if (element.enclosingElement.isNative()) {
+ setNativeName(element);
+ }
+ }
+
registerMethod(Element method) {
if (isNativeMethod(method)) {
+ setNativeName(method);
processNativeBehavior(
NativeBehavior.ofMethod(method, compiler),
method);
@@ -191,6 +241,14 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer {
}
}
+ /// Sets the native name of [element], either from an annotation, or
+ /// defaulting to the Dart name.
+ void setNativeName(Element element) {
+ String name = findJsNameFromAnnotation(element);
+ if (name == null) name = element.name.slowToString();
+ element.setNative(name);
+ }
+
bool isNativeMethod(Element element) {
if (!element.getLibrary().canUseNative) return false;
// Native method?
@@ -666,15 +724,15 @@ Token handleNativeFunctionBody(ElementListener listener, Token token) {
}
SourceString checkForNativeClass(ElementListener listener) {
- SourceString nativeName;
+ SourceString nativeTagInfo;
Node node = listener.nodes.head;
if (node != null
&& node.asIdentifier() != null
&& node.asIdentifier().source.stringValue == 'native') {
- nativeName = node.asIdentifier().token.next.value;
+ nativeTagInfo = node.asIdentifier().token.next.value;
listener.popNode();
}
- return nativeName;
+ return nativeTagInfo;
}
bool isOverriddenMethod(FunctionElement element,
@@ -693,7 +751,6 @@ final RegExp nativeRedirectionRegExp = new RegExp(r'^[a-zA-Z][a-zA-Z_$0-9]*$');
void handleSsaNative(SsaBuilder builder, Expression nativeBody) {
Compiler compiler = builder.compiler;
FunctionElement element = builder.work.element;
- element.setNative();
NativeEmitter nativeEmitter = builder.emitter.nativeEmitter;
// If what we're compiling is a getter named 'typeName' and the native
// class is named 'DOMType', we generate a call to the typeNameOf
@@ -723,22 +780,22 @@ void handleSsaNative(SsaBuilder builder, Expression nativeBody) {
}
// Check which pattern this native method follows:
- // 1) foo() native; hasBody = false, isRedirecting = false
- // 2) foo() native "bar"; hasBody = false, isRedirecting = true
- // 3) foo() native "return 42"; hasBody = true, isRedirecting = false
+ // 1) foo() native;
+ // hasBody = false, isRedirecting = false
+ // 2) foo() native "bar";
+ // hasBody = false, isRedirecting = true, no longer supported.
+ // 3) foo() native "return 42";
+ // hasBody = true, isRedirecting = false
bool hasBody = false;
- bool isRedirecting = false;
- String nativeMethodName = element.name.slowToString();
+ String nativeMethodName = element.nativeName();
if (nativeBody != null) {
LiteralString jsCode = nativeBody.asLiteralString();
String str = jsCode.dartString.slowToString();
if (nativeRedirectionRegExp.hasMatch(str)) {
- nativeMethodName = str;
- isRedirecting = true;
- nativeEmitter.addRedirectingMethod(element, nativeMethodName);
- } else {
- hasBody = true;
+ compiler.cancel("Deprecated syntax, use @JSName('name') instead.",
+ node: nativeBody);
}
+ hasBody = true;
}
if (!hasBody) {

Powered by Google App Engine
This is Rietveld 408576698