public static void maybeSetJsInteropProperties(JDeclaredType type, Annotation... annotations) { AnnotationBinding jsType = JdtUtil.getAnnotation(annotations, JSTYPE_CLASS); String namespace = maybeGetJsNamespace(annotations); String exportName = maybeGetJsExportName(annotations, ""); String jsPrototype = JdtUtil.getAnnotationParameterString(jsType, "prototype"); boolean isJsNative = jsPrototype != null; if (isJsNative) { int indexOf = jsPrototype.lastIndexOf("."); namespace = indexOf == -1 ? "" : jsPrototype.substring(0, indexOf); exportName = jsPrototype.substring(indexOf + 1); } boolean isJsType = jsType != null; boolean isClassWideExport = exportName != null; boolean isJsFunction = JdtUtil.getAnnotation(annotations, JSFUNCTION_CLASS) != null; boolean canBeImplementedExternally = (type instanceof JInterfaceType && (isJsType || isJsFunction)) || (type instanceof JClassType && isJsNative); type.setJsTypeInfo( isJsType, isJsNative, isJsFunction, namespace, exportName, isClassWideExport, canBeImplementedExternally); }
private static String maybeGetJsExportName(Annotation[] annotations, String calculatedName) { AnnotationBinding jsExport = JdtUtil.getAnnotation(annotations, JSEXPORT_CLASS); if (jsExport == null) { return null; } String value = JdtUtil.getAnnotationParameterString(jsExport, "value"); return Strings.isNullOrEmpty(value) ? calculatedName : value; }
private static void resolveJsniRef(JsniRef jsniRef, MethodBinding methodBinding) { if (methodBinding == null) { return; } ReferenceBinding declaringClassBinding = methodBinding.declaringClass; jsniRef.setResolvedClassName(JdtUtil.getSourceName(declaringClassBinding)); jsniRef.setResolvedMemberWithSignature(JdtUtil.formatMethodSignature(methodBinding)); }
private MethodBinding checkAndResolveMethodRef( SourceInfo errorInfo, ReferenceBinding clazz, JsniRef jsniRef, boolean hasQualifier, boolean isLvalue) { assert jsniRef.isMethod(); List<MethodBinding> targets = getMatchingMethods(clazz, jsniRef); if (targets.size() > 1) { emitError( ERR_AMBIGUOUS_WILDCARD_MATCH, errorInfo, jsniRef, JdtUtil.formatBinding(targets.get(0)), JdtUtil.formatBinding(targets.get(1))); return null; } else if (targets.isEmpty()) { emitError(ERR_UNABLE_TO_RESOLVE_METHOD, errorInfo, jsniRef); return null; } MethodBinding target = targets.get(0); resolveJsniRef(jsniRef, target); if (target.isDeprecated() && !isEnclosingClass(method.binding.declaringClass, target.declaringClass)) { emitWarning("deprecation", WARN_DEPRECATED_METHOD, errorInfo, jsniRef); } if (isLvalue) { emitError(ERR_ILLEGAL_ASSIGNMENT_TO_METHOD, errorInfo, jsniRef); } boolean needsQualifer = !target.isStatic() && !target.isConstructor(); if (!needsQualifer && hasQualifier) { emitError(ERR_UNNECESSARY_QUALIFIER_STATIC_METHOD, errorInfo, jsniRef); } else if (needsQualifer && !hasQualifier) { emitError(ERR_MISSING_QUALIFIER_INSTANCE_METHOD, errorInfo, jsniRef); } if (hasUnsafeLongsAnnotation) { return target; } if (containsLong(target.returnType)) { emitError(ERR_ILLEGAL_RETURN_TYPE, errorInfo, jsniRef, typeString(target.returnType)); } if (target.parameters != null) { int i = 0; for (TypeBinding paramType : target.parameters) { ++i; if (containsLong(paramType)) { // It would be nice to print the parameter name, but how to find it? emitError(ERR_ILLEGAL_PARAMETER, errorInfo, jsniRef, i, typeString(paramType)); } } } return target; }
public static void maybeSetJsInteropProperties(JDeclaredType type, Annotation... annotations) { AnnotationBinding jsType = JdtUtil.getAnnotation(annotations, JSTYPE_CLASS); String jsPrototype = JdtUtil.getAnnotationParameterString(jsType, "prototype"); type.setJsTypeInfo(jsType != null, jsPrototype); String namespace = maybeGetJsNamespace(annotations); String exportName = maybeGetJsExportName(annotations, ""); type.setExportInfo(namespace, exportName); type.setJsFunctionInfo(JdtUtil.getAnnotation(annotations, JSFUNCTION_CLASS) != null); }
private static void setJsInteropPropertiesNew( JMember member, Annotation[] annotations, AnnotationBinding memberAnnotation) { if (getInteropAnnotation(annotations, "JsIgnore") != null) { return; } boolean isPublicMemberForJsType = member.getEnclosingType().isJsType() && member.isPublic(); if (!isPublicMemberForJsType && !isNativeConstructor(member) && memberAnnotation == null) { return; } String namespace = JdtUtil.getAnnotationParameterString(memberAnnotation, "namespace"); String name = JdtUtil.getAnnotationParameterString(memberAnnotation, "name"); member.setJsMemberInfo(namespace, name == null ? computeName(member) : name, true); }
private static void resolveJsniRef(JsniRef jsniRef, FieldBinding fieldBinding) { if (fieldBinding == null) { return; } jsniRef.setResolvedClassName(JdtUtil.getSourceName(fieldBinding.declaringClass)); jsniRef.setResolvedMemberWithSignature(new String(fieldBinding.name)); }
public static void maybeSetJsInteropPropertiesNew(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; boolean canBeImplementedExternally = isJsNative || isJsFunction; type.setJsTypeInfo( isJsType, isJsNative, isJsFunction, namespace, name, isJsType, canBeImplementedExternally); }
private static void setJsInteropProperties(JMember member, Annotation... annotations) { String namespace = maybeGetJsNamespace(annotations); String exportName = maybeGetJsExportName(annotations, computeName(member)); member.setJsMemberInfo(namespace, exportName, exportName != null); /* Apply class wide JsInterop annotations */ boolean ignore = JdtUtil.getAnnotation(annotations, JSNOEXPORT_CLASS) != null; if (ignore || (!member.isPublic() && !isNativeConstructor(member)) || exportName != null) { return; } JDeclaredType enclosingType = member.getEnclosingType(); if (enclosingType.isJsType() && member.needsDynamicDispatch()) { member.setJsMemberInfo(namespace, computeName(member), true); } if (enclosingType.isClassWideExport() && !member.needsDynamicDispatch()) { member.setJsMemberInfo(namespace, computeName(member), true); } }
private static String maybeGetJsNamespace(Annotation[] annotations) { AnnotationBinding jsNamespace = JdtUtil.getAnnotation(annotations, JSNAMESPACE_CLASS); return JdtUtil.getAnnotationParameterString(jsNamespace, "value"); }
private static AnnotationBinding getInteropAnnotation(Annotation[] annotations, String name) { return JdtUtil.getAnnotation(annotations, "jsinterop.annotations." + name); }
@Override public boolean visitValid(TypeDeclaration typeDeclaration, BlockScope scope) { suppressWarningsStack.push(JdtUtil.getSuppressedWarnings(typeDeclaration.annotations)); return true; }
public static boolean isJsPrototypeFlag(TypeDeclaration x) { return JdtUtil.getAnnotation(x.annotations, JSTYPEPROTOTYPE_CLASS) != null; }
private Binding resolveReference( SourceInfo errorInfo, JsniRef jsniRef, boolean hasQualifier, boolean isLvalue) { resolveClassReference(jsniRef); String className = jsniRef.getResolvedClassName(); boolean isPrimitive; ReferenceBinding clazz; TypeBinding binding = method.scope.getBaseType(className.toCharArray()); if (binding != null) { isPrimitive = true; clazz = null; } else { isPrimitive = false; binding = clazz = findClass(className); } if (binding != null && binding.isAnonymousType()) { // There seems that there is no way to write a JSNI reference to an anonymous class as // it will require to accept a source name of the form A.1 where one of the identifier parts // consists only of digits and therefore is not a valid identifier. // This error case is left here in case names of that form start appearing from the JSNI // parser. emitError(ERR_ILLEGAL_ANONYMOUS_INNER_CLASS, errorInfo, jsniRef); return null; } else if (binding == null) { emitError(ERR_UNABLE_TO_RESOLVE_CLASS, errorInfo, jsniRef); return null; } if (clazz != null && clazz.isDeprecated() && !isEnclosingClass(method.binding.declaringClass, clazz)) { emitWarning("deprecation", WARN_DEPRECATED_CLASS, errorInfo, jsniRef); } if (jsniRef.isField() && "class".equals(jsniRef.memberName())) { if (isLvalue) { emitError(ERR_ILLEGAL_ASSIGNMENT_TO_CLASS_LITERAL, errorInfo, jsniRef); return null; } // Reference to the class itself. jsniRef.setResolvedClassName(JdtUtil.getSourceName(binding)); jsniRef.setResolvedMemberWithSignature(jsniRef.memberSignature()); if (jsniRef.isArray()) { ArrayBinding arrayBinding = method.scope.createArrayType(binding, jsniRef.getDimensions()); return arrayBinding; } else { return binding; } } if (jsniRef.isArray() || isPrimitive) { emitError(ERR_ILLEGAL_ARRAY_OR_PRIMITIVE_REFERENCE, errorInfo, jsniRef); return null; } assert clazz != null; if (jsniRef.isMethod()) { return checkAndResolveMethodRef(errorInfo, clazz, jsniRef, hasQualifier, isLvalue); } else { return checkAndResolveFieldRef(errorInfo, clazz, jsniRef, hasQualifier, isLvalue); } }
private void resolveClassReference(JsniRef jsniRef) { // Precedence rules as of JLS 6.4.1. // 1. Enclosing type. // 2. Visible type in same compilation unit. // 3. Named import. // 4. Same package. // 5. Import on demand. String originalName = jsniRef.className(); String importedClassName = originalName; if (importedClassName.contains(".")) { // Only retain up the first dot to support innerclasses. E.g. import c.g.A and reference // @A.I::f. importedClassName = importedClassName.substring(0, importedClassName.indexOf(".")); } // 1 & 2. Check to see if this name refers to the enclosing class or is directly accessible // from it. ReferenceBinding declaringClass = method.binding.declaringClass; while (declaringClass != null) { String declaringClassName = JdtUtil.getSourceName(declaringClass); if (declaringClassName.equals(importedClassName) || declaringClassName.endsWith("." + importedClassName)) { // Referring to declaring class name using unqualified name. jsniRef.setResolvedClassName( declaringClassName + originalName.substring(importedClassName.length())); return; } String fullClassName = JdtUtil.getBinaryName(declaringClass) + "$" + originalName.replace('.', '$'); if (typeResolver.resolveType(fullClassName) != null) { jsniRef.setResolvedClassName(JdtUtil.getSourceName(declaringClass) + "." + originalName); return; } declaringClass = declaringClass.enclosingTypeAt(1); } // 3. Check to see if this name is one of the named imports. for (ImportReference importReference : cudImports) { String nameFromImport = JdtUtil.asDottedString(importReference.getImportName()); if (!importReference.isStatic() && importReference.trailingStarPosition == 0 && nameFromImport.endsWith("." + importedClassName)) { jsniRef.setResolvedClassName( nameFromImport + originalName.substring(importedClassName.length())); return; } } // 4. Check to see if this name is resolvable from the current package. String currentPackageBinaryClassName = JdtUtil.getBinaryName( CharOperation.charToString(method.binding.declaringClass.qualifiedPackageName()), originalName); if (typeResolver.resolveType(currentPackageBinaryClassName) != null) { jsniRef.setResolvedClassName( JdtUtil.getSourceName( CharOperation.charToString(method.binding.declaringClass.qualifiedPackageName()), originalName)); return; } // 5. Check to see if this name is resolvable as an import on demand. List<String> importPackages = Lists.newArrayList("java.lang"); for (ImportReference importReference : cudImports) { if (importReference.isStatic() || importReference.trailingStarPosition == 0) { continue; } importPackages.add(JdtUtil.asDottedString(importReference.getImportName())); } for (String importPackage : importPackages) { String fullClassName = importPackage + "." + originalName.replace('.', '$'); if (typeResolver.resolveType(fullClassName) != null) { jsniRef.setResolvedClassName(importPackage + "." + originalName); return; } } // Otherwise leave it as it is. // TODO(rluble): Maybe we should leave it null here. jsniRef.setResolvedClassName(jsniRef.className()); }
public static void maybeSetJsInteropProperties(JMethod method, Annotation... annotations) { setJsInteropProperties(method, annotations); if (JdtUtil.getAnnotation(annotations, JSPROPERTY_CLASS) != null) { setJsPropertyProperties(method); } }
@Override public boolean visit(MethodDeclaration meth, ClassScope scope) { suppressWarningsStack.push(JdtUtil.getSuppressedWarnings(meth.annotations)); return true; }