@Nullable
  private static Method concreteMethodByName(@NotNull ClassType type, @NotNull String name, @Nullable String signature) {
    Processor<Method> signatureChecker = signature != null ? m -> m.signature().equals(signature) : CommonProcessors.alwaysTrue();
    LinkedList<ReferenceType> types = new LinkedList<>();
    // first check classes
    while (type != null) {
      for (Method candidate : type.methods()) {
        if (candidate.name().equals(name) && signatureChecker.process(candidate)) {
          return !candidate.isAbstract() ? candidate : null;
        }
      }
      types.add(type);
      type = type.superclass();
    }
    // then interfaces
    Set<ReferenceType> checkedInterfaces = new HashSet<>();
    ReferenceType t;
    while ((t = types.poll()) != null) {
      if (t instanceof ClassType) {
        types.addAll(0, ((ClassType)t).interfaces());
      }
      else if (t instanceof InterfaceType && checkedInterfaces.add(t)) {
        for (Method candidate : t.methods()) {
          if (candidate.name().equals(name) && signatureChecker.process(candidate) && !candidate.isAbstract()) {
            return candidate;
          }
        }
        types.addAll(0, ((InterfaceType)t).superinterfaces());
      }
    }
    return null;
  }
@Nullable
  private static Method concreteMethodByName(@NotNull ClassType type, @NotNull String name, @Nullable String signature)