/**
   * Checks if there is a method with the provided name. In case of multiple methods (overloading),
   * only the first method decides if EXISTS_BY_USER or EXISTS_BY_LOMBOK is returned.
   *
   * @param methodName the method name to check for.
   * @param node Any node that represents the Type (JCClassDecl) to look in, or any child node
   *     thereof.
   * @param caseSensitive If the search should be case sensitive.
   * @param params The number of parameters the method should have; varargs count as 0-*. Set to -1
   *     to find any method with the appropriate name regardless of parameter count.
   */
  public static MemberExistsResult methodExists(
      String methodName, JavacNode node, boolean caseSensitive, int params) {
    node = upToTypeNode(node);

    if (node != null && node.get() instanceof JCClassDecl) {
      for (JCTree def : ((JCClassDecl) node.get()).defs) {
        if (def instanceof JCMethodDecl) {
          JCMethodDecl md = (JCMethodDecl) def;
          String name = md.name.toString();
          boolean matches =
              caseSensitive ? name.equals(methodName) : name.equalsIgnoreCase(methodName);
          if (matches) {
            if (params > -1) {
              List<JCVariableDecl> ps = md.params;
              int minArgs = 0;
              int maxArgs = 0;
              if (ps != null && ps.length() > 0) {
                minArgs = ps.length();
                if ((ps.last().mods.flags & Flags.VARARGS) != 0) {
                  maxArgs = Integer.MAX_VALUE;
                  minArgs--;
                } else {
                  maxArgs = minArgs;
                }
              }

              if (params < minArgs || params > maxArgs) continue;
            }
            return getGeneratedBy(def) == null
                ? MemberExistsResult.EXISTS_BY_USER
                : MemberExistsResult.EXISTS_BY_LOMBOK;
          }
        }
      }
    }

    return MemberExistsResult.NOT_EXISTS;
  }