如何在ReSharper 10中实现批量操作?

时间:2016-03-17 10:18:37

标签: c# .net visual-studio resharper resharper-sdk

我试图概述如何为ReSharper实现插件。我能够开发一个非常简单的插件,部署它,然后用它来执行我想要的动作。

但是,我想更改我的插件以支持批量操作模式。因此,我首先关注过时的official ReSharper guidelines,目前仅对v8.0有效。然后我发现了这个github issue,很明显,批量操作尚未正确记录。但是,我能够把#34;"一起基于github问题中引用的google groups post

我想实现一些非常简单和愚蠢的东西,只是一个概念证明,因此我反编译了一些ReSharper程序集并将ToggleVarFix的实现复制到我的解决方案中。我根据google groups post对其进行了修改并进行了功能更改 - 原始版本替换了var的显式类型,我的自定义版本将其替换为abstract。这当然没有意义,我只想看到批量行动的实际效果。

令我惊讶的是,我的插件仍然只能在单一修复模式下工作,即我可以将单一声明的显式类型更改为abstract关键字。但是,一旦我尝试以批量模式(对于文件或项目)调用我的操作,显式类型将更改为var,我真的不知道为什么会发生这种情况以及为什么它不是abstract 1}}而不是。下面的图片更好地解释了我的插件目前的工作原理:

enter image description here

有人可以查看我的插件的实现,也许可以提出我做错了吗?以下是我的代码,唯一的"功能"更改与原始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 个答案:

没有答案