/** Recursively creates enclosing types first. */ private void createCompiledClass(ClassFile classFile, Map<ClassFile, CompiledClass> results) { if (results.containsKey(classFile)) { // Already created. return; } CompiledClass enclosingClass = null; if (classFile.enclosingClassFile != null) { ClassFile enclosingClassFile = classFile.enclosingClassFile; createCompiledClass(enclosingClassFile, results); enclosingClass = results.get(enclosingClassFile); assert enclosingClass != null; } String internalName = CharOperation.charToString(classFile.fileName()); CompiledClass result = new CompiledClass( classFile.getBytes(), enclosingClass, isLocalType(classFile), internalName); results.put(classFile, result); }
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()); }