All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sootup.jimple.parser.JimpleConverter Maven / Gradle / Ivy

The newest version!
package sootup.jimple.parser;

/*-
 * #%L
 * SootUp
 * %%
 * Copyright (C) 1997 - 2024 Raja Vallée-Rai and others
 * %%
 * 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 2.1 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 General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.misc.ParseCancellationException;
import sootup.core.IdentifierFactory;
import sootup.core.frontend.OverridingBodySource;
import sootup.core.frontend.OverridingClassSource;
import sootup.core.frontend.ResolveException;
import sootup.core.graph.MutableBlockStmtGraph;
import sootup.core.inputlocation.AnalysisInputLocation;
import sootup.core.jimple.Jimple;
import sootup.core.jimple.basic.*;
import sootup.core.jimple.common.constant.*;
import sootup.core.jimple.common.expr.*;
import sootup.core.jimple.common.ref.IdentityRef;
import sootup.core.jimple.common.stmt.BranchingStmt;
import sootup.core.jimple.common.stmt.Stmt;
import sootup.core.jimple.javabytecode.stmt.JSwitchStmt;
import sootup.core.model.*;
import sootup.core.signatures.FieldSignature;
import sootup.core.signatures.MethodSignature;
import sootup.core.signatures.SootClassMemberSignature;
import sootup.core.signatures.SootClassMemberSubSignature;
import sootup.core.transform.BodyInterceptor;
import sootup.core.types.*;
import sootup.java.core.JavaIdentifierFactory;
import sootup.java.core.language.JavaJimple;
import sootup.jimple.JimpleBaseVisitor;
import sootup.jimple.JimpleParser;

public class JimpleConverter {

  public OverridingClassSource run(
      @Nonnull CharStream charStream,
      @Nonnull AnalysisInputLocation inputlocation,
      @Nonnull Path sourcePath) {
    return run(charStream, inputlocation, sourcePath, Collections.emptyList());
  }

  public OverridingClassSource run(
      @Nonnull CharStream charStream,
      @Nonnull AnalysisInputLocation inputlocation,
      @Nonnull Path sourcePath,
      @Nonnull List bodyInterceptors) {

    final JimpleParser jimpleParser =
        JimpleConverterUtil.createJimpleParser(charStream, sourcePath);
    jimpleParser.setErrorHandler(new BailErrorStrategy());

    return run(jimpleParser, inputlocation, sourcePath, bodyInterceptors);
  }

  public OverridingClassSource run(
      @Nonnull JimpleParser parser,
      @Nonnull AnalysisInputLocation inputlocation,
      @Nonnull Path sourcePath) {
    return run(parser, inputlocation, sourcePath, Collections.emptyList());
  }

  public OverridingClassSource run(
      @Nonnull JimpleParser parser,
      @Nonnull AnalysisInputLocation inputlocation,
      @Nonnull Path sourcePath,
      @Nonnull List bodyInterceptors) {

    // FIXME: [ms] apply bodyInterceptors or better: move that logic into View itself!

    ClassVisitor classVisitor;
    try {
      classVisitor = new ClassVisitor(sourcePath);
      classVisitor.visit(parser.file());
    } catch (ParseCancellationException ex) {
      throw new ResolveException("Syntax Error", sourcePath, ex);
    }

    return new OverridingClassSource(
        classVisitor.methods,
        classVisitor.fields,
        classVisitor.modifiers,
        classVisitor.interfaces,
        classVisitor.superclass,
        classVisitor.outerclass,
        classVisitor.position,
        sourcePath,
        classVisitor.clazz,
        inputlocation);
  }

  private static class ClassVisitor extends JimpleBaseVisitor {

    @Nonnull
    private final IdentifierFactory identifierFactory = JavaIdentifierFactory.getInstance();

    @Nonnull private final JimpleConverterUtil util;
    @Nonnull private final Path path;

    public ClassVisitor(@Nonnull Path path) {
      this.path = path;
      util = new JimpleConverterUtil(path);
    }

    private ClassType clazz = null;
    Set fields = new HashSet<>();
    Set methods = new HashSet<>();
    ClassType superclass = null;
    Set interfaces = null;
    ClassType outerclass = null; // currently not determined in Java etc -> heuristic will be used
    Position position = NoPositionInformation.getInstance();
    EnumSet modifiers = null;

    @Override
    @Nonnull
    public Boolean visitFile(@Nonnull JimpleParser.FileContext ctx) {

      position = JimpleConverterUtil.buildPositionFromCtx(ctx);

      // imports
      ctx.importItem().stream().filter(item -> item.location != null).forEach(util::addImport);

      // class_name
      if (ctx.classname != null) {

        // "$" in classname is a heuristic for an inner/outer class
        final String classname = ctx.classname.getText();
        final int dollarPostition = classname.indexOf('$');
        if (dollarPostition > -1) {
          outerclass = util.getClassType(classname.substring(0, dollarPostition));
        }
        clazz = util.getClassType(classname);

      } else {
        throw new ResolveException(
            "Classname is not well formed.", path, JimpleConverterUtil.buildPositionFromCtx(ctx));
      }

      modifiers = getClassModifiers(ctx.class_modifier());
      // file_type
      if (ctx.file_type() != null) {
        if (ctx.file_type().getText().equals("interface")) {
          modifiers.add(ClassModifier.INTERFACE);
        }
        if (ctx.file_type().getText().equals("annotation")) {
          modifiers.add(ClassModifier.ANNOTATION);
        }
      }

      // extends_clause
      if (ctx.extends_clause() != null) {
        superclass = util.getClassType(ctx.extends_clause().classname.getText());
      } else {
        superclass = null;
      }

      // implements_clause
      if (ctx.implements_clause() != null) {
        interfaces = util.getClassTypeSet(ctx.implements_clause().type_list());
      } else {
        interfaces = Collections.emptySet();
      }

      // member
      for (int i = 0; i < ctx.member().size(); i++) {
        if (ctx.member(i).method() != null) {
          final SootMethod m = new MethodVisitor().visitMember(ctx.member(i));
          if (methods.stream()
              .anyMatch(
                  meth -> {
                    final MethodSignature signature = m.getSignature();
                    return meth.getSignature().equals(signature);
                  })) {
            throw new ResolveException(
                "Method with the same Signature does already exist.", path, m.getPosition());
          }
          methods.add(m);

        } else {
          final JimpleParser.FieldContext fieldCtx = ctx.member(i).field();
          EnumSet modifier = getFieldModifiers(fieldCtx.field_modifier());
          final Position pos = JimpleConverterUtil.buildPositionFromCtx(fieldCtx);
          final String fieldName = Jimple.unescape(fieldCtx.identifier().getText());
          final SootField f =
              new SootField(
                  identifierFactory.getFieldSignature(fieldName, clazz, fieldCtx.type().getText()),
                  modifier,
                  pos);
          if (fields.stream().anyMatch(e -> e.getName().equals(fieldName))) {
            throw new ResolveException("Field with the same name does already exist.", path, pos);
          } else {
            fields.add(f);
          }
        }
      }

      return true;
    }

    private EnumSet getClassModifiers(
        List modifier) {
      return modifier.stream()
          .map(modContext -> ClassModifier.valueOf(modContext.getText().toUpperCase()))
          .collect(Collectors.toCollection(() -> EnumSet.noneOf(ClassModifier.class)));
    }

    private EnumSet getMethodModifiers(
        List modifier) {
      return modifier.stream()
          .map(
              modContext -> {
                // we need the following check, as old Soot wrongfully mapped VARARGS method
                // modifiers to TRANSIENT modifiers
                if (modContext.getText().equalsIgnoreCase("TRANSIENT")) {
                  return MethodModifier.valueOf("VARARGS");
                }
                return MethodModifier.valueOf(modContext.getText().toUpperCase());
              })
          .collect(Collectors.toCollection(() -> EnumSet.noneOf(MethodModifier.class)));
    }

    private EnumSet getFieldModifiers(
        List modifier) {
      return modifier.stream()
          .map(modContext -> FieldModifier.valueOf(modContext.getText().toUpperCase()))
          .collect(Collectors.toCollection(() -> EnumSet.noneOf(FieldModifier.class)));
    }

    private class MethodVisitor extends JimpleBaseVisitor {

      private final HashMap> unresolvedBranches = new HashMap<>();
      private final HashMap labeledStmts = new HashMap<>();
      private HashMap locals = new HashMap<>();

      public Local getLocal(@Nonnull String name) {
        return locals.computeIfAbsent(
            name, (ignored) -> new Local(name, UnknownType.getInstance()));
      }

      @Override
      @Nonnull
      public SootMethod visitMethod(@Nonnull JimpleParser.MethodContext ctx) {

        EnumSet modifier =
            ctx.method_modifier() == null
                ? EnumSet.noneOf(MethodModifier.class)
                : getMethodModifiers(ctx.method_modifier());

        final JimpleParser.Method_subsignatureContext method_subsignatureContext =
            ctx.method_subsignature();
        if (method_subsignatureContext == null) {
          throw new ResolveException(
              "Methodsubsignature not found.", path, JimpleConverterUtil.buildPositionFromCtx(ctx));
        }

        final Type type = util.getType(method_subsignatureContext.type().getText());
        if (type == null) {
          throw new ResolveException(
              "Returntype not found.", path, JimpleConverterUtil.buildPositionFromCtx(ctx));
        }

        final String methodname = method_subsignatureContext.method_name().getText();
        if (methodname == null) {
          throw new ResolveException(
              "Methodname not found.", path, JimpleConverterUtil.buildPositionFromCtx(ctx));
        }

        List params = util.getTypeList(method_subsignatureContext.type_list());

        MethodSignature methodSignature =
            identifierFactory.getMethodSignature(clazz, Jimple.unescape(methodname), type, params);

        List exceptions =
            ctx.throws_clause() == null
                ? Collections.emptyList()
                : util.getClassTypeList(ctx.throws_clause().type_list());

        List traps = new ArrayList<>();
        List> blocks = new ArrayList<>();
        Map> successorMap = new HashMap<>();

        if (ctx.method_body() == null) {
          throw new ResolveException(
              "404 Body not found.", path, JimpleConverterUtil.buildPositionFromCtx(ctx));
        } else if (ctx.method_body().SEMICOLON() == null) {

          // declare locals
          locals = new HashMap<>();
          final JimpleParser.Method_body_contentsContext method_body_contentsContext =
              ctx.method_body().method_body_contents();
          if (method_body_contentsContext.declarations() != null) {
            for (JimpleParser.DeclarationContext it :
                method_body_contentsContext.declarations().declaration()) {
              final String typeStr = it.type().getText();
              Type localtype =
                  typeStr.equals("unknown") ? UnknownType.getInstance() : util.getType(typeStr);

              // validate nonvoid
              if (localtype == VoidType.getInstance()) {
                throw new ResolveException(
                    "Void is not an allowed Type for a Local.",
                    path,
                    JimpleConverterUtil.buildPositionFromCtx(ctx));
              }

              if (it.arg_list() != null) {
                final List immediates = it.arg_list().immediate();
                if (immediates != null) {
                  for (JimpleParser.ImmediateContext immediate : immediates) {
                    if (immediate != null && immediate.local != null) {
                      String localname = immediate.local.getText();
                      locals.put(localname, new Local(localname, localtype));
                    } else {
                      throw new ResolveException(
                          "Thats not a Local in the Local Declaration.",
                          path,
                          JimpleConverterUtil.buildPositionFromCtx(ctx));
                    }
                  }
                }
              }
            }
          }

          // statements
          StmtVisitor stmtVisitor = new StmtVisitor();
          final JimpleParser.StatementsContext statements =
              method_body_contentsContext.statements();
          if (statements != null && statements.statement() != null) {
            List currentStmtList = new ArrayList<>();
            for (JimpleParser.StatementContext stmtCtx : statements.statement()) {
              Stmt newestStmt = stmtVisitor.visitStatement(stmtCtx);
              if (stmtCtx.label_name != null) {
                if (!currentStmtList.isEmpty()) {
                  blocks.add(currentStmtList);
                  currentStmtList = new ArrayList<>();
                }
                final String labelname = stmtCtx.label_name.getText();
                labeledStmts.put(labelname, newestStmt);
              }

              currentStmtList.add(newestStmt);

              if (newestStmt.branches()) {
                if (!currentStmtList.isEmpty()) {
                  blocks.add(currentStmtList);
                  currentStmtList = new ArrayList<>();
                }
              }
            }

            // check for dangling Block
            if (!currentStmtList.isEmpty()) {
              blocks.add(currentStmtList);
            }
          }

          // catch_clause
          final List trap_clauseContexts =
              method_body_contentsContext.trap_clauses().trap_clause();
          if (trap_clauseContexts != null) {
            for (JimpleParser.Trap_clauseContext it : trap_clauseContexts) {
              ClassType exceptionType = util.getClassType(it.exceptiontype.getText());
              String beginLabel = it.from.getText();
              String toLabel = it.to.getText();
              if (beginLabel.equals(toLabel)) continue;

              String handlerLabel = it.with.getText();
              traps.add(
                  Jimple.newTrap(
                      exceptionType,
                      labeledStmts.get(beginLabel),
                      labeledStmts.get(toLabel),
                      labeledStmts.get(handlerLabel)));
            }
          }
        }

        Position classPosition = JimpleConverterUtil.buildPositionFromCtx(ctx);

        // associate labeled Stmts with Branching Stmts
        for (Map.Entry> item : unresolvedBranches.entrySet()) {
          final List targetLabels = item.getValue();
          final List targets = new ArrayList<>(targetLabels.size());
          for (String targetLabel : targetLabels) {
            final Stmt target = labeledStmts.get(targetLabel);
            if (target == null) {
              throw new ResolveException(
                  "Don't jump into the Space! The target Stmt is not found i.e. no label for: "
                      + item.getKey()
                      + " to "
                      + targetLabel,
                  path,
                  JimpleConverterUtil.buildPositionFromCtx(ctx));
            }
            targets.add(target);
          }
          successorMap.put(item.getKey(), targets);
        }

        Position methodPosition = JimpleConverterUtil.buildPositionFromCtx(ctx);
        final Body build;
        try {

          MutableBlockStmtGraph graph = new MutableBlockStmtGraph();
          graph.initializeWith(blocks, successorMap, traps);
          Body.BodyBuilder builder = Body.builder(graph);

          builder.setModifiers(modifier);
          builder.setMethodSignature(methodSignature);
          builder.setLocals(new HashSet<>(locals.values()));
          builder.setPosition(classPosition);

          build = builder.build();
        } catch (Exception e) {
          throw new ResolveException(methodname + " " + e.getMessage(), path, methodPosition, e);
        }

        OverridingBodySource oms = new OverridingBodySource(methodSignature, build);
        return new SootMethod(oms, methodSignature, modifier, exceptions, methodPosition);
      }

      private class StmtVisitor extends JimpleBaseVisitor {
        final ValueVisitor valueVisitor = new ValueVisitor();

        private StmtVisitor() {}

        @Override
        public Stmt visitStatement(JimpleParser.StatementContext ctx) {
          final JimpleParser.StmtContext stmtCtx = ctx.stmt();
          if (stmtCtx == null) {
            throw new ResolveException(
                "Couldn't parse Stmt.", path, JimpleConverterUtil.buildPositionFromCtx(ctx));
          }
          return visitStmt(stmtCtx);
        }

        @Override
        @Nonnull
        public Stmt visitStmt(JimpleParser.StmtContext ctx) {
          StmtPositionInfo pos = new SimpleStmtPositionInfo(ctx.start.getLine());

          if (ctx.BREAKPOINT() != null) {
            return Jimple.newBreakpointStmt(pos);
          } else {
            if (ctx.ENTERMONITOR() != null) {
              return Jimple.newEnterMonitorStmt(valueVisitor.visitImmediate(ctx.immediate()), pos);
            } else if (ctx.EXITMONITOR() != null) {
              return Jimple.newExitMonitorStmt(valueVisitor.visitImmediate(ctx.immediate()), pos);
            } else if (ctx.SWITCH() != null) {

              Immediate key = valueVisitor.visitImmediate(ctx.immediate());
              List lookup = new ArrayList<>();
              List targetLabels = new ArrayList<>();
              int min = Integer.MAX_VALUE;
              String defaultLabel = null;

              for (JimpleParser.Case_stmtContext it : ctx.case_stmt()) {
                final JimpleParser.Case_labelContext case_labelContext = it.case_label();
                if (case_labelContext.getText() != null && case_labelContext.DEFAULT() != null) {
                  if (defaultLabel == null) {
                    defaultLabel = it.goto_stmt().label_name.getText();
                  } else {
                    throw new ResolveException(
                        "Only one default label is allowed!",
                        path,
                        JimpleConverterUtil.buildPositionFromCtx(ctx));
                  }
                } else if (case_labelContext.integer_constant().getText() != null) {
                  final int value =
                      Integer.parseInt(case_labelContext.integer_constant().getText());
                  min = Math.min(min, value);
                  lookup.add(IntConstant.getInstance(value));
                  targetLabels.add(it.goto_stmt().label_name.getText());
                } else {
                  throw new ResolveException(
                      "Label is invalid.", path, JimpleConverterUtil.buildPositionFromCtx(ctx));
                }
              }
              targetLabels.add(defaultLabel);

              JSwitchStmt switchStmt;
              if (ctx.SWITCH().getText().charAt(0) == 't') {
                int high = min + lookup.size() - 1;
                switchStmt = Jimple.newTableSwitchStmt(key, min, high, pos);
              } else {
                switchStmt = Jimple.newLookupSwitchStmt(key, lookup, pos);
              }
              unresolvedBranches.put(switchStmt, targetLabels);
              return switchStmt;
            } else {
              final JimpleParser.AssignmentsContext assignments = ctx.assignments();
              if (assignments != null) {
                if (assignments.COLON_EQUALS() != null) {
                  Local left = getLocal(assignments.local.getText());

                  IdentityRef ref;
                  final JimpleParser.Identity_refContext identityRefCtx =
                      assignments.identity_ref();
                  if (identityRefCtx.caught != null) {
                    ref = JavaJimple.getInstance().newCaughtExceptionRef();
                  } else {
                    final String type = assignments.identity_ref().type().getText();
                    if (identityRefCtx.parameter_idx != null) {
                      int idx = Integer.parseInt(identityRefCtx.parameter_idx.getText());
                      ref = Jimple.newParameterRef(util.getType(type), idx);
                    } else {
                      if (clazz.toString().equals(type)) {
                        // reuse
                        ref = Jimple.newThisRef(clazz);
                      } else {
                        ref = Jimple.newThisRef(util.getClassType(type));
                      }
                    }
                  }
                  return Jimple.newIdentityStmt(left, ref, pos);

                } else if (assignments.EQUALS() != null) {
                  LValue left =
                      assignments.local != null
                          ? getLocal(assignments.local.getText())
                          : (LValue) valueVisitor.visitReference(assignments.reference());

                  final Value right = valueVisitor.visitValue(assignments.value());
                  return Jimple.newAssignStmt(left, right, pos);
                } else {
                  throw new ResolveException(
                      "Invalid assignment.", path, JimpleConverterUtil.buildPositionFromCtx(ctx));
                }

              } else if (ctx.IF() != null) {
                final BranchingStmt stmt =
                    Jimple.newIfStmt(
                        (AbstractConditionExpr) valueVisitor.visitBool_expr(ctx.bool_expr()), pos);
                unresolvedBranches.put(
                    stmt, Collections.singletonList(ctx.goto_stmt().label_name.getText()));
                return stmt;
              } else if (ctx.goto_stmt() != null) {
                final BranchingStmt stmt = Jimple.newGotoStmt(pos);
                unresolvedBranches.put(
                    stmt, Collections.singletonList(ctx.goto_stmt().label_name.getText()));
                return stmt;
              } else if (ctx.NOP() != null) {
                return Jimple.newNopStmt(pos);
              } else if (ctx.RET() != null) {
                return Jimple.newRetStmt(valueVisitor.visitImmediate(ctx.immediate()), pos);
              } else if (ctx.RETURN() != null) {
                if (ctx.immediate() == null) {
                  return Jimple.newReturnVoidStmt(pos);
                } else {
                  return Jimple.newReturnStmt(valueVisitor.visitImmediate(ctx.immediate()), pos);
                }
              } else if (ctx.THROW() != null) {
                return Jimple.newThrowStmt(valueVisitor.visitImmediate(ctx.immediate()), pos);
              } else if (ctx.invoke_expr() != null) {
                return Jimple.newInvokeStmt(
                    (AbstractInvokeExpr) valueVisitor.visitInvoke_expr(ctx.invoke_expr()), pos);
              }
            }
          }
          throw new ResolveException(
              "Unknown Stmt.", path, JimpleConverterUtil.buildPositionFromCtx(ctx));
        }
      }

      private class ValueVisitor extends JimpleBaseVisitor {

        @Override
        public Value visitValue(JimpleParser.ValueContext ctx) {
          if (ctx.NEW() != null && ctx.base_type != null) {
            final Type type = util.getType(ctx.base_type.getText());
            if (!(type instanceof ReferenceType)) {
              throw new ResolveException(
                  type + " is not a ReferenceType.",
                  path,
                  JimpleConverterUtil.buildPositionFromCtx(ctx));
            }
            return Jimple.newNewExpr((ClassType) type);
          } else if (ctx.NEWARRAY() != null) {
            final Type type = util.getType(ctx.array_type.getText());
            if (type instanceof VoidType || type instanceof NullType) {
              throw new ResolveException(
                  type + " can not be an ArrayType.",
                  path,
                  JimpleConverterUtil.buildPositionFromCtx(ctx));
            }

            Immediate dim = visitImmediate(ctx.array_descriptor().immediate());
            return JavaJimple.getInstance().newNewArrayExpr(type, dim);
          } else if (ctx.NEWMULTIARRAY() != null && ctx.immediate() != null) {
            final Type type = util.getType(ctx.multiarray_type.getText());
            if (!(type instanceof ReferenceType || type instanceof PrimitiveType)) {
              throw new ResolveException(
                  " Only base types are allowed",
                  path,
                  JimpleConverterUtil.buildPositionFromCtx(ctx));
            }

            List sizes =
                ctx.immediate().stream().map(this::visitImmediate).collect(Collectors.toList());
            if (sizes.isEmpty()) {
              throw new ResolveException(
                  "The Size list must have at least one Element.",
                  path,
                  JimpleConverterUtil.buildPositionFromCtx(ctx));
            }
            ArrayType arrtype = identifierFactory.getArrayType(type, sizes.size());
            return Jimple.newNewMultiArrayExpr(arrtype, sizes);
          } else if (ctx.nonvoid_cast != null && ctx.op != null) {
            final Type type = util.getType(ctx.nonvoid_cast.getText());
            Immediate val = visitImmediate(ctx.op);
            return Jimple.newCastExpr(val, type);
          } else if (ctx.INSTANCEOF() != null && ctx.op != null) {
            final Type type = util.getType(ctx.nonvoid_type.getText());
            Immediate val = visitImmediate(ctx.op);
            return Jimple.newInstanceOfExpr(val, type);
          }
          return super.visitValue(ctx);
        }

        @Override
        public Immediate visitImmediate(JimpleParser.ImmediateContext ctx) {
          if (ctx.identifier() != null) {
            return getLocal(ctx.identifier().getText());
          }
          return visitConstant(ctx.constant());
        }

        @Override
        public Value visitReference(JimpleParser.ReferenceContext ctx) {

          if (ctx.array_descriptor() != null) {
            // array
            Immediate idx = visitImmediate(ctx.array_descriptor().immediate());
            Local type = getLocal(ctx.identifier().getText());
            return JavaJimple.getInstance().newArrayRef(type, idx);
          } else if (ctx.DOT() != null) {
            // instance field
            String base = ctx.identifier().getText();
            FieldSignature fs = util.getFieldSignature(ctx.field_signature());
            return Jimple.newInstanceFieldRef(getLocal(base), fs);

          } else {
            // static field
            FieldSignature fs = util.getFieldSignature(ctx.field_signature());
            return Jimple.newStaticFieldRef(fs);
          }
        }

        @Override
        public Expr visitInvoke_expr(JimpleParser.Invoke_exprContext ctx) {

          List arglist = getArgList(ctx.arg_list(0));

          if (ctx.nonstaticinvoke != null) {
            Local base = getLocal(ctx.local_name.getText());
            MethodSignature methodSig = util.getMethodSignature(ctx.method_signature(), ctx);

            switch (ctx.nonstaticinvoke.getText().charAt(0)) {
              case 'i':
                return Jimple.newInterfaceInvokeExpr(base, methodSig, arglist);
              case 'v':
                return Jimple.newVirtualInvokeExpr(base, methodSig, arglist);
              case 's':
                return Jimple.newSpecialInvokeExpr(base, methodSig, arglist);
              default:
                throw new ResolveException(
                    "Unknown Nonstatic Invoke.",
                    path,
                    JimpleConverterUtil.buildPositionFromCtx(ctx));
            }

          } else if (ctx.staticinvoke != null) {
            MethodSignature methodSig = util.getMethodSignature(ctx.method_signature(), ctx);
            return Jimple.newStaticInvokeExpr(methodSig, arglist);
          } else if (ctx.dynamicinvoke != null) {

            List bootstrapMethodRefParams = util.getTypeList(ctx.type_list());
            MethodSignature bootstrapMethodRef =
                identifierFactory.getMethodSignature(
                    identifierFactory.getClassType(
                        JDynamicInvokeExpr.INVOKEDYNAMIC_DUMMY_CLASS_NAME),
                    ctx.STRING_CONSTANT().getText().replace("\"", ""),
                    util.getType(ctx.name.getText()),
                    bootstrapMethodRefParams);

            MethodSignature methodRef = util.getMethodSignature(ctx.bsm, ctx);

            List bootstrapArgs = getArgList(ctx.staticargs);

            return Jimple.newDynamicInvokeExpr(
                methodRef, bootstrapArgs, bootstrapMethodRef, getArgList(ctx.dyn_args));
          }
          throw new ResolveException(
              "Malformed Invoke Expression.", path, JimpleConverterUtil.buildPositionFromCtx(ctx));
        }

        @Override
        public Constant visitConstant(JimpleParser.ConstantContext ctx) {

          if (ctx.integer_constant() != null) {
            String intConst = ctx.integer_constant().getText();
            int lastCharPos = intConst.length() - 1;
            if (intConst.charAt(lastCharPos) == 'L' || intConst.charAt(lastCharPos) == 'l') {
              intConst = intConst.substring(0, lastCharPos);
              return LongConstant.getInstance(Long.parseLong(intConst));
            }
            return IntConstant.getInstance(Integer.parseInt(intConst));
          } else if (ctx.FLOAT_CONSTANT() != null) {
            String floatStr = ctx.FLOAT_CONSTANT().getText();
            int lastCharPos = floatStr.length() - 1;
            if (floatStr.charAt(lastCharPos) == 'F' || floatStr.charAt(lastCharPos) == 'f') {
              floatStr = floatStr.substring(0, lastCharPos);
              return FloatConstant.getInstance(Float.parseFloat(floatStr));
            }

            if (floatStr.charAt(0) == '#') {
              switch (floatStr.substring(1)) {
                case "Infinity":
                  return DoubleConstant.getInstance(Double.POSITIVE_INFINITY);
                case "-Infinity":
                  return DoubleConstant.getInstance(Double.NEGATIVE_INFINITY);
                case "NaN":
                  return DoubleConstant.getInstance(Double.NaN);
              }
            }

            return DoubleConstant.getInstance(Double.parseDouble(floatStr));
          } else if (ctx.CLASS() != null) {
            final String text = Jimple.unescape(ctx.STRING_CONSTANT().getText());
            return JavaJimple.getInstance().newClassConstant(text);
          } else if (ctx.STRING_CONSTANT() != null) {
            final String text = Jimple.unescape(ctx.STRING_CONSTANT().getText());
            return JavaJimple.getInstance().newStringConstant(text);
          } else if (ctx.BOOL_CONSTANT() != null) {
            final char firstChar = ctx.BOOL_CONSTANT().getText().charAt(0);
            return BooleanConstant.getInstance(firstChar == 't' || firstChar == 'T');
          } else if (ctx.NULL() != null) {
            return NullConstant.getInstance();
          } else if (ctx.methodhandle() != null) {
            JimpleParser.MethodhandleContext methodhandleContext = ctx.methodhandle();
            final String kindName = methodhandleContext.STRING_CONSTANT().getText();
            final SootClassMemberSignature
                referenceSignature =
                    (methodhandleContext.method_signature() != null)
                        ? util.getMethodSignature(
                            methodhandleContext.method_signature(), methodhandleContext)
                        : util.getFieldSignature(methodhandleContext.field_signature());
            return JavaJimple.getInstance()
                .newMethodHandle(
                    referenceSignature,
                    MethodHandle.Kind.getKind(kindName.substring(1, kindName.length() - 1)));
          } else if (ctx.methodtype != null && ctx.method_subsignature() != null) {
            final JimpleParser.Type_listContext typelist = ctx.method_subsignature().type_list();
            final List typeList = util.getTypeList(typelist);
            return JavaJimple.getInstance()
                .newMethodType(
                    typeList,
                    identifierFactory.getType(ctx.method_subsignature().type().getText()));
          }
          throw new ResolveException(
              "Unknown Constant.", path, JimpleConverterUtil.buildPositionFromCtx(ctx));
        }

        @Override
        public AbstractBinopExpr visitBinop_expr(JimpleParser.Binop_exprContext ctx) {

          Immediate left = visitImmediate(ctx.left);
          Immediate right = visitImmediate(ctx.right);

          JimpleParser.BinopContext binopctx = ctx.binop();

          if (binopctx.AND() != null) {
            return new JAndExpr(left, right);
          } else if (binopctx.OR() != null) {
            return new JOrExpr(left, right);
          } else if (binopctx.CMP() != null) {
            return new JCmpExpr(left, right);
          } else if (binopctx.CMPG() != null) {
            return new JCmpgExpr(left, right);
          } else if (binopctx.CMPL() != null) {
            return new JCmplExpr(left, right);
          } else if (binopctx.CMPEQ() != null) {
            return new JEqExpr(left, right);
          } else if (binopctx.CMPNE() != null) {
            return new JNeExpr(left, right);
          } else if (binopctx.CMPGT() != null) {
            return new JGtExpr(left, right);
          } else if (binopctx.CMPGE() != null) {
            return new JGeExpr(left, right);
          } else if (binopctx.CMPLT() != null) {
            return new JLtExpr(left, right);
          } else if (binopctx.CMPLE() != null) {
            return new JLeExpr(left, right);
          } else if (binopctx.SHL() != null) {
            return new JShlExpr(left, right);
          } else if (binopctx.SHR() != null) {
            return new JShrExpr(left, right);
          } else if (binopctx.USHR() != null) {
            return new JUshrExpr(left, right);
          } else if (binopctx.PLUS() != null) {
            return new JAddExpr(left, right);
          } else if (binopctx.MINUS() != null) {
            return new JSubExpr(left, right);
          } else if (binopctx.MULT() != null) {
            return new JMulExpr(left, right);
          } else if (binopctx.DIV() != null) {
            return new JDivExpr(left, right);
          } else if (binopctx.XOR() != null) {
            return new JXorExpr(left, right);
          } else if (binopctx.MOD() != null) {
            return new JRemExpr(left, right);
          }
          throw new ResolveException(
              "Unknown BinOp: " + binopctx.getText(),
              path,
              JimpleConverterUtil.buildPositionFromCtx(ctx));
        }

        @Override
        public Expr visitUnop_expr(JimpleParser.Unop_exprContext ctx) {
          Immediate value = visitImmediate(ctx.immediate());
          if (ctx.unop().NEG() != null) {
            return Jimple.newNegExpr(value);
          } else {
            return Jimple.newLengthExpr(value);
          }
        }

        @Nonnull
        private List getArgList(JimpleParser.Arg_listContext ctx) {
          if (ctx == null || ctx.immediate() == null) {
            return Collections.emptyList();
          }
          final List immediates = ctx.immediate();
          List arglist = new ArrayList<>(immediates.size());
          for (JimpleParser.ImmediateContext immediate : immediates) {
            arglist.add(visitImmediate(immediate));
          }
          return arglist;
        }
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy