/**
   * Resolve the concrete target of a special invoke using our modified semantics for special invoke
   * expression.
   */
  private SootMethod resolveSpecialInvokeTarget(SpecialInvokeExpr si) {
    SootMethod target = null;

    try {
      target = SootUtils.resolve(si.getMethodRef());
    } catch (CannotFindMethodException e) {
      logger.error("Cannot find concrete method target for special invoke: {}", si);
      return null;
    }

    String targetSubSig = target.getSubSignature();

    SootClass current = target.getDeclaringClass();

    while (true) {
      if (current.declaresMethod(targetSubSig)) {
        return current.getMethod(targetSubSig);
      }

      // not a match in current, try superclass on next loop
      if (current.hasSuperclass()) current = current.getSuperclass();
      else {
        logger.error("Cannot find concrete method target for special invoke: {}", si);
        droidsafe.main.Main.exit(1);
        return null;
      }
    }
  }
Beispiel #2
0
  /**
   * Uses EXACT of possible runtime types referenced by values. These types of Value can represent
   * an object: 1. NewExpr/NewArrayExpr (instance) 2. InvokeExpr (static or instance) 3.
   * Local/statfield ref var (instance) 4. StringConstant (instance)
   */
  public static boolean objValuesMustEqual(Value v1, Value v2) {
    // case 5: (lib) object, either static or instance
    //         objects are (possibly) the same if they are both static or both instance,
    //         and there is at least one object type that v1 and v2 can refer to in their call.
    // NOTE: includes automatically constructed Strings, represented by StringConstant values

    // first, handle special case with more precision: both values are string constants
    if (v1 instanceof StringConstant && v2 instanceof StringConstant)
      return ((StringConstant) v1).value.equals(((StringConstant) v2).value);

    // get list of ref types of instances to which each value can refer
    // (null if val refers to class itself, not instances)
    Set<RefLikeType> clsTargets1 = getAllPossibleRuntimeRefTypes(v1);
    Set<RefLikeType> clsTargets2 = getAllPossibleRuntimeRefTypes(v2);

    // first, handle special case of values referring to class object (static)
    if (clsTargets1 == null) {
      if (clsTargets2 != null) return false;
      SootClass cls1 = ((StaticInvokeExpr) v1).getMethod().getDeclaringClass();
      SootClass cls2 = ((StaticInvokeExpr) v2).getMethod().getDeclaringClass();
      return cls1.equals(cls2);
    } else if (clsTargets2 == null) return false;

    //		// now, just check for intersection of returned lists of possible target classes
    //		return clsTargets1.removeAll(clsTargets2);
    // *** Strengthened to be completely equal, respecting TRANSITIVITY of equality
    return clsTargets1.equals(clsTargets2);
  }
Beispiel #3
0
  private void createLookupFunction(SootMethod m) {
    // TODO: This should use a virtual method table or interface method table.
    Function function = FunctionBuilder.lookup(m);
    mb.addFunction(function);

    Variable reserved0 = function.newVariable(I8_PTR_PTR);
    function.add(new Getelementptr(reserved0, function.getParameterRef(0), 0, 4));
    Variable reserved1 = function.newVariable(I8_PTR_PTR);
    function.add(new Getelementptr(reserved1, function.getParameterRef(0), 0, 5));
    function.add(new Store(getString(m.getName()), reserved0.ref()));
    function.add(new Store(getString(getDescriptor(m)), reserved1.ref()));

    Value lookupFn =
        sootClass.isInterface() ? BC_LOOKUP_INTERFACE_METHOD : BC_LOOKUP_VIRTUAL_METHOD;
    List<Value> args = new ArrayList<Value>();
    args.add(function.getParameterRef(0));
    if (sootClass.isInterface()) {
      Value info = getInfoStruct(function);
      args.add(info);
    }
    args.add(function.getParameterRef(1));
    args.add(getString(m.getName()));
    args.add(getString(getDescriptor(m)));
    Value fptr = call(function, lookupFn, args);
    Variable f = function.newVariable(function.getType());
    function.add(new Bitcast(f, fptr, f.getType()));
    Value result = call(function, f.ref(), function.getParameterRefs());
    function.add(new Ret(result));
  }
 private void loadClasses() {
   Date start = new Date();
   if (entryClass != null) {
     SootUtils.loadClassesForEntry(entryClass);
   } else {
     for (JavaCriticalSection cs : results) {
       String clsname = cs.getClassName();
       String regex = "\\$\\d";
       Pattern pattern = Pattern.compile(regex);
       Matcher matcher = pattern.matcher(clsname);
       if (matcher.find()) {
         System.out.println("can't find the class created randomly by compiler");
         continue;
       }
       SootClass cls = Scene.v().loadClassAndSupport(clsname);
       if (setMainClass == true
           && cls.declaresMethod(
               Scene.v().getSubSigNumberer().findOrAdd("void main(java.lang.String[])"))) {
         Scene.v().setMainClass(cls);
         setMainClass = false;
       }
     }
     Scene.v().loadNecessaryClasses();
   }
   Date end = new Date();
   System.out.println(
       "load " + Scene.v().getClasses().size() + " classes in " + getTimeConsumed(start, end));
 }
 private void run(String cls, boolean app_class) {
   SootClass soot_class = Scene.v().getSootClass(cls);
   List<SootMethod> methods = soot_class.getMethods();
   for (SootMethod method : methods) {
     visit(method);
   }
 }
Beispiel #6
0
 private static boolean hasFinalizer(SootClass clazz) {
   // Don't search interfaces or java.lang.Object
   if (clazz.isInterface() || !clazz.hasSuperclass()) {
     return false;
   }
   return clazz.declaresMethod("finalize", Collections.emptyList(), VoidType.v());
 }
Beispiel #7
0
 public static boolean isInstanceOfClass(SootClass sc, String className) {
   SootClass clazz = sc;
   if (className.equals(clazz.getName())) {
     return true;
   }
   return isSubclass(sc, className);
 }
  protected void internalTransform(String pn, Map map) {
    SymbiosisTransformer.tlo = new ThreadLocalObjectsAnalysis(new SynchObliviousMhpAnalysis());
    SymbiosisTransformer.ftea = new XFieldThreadEscapeAnalysis();
    SymbiosisTransformer.pecg = new PegCallGraph(Scene.v().getCallGraph());

    Iterator<SootClass> classIt = Scene.v().getApplicationClasses().iterator();
    while (classIt.hasNext()) {
      SootClass sc = classIt.next();

      Iterator<SootMethod> methodIt = sc.getMethods().iterator();

      while (methodIt.hasNext()) {
        SootMethod sm = methodIt.next();

        if (sm.isAbstract() || sm.isNative()) continue;

        try {
          Body body = sm.retrieveActiveBody();
          SymbFindSVPass.v().internalTransform(body, pn, map);
        } catch (Exception e) {
          System.err.println("[SymbiosisTransformer] SymbScenePass: " + e.getMessage());
          e.printStackTrace();
          continue;
        }
      }
    }
  }
Beispiel #9
0
  private static StructureType getInstanceType0(
      SootClass clazz, int subClassAlignment, int[] superSize) {
    List<Type> types = new ArrayList<Type>();
    List<SootField> fields = getInstanceFields(clazz);
    int superAlignment = 1;
    if (!fields.isEmpty()) {
      // Pad the super type so that the first field is aligned properly
      SootField field = fields.get(0);
      superAlignment = getFieldAlignment(field);
    }
    if (clazz.hasSuperclass()) {
      types.add(getInstanceType0(clazz.getSuperclass(), superAlignment, superSize));
    }
    int offset = superSize[0];
    for (SootField field : fields) {
      int falign = getFieldAlignment(field);
      int padding = (offset & (falign - 1)) != 0 ? (falign - (offset & (falign - 1))) : 0;
      types.add(padType(getType(field.getType()), padding));
      offset += padding + getFieldSize(field);
    }

    int padding =
        (offset & (subClassAlignment - 1)) != 0
            ? (subClassAlignment - (offset & (subClassAlignment - 1)))
            : 0;
    for (int i = 0; i < padding; i++) {
      types.add(I8);
      offset++;
    }

    superSize[0] = offset;

    return new StructureType(types.toArray(new Type[types.size()]));
  }
  public void staticBlockInlining(SootClass sootClass) {
    this.sootClass = sootClass;
    // retrieve the clinit method if any for sootClass
    if (!sootClass.declaresMethod("void <clinit>()")) {
      System.out.println("no clinit");
      return;
    }

    SootMethod clinit = sootClass.getMethod("void <clinit>()");
    // System.out.println(clinit);

    // retireve the active body
    if (!clinit.hasActiveBody())
      throw new RuntimeException("method " + clinit.getName() + " has no active body!");

    Body clinitBody = clinit.getActiveBody();

    Chain units = ((DavaBody) clinitBody).getUnits();

    if (units.size() != 1) {
      throw new RuntimeException("DavaBody AST doesn't have single root.");
    }

    ASTNode AST = (ASTNode) units.getFirst();
    if (!(AST instanceof ASTMethodNode))
      throw new RuntimeException("Starting node of DavaBody AST is not an ASTMethodNode");

    AST.apply(new MethodCallFinder(this));
  }
 protected boolean differentPackageAndPrivate(RefType ref_inspecting) {
   RefType ref_type = (RefType) m_thisRef.getType();
   SootClass this_class = getClassForType(ref_type);
   SootClass class_inspecting = getClassForType(ref_inspecting);
   if (this_class.getPackageName().equals(class_inspecting.getPackageName())) return false;
   if (class_inspecting.isPublic() == false) return true;
   return false;
 }
 public void caseStaticInvokeExpr(StaticInvokeExpr arg0) {
   SootMethod soot_method = arg0.getMethod();
   SootClass soot_class = soot_method.getDeclaringClass();
   if (soot_class.getName().equals("java.lang.Object")) return;
   OpenCLMethod ocl_method = new OpenCLMethod(soot_method, soot_class);
   m_output.append(ocl_method.getStaticInvokeString(arg0));
   setCheckException();
 }
Beispiel #13
0
  public static SootMethod mockSootMethod(
      String clsName, String methodSubSignature, boolean isStatic) {
    SootClass sc = mockSootClass(clsName);

    SootMethod sm = null;

    try {
      sm = sc.getMethod(methodSubSignature);
    } catch (Exception ex) {
      sm = null;
    }

    if (null == sm) {
      int m = Modifier.PUBLIC;
      if (isStatic) {
        m = m | Modifier.STATIC;
      }

      List<Type> paramTypes = new ArrayList<Type>();
      paramTypes.add(ArrayType.v(RefType.v("java.lang.Object"), 1));

      String[] strs = methodSubSignature.split(" ");
      String methodName = strs[1].trim().substring(0, strs[1].trim().indexOf("("));

      if (null == methodName || methodName.isEmpty()) {
        return null;
      }

      sm = new SootMethod(methodName, paramTypes, RefType.v("java.lang.Object"), m);
      sc.addMethod(sm);

      // Add body of sm
      JimpleBody b = Jimple.v().newBody(sm);
      sm.setActiveBody(b);
      // LocalGenerator lg = new LocalGenerator(b);
      {
        b.insertIdentityStmts();

        // Local rtLoc = lg.generateLocal(RefType.v("java.lang.Object"));

        // Local param0 = lg.generateLocal(ArrayType.v(RefType.v("java.lang.Object"), 1));
        // Unit param0U = Jimple.v().newIdentityStmt(rtLoc,
        // Jimple.v().newParameterRef(ArrayType.v(RefType.v("java.lang.Object"), 1), 0));

        // Unit rtLocAssignU = Jimple.v().newAssignStmt(rtLoc, param0);

        Unit returnU = Jimple.v().newReturnStmt(b.getParameterLocal(0));

        // b.getUnits().add(param0U);
        b.getUnits().add(returnU);
      }

      System.out.println("validation:" + b);
      b.validate();
    }

    return sm;
  }
  /**
   * For a concrete method (declared in an application class), find statements containing an invoke
   * expression for which the method is one of the method in 'allEventInformation' (i.e.,
   * getLine1Number(), ...).
   *
   * @param cfg
   */
  private void doAccessControlChecks(BiDiInterproceduralCFG<Unit, SootMethod> cfg) {
    for (SootClass sc : Scene.v().getApplicationClasses()) {
      for (SootMethod sm : sc.getMethods()) {
        if (sm.isConcrete()) {
          Body body = sm.retrieveActiveBody();
          // only instrument application methods (i.e., not methods declared in PEP helper classes
          // or in a Java library classes or in an Android classes, ...)
          if (isInstrumentationNecessary(sm)) {

            // important to use snapshotIterator here
            Iterator<Unit> i = body.getUnits().snapshotIterator();
            log.debug("method: " + sm);
            while (i.hasNext()) {
              Stmt s = (Stmt) i.next();

              if (s.containsInvokeExpr()) {
                InvokeExpr invExpr = s.getInvokeExpr();
                String methodSignature = invExpr.getMethod().getSignature();

                if (allEventInformation.containsKey(methodSignature)) {
                  log.debug("statement " + s + " matches " + methodSignature + ".");
                  ResultSinkInfo sink = null;

                  outer:
                  for (ResultSinkInfo key : results.getResults().keySet()) {

                    // iterate over all the arguments of the invoke expression
                    // and check if an argument is a tainted sink. If one is
                    // set variable 'sink' to the ResultSinkInfo key.
                    for (Value v : invExpr.getArgs()) {
                      Value pathValue = key.getAccessPath().getPlainValue();
                      if (v == pathValue) {
                        sink = key;
                        log.debug("found a sink: " + pathValue);
                        break outer;
                      }
                    }
                  }

                  if (sink != null) {
                    log.debug("instrument with data flow information )" + s + ")");
                    instrumentSourceToSinkConnections(cfg, sink, s instanceof AssignStmt);
                    instrumentWithNoDataFlowInformation(
                        methodSignature, s, invExpr, body, s instanceof AssignStmt);
                  } else {
                    log.debug("instrument without data flow information (" + s + ")");
                    instrumentWithNoDataFlowInformation(
                        methodSignature, s, invExpr, body, s instanceof AssignStmt);
                  }
                }
              } // if stmt containts invoke expression
            } // loop on statements
          }
        }
      }
    }
  }
 public static List<ExceptionalUnitGraph> getMethodExceptionalUnitGraphs(
     String className, SootClassLoader loader) {
   SootClass sootClass = getExceptionalUnitGraph(className, loader);
   List<ExceptionalUnitGraph> methodExceptionalUnitGraphs = new ArrayList<ExceptionalUnitGraph>();
   for (SootMethod sootMethod : sootClass.getMethods()) {
     methodExceptionalUnitGraphs.add(Util.getUnitGraph(sootMethod));
   }
   return methodExceptionalUnitGraphs;
 }
