/** Creates a {@link Descriptor} based on a signature (such as {@code Ljava/lang/String;}. */ @SuppressWarnings("unchecked") Pair<Descriptor, Entity> create( String signature, EntityDescriptorStore store, FieldDescriptor fieldDescriptor, Map<Type, Class<?>> types) { SignatureReader r = new SignatureReader(signature); EntitySignatureVisitor entitySignatureVisitor = new EntitySignatureVisitor(signature, store, fieldDescriptor, types); r.accept(entitySignatureVisitor); return entitySignatureVisitor.getDescriptor(); }
@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); }
@Override public MethodVisitor visitMethod( int flags, String name, String desc, @Nullable String signature, @Nullable String[] exceptions) { Preconditions.checkNotNull(name); Preconditions.checkNotNull(desc); if (!BytecodeCompleter.isSynthetic(flags)) { Preconditions.checkState( (flags & Opcodes.ACC_BRIDGE) == 0, "bridge method not marked as synthetic in class " + className); // TODO(Godin): according to JVMS 4.7.24 - parameter can be marked as synthetic MethodJavaType type = new MethodJavaType( convertAsmTypes(org.objectweb.asm.Type.getArgumentTypes(desc)), convertAsmType(org.objectweb.asm.Type.getReturnType(desc)), getCompletedClassSymbolsType(exceptions), classSymbol); final JavaSymbol.MethodJavaSymbol methodSymbol = new JavaSymbol.MethodJavaSymbol( bytecodeCompleter.filterBytecodeFlags(flags), name, type, classSymbol); classSymbol.members.enter(methodSymbol); if (signature != null) { SignatureReader signatureReader = new SignatureReader(signature); signatureReader.accept(new TypeParameterDeclaration(methodSymbol)); signatureReader.accept(new ReadMethodSignature(methodSymbol)); } methodSymbol.parameters = new Scope(methodSymbol); for (int i = 0; i < type.argTypes.size(); i += 1) { methodSymbol.parameters.enter( new JavaSymbol.VariableJavaSymbol(0, "arg" + i, methodSymbol)); } // checks for annotations on the method and its parameters return new BytecodeMethodVisitor(methodSymbol, this); } return null; }
@Test public void testAsm() { // String sig = "<E:Ljava/lang/Number;F:Ljava/lang/Object;>Ljava/lang/Object;"; // String sig = // "<V:Ljava/lang/Object;>Lcom/pongasoft/kiwidoc/testdata/pubdir1/Pub1Class2<Ljava/lang/Integer;Ljava/lang/Float;>;Lcom/pongasoft/kiwidoc/testdata/pubdir1/Pub1Interface2<TV;>;"; // String sig = // "<K:Ljava/lang/Object;>(TK;Lorg/hamcrest/Matcher<TK;>;Ljava/util/Set<Ljava/lang/String;>;)V"; // String sig // ="<E:Ljava/lang/Object;F:Ljava/lang/Number;G:Ljava/lang/Number;:Ljava/lang/Comparable<Ljava/lang/Number;>;H:TE;I::Ljava/util/List<TE;>;J::Ljava/util/List<Ljava/lang/Number;>;K::Ljava/util/List<+Ljava/lang/Number;>;L::Ljava/util/List<-Ljava/lang/Number;>;M::Ljava/util/List<+Ljava/util/List<Ljava/lang/Number;>;>;>Ljava/lang/Object;"; String sig = "<E:Ljava/lang/Object;F:Ljava/lang/Number;G:Ljava/lang/Number;:Ljava/lang/Comparable<Ljava/lang/Number;>;H:TE;I::Ljava/util/List<TE;>;J::Ljava/util/List<Ljava/lang/Number;>;K::Ljava/util/List<+Ljava/lang/Number;>;L::Ljava/util/List<-Ljava/lang/Number;>;M::Ljava/util/List<+Ljava/util/List<Ljava/lang/Number;>;>;N:Lcom/pongasoft/kiwidoc/testdata/pubdir1/C1$Inner1;:Lcom/pongasoft/kiwidoc/testdata/pubdir1/I1$Inner1;:Ljava/util/List<+Lcom/pongasoft/kiwidoc/testdata/pubdir1/C1$Inner1;>;>Ljava/lang/Object;"; // String sig = "<K:Ljava/util/List<+Ljava/lang/Number;>;>Ljava/lang/Object;"; // String sig = "Ljava/util/HashMap<TK;TV;>.HashIterator<TK;>;"; SignatureReader reader = new SignatureReader(sig); reader.accept(new MySignatureVisitor("")); }
public MethodParameters(String desc) { super(Opcodes.ASM5); parameters = new ArrayList<Param>(); SignatureReader reader = new SignatureReader(desc); reader.accept(this); }
private void insertDeclMethod(String type, String signature, String desc, String name, int access) throws URISyntaxException { String sig; if (signature != null) { sig = extractSignature(signature); // TypeVariables SignatureReader sr = new SignatureReader(signature); sr.accept(new SigVisitor(Opcodes.ASM4)); } else { sig = extractSignature(desc); } // Typedepency methods String TypeSig = sig; // Loop over all parameters in the signature String[] params; if ((TypeSig != null) && (!TypeSig.equals(""))) { params = TypeSig.split(","); for (int i = 0; i < params.length; i++) { this.insert( this.typeDependency, values.sourceLocation( "java+parameter", "", LogPath + "/" + name + "(" + sig + ")" + "/" + params[i] + i), values.sourceLocation(printParameterType(params[i]), "", params[i])); } } // Return type if (type.equals("java+constructor")) { this.insert( this.typeDependency, values.sourceLocation("java+constructor", "", LogPath + "/" + name + "(" + sig + ")"), values.sourceLocation("java+class", "", LogPath)); } else { String rType = null; if (signature != null) { rType = Signature.toString(signature); } else { rType = Signature.toString(desc); } rType = rType.substring(0, rType.indexOf(' ')); this.insert( this.typeDependency, values.sourceLocation("java+method", "", LogPath + "/" + name + "(" + sig + ")"), values.sourceLocation(printParameterType(rType), "", rType)); } this.insert( this.declarations, values.sourceLocation(type, "", LogPath + "/" + name + "(" + sig + ")"), values.sourceLocation(jarFile + "!" + ClassFile)); for (int fs = 0; fs < 15; fs++) { if ((access & (0x0001 << fs)) != 0) { this.insert( this.modifiers, values.sourceLocation(type, "", LogPath + "/" + name + "(" + sig + ")"), mapFieldAccesCode(0x0001 << fs, METHODE)); } } // Containment of methods. this.insert( this.containment, values.sourceLocation(classScheme, "", LogPath), values.sourceLocation(type, "", LogPath + "/" + name + "(" + sig + ")")); // Deprecated method emit type annotation dependency Deprecated. if ((access & 0x20000) == 0x20000) this.insert( this.annotations, values.sourceLocation("java+method", "", LogPath + "/" + name + "(" + sig + ")"), values.sourceLocation("java+interface", "", "/java/lang/Deprecated")); // <|java+method:///Main/Main/FindMe(java.lang.String)|,|java+interface:///java/lang/Deprecated|>, }
private ClassObject parseBytecode(File file) { final ClassObject co = new ClassObject(); try { FileInputStream fin = new FileInputStream(file); ClassReader cr = new ClassReader(new DataInputStream(fin)); ClassNode cn = new ClassNode(); cr.accept(cn, ClassReader.SKIP_DEBUG); String name = cn.name; co.setName(name.replaceAll("/", ".")); if ((cn.access & Opcodes.ACC_INTERFACE) != 0) co.setInterface(true); else if ((cn.access & Opcodes.ACC_ABSTRACT) != 0) co.setAbstract(true); if ((cn.access & Opcodes.ACC_PUBLIC) != 0) co.setAccess(Access.PUBLIC); else if ((cn.access & Opcodes.ACC_PROTECTED) != 0) co.setAccess(Access.PROTECTED); else if ((cn.access & Opcodes.ACC_PRIVATE) != 0) co.setAccess(Access.PRIVATE); if ((cn.access & Opcodes.ACC_STATIC) != 0) co.setStatic(true); String superClass = cn.superName; co.setSuperclass(superClass.replaceAll("/", ".")); List interfaces = cn.interfaces; for (Object anInterface : interfaces) { String interfaceString = (String) anInterface; co.addInterface(interfaceString.replaceAll("/", ".")); } List fields = cn.fields; for (Object field : fields) { FieldNode fieldNode = (FieldNode) field; Type fieldType = Type.getType(fieldNode.desc); TypeObject typeObject = new TypeObject(fieldType.getClassName()); if (fieldNode.signature != null) { TraceSignatureVisitor v = new TraceSignatureVisitor(ClassReader.SKIP_DEBUG); SignatureReader r = new SignatureReader(fieldNode.signature); r.accept(v); String declaration = v.getDeclaration(); if (declaration.contains("<") && declaration.contains(">")) typeObject.setGeneric( declaration.substring(declaration.indexOf("<") + 1, declaration.lastIndexOf(">"))); } FieldObject fo = new FieldObject(typeObject, fieldNode.name); if ((fieldNode.access & Opcodes.ACC_PUBLIC) != 0) fo.setAccess(Access.PUBLIC); else if ((fieldNode.access & Opcodes.ACC_PROTECTED) != 0) fo.setAccess(Access.PROTECTED); else if ((fieldNode.access & Opcodes.ACC_PRIVATE) != 0) fo.setAccess(Access.PRIVATE); if ((fieldNode.access & Opcodes.ACC_STATIC) != 0) fo.setStatic(true); co.addField(fo); } List methods = cn.methods; for (Object method : methods) { MethodNode methodNode = (MethodNode) method; final ConstructorObject constructorObject = new ConstructorObject(); if ((methodNode.access & Opcodes.ACC_PUBLIC) != 0) constructorObject.setAccess(Access.PUBLIC); else if ((methodNode.access & Opcodes.ACC_PROTECTED) != 0) constructorObject.setAccess(Access.PROTECTED); else if ((methodNode.access & Opcodes.ACC_PRIVATE) != 0) constructorObject.setAccess(Access.PRIVATE); if (methodNode.signature != null) { TraceSignatureVisitor v = new TraceSignatureVisitor(ClassReader.SKIP_DEBUG); SignatureReader r = new SignatureReader(methodNode.signature); r.accept(v); String declaration = v.getDeclaration(); String temp = declaration; if (temp.startsWith("(")) temp = temp.substring(1, temp.length()); if (temp.endsWith("")) temp = temp.substring(0, temp.length() - 1); if (!temp.equals("")) { ParameterAnalyzer analyzer = new ParameterAnalyzer(temp); for (String token : analyzer.getParameters()) { if (token.contains("<") && token.contains(">")) { TypeObject typeObject = new TypeObject(token.substring(0, token.indexOf("<"))); typeObject.setGeneric( token.substring(token.indexOf("<") + 1, token.lastIndexOf(">"))); constructorObject.addParameter(typeObject); } else { constructorObject.addParameter(new TypeObject(token)); } } } } else { Type[] argumentTypes = Type.getArgumentTypes(methodNode.desc); for (Type argumentType : argumentTypes) constructorObject.addParameter(new TypeObject(argumentType.getClassName())); } if (methodNode.instructions.size() > 0) { Map<String, Integer> labelIndexMap = new HashMap<String, Integer>(); List<LoopObject> activeLoops = new ArrayList<LoopObject>(); Iterator insnIt = methodNode.instructions.iterator(); int index = 0; while (insnIt.hasNext()) { AbstractInsnNode ainsn = (AbstractInsnNode) insnIt.next(); if (ainsn instanceof LabelNode) { LabelNode labelNode = (LabelNode) ainsn; Label label = labelNode.getLabel(); LoopObject loop = new LoopObject(label.toString()); activeLoops.add(loop); labelIndexMap.put(label.toString(), index); } if (ainsn instanceof JumpInsnNode) { JumpInsnNode jumpNode = (JumpInsnNode) ainsn; Label label = jumpNode.label.getLabel(); if (labelIndexMap.containsKey(label.toString())) { LoopObject matchingLoop = null; for (LoopObject loop : activeLoops) { if (loop.getLabel().equals(label.toString())) { matchingLoop = loop; break; } } if (matchingLoop != null) { constructorObject.addLoop(matchingLoop); activeLoops.remove(matchingLoop); } } } if (ainsn instanceof FieldInsnNode) { FieldInsnNode fieldInsnNode = (FieldInsnNode) ainsn; Type fieldType = Type.getType(fieldInsnNode.desc); FieldInstructionObject fieldObject = new FieldInstructionObject( fieldInsnNode.owner.replaceAll("/", "."), fieldType.getClassName(), fieldInsnNode.name); constructorObject.addFieldInstruction(fieldObject); for (LoopObject loop : activeLoops) { loop.addFieldInstruction(fieldObject); } } if ((ainsn.getOpcode() == Opcodes.INVOKEVIRTUAL) || (ainsn.getOpcode() == Opcodes.INVOKESTATIC) || (ainsn.getOpcode() == Opcodes.INVOKESPECIAL) || (ainsn.getOpcode() == Opcodes.INVOKEINTERFACE)) { MethodInsnNode minsn = (MethodInsnNode) ainsn; MethodInvocationObject mio = new MethodInvocationObject( minsn.owner.replaceAll("/", "."), minsn.name, Type.getReturnType(minsn.desc).getClassName()); Type[] argTypes = Type.getArgumentTypes(minsn.desc); for (Type argType : argTypes) mio.addParameter(argType.getClassName()); constructorObject.addMethodInvocation(mio); for (LoopObject loop : activeLoops) { loop.addMethodInvocation(mio); } } if ((ainsn.getOpcode() == Opcodes.NEW) || (ainsn.getOpcode() == Opcodes.ANEWARRAY)) { TypeInsnNode tinsn = (TypeInsnNode) ainsn; constructorObject.addObjectInstantiation(tinsn.desc.replaceAll("/", ".")); } index++; } } if (methodNode.name.equals("<init>")) { constructorObject.setName(co.getName()); co.addConstructor(constructorObject); } else { Type returnType = Type.getReturnType(methodNode.desc); constructorObject.setName(methodNode.name); MethodObject methodObject = new MethodObject(constructorObject); TypeObject typeObject = new TypeObject(returnType.getClassName()); if (methodNode.signature != null) { TraceSignatureVisitor v = new TraceSignatureVisitor(ClassReader.SKIP_DEBUG); SignatureReader r = new SignatureReader(methodNode.signature); r.accept(v); String genericReturnType = v.getReturnType(); if (genericReturnType.contains("<") && genericReturnType.contains(">")) typeObject.setGeneric( genericReturnType.substring( genericReturnType.indexOf("<") + 1, genericReturnType.lastIndexOf(">"))); } methodObject.setReturnType(typeObject); methodObject.setClassName(co.getName()); if ((methodNode.access & Opcodes.ACC_ABSTRACT) != 0) methodObject.setAbstract(true); if ((methodNode.access & Opcodes.ACC_STATIC) != 0) methodObject.setStatic(true); co.addMethod(methodObject); } } fin.close(); } catch (FileNotFoundException fnfe) { fnfe.printStackTrace(); } catch (IOException ioe) { ioe.printStackTrace(); } return co; }