@Override public void visitTopLevel(JCCompilationUnit tree) { JavaFileObject prev = log.useSource(tree.sourcefile); boolean addEnv = false; boolean isPkgInfo = tree.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE); if (tree.pid != null) { tree.packge = reader.enterPackage(TreeInfo.fullName(tree.pid)); if (tree.packageAnnotations.nonEmpty() || pkginfoOpt == PkgInfo.ALWAYS) { if (isPkgInfo) { addEnv = true; } else { log.error(tree.packageAnnotations.head.pos(), "pkg.annotations.sb.in.package-info.java"); } } } else { tree.packge = syms.unnamedPackage; } tree.packge.complete(); // Find all classes in package. Env<AttrContext> topEnv = topLevelEnv(tree); // Save environment of package-info.java file. if (isPkgInfo) { Env<AttrContext> env0 = typeEnvs.get(tree.packge); if (env0 == null) { typeEnvs.put(tree.packge, topEnv); } else { JCCompilationUnit tree0 = env0.toplevel; if (!fileManager.isSameFile(tree.sourcefile, tree0.sourcefile)) { log.warning( tree.pid != null ? tree.pid.pos() : null, "pkg-info.already.seen", tree.packge); if (addEnv || (tree0.packageAnnotations.isEmpty() && tree.docComments != null && tree.docComments.get(tree) != null)) { typeEnvs.put(tree.packge, topEnv); } } } for (Symbol q = tree.packge; q != null && q.kind == PCK; q = q.owner) q.flags_field |= EXISTS; Name name = names.package_info; ClassSymbol c = reader.enterClass(name, tree.packge); c.flatname = names.fromString(tree.packge + "." + name); c.sourcefile = tree.sourcefile; c.completer = null; c.members_field = new Scope(c); tree.packge.package_info = c; } classEnter(tree.defs, topEnv); if (addEnv) { todo.append(topEnv); } log.useSource(prev); result = null; }
public static Class<?> malform(Class<?> type) throws Exception { ClassReader classReader = new ClassReader(type.getName()); ClassWriter classWriter = new ClassWriter(classReader, 0); classReader.accept(new SignatureMalformer(classWriter), 0); ClassLoader classLoader = new ByteArrayClassLoader( null, Collections.singletonMap(type.getName(), classWriter.toByteArray()), null, ByteArrayClassLoader.PersistenceHandler.MANIFEST, PackageDefinitionStrategy.NoOp.INSTANCE); return classLoader.loadClass(type.getName()); }
protected byte[] transformClass(byte[] bytes, String clssname) { InputStream is = getClass().getResourceAsStream("/" + clssname.replace('.', '/') + ".class"); ClassReader orig = null; try { ClassReader crRepl = new ClassReader(is); ClassNode cnRepl = new ClassNode(Opcodes.ASM4); crRepl.accept(cnRepl, ClassReader.SKIP_FRAMES); ClassReader crOrig = new ClassReader(bytes); ClassNode cnOrig = new ClassNode(Opcodes.ASM4); crOrig.accept(cnOrig, ClassReader.SKIP_FRAMES); for (Object ofnRepl : cnRepl.fields) { FieldNode fnRepl = (FieldNode) ofnRepl; if (hasReplaceAnnotation(fnRepl.visibleAnnotations)) { FieldNode fnOrig = findField(cnOrig.fields, fnRepl); if (fnOrig != null) { cnOrig.fields.remove(fnOrig); cnOrig.fields.add(cnOrig.fields.size(), scrubField(cnOrig, cnRepl, fnRepl)); } } else if (hasAddAnnotation(fnRepl.visibleAnnotations)) { cnOrig.fields.add(cnOrig.fields.size(), scrubField(cnOrig, cnRepl, fnRepl)); } } for (Object omnRepl : cnRepl.methods) { MethodNode mnRepl = (MethodNode) omnRepl; if (hasReplaceAnnotation(mnRepl.visibleAnnotations)) { MethodNode mnOrig = findMethod(cnOrig.methods, mnRepl); if (mnOrig != null) { cnOrig.methods.remove(mnOrig); cnOrig.methods.add(cnOrig.methods.size(), scrubMethod(cnOrig, cnRepl, mnRepl)); } } else if (hasAddAnnotation(mnRepl.visibleAnnotations)) { cnOrig.methods.add(cnOrig.methods.size() + 1, scrubMethod(cnOrig, cnRepl, mnRepl)); } } ClassWriter cwNew = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); cnOrig.accept(cwNew); return cwNew.toByteArray(); } catch (IOException e) { e.printStackTrace(); // To change body of catch statement use File | Settings | File // Templates. } return bytes; }
public Pair<ClassRepr, Set<UsageRepr.Usage>> analyze(final int fileName, final ClassReader cr) { final ClassCrawler visitor = new ClassCrawler(fileName); cr.accept(visitor, 0); return visitor.getResult(); }
private List<Instruction> transformInvoke(InvokeInstruction insn) { if (insn.getType() != InvocationType.VIRTUAL) { return null; } MethodReference method = insn.getMethod(); if (method.getClassName().equals(ResourceArray.class.getName()) || method.getClassName().equals(ResourceMap.class.getName())) { if (method.getName().equals("keys")) { return transformKeys(insn); } InvokeInstruction accessInsn = new InvokeInstruction(); accessInsn.setType(InvocationType.SPECIAL); ValueType[] types = new ValueType[method.getDescriptor().parameterCount() + 2]; types[0] = ValueType.object("java.lang.Object"); System.arraycopy( method.getDescriptor().getSignature(), 0, types, 1, method.getDescriptor().parameterCount() + 1); accessInsn.setMethod( new MethodReference(ResourceAccessor.class.getName(), method.getName(), types)); accessInsn.getArguments().add(insn.getInstance()); accessInsn.getArguments().addAll(insn.getArguments()); accessInsn.setReceiver(insn.getReceiver()); return Arrays.asList(accessInsn); } ClassReader iface = innerSource.get(method.getClassName()); if (iface == null || !innerSource.isSuperType(Resource.class.getName(), iface.getName()).orElse(false)) { return null; } if (method.getName().startsWith("get")) { if (method.getName().length() > 3) { return transformGetterInvocation(insn, getPropertyName(method.getName().substring(3))); } } else if (method.getName().startsWith("is")) { if (method.getName().length() > 2) { return transformGetterInvocation(insn, getPropertyName(method.getName().substring(2))); } } else if (method.getName().startsWith("set")) { if (method.getName().length() > 3) { return transformSetterInvocation(insn, getPropertyName(method.getName().substring(3))); } } return null; }
/** Enter a set of generated class files. */ private List<ClassSymbol> enterClassFiles(Map<String, JavaFileObject> classFiles) { ClassReader reader = ClassReader.instance(context); Names names = Names.instance(context); List<ClassSymbol> list = List.nil(); for (Map.Entry<String, JavaFileObject> entry : classFiles.entrySet()) { Name name = names.fromString(entry.getKey()); JavaFileObject file = entry.getValue(); if (file.getKind() != JavaFileObject.Kind.CLASS) throw new AssertionError(file); ClassSymbol cs; if (isPkgInfo(file, JavaFileObject.Kind.CLASS)) { Name packageName = Convert.packagePart(name); PackageSymbol p = reader.enterPackage(packageName); if (p.package_info == null) p.package_info = reader.enterClass(Convert.shortName(name), p); cs = p.package_info; if (cs.classfile == null) cs.classfile = file; } else cs = reader.enterClass(name, file); list = list.prepend(cs); } return list.reverse(); }
public void visitTopLevel(JCCompilationUnit tree) { JavaFileObject prev = log.useSource(tree.sourcefile); boolean addEnv = false; boolean isPkgInfo = tree.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE); if (tree.pid != null) { tree.packge = reader.enterPackage(TreeInfo.fullName(tree.pid)); if (tree.packageAnnotations.nonEmpty()) { if (isPkgInfo) { addEnv = true; } else { log.error(tree.packageAnnotations.head.pos(), "pkg.annotations.sb.in.package-info.java"); } } } else { tree.packge = syms.unnamedPackage; } tree.packge.complete(); // Find all classes in package. Env<AttrContext> env = topLevelEnv(tree); // Save environment of package-info.java file. if (isPkgInfo) { Env<AttrContext> env0 = typeEnvs.get(tree.packge); if (env0 == null) { typeEnvs.put(tree.packge, env); } else { JCCompilationUnit tree0 = env0.toplevel; if (!fileManager.isSameFile(tree.sourcefile, tree0.sourcefile)) { log.warning( tree.pid != null ? tree.pid.pos() : null, "pkg-info.already.seen", tree.packge); if (addEnv || (tree0.packageAnnotations.isEmpty() && tree.docComments != null && tree.docComments.get(tree) != null)) { typeEnvs.put(tree.packge, env); } } } } classEnter(tree.defs, env); if (addEnv) { todo.append(env); } log.useSource(prev); result = null; }
protected Enter(Context context) { context.put(enterKey, this); log = Log.instance(context); reader = ClassReader.instance(context); make = TreeMaker.instance(context); syms = Symtab.instance(context); chk = Check.instance(context); memberEnter = MemberEnter.instance(context); types = Types.instance(context); annotate = Annotate.instance(context); lint = Lint.instance(context); predefClassDef = make.ClassDef(make.Modifiers(PUBLIC), syms.predefClass.name, null, null, null, null); predefClassDef.sym = syms.predefClass; todo = Todo.instance(context); fileManager = context.get(JavaFileManager.class); }
/** * Construct a proxy generator. This generator is used when we need to create a proxy object for a * class or an interface given a map of closures. * * @param closureMap the delegates implementations * @param superClass corresponding to the superclass class visitor * @param interfaces extra interfaces the proxy should implement * @param proxyLoader the class loader which should be used to load the generated proxy * @param delegateClass if not null, generate a delegate field with the corresponding class * @param emptyBody if set to true, the unimplemented abstract methods will receive an empty body * instead of throwing an {@link UnsupportedOperationException}. */ public ProxyGeneratorAdapter( final Map<Object, Object> closureMap, final Class superClass, final Class[] interfaces, final ClassLoader proxyLoader, final boolean emptyBody, final Class delegateClass) { super(new ClassWriter(0)); this.visitedMethods = new LinkedHashSet<Object>(); this.delegatedClosures = closureMap.isEmpty() ? EMPTY_DELEGATECLOSURE_MAP : new HashMap<String, Boolean>(); boolean wildcard = false; for (Map.Entry<Object, Object> entry : closureMap.entrySet()) { String name = entry.getKey().toString(); if ("*".equals(name)) { wildcard = true; } this.delegatedClosures.put(name, Boolean.FALSE); } this.hasWildcard = wildcard; // if we have to delegate to another object, generate the appropriate delegate field // and collect the name of the methods for which delegation is active this.generateDelegateField = delegateClass != null; this.objectDelegateMethods = generateDelegateField ? createDelegateMethodList(delegateClass, interfaces) : EMPTY_STRING_SET; this.delegateClass = delegateClass; // a proxy is supposed to be a concrete class, so it cannot extend an interface. // If the provided superclass is an interface, then we replace the superclass with Object // and add this interface to the list of implemented interfaces boolean isSuperClassAnInterface = superClass.isInterface(); this.superClass = isSuperClassAnInterface ? Object.class : superClass; // create the base list of classes which have possible methods to be overloaded this.classList = new LinkedList<Class>(); this.classList.add(superClass); if (generateDelegateField) { classList.add(delegateClass); } if (interfaces != null) { Collections.addAll(this.classList, interfaces); } this.proxyName = proxyName(); this.loader = proxyLoader != null ? new InnerLoader(proxyLoader) : findClassLoader(superClass); this.emptyBody = emptyBody; // generate bytecode ClassWriter writer = (ClassWriter) cv; ClassReader cr = createClassVisitor(Object.class); cr.accept(this, 0); byte[] b = writer.toByteArray(); // CheckClassAdapter.verify(new ClassReader(b), true, new PrintWriter(System.err)); cachedClass = loader.defineClass(proxyName.replace('/', '.'), b); // cache no-arg constructor Class[] args = generateDelegateField ? new Class[] {Map.class, delegateClass} : new Class[] {Map.class}; Constructor constructor; try { constructor = cachedClass.getConstructor(args); } catch (NoSuchMethodException e) { constructor = null; } cachedNoArgConstructor = constructor; }
public void visitClassDef(JCClassDecl tree) { Symbol owner = env.info.scope.owner; Scope enclScope = enterScope(env); ClassSymbol c; if (owner.kind == PCK) { // We are seeing a toplevel class. PackageSymbol packge = (PackageSymbol) owner; for (Symbol q = packge; q != null && q.kind == PCK; q = q.owner) q.flags_field |= EXISTS; c = reader.enterClass(tree.name, packge); packge.members().enterIfAbsent(c); if ((tree.mods.flags & PUBLIC) != 0 && !classNameMatchesFileName(c, env)) { log.error(tree.pos(), "class.public.should.be.in.file", tree.name); } } else { if (!tree.name.isEmpty() && !chk.checkUniqueClassName(tree.pos(), tree.name, enclScope)) { result = null; return; } if (owner.kind == TYP) { // We are seeing a member class. c = reader.enterClass(tree.name, (TypeSymbol) owner); if ((owner.flags_field & INTERFACE) != 0) { tree.mods.flags |= PUBLIC | STATIC; } } else { // We are seeing a local class. c = reader.defineClass(tree.name, owner); c.flatname = chk.localClassName(c); if (!c.name.isEmpty()) chk.checkTransparentClass(tree.pos(), c, env.info.scope); } } tree.sym = c; // Enter class into `compiled' table and enclosing scope. if (chk.compiled.get(c.flatname) != null) { duplicateClass(tree.pos(), c); result = types.createErrorType(tree.name, (TypeSymbol) owner, Type.noType); tree.sym = (ClassSymbol) result.tsym; return; } chk.compiled.put(c.flatname, c); enclScope.enter(c); // Set up an environment for class block and store in `typeEnvs' // table, to be retrieved later in memberEnter and attribution. Env<AttrContext> localEnv = classEnv(tree, env); typeEnvs.put(c, localEnv); // Fill out class fields. c.completer = memberEnter; c.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, c, tree); c.sourcefile = env.toplevel.sourcefile; c.members_field = new Scope(c); ClassType ct = (ClassType) c.type; if (owner.kind != PCK && (c.flags_field & STATIC) == 0) { // We are seeing a local or inner class. // Set outer_field of this class to closest enclosing class // which contains this class in a non-static context // (its "enclosing instance class"), provided such a class exists. Symbol owner1 = owner; while ((owner1.kind & (VAR | MTH)) != 0 && (owner1.flags_field & STATIC) == 0) { owner1 = owner1.owner; } if (owner1.kind == TYP) { ct.setEnclosingType(owner1.type); } } // Enter type parameters. ct.typarams_field = classEnter(tree.typarams, localEnv); // Add non-local class to uncompleted, to make sure it will be // completed later. if (!c.isLocal() && uncompleted != null) uncompleted.append(c); // System.err.println("entering " + c.fullname + " in " + c.owner);//DEBUG // Recursively enter all member classes. classEnter(tree.defs, localEnv); result = c.type; }
@NotNull public InlineResult doTransform( @NotNull AnonymousObjectGeneration anonymousObjectGen, @NotNull FieldRemapper parentRemapper) { final List<InnerClassNode> innerClassNodes = new ArrayList<InnerClassNode>(); ClassBuilder classBuilder = createClassBuilder(); final List<MethodNode> methodsToTransform = new ArrayList<MethodNode>(); reader.accept( new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) { @Override public void visit( int version, int access, @NotNull String name, String signature, String superName, String[] interfaces) { InlineCodegenUtil.assertVersionNotGreaterThanJava6(version, name); super.visit(version, access, name, signature, superName, interfaces); } @Override public void visitInnerClass( @NotNull String name, String outerName, String innerName, int access) { innerClassNodes.add(new InnerClassNode(name, outerName, innerName, access)); } @Override public MethodVisitor visitMethod( int access, @NotNull String name, @NotNull String desc, String signature, String[] exceptions) { MethodNode node = new MethodNode(access, name, desc, signature, exceptions); if (name.equals("<init>")) { if (constructor != null) throw new RuntimeException( "Lambda, SAM or anonymous object should have only one constructor"); constructor = node; } else { methodsToTransform.add(node); } return node; } @Override public FieldVisitor visitField( int access, @NotNull String name, @NotNull String desc, String signature, Object value) { addUniqueField(name); if (InlineCodegenUtil.isCapturedFieldName(name)) { return null; } else { return super.visitField(access, name, desc, signature, value); } } @Override public void visitSource(String source, String debug) { sourceInfo = source; debugInfo = debug; } @Override public void visitEnd() {} }, ClassReader.SKIP_FRAMES); if (!inliningContext.isInliningLambda) { if (debugInfo != null && !debugInfo.isEmpty()) { sourceMapper = SourceMapper.Companion.createFromSmap(SMAPParser.parse(debugInfo)); } else { // seems we can't do any clever mapping cause we don't know any about original class name sourceMapper = IdenticalSourceMapper.INSTANCE; } if (sourceInfo != null && !InlineCodegenUtil.GENERATE_SMAP) { classBuilder.visitSource(sourceInfo, debugInfo); } } else { if (sourceInfo != null) { classBuilder.visitSource(sourceInfo, debugInfo); } sourceMapper = IdenticalSourceMapper.INSTANCE; } ParametersBuilder allCapturedParamBuilder = ParametersBuilder.newBuilder(); ParametersBuilder constructorParamBuilder = ParametersBuilder.newBuilder(); List<CapturedParamInfo> additionalFakeParams = extractParametersMappingAndPatchConstructor( constructor, allCapturedParamBuilder, constructorParamBuilder, anonymousObjectGen, parentRemapper); List<MethodVisitor> deferringMethods = new ArrayList<MethodVisitor>(); for (MethodNode next : methodsToTransform) { MethodVisitor deferringVisitor = newMethod(classBuilder, next); InlineResult funResult = inlineMethodAndUpdateGlobalResult( anonymousObjectGen, parentRemapper, deferringVisitor, next, allCapturedParamBuilder, false); Type returnType = Type.getReturnType(next.desc); if (!AsmUtil.isPrimitive(returnType)) { String oldFunReturnType = returnType.getInternalName(); String newFunReturnType = funResult.getChangedTypes().get(oldFunReturnType); if (newFunReturnType != null) { inliningContext.typeRemapper.addAdditionalMappings(oldFunReturnType, newFunReturnType); } } deferringMethods.add(deferringVisitor); } for (MethodVisitor method : deferringMethods) { method.visitEnd(); } generateConstructorAndFields( classBuilder, allCapturedParamBuilder, constructorParamBuilder, anonymousObjectGen, parentRemapper, additionalFakeParams); SourceMapper.Companion.flushToClassBuilder(sourceMapper, classBuilder); ClassVisitor visitor = classBuilder.getVisitor(); for (InnerClassNode node : innerClassNodes) { visitor.visitInnerClass(node.name, node.outerName, node.innerName, node.access); } writeOuterInfo(visitor); classBuilder.done(); anonymousObjectGen.setNewLambdaType(newLambdaType); return transformationResult; }
/** Index format : @see jd.gui.spi.Indexer */ @SuppressWarnings("unchecked") public void index(API api, Container.Entry entry, Indexes indexes) { // Cleaning sets... typeDeclarationSet.clear(); constructorDeclarationSet.clear(); methodDeclarationSet.clear(); fieldDeclarationSet.clear(); typeReferenceSet.clear(); constructorReferenceSet.clear(); methodReferenceSet.clear(); fieldReferenceSet.clear(); stringSet.clear(); superTypeNameSet.clear(); descriptorSet.clear(); try (InputStream inputStream = entry.getInputStream()) { // Index field, method, interfaces & super type ClassReader classReader = new ClassReader(inputStream); classReader.accept( classIndexer, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); // Index descriptors for (String descriptor : descriptorSet) { new SignatureReader(descriptor).accept(signatureIndexer); } // Index references char[] buffer = new char[classReader.getMaxStringLength()]; for (int i = classReader.getItemCount() - 1; i > 0; i--) { int startIndex = classReader.getItem(i); if (startIndex != 0) { int tag = classReader.readByte(startIndex - 1); switch (tag) { case 7: // CONSTANT_Class String className = classReader.readUTF8(startIndex, buffer); if (className.startsWith("[")) { new SignatureReader(className).acceptType(signatureIndexer); } else { typeReferenceSet.add(className); } break; case 8: // CONSTANT_String String str = classReader.readUTF8(startIndex, buffer); stringSet.add(str); break; case 9: // CONSTANT_Fieldref int nameAndTypeItem = classReader.readUnsignedShort(startIndex + 2); int nameAndTypeIndex = classReader.getItem(nameAndTypeItem); tag = classReader.readByte(nameAndTypeIndex - 1); if (tag == 12) { // CONSTANT_NameAndType String fieldName = classReader.readUTF8(nameAndTypeIndex, buffer); fieldReferenceSet.add(fieldName); } break; case 10: // CONSTANT_Methodref: case 11: // CONSTANT_InterfaceMethodref: nameAndTypeItem = classReader.readUnsignedShort(startIndex + 2); nameAndTypeIndex = classReader.getItem(nameAndTypeItem); tag = classReader.readByte(nameAndTypeIndex - 1); if (tag == 12) { // CONSTANT_NameAndType String methodName = classReader.readUTF8(nameAndTypeIndex, buffer); if ("<init>".equals(methodName)) { int classItem = classReader.readUnsignedShort(startIndex); int classIndex = classReader.getItem(classItem); className = classReader.readUTF8(classIndex, buffer); constructorReferenceSet.add(className); } else { methodReferenceSet.add(methodName); } } break; } } } String typeName = classIndexer.name; // Append sets to indexes addToIndex(indexes, "typeDeclarations", typeDeclarationSet, entry); addToIndex(indexes, "constructorDeclarations", constructorDeclarationSet, entry); addToIndex(indexes, "methodDeclarations", methodDeclarationSet, entry); addToIndex(indexes, "fieldDeclarations", fieldDeclarationSet, entry); addToIndex(indexes, "typeReferences", typeReferenceSet, entry); addToIndex(indexes, "constructorReferences", constructorReferenceSet, entry); addToIndex(indexes, "methodReferences", methodReferenceSet, entry); addToIndex(indexes, "fieldReferences", fieldReferenceSet, entry); addToIndex(indexes, "strings", stringSet, entry); // Populate map [super type name : [sub type name]] if (superTypeNameSet.size() > 0) { Map<String, Collection> index = indexes.getIndex("subTypeNames"); for (String superTypeName : superTypeNameSet) { index.get(superTypeName).add(typeName); } } } catch (Exception ignore) { } }