org.sonar.java.bytecode.cfg.BytecodeListingParser.java Source code

Java tutorial

Introduction

Here is the source code for org.sonar.java.bytecode.cfg.BytecodeListingParser.java

Source

/*
 * SonarQube Java
 * Copyright (C) 2012-2018 SonarSource SA
 * mailto:info AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonar.java.bytecode.cfg;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.util.Printer;
import org.sonar.java.resolve.JavaSymbol;

import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.IINC;
import static org.objectweb.asm.Opcodes.V1_8;
import static org.sonar.java.bytecode.cfg.Instructions.FIELD_INSN;
import static org.sonar.java.bytecode.cfg.Instructions.INT_INSN;
import static org.sonar.java.bytecode.cfg.Instructions.JUMP_INSN;
import static org.sonar.java.bytecode.cfg.Instructions.METHOD_INSN;
import static org.sonar.java.bytecode.cfg.Instructions.NO_OPERAND_INSN;
import static org.sonar.java.bytecode.cfg.Instructions.TYPE_INSN;
import static org.sonar.java.bytecode.cfg.Instructions.VAR_INSN;
import static org.sonar.java.resolve.BytecodeCompleter.ASM_API_VERSION;

public class BytecodeListingParser {

    public static BytecodeCFG getCFG(String bytecodeInstructions) {
        // Define class and method stub for instructions
        ClassWriter cw = new ClassWriter(ASM_API_VERSION);
        cw.visit(V1_8, ACC_PUBLIC, "A", null, "java/lang/Object", null);
        MethodVisitor mv = cw.visitMethod(ACC_PRIVATE, "test", "()V", null, null);
        JavaSymbol.MethodJavaSymbol methodStub = new JavaSymbol.MethodJavaSymbol(0, "test", null);
        Map<Integer, Label> labelIndexes = new HashMap<>();
        String[] lines = bytecodeInstructions.split("\n");
        for (String line : lines) {
            visitLine(line.trim().split(" "), mv, labelIndexes);
        }
        mv.visitEnd();
        cw.visitEnd();
        byte[] bytes = cw.toByteArray();
        return Instructions.getBytecodeCFG(bytes);
    }

    private static void visitLine(String[] words, MethodVisitor mv, Map<Integer, Label> labelIndexes) {
        // labels :
        String initWord = words[0];
        if (initWord.matches("L\\d+")) {
            mv.visitLabel(labelIndexes.computeIfAbsent(Integer.parseInt(initWord.substring(1)), k -> new Label()));
        }

        int opcode = Arrays.asList(Printer.OPCODES).indexOf(initWord);
        if (opcode == -1) {
            return;
        }
        if (NO_OPERAND_INSN.contains(opcode)) {
            mv.visitInsn(opcode);
        } else if (INT_INSN.contains(opcode)) {
            mv.visitIntInsn(opcode, Integer.parseInt(words[1]));
        } else if (VAR_INSN.contains(opcode)) {
            mv.visitVarInsn(opcode, Integer.parseInt(words[1]));
        } else if (TYPE_INSN.contains(opcode)) {
            mv.visitTypeInsn(opcode, words[1]);
        } else if (FIELD_INSN.contains(opcode)) {
            mv.visitFieldInsn(opcode, words[1], words[2], words[3]);
        } else if (METHOD_INSN.contains(opcode)) {
            // FIXME: interface flag is hardcoded.
            mv.visitMethodInsn(opcode, words[1], words[2], words[3], false);
        } else if (JUMP_INSN.contains(opcode)) {
            mv.visitJumpInsn(opcode,
                    labelIndexes.computeIfAbsent(Integer.parseInt(words[1].substring(1)), k -> new Label()));
        } else if (opcode == IINC) {
            mv.visitIincInsn(Integer.parseInt(words[1]), Integer.parseInt(words[2]));
        }

    }
}