@VisibleForTesting
  static @NotNull ResolveConflictResult resolveConflict(@NotNull FileNameMatcher matcher,
                                                        @NotNull FileTypeManagerImpl.FileTypeWithDescriptor oldFtd,
                                                        @NotNull FileTypeManagerImpl.FileTypeWithDescriptor newFtd) {
    assert !oldFtd.equals(newFtd) : oldFtd;
    if (newFtd.pluginDescriptor().isBundled() &&
        (!oldFtd.pluginDescriptor().isBundled() || isCorePlugin(newFtd.pluginDescriptor()) && !isCorePlugin(oldFtd.pluginDescriptor()))) {
      FileTypeManagerImpl.FileTypeWithDescriptor ftd = newFtd;
      newFtd = oldFtd;
      oldFtd = ftd;
    }
    // now the bundled or core plugin, if any, is stored in oldFtd
    PluginDescriptor oldPlugin = oldFtd.pluginDescriptor();
    PluginDescriptor newPlugin = newFtd.pluginDescriptor();
    FileType oldFileType = oldFtd.fileType();
    FileType newFileType = newFtd.fileType();
    // do not show notification if the new plugin reassigned core or bundled plugin
    String oldPluginName = oldPlugin.isBundled() ? "bundled" : oldPlugin.getName();
    String explanation = FileTypesBundle.message("notification.content.file.type.reassigned.explanation", matcher.getPresentableString());
    // override core unconditionally
    if (!newPlugin.isBundled() || isCorePlugin(oldPlugin) && !isCorePlugin(newPlugin)) {
      boolean approved = oldPlugin.isBundled();
      // new plugin overrides pattern
      String message = FileTypesBundle.message("notification.content.file.type.reassigned.plugin", matcher.getPresentableString(), oldPluginName, newFileType.getDisplayName(), newPlugin.getName());
      return new ResolveConflictResult(newFtd, message, explanation, approved);
    }
    if (oldFileType == NativeFileType.INSTANCE) {
      // somebody overridden NativeFileType extension with their own type, which is always good
      String message = FileTypesBundle.message("notification.content.file.pattern.was.reassigned.to", matcher.getPresentableString(), newFileType.getDisplayName());
      return new ResolveConflictResult(newFtd, message, explanation, true);
    }
    
    // if both bundled, should win the bundle from other vendor as more specific
    // see the case "Image" plugin vs "Adobe Photoshop" from Android
    boolean isOldJetBrains = PluginManagerCore.isVendorJetBrains(StringUtil.notNullize(oldPlugin.getVendor()));
    boolean isNewJetBrains = PluginManagerCore.isVendorJetBrains(StringUtil.notNullize(newPlugin.getVendor()));
    if (isOldJetBrains != isNewJetBrains) {
      FileTypeManagerImpl.FileTypeWithDescriptor result = isOldJetBrains ? newFtd : oldFtd;
      String message = FileTypesBundle.message("notification.content.file.pattern.was.reassigned.to", matcher.getPresentableString(), result.fileType()
        .getDisplayName());
      return new ResolveConflictResult(result, message, explanation, true);
    }

    /* ? wild guess: two bundled file types */
    String message = FileTypesBundle.message("notification.content.file.pattern.was.reassigned.to", matcher.getPresentableString(), oldFileType.getDisplayName());
    // prefer old file type to avoid notification about file type reassignments twice
    return new ResolveConflictResult(oldFtd, message, explanation, false);
  }
@VisibleForTesting
  static @NotNull ResolveConflictResult resolveConflict(@NotNull FileNameMatcher matcher,
                                                        @NotNull FileTypeManagerImpl.FileTypeWithDescriptor oldFtd,
                                                        @NotNull FileTypeManagerImpl.FileTypeWithDescriptor newFtd)