Beispiel #16
0
 public static boolean isSubclass(SootClass sc, String className) {
   SootClass clazz = sc;
   while (clazz.hasSuperclass()) {
     clazz = clazz.getSuperclass();
     if (className.equals(clazz.getName())) {
       return true;
     }
   }
   return false;
 }
  public static SootClass createSootClass(String clsName) {
    SootClass sc = new SootClass(clsName);
    sc.setSuperclass(Scene.v().getSootClass("java.lang.Object"));

    sc.setApplicationClass();
    sc.setPhantom(false);
    sc.setInScene(true);

    return sc;
  }
Beispiel #18
0
  public static SootClass mockSootClass(String clsName) {
    SootClass sc = null;

    if (Scene.v().containsClass(clsName)) {
      sc = Scene.v().getSootClass(clsName);

      if (sc.isPhantom()) {
        // sc.setPhantom(false);
        sc.setApplicationClass();
        sc.setInScene(true);

        try {
          for (Field field : sc.getClass().getFields()) {
            if (field.getName().equals("isPhantom")) {
              field.setAccessible(true);
              field.setBoolean(sc, false);
            }
          }
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    } else {
      sc = new SootClass(clsName);
      sc.setSuperclass(Scene.v().getSootClass("java.lang.Object"));

      sc.setPhantom(false);
      sc.setApplicationClass();
      sc.setInScene(true);
    }

    mockConstructor(sc);

    return sc;
  }
Beispiel #19
0
    /**
     * Transform the Scene according to the information specified in the model for this transform.
     *
     * @param phaseName The phase this transform is operating under.
     * @param options The options to apply.
     */
    protected void internalTransform(String phaseName, Map options) {
      // For some reason, soot 2.0.1 gives java.lang.Object as
      // its own superclass!
      PtolemyUtilities.objectClass.setSuperclass(null);

      for (Iterator classes = Scene.v().getApplicationClasses().snapshotIterator();
          classes.hasNext(); ) {
        SootClass theClass = (SootClass) classes.next();
        theClass.setLibraryClass();
      }
    }
Beispiel #20
0
 public ResolvedEntry resolve(SootClass clazz) {
   while (clazz != null) {
     for (SootMethod m : clazz.getMethods()) {
       if (m.getName().equals(name) && desc.equals(Types.getDescriptor(m))) {
         return new ResolvedEntry(this, m);
       }
     }
     clazz = clazz.hasSuperclass() ? clazz.getSuperclass() : null;
   }
   return null;
 }
  public static boolean isAssignable(SootClass taintType, SootClass declaredType) {
    if (taintType.equals(declaredType)) return true;

    if (taintType.hasSuperclass() && isAssignable(taintType.getSuperclass(), declaredType)) {
      return true;
    }
    for (SootClass interf : taintType.getInterfaces()) {
      if (isAssignable(interf, declaredType)) return true;
    }
    return false;
  }
Beispiel #22
0
 public ITable get(SootClass clazz) {
   if (!clazz.isInterface()) {
     throw new IllegalArgumentException("Not an interface: " + clazz.getName());
   }
   ITable itable = cache.get(clazz.getName());
   if (itable != null) {
     return itable;
   }
   itable = new ITable(clazz);
   cache.put(clazz.getName(), itable);
   return itable;
 }
  private void iterateAllMethods() {

    // Find methods
    Iterator<SootClass> getClassesIt = Scene.v().getApplicationClasses().iterator();
    while (getClassesIt.hasNext()) {
      SootClass appClass = getClassesIt.next();
      Iterator<SootMethod> getMethodsIt = appClass.getMethods().iterator();
      while (getMethodsIt.hasNext()) {
        SootMethod method = getMethodsIt.next();
        analyzeMethod(method);
      }
    }
  }
  public void transform() {
    if (clazz.isPhantom()) return;

    // build ancestor
    // List<SootClass> ancestors = Scene.v().getActiveHierarchy().getSuperclassesOf(clazz);
    List<SootClass> ancestors = new LinkedList<SootClass>();

    // fill in ancestor list without using Soot.Hierarchy
    SootClass curAncestor = clazz;
    while (curAncestor.hasSuperclass()) {
      ancestors.add(curAncestor.getSuperclass());
      curAncestor = curAncestor.getSuperclass();
    }

    for (SootClass ancestor : ancestors) {
      if (ancestor.isPhantom()) continue;

      cloneReachableNonHiddenAncestorMethods(ancestor);
    }

    // modify ancestors fields
    for (SootClass ancestor : ancestors) {
      if (ancestor.isPhantom()) continue;

      SootUtils.makeFieldsVisible(ancestor);
    }

    cloneHiddenAncestorMethodsAndFixInvokeSpecial();
  }
Beispiel #25
0
  /** For instance invokes */
  public static ArrayList<SootMethod> resolveAppCall(Type tgtType, SootMethodRef methodRef) {
    final NumberedString mSubsignature = methodRef.getSubSignature();
    if (tgtType instanceof RefType) {
      // find first class upwards in hierarchy, starting from cls, that implements method (i.e.,
      // *concrete* method)
      SootClass cls = ((RefType) tgtType).getSootClass();
      while (!cls.declaresMethod(mSubsignature))
        cls =
            cls
                .getSuperclass(); // if method not in this class, it HAS to be in a superclass, so a
                                  // superclass must exist

      if (!cls.hasTag(ClassTag.TAG_NAME)) return null; // not an app method

      // finally, store resolved app method
      SootMethod m = cls.getMethod(mSubsignature);
      assert m.hasTag(MethodTag.TAG_NAME);

      ArrayList<SootMethod> methods = new ArrayList<SootMethod>();
      methods.add(m); // just one element, directly resolved
      return methods;
    }

    if (tgtType instanceof AnySubType) {
      // return set of all app subtypes that implement referenced method
      SootClass baseCls = ((AnySubType) tgtType).getBase().getSootClass();
      List subClasses =
          baseCls.isInterface()
              ? Scene.v().getActiveHierarchy().getImplementersOf(baseCls)
              : Scene.v().getActiveHierarchy().getSubclassesOf(baseCls);
      ArrayList<SootMethod> methods = new ArrayList<SootMethod>();
      for (Object oSubCls : subClasses) {
        SootClass subCls = (SootClass) oSubCls;
        if (subCls.hasTag(ClassTag.TAG_NAME)) {
          try {
            SootMethod m = subCls.getMethod(mSubsignature);
            assert m.hasTag(MethodTag.TAG_NAME);
            if (!m.isAbstract()) methods.add(m);
          } catch (RuntimeException e) {
          }
        }
      }

      return methods;
    }

    assert tgtType instanceof ArrayType; // only other case observed so far
    return new ArrayList(); // no array class/method is in app
  }
Beispiel #26
0
  private static void writeFile(Set<SootClass> reachableClasses) {
    try {
      TreeSet<String> treeSet = new TreeSet<>();
      for (SootClass sootClass : reachableClasses) {
        treeSet.add(sootClass.toString());
      }

      FileWriter writer = new FileWriter(new File("reachableClasses.txt"));
      for (String sootClass : treeSet) {
        writer.write(sootClass + "\n");
      }
      writer.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
 protected List<OpenCLField> getRefFields(SootClass soot_class) {
   OpenCLClass ocl_class = OpenCLScene.v().getOpenCLClass(soot_class);
   if (ocl_class == null) {
     System.out.println("ocl_class == null: " + soot_class.getName());
   }
   return ocl_class.getInstanceRefFields();
 }
  /**
   * Clone non-static ancestor methods that are not hidden by virtual dispatch and that are
   * reachable based on a pta run.
   */
  private void cloneReachableNonHiddenAncestorMethods(SootClass ancestor) {
    if (ClassCloner.isClonedClass(ancestor)) {
      logger.error("Cloning method from clone: {}", ancestor);
      droidsafe.main.Main.exit(1);
    }

    // create all methods, cloning body, replacing instance field refs
    for (SootMethod ancestorM : ancestor.getMethods()) {
      if (ancestorM.isAbstract()
          || ancestorM.isPhantom()
          || !ancestorM.isConcrete()
          || SootUtils.isRuntimeStubMethod(ancestorM)) continue;

      // never clone static methods
      if (ancestorM.isStatic()) continue;

      // clone only reachable methods
      if (!cloneAllMethods && !PTABridge.v().getReachableMethods().contains(ancestorM)) continue;

      // check if this method already exists
      if (containsMethod(ancestorM.getSignature())) {
        // System.out.printf("\tAlready contains method %s.\n", ancestorM);
        continue;
      }

      // turn off final for ancestor methods
      if (ancestorM.isFinal()) ancestorM.setModifiers(ancestorM.getModifiers() ^ Modifier.FINAL);

      cloneMethod(ancestorM, ancestorM.getName());
    }
  }
  /**
   * Clone given method into this class with given name. Update necessary state of prior analyses.
   */
  private SootMethod cloneMethod(SootMethod ancestorM, String cloneName) {
    // check if we are cloning a method multiple times
    if (clonedToOriginal.containsValue(ancestorM)) {
      logger.error("Cloning method twice: {}", ancestorM);
      droidsafe.main.Main.exit(1);
    }

    SootMethod newMeth =
        new SootMethod(
            cloneName,
            ancestorM.getParameterTypes(),
            ancestorM.getReturnType(),
            ancestorM.getModifiers(),
            ancestorM.getExceptions());

    // System.out.printf("\tAdding method %s.\n", ancestorM);
    // register method
    methods.addMethod(newMeth);
    clazz.addMethod(newMeth);

    clonedToOriginal.put(newMeth, ancestorM);

    API.v().cloneMethodClassifications(ancestorM, newMeth);

    // clone body
    Body newBody = (Body) ancestorM.retrieveActiveBody().clone();
    newMeth.setActiveBody(newBody);

    JSAStrings.v().updateJSAResults(ancestorM.retrieveActiveBody(), newBody);

    return newMeth;
  }
Beispiel #30
0
  /** Conveniently create a class deriving from Code.testClass */
  public Pair<SootClass, SignatureTable<Level>> makeDerivedClass(
      String name, SootClass superClass, List<MethodWithSignature<Level>> methods) {
    SootClass result = makeFreshClass(name);
    result.setSuperclass(superClass);
    SignatureTable<Level> newSignatures = this.signatures;
    for (MethodWithSignature<Level> m : methods) {
      result.addMethod(m.method);
      newSignatures =
          newSignatures.extendWith(
              m.method,
              Interop.asJavaStream(m.signature.constraints.stream()).collect(Collectors.toList()),
              m.signature.effects);
    }

    return Pair.of(result, newSignatures);
  }