/** * Lookup a class. <em>Use this method instead of Repository.lookupClass().</em> * * @param className the name of the class * @return the JavaClass representing the class * @throws ClassNotFoundException (but not really) */ public JavaClass lookupClass(@Nonnull @DottedClassName String className) throws ClassNotFoundException { try { if (className.length() == 0) { throw new IllegalArgumentException("Class name is empty"); } if (!ClassName.isValidClassName(className)) { throw new ClassNotFoundException("Invalid class name: " + className); } return Global.getAnalysisCache() .getClassAnalysis( JavaClass.class, DescriptorFactory.instance() .getClassDescriptor(ClassName.toSlashedClassName(className))); } catch (CheckedAnalysisException e) { throw new ClassNotFoundException("Class not found: " + className, e); } }
/** * Get the ClassContext for a class. * * @param javaClass the class * @return the ClassContext for that class */ public ClassContext getClassContext(JavaClass javaClass) { // This is a bit silly since we're doing an unnecessary // ClassDescriptor->JavaClass lookup. // However, we can be assured that it will succeed. ClassDescriptor classDescriptor = DescriptorFactory.instance() .getClassDescriptor(ClassName.toSlashedClassName(javaClass.getClassName())); try { return Global.getAnalysisCache().getClassAnalysis(ClassContext.class, classDescriptor); } catch (CheckedAnalysisException e) { IllegalStateException ise = new IllegalStateException("Could not get ClassContext for JavaClass"); ise.initCause(e); throw ise; } }
private static String getFullMethodName(ConstantPoolGen cpg, InvokeInstruction invoke) { String dottedClassName = invoke.getReferenceType(cpg).toString(); StringBuilder builder = new StringBuilder(ClassName.toSlashedClassName(dottedClassName)); builder.append(".").append(invoke.getMethodName(cpg)).append(invoke.getSignature(cpg)); return builder.toString(); }
/** * Construct a ClassDescriptor from a JavaClass. * * @param jclass a JavaClass * @return a ClassDescriptor identifying that JavaClass */ public static ClassDescriptor getClassDescriptor(JavaClass jclass) { return DescriptorFactory.instance() .getClassDescriptor(ClassName.toSlashedClassName(jclass.getClassName())); }
private String getClassName(JavaClass c, int classIndex) { String name = c.getConstantPool().getConstantString(classIndex, CONSTANT_Class); return ClassName.extractClassName(name).replace('/', '.'); }
private String getSlashedClassName(FieldOrMethod obj) { String className = obj.getReferenceType(cpg).toString(); return ClassName.toSlashedClassName(className); }
private void handle(@SlashedClassName String className, boolean isFloatingPoint, String sig) { XMethod m = XFactory.createXMethod(ClassName.toDottedClassName(className), "valueOf", sig, true); boxClasses.put(className, m); }
/* * (non-Javadoc) * * @see * edu.umd.cs.findbugs.classfile.engine.ClassParserInterface#parse(edu.umd * .cs.findbugs.classfile.analysis.ClassNameAndSuperclassInfo.Builder) */ public void parse(final ClassNameAndSuperclassInfo.Builder cBuilder) throws InvalidClassFileFormatException { cBuilder.setCodeBaseEntry(codeBaseEntry); final TreeSet<ClassDescriptor> calledClassSet = new TreeSet<ClassDescriptor>(); classReader.accept( new ClassVisitor() { boolean isInnerClass = false; public void visit( int version, int access, String name, String signature, String superName, String[] interfaces) { ClassParserUsingASM.this.slashedClassName = name; cBuilder.setClassfileVersion(version >>> 16, version & 0xffff); cBuilder.setAccessFlags(access); cBuilder.setClassDescriptor(DescriptorFactory.createClassDescriptor(name)); cBuilder.setInterfaceDescriptorList( DescriptorFactory.createClassDescriptor(interfaces)); if (superName != null) cBuilder.setSuperclassDescriptor(DescriptorFactory.createClassDescriptor(superName)); if (cBuilder instanceof ClassInfo.Builder) { ((ClassInfo.Builder) cBuilder).setSourceSignature(signature); } } public org.objectweb.asm.AnnotationVisitor visitAnnotation( String desc, boolean isVisible) { if (cBuilder instanceof ClassInfo.Builder) { AnnotationValue value = new AnnotationValue(desc); ((ClassInfo.Builder) cBuilder).addAnnotation(desc, value); return value.getAnnotationVisitor(); } return null; } public void visitAttribute(Attribute arg0) { // TODO Auto-generated method stub } public void visitEnd() { // TODO Auto-generated method stub } public FieldVisitor visitField( int access, String name, String desc, String signature, Object value) { if (name.equals("this$0")) isInnerClass = true; if (desc == null) throw new NullPointerException("Description cannot be null"); if (cBuilder instanceof ClassInfo.Builder) { final ClassInfo.Builder cBuilder2 = (ClassInfo.Builder) cBuilder; if ((access & Opcodes.ACC_VOLATILE) != 0 || desc.contains("util/concurrent")) cBuilder2.setUsesConcurrency(); final FieldInfo.Builder fBuilder = new FieldInfo.Builder(slashedClassName, name, desc, access); fBuilder.setSourceSignature(signature); return new AbstractFieldAnnotationVisitor() { public org.objectweb.asm.AnnotationVisitor visitAnnotation( final String desc, boolean visible) { AnnotationValue value = new AnnotationValue(desc); fBuilder.addAnnotation(desc, value); return value.getAnnotationVisitor(); } public void visitEnd() { cBuilder2.addFieldDescriptor(fBuilder.build()); } }; } return null; } public void visitInnerClass(String name, String outerName, String innerName, int access) { if (name.equals(slashedClassName) && outerName != null) { if (cBuilder instanceof ClassInfo.Builder) { ClassDescriptor outerClassDescriptor = DescriptorFactory.createClassDescriptor(outerName); ((ClassInfo.Builder) cBuilder).setImmediateEnclosingClass(outerClassDescriptor); ((ClassInfo.Builder) cBuilder).setAccessFlags(access); } } } public MethodVisitor visitMethod( final int access, final String methodName, final String methodDesc, String signature, String[] exceptions) { if (cBuilder instanceof ClassInfo.Builder) { final MethodInfo.Builder mBuilder = new MethodInfo.Builder(slashedClassName, methodName, methodDesc, access); mBuilder.setSourceSignature(signature); mBuilder.setThrownExceptions(exceptions); if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) mBuilder.setUsesConcurrency(); return new AbstractMethodVisitor() { int variable; boolean sawReturn = (access & Opcodes.ACC_NATIVE) != 0; boolean sawNormalThrow = false; boolean sawUnsupportedThrow = false; boolean sawSystemExit = false; boolean sawBranch = false; boolean sawBackBranch = false; int methodCallCount = 0; boolean sawStubThrow = false; boolean justSawInitializationOfUnsupportedOperationException; boolean isBridge = (access & Opcodes.ACC_SYNTHETIC) != 0 && (access & Opcodes.ACC_BRIDGE) != 0; String bridgedMethodSignature; State state = State.INITIAL; StubState stubState = StubState.INITIAL; boolean isAccessMethod = methodName.startsWith("access$"); String accessOwner, accessName, accessDesc; boolean accessIsStatic; HashSet<Label> labelsSeen = new HashSet<Label>(); @Override public void visitLdcInsn(Object cst) { if (cst.equals("Stub!")) stubState = StubState.LOADED_STUB; else stubState = StubState.INITIAL; } @Override public void visitInsn(int opcode) { if (opcode == Opcodes.MONITORENTER) mBuilder.setUsesConcurrency(); if (RETURN_OPCODE_SET.get(opcode)) sawReturn = true; else if (opcode == Opcodes.ATHROW) { if (stubState == StubState.INITIALIZE_RUNTIME) { sawStubThrow = true; } else if (justSawInitializationOfUnsupportedOperationException) sawUnsupportedThrow = true; else sawNormalThrow = true; } resetState(); } public void resetState() { if (state != State.AFTER_METHOD_CALL) state = State.INITIAL; stubState = StubState.INITIAL; } @Override public void visitSomeInsn() { resetState(); } @Override public void visitVarInsn(int opcode, int var) { if (opcode == Opcodes.ALOAD && var == 0) state = State.THIS_LOADED; else if (state == State.THIS_LOADED) switch (opcode) { case Opcodes.ALOAD: case Opcodes.ILOAD: case Opcodes.LLOAD: case Opcodes.DLOAD: case Opcodes.FLOAD: state = State.VARIABLE_LOADED; variable = var; } else visitSomeInsn(); } public org.objectweb.asm.AnnotationVisitor visitAnnotation( final String desc, boolean visible) { AnnotationValue value = new AnnotationValue(desc); mBuilder.addAnnotation(desc, value); return value.getAnnotationVisitor(); } @Override public void visitMethodInsn(int opcode, String owner, String name, String desc) { methodCallCount++; if (isAccessMethod && methodCallCount == 1) { this.accessOwner = owner; this.accessName = name; this.accessDesc = desc; this.accessIsStatic = opcode == Opcodes.INVOKESTATIC; } if (stubState == StubState.LOADED_STUB && opcode == Opcodes.INVOKESPECIAL && owner.equals("java/lang/RuntimeException") && name.equals("<init>")) stubState = StubState.INITIALIZE_RUNTIME; else stubState = StubState.INITIAL; if (owner.startsWith("java/util/concurrent")) mBuilder.setUsesConcurrency(); if (opcode == Opcodes.INVOKEINTERFACE) return; if (owner.charAt(0) == '[' && owner.charAt(owner.length() - 1) != ';') { // primitive array return; } if (opcode == Opcodes.INVOKESTATIC && owner.equals("java/lang/System") && name.equals("exit") && !sawReturn) sawSystemExit = true; justSawInitializationOfUnsupportedOperationException = opcode == Opcodes.INVOKESPECIAL && owner.equals("java/lang/UnsupportedOperationException") && name.equals("<init>"); if (isBridge && bridgedMethodSignature == null) switch (opcode) { case Opcodes.INVOKEVIRTUAL: case Opcodes.INVOKESPECIAL: case Opcodes.INVOKESTATIC: case Opcodes.INVOKEINTERFACE: if (desc != null && name.equals(methodName)) bridgedMethodSignature = desc; } // System.out.println("Call from " + // ClassParserUsingASM.this.slashedClassName + // " to " + owner + " : " + desc); if (desc == null || desc.indexOf('[') == -1 && desc.indexOf('L') == -1) return; if (ClassParserUsingASM.this.slashedClassName.equals(owner)) return; ClassDescriptor classDescriptor = DescriptorFactory.instance().getClassDescriptor(owner); calledClassSet.add(classDescriptor); // System.out.println("Added call from " + // ClassParserUsingASM.this.slashedClassName + // " to " + owner); state = State.AFTER_METHOD_CALL; } @Override public void visitJumpInsn(int opcode, Label label) { sawBranch = true; if (labelsSeen.contains(label)) sawBackBranch = true; super.visitJumpInsn(opcode, label); } @Override public void visitLabel(Label label) { labelsSeen.add(label); super.visitLabel(label); } public void visitEnd() { labelsSeen.clear(); if (isAccessMethod && methodCallCount == 1) { mBuilder.setAccessMethodFor( accessOwner, accessName, accessDesc, accessIsStatic); } if (sawBackBranch) mBuilder.setHasBackBranch(); boolean sawThrow = sawNormalThrow | sawUnsupportedThrow | sawStubThrow; if (sawThrow && !sawReturn || sawSystemExit && !sawBranch) { mBuilder.setIsUnconditionalThrower(); if (!sawReturn && !sawNormalThrow) { if (sawUnsupportedThrow) mBuilder.setUnsupported(); if (sawStubThrow) { mBuilder.addAccessFlags(Constants.ACC_SYNTHETIC); mBuilder.setIsStub(); } } // else // System.out.println(slashedClassName+"."+methodName+methodDesc // + " is thrower"); } mBuilder.setNumberMethodCalls(methodCallCount); MethodInfo methodInfo = mBuilder.build(); Builder classBuilder = (ClassInfo.Builder) cBuilder; if (isBridge && bridgedMethodSignature != null && !bridgedMethodSignature.equals(methodDesc)) classBuilder.addBridgeMethodDescriptor(methodInfo, bridgedMethodSignature); else classBuilder.addMethodDescriptor(methodInfo); if (methodInfo.usesConcurrency()) classBuilder.setUsesConcurrency(); if (methodInfo.isStub()) classBuilder.setHasStubs(); } public org.objectweb.asm.AnnotationVisitor visitParameterAnnotation( int parameter, String desc, boolean visible) { AnnotationValue value = new AnnotationValue(desc); mBuilder.addParameterAnnotation(parameter, desc, value); return value.getAnnotationVisitor(); } }; } return null; } public void visitOuterClass(String owner, String name, String desc) {} public void visitSource(String arg0, String arg1) { if (cBuilder instanceof ClassInfo.Builder) { ((ClassInfo.Builder) cBuilder).setSource(arg0); } } }, ClassReader.SKIP_FRAMES); HashSet<ClassDescriptor> referencedClassSet = new HashSet<ClassDescriptor>(); // collect class references int constantPoolCount = classReader.readUnsignedShort(8); int offset = 10; char[] buf = new char[1024]; // System.out.println("constant pool count: " + constantPoolCount); for (int count = 1; count < constantPoolCount; count++) { int tag = classReader.readByte(offset); int size; switch (tag) { case Constants.CONSTANT_Methodref: case Constants.CONSTANT_InterfaceMethodref: case Constants.CONSTANT_Fieldref: case Constants.CONSTANT_Integer: case Constants.CONSTANT_Float: case Constants.CONSTANT_NameAndType: size = 5; break; case Constants.CONSTANT_Long: case Constants.CONSTANT_Double: size = 9; count++; break; case Constants.CONSTANT_Utf8: size = 3 + classReader.readUnsignedShort(offset + 1); break; case Constants.CONSTANT_Class: @SlashedClassName String className = classReader.readUTF8(offset + 1, buf); if (className.indexOf('[') >= 0) { ClassParser.extractReferencedClassesFromSignature(referencedClassSet, className); } else if (ClassName.isValidClassName(className)) { ClassDescriptor classDescriptor = DescriptorFactory.instance().getClassDescriptor(className); referencedClassSet.add(classDescriptor); } size = 3; break; // case ClassWriter.CLASS: // case ClassWriter.STR: case Constants.CONSTANT_String: size = 3; break; default: throw new IllegalStateException( "Unexpected tag of " + tag + " at offset " + offset + " while parsing " + slashedClassName + " from " + codeBaseEntry); } // System.out.println(count + "@" + offset + " : [" + tag // +"] size="+size); offset += size; } cBuilder.setCalledClassDescriptors(calledClassSet); cBuilder.setReferencedClassDescriptors(referencedClassSet); }