Help Assigning default value to a parameter in a Quick Fix

I am writing a resharper plugin to help my organization enforce best practices with the new .NET 4.5 async / await keywords.  In doing so one of the items which I wish to do is suggest a quick fix for the case when an async task takes a CancellationToken parameter but does not provide a default value for that parameter.  The quick fix should add a default of "default(CancellationToken)" as that is the equivalent of CancellationToken.None, which is not allowed to be used as default parameter value.

I've come up with a daemon stage class which identifies the parameters I want to offer the quick fix on correctly.  The code below is what I've come up with so far to do the actual fixing. It adds a default value of "new CancellationToken()" which is not what is desired.  I've had to poke around inside reflector just to get this far but at this point I'm stumped.  Any suggestions and guidance would be appreciated.

    [StaticSeverityHighlighting(Severity.SUGGESTION, "Justin Thyme")]
    public class AddCancellationTokenDefaultValueSuggestion : CSharpHighlightingBase, IHighlighting
    {
        public IRegularParameterDeclaration CancellationTokenParameter { get; private set; }

        public string ToolTip { get { return "Consider providing a default value for the CancellationToken so that callers which don't care about cancellation don't have to pass in CancellationToken.None."; } }

        public string ErrorStripeToolTip { get { return ToolTip; } }

        public int NavigationOffsetPatch { get { return 0; } }

        public AddCancellationTokenDefaultValueSuggestion(IRegularParameterDeclaration cancellationTokenParam)
        {
            CancellationTokenParameter = cancellationTokenParam;
        }

        public override bool IsValid()
        {
            return CancellationTokenParameter.IsValid();
        }
    }

    [QuickFix]
    public class AddCancellationTokenDefaultValueQuckFix : QuickFixBase
    {
        public AddCancellationTokenDefaultValueSuggestion Highlighter { get; private set; }

        public override string Text
        {
            get { return "Add default value equivalent to CancellationToken.None"; }
        }

        public AddCancellationTokenDefaultValueQuckFix(AddCancellationTokenDefaultValueSuggestion highlighter)
        {
            Highlighter = highlighter;
        }

        protected override Action<ITextControl> ExecutePsiTransaction(ISolution solution, IProgressIndicator progress)
        {
            var module = Highlighter.CancellationTokenParameter.GetPsiModule();
            var cancellationTokenType = TypeFactory.CreateTypeByCLRName(typeof(CancellationToken).FullName, module);
            var factory = CSharpElementFactory.GetInstance(module);

            var defaultVal = factory.CreateExpressionByDefaultValue(new DefaultValue(cancellationTokenType.ToIType()));
            Highlighter.CancellationTokenParameter.SetDefaultValue(defaultVal);

            return null;
        }

        public override bool IsAvailable(IUserDataHolder cache)
        {
            return Highlighter.IsValid();
        }
    }


Thanks in advance.
-Josh

1 comment
Comment actions Permalink

ReSharper is using "new CancellationToken" because CancellationToken is a struct, and "default(CancellationToken)" is exactly the same as "new CancellationToken()".

If you really want to use "default(CancellationToken)", you can call factory.CreateExpression("default($0)", factory.CreateTypeUsageNode(cancellationTokenType.ToIType())), and you're taking responsibility for the IType you're passing in working with default(), which CreateExpressionByDefaultValue handles for you.

0

Please sign in to leave a comment.