blob: 0db2245a04c544de9e9924ec1c6e1fd917db3e18 [file] [log] [blame]
/*
* Copyright 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.dev.javac;
import com.google.gwt.dev.jjs.ast.HasJsInfo.JsMemberType;
import com.google.gwt.dev.jjs.ast.JConstructor;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JMember;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JParameter;
import com.google.gwt.dev.jjs.ast.JPrimitiveType;
import com.google.gwt.thirdparty.guava.common.base.Joiner;
import com.google.gwt.thirdparty.guava.common.collect.Lists;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
import java.util.List;
/**
* Utility functions to interact with JDT classes for JsInterop.
*/
public final class JsInteropUtil {
public static final String UNUSABLE_BY_JS = "unusable-by-js";
public static final String INVALID_JSNAME = "<invalid>";
public static boolean isGlobal(String jsNamespace) {
return "<global>".equals(jsNamespace);
}
public static boolean isWindow(String jsNamespace) {
return "<window>".equals(jsNamespace);
}
public static String normalizeQualifier(String qualifier) {
assert !qualifier.isEmpty();
List<String> components = Lists.newArrayList(qualifier.split("\\."));
if (isWindow(components.get(0))) {
// Emit unqualified if '<window>' namespace was specified.
components.remove(0);
} else if (isGlobal(components.get(0))) {
// Replace global with $wnd.
components.set(0, "$wnd");
} else {
// still emit $wnd as rest implicitly points to global.
components.add(0, "$wnd");
}
return Joiner.on('.').join(components);
}
public static void maybeSetJsInteropProperties(JDeclaredType type, Annotation[] annotations) {
AnnotationBinding jsType = getInteropAnnotation(annotations, "JsType");
String namespace = JdtUtil.getAnnotationParameterString(jsType, "namespace");
String name = JdtUtil.getAnnotationParameterString(jsType, "name");
boolean isJsNative = JdtUtil.getAnnotationParameterBoolean(jsType, "isNative", false);
AnnotationBinding jsPackage = getInteropAnnotation(annotations, "JsPackage");
String packageNamespace = JdtUtil.getAnnotationParameterString(jsPackage, "namespace");
if (packageNamespace != null) {
namespace = packageNamespace;
}
boolean isJsType = jsType != null;
boolean isJsFunction = getInteropAnnotation(annotations, "JsFunction") != null;
type.setJsTypeInfo(isJsType, isJsNative, isJsFunction, namespace, name, isJsType);
}
public static void maybeSetJsInteropProperties(
JMethod method, boolean generateExport, Annotation... annotations) {
AnnotationBinding annotation = getInteropAnnotation(annotations, "JsMethod");
if (annotation == null) {
annotation = getInteropAnnotation(annotations, "JsConstructor");
}
if (annotation == null) {
annotation = getInteropAnnotation(annotations, "JsProperty");
}
boolean isPropertyAccessor = getInteropAnnotation(annotations, "JsProperty") != null;
setJsInteropProperties(method, annotations, annotation, isPropertyAccessor, generateExport);
}
public static void maybeSetJsInteropProperties(JParameter parameter, Annotation... annotations) {
if (getInteropAnnotation(annotations, "JsOptional") != null) {
parameter.setOptional();
}
}
public static void maybeSetJsInteropProperties(
JField field, boolean generateExport, Annotation... annotations) {
AnnotationBinding annotation = getInteropAnnotation(annotations, "JsProperty");
setJsInteropProperties(field, annotations, annotation, false, generateExport);
}
private static void setJsInteropProperties(JMember member, Annotation[] annotations,
AnnotationBinding memberAnnotation, boolean isAccessor, boolean generateExport) {
if (getInteropAnnotation(annotations, "JsOverlay") != null) {
member.setJsOverlay();
}
if (getInteropAnnotation(annotations, "JsIgnore") != null) {
return;
}
boolean isPublicMemberForJsType = member.getEnclosingType().isJsType() && member.isPublic();
boolean memberForNativeType = member.getEnclosingType().isJsNative();
if (memberAnnotation == null
&& (!isPublicMemberForJsType && !memberForNativeType || member.isJsOverlay())) {
return;
}
String namespace = JdtUtil.getAnnotationParameterString(memberAnnotation, "namespace");
String name = JdtUtil.getAnnotationParameterString(memberAnnotation, "name");
JsMemberType memberType = getJsMemberType(member, isAccessor);
member.setJsMemberInfo(memberType, namespace, name, generateExport);
}
private static JsMemberType getJsMemberType(JMember member, boolean isPropertyAccessor) {
if (member instanceof JField) {
return JsMemberType.PROPERTY;
}
if (member instanceof JConstructor) {
return JsMemberType.CONSTRUCTOR;
}
if (isPropertyAccessor) {
return getJsPropertyAccessorType((JMethod) member);
}
return JsMemberType.METHOD;
}
private static JsMemberType getJsPropertyAccessorType(JMethod method) {
if (method.getParams().size() == 1 && method.getType() == JPrimitiveType.VOID) {
return JsMemberType.SETTER;
} else if (method.getParams().isEmpty() && method.getType() != JPrimitiveType.VOID) {
return JsMemberType.GETTER;
}
return JsMemberType.UNDEFINED_ACCESSOR;
}
private static AnnotationBinding getInteropAnnotation(Annotation[] annotations, String name) {
return JdtUtil.getAnnotationByName(annotations, "jsinterop.annotations." + name);
}
}