private JavaSymbol findMemberType( Env env, JavaSymbol.TypeJavaSymbol site, String name, JavaSymbol.TypeJavaSymbol c) { JavaSymbol bestSoFar = symbolNotFound; for (JavaSymbol symbol : c.members().lookup(name)) { if (symbol.kind == JavaSymbol.TYP) { return isAccessible(env, site, symbol) ? symbol : new AccessErrorJavaSymbol(symbol, Symbols.unknownType); } } if (c.getSuperclass() != null) { JavaSymbol symbol = findMemberType(env, site, name, c.getSuperclass().symbol); if (symbol.kind < bestSoFar.kind) { bestSoFar = symbol; } } if (c.getInterfaces() == null) { // Invariant to check that interfaces are not set only when we are looking into the symbol we // are currently completing. // required for generics Preconditions.checkState( c.completing, "interfaces of a symbol not currently completing are not set."); Preconditions.checkState(c == site); } else { for (JavaType interfaceType : c.getInterfaces()) { JavaSymbol symbol = findMemberType(env, site, name, interfaceType.symbol); if (symbol.kind < bestSoFar.kind) { bestSoFar = symbol; } } } return bestSoFar; }
/** Finds field with given name. */ private Resolution findField( Env env, JavaSymbol.TypeJavaSymbol site, String name, JavaSymbol.TypeJavaSymbol c) { Resolution bestSoFar = unresolved(); Resolution resolution = new Resolution(); for (JavaSymbol symbol : c.members().lookup(name)) { if (symbol.kind == JavaSymbol.VAR) { if (isAccessible(env, site, symbol)) { resolution.symbol = symbol; resolution.type = resolveTypeSubstitution(symbol.type, c.type); return resolution; } else { return Resolution.resolution(new AccessErrorJavaSymbol(symbol, Symbols.unknownType)); } } } if (c.getSuperclass() != null) { resolution = findField(env, site, name, c.getSuperclass().symbol); if (resolution.symbol.kind < bestSoFar.symbol.kind) { resolution.type = resolveTypeSubstitution(resolution.symbol.type, c.getSuperclass()); bestSoFar = resolution; } } for (JavaType interfaceType : c.getInterfaces()) { resolution = findField(env, site, name, interfaceType.symbol); if (resolution.symbol.kind < bestSoFar.symbol.kind) { bestSoFar = resolution; } } return bestSoFar; }
/** Registers builtin types as symbols, so that they can be found as an usual identifiers. */ private JavaType initType(int tag, String name) { JavaSymbol.TypeJavaSymbol symbol = new JavaSymbol.TypeJavaSymbol(Flags.PUBLIC, name, rootPackage); symbol.members = new Scope(symbol); predefClass.members.enter(symbol); ((JavaType.ClassJavaType) symbol.type).interfaces = ImmutableList.of(); symbol.type.tag = tag; return symbol.type; }
@Override public void visit( int version, int flags, String name, @Nullable String signature, @Nullable String superName, @Nullable String[] interfaces) { Preconditions.checkState( name.endsWith(classSymbol.name), "Name : '" + name + "' should ends with " + classSymbol.name); Preconditions.checkState(!BytecodeCompleter.isSynthetic(flags), name + " is synthetic"); className = name; if (signature != null) { SignatureReader signatureReader = new SignatureReader(signature); signatureReader.accept(new TypeParameterDeclaration(classSymbol)); ReadGenericSignature readGenericSignature = new ReadGenericSignature(); signatureReader.accept(readGenericSignature); ((ClassJavaType) classSymbol.type).interfaces = readGenericSignature.interfaces(); } else { if (superName == null) { Preconditions.checkState( "java/lang/Object".equals(className), "superName must be null only for java/lang/Object, but not for " + className); // TODO(Godin): what about interfaces and annotations } else { ((ClassJavaType) classSymbol.type).supertype = getClassSymbol(superName).type; } ((ClassJavaType) classSymbol.type).interfaces = getCompletedClassSymbolsType(interfaces); } // if class has already access flags set (inner class) then do not reset those. // The important access flags are the one defined in the outer class. if ((classSymbol.flags & Flags.ACCESS_FLAGS) != 0) { classSymbol.flags |= bytecodeCompleter.filterBytecodeFlags(flags & ~Flags.ACCESS_FLAGS); } else { classSymbol.flags |= bytecodeCompleter.filterBytecodeFlags(flags); } classSymbol.members = new Scope(classSymbol); }
static { rootPackage = new JavaSymbol.PackageJavaSymbol("", null); unknownSymbol = new JavaSymbol.TypeJavaSymbol(Flags.PUBLIC, "!unknownSymbol!", rootPackage) { @Override public void addUsage(IdentifierTree tree) { // noop } @Override public boolean isTypeSymbol() { return false; } @Override public boolean isUnknown() { return true; } }; unknownSymbol.members = new Scope(unknownSymbol) { @Override public void enter(JavaSymbol symbol) { // noop } }; unknownType = new JavaType.ClassJavaType(unknownSymbol) { @Override public String toString() { return "!unknown!"; } }; unknownType.tag = JavaType.UNKNOWN; unknownType.supertype = null; unknownType.interfaces = ImmutableList.of(); unknownSymbol.type = unknownType; }
public Symbols(BytecodeCompleter bytecodeCompleter) { defaultPackage = new JavaSymbol.PackageJavaSymbol("", rootPackage); predefClass = new JavaSymbol.TypeJavaSymbol(Flags.PUBLIC, "", rootPackage); predefClass.members = new Scope(predefClass); ((JavaType.ClassJavaType) predefClass.type).interfaces = ImmutableList.of(); // TODO should have type "noType": noSymbol = new JavaSymbol.TypeJavaSymbol(0, "", rootPackage); methodClass = new JavaSymbol.TypeJavaSymbol(Flags.PUBLIC, "", noSymbol); // builtin types byteType = initType(JavaType.BYTE, "byte"); charType = initType(JavaType.CHAR, "char"); shortType = initType(JavaType.SHORT, "short"); intType = initType(JavaType.INT, "int"); longType = initType(JavaType.LONG, "long"); floatType = initType(JavaType.FLOAT, "float"); doubleType = initType(JavaType.DOUBLE, "double"); booleanType = initType(JavaType.BOOLEAN, "boolean"); nullType = initType(JavaType.BOT, "<nulltype>"); voidType = initType(JavaType.VOID, "void"); bytecodeCompleter.init(this); // predefined types for java lang JavaSymbol.PackageJavaSymbol javalang = bytecodeCompleter.enterPackage("java.lang"); // define a star import scope to let resolve types to java.lang when needed. javalang.members = new Scope.StarImportScope(javalang, bytecodeCompleter); javalang.members.enter(javalang); objectType = bytecodeCompleter.loadClass("java.lang.Object").type; classType = bytecodeCompleter.loadClass("java.lang.Class").type; stringType = bytecodeCompleter.loadClass("java.lang.String").type; cloneableType = bytecodeCompleter.loadClass("java.lang.Cloneable").type; serializableType = bytecodeCompleter.loadClass("java.io.Serializable").type; annotationType = bytecodeCompleter.loadClass("java.lang.annotation.Annotation").type; enumType = bytecodeCompleter.loadClass("java.lang.Enum").type; // Associate boxed types boxedTypes = HashBiMap.create(); boxedTypes.put(byteType, bytecodeCompleter.loadClass("java.lang.Byte").type); boxedTypes.put(charType, bytecodeCompleter.loadClass("java.lang.Character").type); boxedTypes.put(shortType, bytecodeCompleter.loadClass("java.lang.Short").type); boxedTypes.put(intType, bytecodeCompleter.loadClass("java.lang.Integer").type); boxedTypes.put(longType, bytecodeCompleter.loadClass("java.lang.Long").type); boxedTypes.put(floatType, bytecodeCompleter.loadClass("java.lang.Float").type); boxedTypes.put(doubleType, bytecodeCompleter.loadClass("java.lang.Double").type); boxedTypes.put(booleanType, bytecodeCompleter.loadClass("java.lang.Boolean").type); for (Entry<JavaType, JavaType> entry : boxedTypes.entrySet()) { entry.getKey().primitiveWrapperType = entry.getValue(); entry.getValue().primitiveType = entry.getKey(); } // TODO comment me arrayClass = new JavaSymbol.TypeJavaSymbol(Flags.PUBLIC, "Array", noSymbol); JavaType.ClassJavaType arrayClassType = (JavaType.ClassJavaType) arrayClass.type; arrayClassType.supertype = objectType; arrayClassType.interfaces = ImmutableList.of(cloneableType, serializableType); arrayClass.members = new Scope(arrayClass); arrayClass .members() .enter( new JavaSymbol.VariableJavaSymbol( Flags.PUBLIC | Flags.FINAL, "length", intType, arrayClass)); // TODO arrayClass implements clone() method enterOperators(); }