private static void resolveJsniRef(JsniRef jsniRef, FieldBinding fieldBinding) { if (fieldBinding == null) { return; } jsniRef.setResolvedClassName(JdtUtil.getSourceName(fieldBinding.declaringClass)); jsniRef.setResolvedMemberWithSignature(new String(fieldBinding.name)); }
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 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()); }