Как реализовать массовые действия в ReSharper 10?

Я пытаюсь получить общий обзор о том, как реализовать плагины для ReSharper. Я смог разработать очень простой плагин, развернуть его и использовать для выполнения желаемых действий.

Однако я хотел изменить свой плагин для поддержки режима массовых действий. Поэтому я сначала следовал официальным рекомендациям ReSharper, которые на данный момент устарели и действительны только для v8.0. Затем я обнаружил эту проблему, и стало ясно, что массовые действия еще не задокументированы должным образом. Тем не менее, я смог собрать "что-то" вместе, основываясь на сообщении групп Google, на которое ссылается проблема github.

Я хотел реализовать что-то действительно простое и глупое, просто подтверждение концепции, поэтому я декомпилировал некоторые сборки ReSharper и скопировал реализацию ToggleVarFix в мое решение. Я изменил его в соответствии с публикацией в группах Google и произвел функциональное изменение - оригинальная версия заменяет явный тип на varМоя пользовательская версия заменяет ее на abstract, Что, конечно, не имеет смысла, я просто хотел увидеть массовое действие в действии.

Удивительно для меня, но мой плагин все еще работает только в режиме одиночного исправления, т.е. я могу изменить явный тип на abstract Ключевое слово для одного объявления. Однако, как только я пытаюсь вызвать мое действие в массовом режиме (для файла или проекта), явный тип изменяется на var и я действительно понятия не имею, почему это происходит, и почему это не так abstract вместо. Следующее изображение лучше объясняет, что я не понимаю о том, как работает мой плагин:

введите описание изображения здесь

Может ли кто-нибудь проверить реализацию моего плагина и, возможно, предложить, что я сделал не так? Ниже мой код, единственное "функциональное" изменение по сравнению с оригинальным ToggleVarFix следует закомментировать declaration.SetVar();, заменен слегка измененной версией, где abstract используется в качестве замены для явных типов, в отличие от var от оригинальной версии.

using System;
using JetBrains.Annotations;
using JetBrains.Application.Progress;
using JetBrains.ProjectModel;
using JetBrains.ReSharper.Daemon.CSharp.CodeCleanup.CodeStyles;
using JetBrains.ReSharper.Daemon.CSharp.Errors;
using JetBrains.ReSharper.Feature.Services.Bulk;
using JetBrains.ReSharper.Feature.Services.Bulk.Actions;
using JetBrains.ReSharper.Feature.Services.CodeCleanup;
using JetBrains.ReSharper.Feature.Services.QuickFixes;
using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.CSharp;
using JetBrains.ReSharper.Psi.CSharp.CodeStyle;
using JetBrains.ReSharper.Psi.CSharp.Tree;
using JetBrains.ReSharper.Psi.ExtensionsAPI.Tree;
using JetBrains.ReSharper.Psi.Tree;
using JetBrains.ReSharper.Resources.Shell;
using JetBrains.TextControl;
using JetBrains.Util;

namespace RSharpExtensionSample
{
    [QuickFix]
    public class CustomToggleVarFix : QuickFixBase, ICodeCleanupAction
    {
        private static readonly Key InstanceKey = new Key("CustomToggleVarFix");

        private readonly ITreeNode m_myDeclaration;

        private readonly CodeCleanupProfile m_myCodeCleanupProfile;

        private readonly IProjectFile m_myProjectFile;

        public override string Text
        {
            get { return IsConvertingToVar() ? "[Custom] Use 'var'" : "[Custom] Use explicit type"; }
        }

        public string BulkText
        {
            get { return Text + " everywhere"; }
        }

        public FileCollectorInfo FileCollectorInfo
        {
            get { return new FileCollectorInfo(m_myProjectFile, CSharpLanguage.Instance); }
        }

        public bool Single
        {
            get { return false; }
        }

        public CustomToggleVarFix([NotNull] UseVarOrTypeForBuiltInTypesWarning warning)
            : this(warning.Declaration)
        {
        }

        public CustomToggleVarFix([NotNull] UseVarOrTypeElsewhereWarning warning)
            : this(warning.Declaration)
        {
        }

        public CustomToggleVarFix([NotNull] UseVarOrTypeForSimpleTypesWarning warning)
            : this(warning.Declaration)
        {
        }

