@Override
  @Nullable
  public MethodVisitor visitMethod(
      final int access,
      final String name,
      final String desc,
      final String signature,
      final String[] exceptions) {
    // JLS 13.1 says: Any constructs introduced by the compiler that do not have a corresponding
    // construct in the source code
    // must be marked as synthetic, except for default constructors and the class initialization
    // method.
    // However Scala compiler erroneously generates ACC_BRIDGE instead of ACC_SYNTHETIC flag for
    // in-trait implementation delegation.
    // See IDEA-78649
    if ((access & Opcodes.ACC_SYNTHETIC) != 0) return null;

    if (SYNTHETIC_CLASS_INIT_METHOD.equals(name)) return null;

    boolean isDeprecated = (access & Opcodes.ACC_DEPRECATED) != 0;
    boolean isConstructor = SYNTHETIC_INIT_METHOD.equals(name);
    boolean isVarargs = (access & Opcodes.ACC_VARARGS) != 0;
    boolean isAnnotationMethod = myResult.isAnnotationType();

    if (!isConstructor && !isCorrectName(name)) return null;

    final byte flags =
        PsiMethodStubImpl.packFlags(
            isConstructor, isAnnotationMethod, isVarargs, isDeprecated, false);

    final String canonicalMethodName = isConstructor ? myResult.getName() : name;
    final List<String> args = new ArrayList<String>();
    final List<String> throwables = exceptions != null ? new ArrayList<String>() : null;

    final PsiMethodStubImpl stub =
        new PsiMethodStubImpl(myResult, StringRef.fromString(canonicalMethodName), flags, null);

    final PsiModifierListStub modList =
        new PsiModifierListStubImpl(stub, packMethodFlags(access, myResult.isInterface()));

    boolean parsedViaGenericSignature = false;
    String returnType;
    if (signature == null) {
      returnType = parseMethodViaDescription(desc, stub, args);
    } else {
      try {
        returnType = parseMethodViaGenericSignature(signature, stub, args, throwables);
        parsedViaGenericSignature = true;
      } catch (ClsFormatException e) {
        returnType = parseMethodViaDescription(desc, stub, args);
      }
    }

    stub.setReturnType(TypeInfo.fromString(returnType));

    final boolean isNonStaticInnerClassConstructor =
        isConstructor
            && !(myParent instanceof PsiFileStub)
            && (myModList.getModifiersMask() & Opcodes.ACC_STATIC) == 0;
    final boolean shouldSkipFirstParamForNonStaticInnerClassConstructor =
        !parsedViaGenericSignature && isNonStaticInnerClassConstructor;

    final PsiParameterListStubImpl parameterList = new PsiParameterListStubImpl(stub);
    final int paramCount = args.size();
    final PsiParameterStubImpl[] paramStubs = new PsiParameterStubImpl[paramCount];
    for (int i = 0; i < paramCount; i++) {
      if (shouldSkipFirstParamForNonStaticInnerClassConstructor && i == 0) continue;

      String arg = args.get(i);
      boolean isEllipsisParam = isVarargs && i == paramCount - 1;
      final TypeInfo typeInfo = TypeInfo.fromString(arg, isEllipsisParam);

      String paramName = i < parameterNames.length ? parameterNames[i] : "p" + (i + 1);
      PsiParameterStubImpl parameterStub =
          new PsiParameterStubImpl(parameterList, paramName, typeInfo, isEllipsisParam);
      paramStubs[i] = parameterStub;
      new PsiModifierListStubImpl(parameterStub, 0);
    }

    String[] thrownTypes = buildThrowsList(exceptions, throwables, parsedViaGenericSignature);
    newReferenceList(JavaStubElementTypes.THROWS_LIST, stub, thrownTypes);

    final int localVarIgnoreCount =
        (access & Opcodes.ACC_STATIC) != 0 ? 0 : isConstructor && myResult.isEnum() ? 3 : 1;
    final int paramIgnoreCount =
        isConstructor && myResult.isEnum() ? 2 : isNonStaticInnerClassConstructor ? 1 : 0;
    return new AnnotationParamCollectingVisitor(
        stub, modList, localVarIgnoreCount, paramIgnoreCount, paramCount, paramStubs);
  }
  @Override
  @Nullable
  public MethodVisitor visitMethod(
      final int access,
      final String name,
      final String desc,
      final String signature,
      final String[] exceptions) {
    // JLS 13.1 says: Any constructs introduced by the compiler that do not have a corresponding
    // construct in the source code
    // must be marked as synthetic, except for default constructors and the class initialization
    // method.
    // However Scala compiler erroneously generates ACC_BRIDGE instead of ACC_SYNTHETIC flag for
    // in-trait implementation delegation.
    // See IDEA-78649
    if ((access & Opcodes.ACC_SYNTHETIC) != 0) return null;

    if (SYNTHETIC_CLASS_INIT_METHOD.equals(name)) return null;

    // skip semi-synthetic enum methods
    boolean isEnum = myResult.isEnum();
    if (isEnum) {
      if ("values".equals(name) && desc.startsWith("()")) return null;
      if ("valueOf".equals(name) && desc.startsWith("(Ljava/lang/String;)")) return null;
    }

    boolean isDeprecated = (access & Opcodes.ACC_DEPRECATED) != 0;
    boolean isConstructor = SYNTHETIC_INIT_METHOD.equals(name);
    boolean isVarargs = (access & Opcodes.ACC_VARARGS) != 0;
    boolean isAnnotationMethod = myResult.isAnnotationType();

    if (!isConstructor && !isCorrectName(name)) return null;

    final byte flags =
        PsiMethodStubImpl.packFlags(
            isConstructor, isAnnotationMethod, isVarargs, isDeprecated, false);

    String canonicalMethodName = isConstructor ? myResult.getName() : name;
    List<String> args = new ArrayList<String>();
    List<String> throwables = exceptions != null ? new ArrayList<String>() : null;

    StringRef stringRef = StringRef.fromString(canonicalMethodName);
    int modifiersMask = packMethodFlags(access, myResult.isInterface());
    PsiMethodStubImpl stub =
        new PsiMethodStubImpl(
            myResult, stringRef, flags, signature, args, throwables, desc, modifiersMask);

    PsiModifierListStub modList =
        (PsiModifierListStub) stub.findChildStubByType(JavaStubElementTypes.MODIFIER_LIST);
    assert modList != null : stub;

    if (isEnum
        && isConstructor
        && signature == null
        && args.size() >= 2
        && JAVA_LANG_STRING.equals(args.get(0))
        && "int".equals(args.get(1))) {
      // exclude synthetic enum constructor parameters
      args = args.subList(2, args.size());
    }

    final boolean isNonStaticInnerClassConstructor =
        isConstructor
            && !(myParent instanceof PsiFileStub)
            && (myModList.getModifiersMask() & Opcodes.ACC_STATIC) == 0;
    boolean parsedViaGenericSignature = stub.isParsedViaGenericSignature();
    final boolean shouldSkipFirstParamForNonStaticInnerClassConstructor =
        !parsedViaGenericSignature && isNonStaticInnerClassConstructor;

    final PsiParameterListStubImpl parameterList = new PsiParameterListStubImpl(stub);
    final int paramCount = args.size();
    final PsiParameterStubImpl[] paramStubs = new PsiParameterStubImpl[paramCount];
    for (int i = 0; i < paramCount; i++) {
      if (shouldSkipFirstParamForNonStaticInnerClassConstructor && i == 0) continue;

      String arg = args.get(i);
      boolean isEllipsisParam = isVarargs && i == paramCount - 1;
      final TypeInfo typeInfo = TypeInfo.fromString(arg, isEllipsisParam);

      String paramName = i < parameterNames.length ? parameterNames[i] : "p" + (i + 1);
      PsiParameterStubImpl parameterStub =
          new PsiParameterStubImpl(parameterList, paramName, typeInfo, isEllipsisParam);
      paramStubs[i] = parameterStub;
      new PsiModifierListStubImpl(parameterStub, 0);
    }

    String[] thrownTypes = buildThrowsList(exceptions, throwables, parsedViaGenericSignature);
    newReferenceList(JavaStubElementTypes.THROWS_LIST, stub, thrownTypes);

    int localVarIgnoreCount =
        (access & Opcodes.ACC_STATIC) != 0 ? 0 : isConstructor && isEnum ? 3 : 1;
    int paramIgnoreCount = isConstructor && isEnum ? 2 : isNonStaticInnerClassConstructor ? 1 : 0;
    return new AnnotationParamCollectingVisitor(
        stub, modList, localVarIgnoreCount, paramIgnoreCount, paramCount, paramStubs);
  }