/** * This method reads constant values in bytecode. It should be called when resolving semantics from source. */ @CheckForNull public Object constantValue(Symbol owner, String constantName) { if (constantValues.containsKey(owner)) { return constantValues.get(owner).get(constantName); } if (owner.isTypeSymbol()) { JavaSymbol.TypeJavaSymbol typeSymbol = (JavaSymbol.TypeJavaSymbol) owner; String bytecodeName = typeSymbol.getFullyQualifiedName(); byte[] bytes = classLoader.getBytesForClass(bytecodeName); if (bytes != null) { Map<String, Object> valuesByFieldName = new HashMap<>(); ClassReader classReader = new ClassReader(bytes); classReader.accept( new ClassVisitor(ASM_API_VERSION) { @Override public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { valuesByFieldName.put(name, value); return super.visitField(access, name, descriptor, signature, value); } }, ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); constantValues.put(typeSymbol, valuesByFieldName); return valuesByFieldName.get(constantName); } } return null; }
/** * This method reads constant values in bytecode. It should be called when resolving semantics from source. */ @CheckForNull public Object constantValue(Symbol owner, String constantName) { if (constantValues.containsKey(owner)) { return constantValues.get(owner).get(constantName); } if (owner.isTypeSymbol()) { JavaSymbol.TypeJavaSymbol typeSymbol = (JavaSymbol.TypeJavaSymbol) owner; String bytecodeName = typeSymbol.getFullyQualifiedName(); byte[] bytes = classLoader.getBytesForClass(bytecodeName); if (bytes != null) { Map<String, Object> valuesByFieldName = new HashMap<>(); ClassReader classReader = new ClassReader(bytes); classReader.accept( new ClassVisitor(ASM_API_VERSION) { @Override public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { valuesByFieldName.put(name, value); return super.visitField(access, name, descriptor, signature, value); } }, ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); constantValues.put(typeSymbol, valuesByFieldName); return valuesByFieldName.get(constantName); } } return null; }
private static MethodLookup lookup(String className, String signature, SquidClassLoader classLoader, LookupMethodVisitor methodVisitor) { byte[] bytes = classLoader.getBytesForClass(className); if (bytes == null) { return null; } ClassReader cr = new ClassReader(bytes); LookupClassVisitor lookupVisitor = new LookupClassVisitor(methodVisitor, signature); cr.accept(lookupVisitor, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); if (lookupVisitor.methodFound) { return new MethodLookup(lookupVisitor.isStatic, lookupVisitor.isVarArgs, lookupVisitor.declaredExceptions); } // we didn't succeed to find the method in the class, try recursively on superclasses and interfaces if (lookupVisitor.superClassName != null) { MethodLookup result = lookup(lookupVisitor.superClassName, signature, classLoader, methodVisitor); if (result != null) { return result; } } if (lookupVisitor.interfaces != null) { return Arrays.stream(lookupVisitor.interfaces) .map(iface -> lookup(iface, signature, classLoader, methodVisitor)) .filter(Objects::nonNull) .findAny().orElse(null); } return null; }
private static MethodLookup lookup(String className, String signature, SquidClassLoader classLoader, LookupMethodVisitor methodVisitor) { byte[] bytes = classLoader.getBytesForClass(className); if (bytes == null) { return null; } ClassReader cr = new ClassReader(bytes); LookupClassVisitor lookupVisitor = new LookupClassVisitor(methodVisitor, signature); cr.accept(lookupVisitor, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); if (lookupVisitor.methodFound) { return new MethodLookup(lookupVisitor.isStatic, lookupVisitor.isVarArgs, lookupVisitor.declaredExceptions); } // we didn't succeed to find the method in the class, try recursively on superclasses and interfaces if (lookupVisitor.superClassName != null) { MethodLookup result = lookup(lookupVisitor.superClassName, signature, classLoader, methodVisitor); if (result != null) { return result; } } if (lookupVisitor.interfaces != null) { return Arrays.stream(lookupVisitor.interfaces) .map(iface -> lookup(iface, signature, classLoader, methodVisitor)) .filter(Objects::nonNull) .findAny().orElse(null); } return null; }
@Override public void complete(JavaSymbol symbol) { String bytecodeName = formFullName(symbol); if(symbol.isPackageSymbol()) { bytecodeName = bytecodeName + ".package-info"; } JavaSymbol.TypeJavaSymbol classSymbol = getClassSymbol(bytecodeName); if(symbol.isPackageSymbol()) { ((JavaSymbol.PackageJavaSymbol) symbol).packageInfo = classSymbol; } Preconditions.checkState(symbol.isPackageSymbol() || classSymbol == symbol); byte[] bytes = classLoader.getBytesForClass(bytecodeName); if (bytes != null) { ClassReader classReader = new ClassReader(bytes); classReader.accept( new BytecodeVisitor(this, symbols, classSymbol, parametrizedTypeCache), ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); } }
/** * <b>Note:</b> Attempt to find something like "java.class" on case-insensitive file system can result in unwanted loading of "JAVA.class". * This method performs check of class name within file in order to avoid such situation. * This is definitely not the best solution in terms of performance, but acceptable for now. * * @return symbol for requested class, if corresponding class file exists, and {@link org.sonar.java.resolve.Resolve.JavaSymbolNotFound} otherwise */ // TODO(Godin): Method name is misleading because of lazy loading. public JavaSymbol loadClass(String fullname) { JavaSymbol.TypeJavaSymbol symbol = classes.get(fullname); if (symbol != null) { return symbol; } byte[] bytesForClass = classLoader.getBytesForClass(fullname); if (bytesForClass == null) { return new Resolve.JavaSymbolNotFound(); } ClassReader classReader = new ClassReader(bytesForClass); String className = classReader.getClassName(); if (!className.equals(Convert.bytecodeName(fullname))) { return new Resolve.JavaSymbolNotFound(); } return getClassSymbol(fullname); }
@Override public void complete(JavaSymbol symbol) { String bytecodeName = formFullName(symbol); if(symbol.isPackageSymbol()) { bytecodeName = bytecodeName + ".package-info"; } JavaSymbol.TypeJavaSymbol classSymbol = getClassSymbol(bytecodeName); if(symbol.isPackageSymbol()) { ((JavaSymbol.PackageJavaSymbol) symbol).packageInfo = classSymbol; } Preconditions.checkState(symbol.isPackageSymbol() || classSymbol == symbol); byte[] bytes = classLoader.getBytesForClass(bytecodeName); if (bytes != null) { ClassReader classReader = new ClassReader(bytes); classReader.accept( new BytecodeVisitor(this, symbols, classSymbol, parametrizedTypeCache), ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); } }
/** * <b>Note:</b> Attempt to find something like "java.class" on case-insensitive file system can result in unwanted loading of "JAVA.class". * This method performs check of class name within file in order to avoid such situation. * This is definitely not the best solution in terms of performance, but acceptable for now. * * @return symbol for requested class, if corresponding class file exists, and {@link org.sonar.java.resolve.Resolve.JavaSymbolNotFound} otherwise */ // TODO(Godin): Method name is misleading because of lazy loading. public JavaSymbol loadClass(String fullname) { JavaSymbol.TypeJavaSymbol symbol = classes.get(fullname); if (symbol != null) { return symbol; } byte[] bytesForClass = classLoader.getBytesForClass(fullname); if (bytesForClass == null) { return new Resolve.JavaSymbolNotFound(); } ClassReader classReader = new ClassReader(bytesForClass); String className = classReader.getClassName(); if (!className.equals(Convert.bytecodeName(fullname))) { return new Resolve.JavaSymbolNotFound(); } return getClassSymbol(fullname); }