        private CustomToggleVarFix([NotNull] ITreeNode node)
        {
            m_myDeclaration = node;
            m_myProjectFile = m_myDeclaration.GetSourceFile().ToProjectFile();
            var value = IsConvertingToVar() ? VariableStyle.UseVar : VariableStyle.UseExplicitType;
            var component = Shell.Instance.GetComponent<CodeCleanupSettingsComponent>();
            m_myCodeCleanupProfile = component.CreateEmptyProfile("Test");
            m_myCodeCleanupProfile.SetSetting(ReplaceByVarCodeCleanupModule.DESCRIPTOR, true);
            m_myCodeCleanupProfile.SetSetting(ReplaceByVarCodeCleanupModule.OPTIONS, new ReplaceByVarCodeCleanupModule.Options {
                ForBuiltInTypes = value,
                ForSimpleTypes = value,
                ForOtherTypes = value
            });
        }

        protected override Action<ITextControl> ExecutePsiTransaction([NotNull] ISolution solution, [NotNull] IProgressIndicator progress)
        {
            TryExecuteFor(m_myDeclaration as IMultipleLocalVariableDeclaration);
            TryExecuteFor(m_myDeclaration as IForeachVariableDeclaration);

            return null;
        }

        private void TryExecuteFor(IForeachVariableDeclaration declaration)
        {
            if (declaration == null)
            {
                return;
            }
            if (declaration.VarKeyword == null)
            {
                //declaration.SetVar();
                ChangeExplicitTypeToAbstract(declaration);
                return;
            }
            declaration.SetType(declaration.DeclaredElement.Type);
        }

        private void TryExecuteFor(IMultipleLocalVariableDeclaration declaration)
        {
            if (declaration == null)
            {
                return;
            }
            if (declaration.VarKeyword == null)
            {
                //declaration.SetVar();
                ChangeExplicitTypeToAbstract(declaration);
                return;
            }
            var localVariableDeclaration = declaration.Declarators[0] as ILocalVariableDeclaration;
            if (localVariableDeclaration == null)
            {
                return;
            }
            var declaredElement = localVariableDeclaration.DeclaredElement;
            localVariableDeclaration.SetType(declaredElement.Type);
        }

        private static void ChangeExplicitTypeToAbstract(IMultipleLocalVariableDeclaration declaration)
        {
            using (WriteLockCookie.Create(declaration.IsPhysical()))
            {
                ModificationUtil.ReplaceChild(
                    declaration.TypeDesignator,
                    JetBrains.ReSharper.Psi.CSharp.Parsing.CSharpTokenType.ABSTRACT_KEYWORD.CreateLeafElement());
            }
        }

        private static void ChangeExplicitTypeToAbstract(IForeachVariableDeclaration declaration)
        {
            if (declaration.TypeUsage == null) return;
            using (WriteLockCookie.Create(declaration.IsPhysical()))
            {
                ModificationUtil.ReplaceChild(
                    declaration.TypeUsage,
                    JetBrains.ReSharper.Psi.CSharp.Parsing.CSharpTokenType.ABSTRACT_KEYWORD.CreateLeafElement());
            }
        }

        public override bool IsAvailable(IUserDataHolder cache)
        {
            if (!IsAvailableEx()) return false;

            cache.PutData(InstanceKey, this);
            return true;
        }

        private bool IsAvailableEx()
        {
            return CSharpExtensionMethods.IsCSharp3Supported(m_myDeclaration)
                && (IsAvailableFor(m_myDeclaration as IMultipleLocalVariableDeclaration)
                    || IsAvailableFor(m_myDeclaration as IForeachVariableDeclaration));
        }

        private bool IsAvailableFor(IForeachVariableDeclaration declaration)
        {
            return declaration != null;
        }

        private bool IsAvailableFor(IMultipleLocalVariableDeclaration declaration)
        {
            return declaration != null && declaration.Declarators.Count == 1;
        }

        private bool IsConvertingToVar()
        {
            var multipleLocalVariableDeclaration = m_myDeclaration as IMultipleLocalVariableDeclaration;
            if (multipleLocalVariableDeclaration != null)
            {
                return multipleLocalVariableDeclaration.VarKeyword == null;
            }
            var foreachVariableDeclaration = m_myDeclaration as IForeachVariableDeclaration;
            if (foreachVariableDeclaration != null)
            {
                return foreachVariableDeclaration.VarKeyword == null;
            }
            throw new InvalidOperationException();
        }

        public CodeCleanupProfile GetCodeCleanupProfile()
        {
            return m_myCodeCleanupProfile;
        }
    }
}

0 ответов

Другие вопросы по тегам