Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to show a specific hint within Visual Studio

I'm currently working on improving my coding sensation so I've started adding some extension methods to the types I'm using.


I figured out, that I'm doing the same action quite often always with the same attributes.

I want to show this hint when someone calls ReplaceNewLine("|"):

The char you want to remove is |. Use the RemoveNewLine() extension without any attributes instead.

I tried it with the [Obsolete(...)] attribute, but this got shown every time I called the function.

My question is: How can I show a specific hint based on my input within Visual Studio?

Code:

public static class StringExtension
{
    public static string ReplaceNewLine(this string s)
    {
        return s.Replace("|", Environment.NewLine);
    }

    // show hint if c is |
    public static string ReplaceNewLine(this string s, string c)
    {
        return s.Replace(c, Environment.NewLine);
    }
}

Apposition:

  • Of course the hint may have the Obsolete code (0618/CS0618) when it is shown, but that's not important for me. I just want to get the hint shown!
  • I'm working with C# 6.0, .NET 4.6 and Visual Studio 2015 RC.
like image 862
cramopy Avatar asked Jun 16 '15 15:06

cramopy


2 Answers

In Visual Studio 2015 this is possible using a Roslyn Diagnostic (and optional Fix). The new Visual Studio 2015 code editor uses Roslyn under the hood to do all it's parsing an the Code Analaysis, Metrics and Refactoring engine is now based on it.

A sample implementation of such an inspection is given on the Roslyn github page. A full implementation would be a bit much for an answer here on StackOverflow, as it entails a number of steps to go through and amounts to a complete tutorial, but this full tutorial of something similar is given here. and may be the basis for your work. (ask additional questions later). Code for the standard rules that ship with the product can be found in the Roslyn GitHub as well.

This piece of code should get you pretty close, but I haven't tested it. Create a standard diagnostic & fix according to the Roslyn SDK totorial and replace the Initialize and AnalyzeNode methods with (replace the namespace with your own):

public override void Initialize(AnalysisContext context)
{
    context.RegisterSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.InvocationExpression);
}

private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context)
{
    InvocationExpressionSyntax invocationExpression = context.Node as InvocationExpressionSyntax;
    IMethodSymbol methodSymbol = context.SemanticModel.GetSymbolInfo(invocationExpression).Symbol as IMethodSymbol;

    if (
        methodSymbol != null
        && methodSymbol.Name == "ReplaceNewline" 
        && methodSymbol.ContainingNamespace.Name == "MySampleFix"
        && methodSymbol.OriginalDefinition.Parameters.Length == 1)
    {
        if (invocationExpression.ArgumentList.Arguments.Count() == 1)
        {
            LiteralExpressionSyntax arg =
                invocationExpression.ArgumentList.Arguments[0].Expression as LiteralExpressionSyntax;

            if (arg != null && arg.Token.ValueText == "|")
            {
                Diagnostic.Create(Rule, invocationExpression.GetLocation());
            }
        }
    }
}

If you want to make something that's backwards compatible with older versions of Visual Studio you can opt to write a custom code analysis rule. This example rule takes the input to a call to Regex.Match and Regex.Replace and gives a warning when it doesn't compile. It would be even simpler to give a warning when it is a constant string.

Visual studio extensions like Resharper and CodeRush offer an SDK which can do things similar to FxCop, but they embed into the IDE like Roslyn does. It may be an option for you to take that approach.

If you want something in the code editor that doesn't use any extension or customization, then adding a <remark /> to the codedoc is about as much as you can do. In the worst case you could put in a Debug.Assert(input != "|"); in the method, that way developers will get early warning (at development/debug time) that they're using your API incorrectly.

like image 162
jessehouwing Avatar answered Sep 22 '22 21:09

jessehouwing


I dont think it is possible, only with the exception of

emphatic comment

:)

/// <summary>
/// Replace specific char with <see cref="Environment.NewLine"/>
/// </summary>
/// <param name="s">input</param>
/// <param name="c">If the char is "|", use the extension method without any parameter instead (<see cref="StringExtension.ReplaceNewLine()" />).</param>
/// <returns>something with maybe new lines.</returns>
public static string ReplaceNewLine(this string s, string c) {...}

I dont know any other way to produce hint in pure Visual Studio, with exception of #warning msg (and #pragma), but they are conditional only by pre-defined build parameters (like #IF DEBUG etc) and they go straight to the error list.

Btw & just for fun: you can solve your example by adding default value

public static class StringExtension
{
    public static string ReplaceNewLine(this string s, string c = "|")
    {
        return s.Replace(c, Environment.NewLine);
    }
}

Edit: jessehouwing answer is much better, this whole answer was more or less a joke about vigorous comments :)

like image 25
Jan 'splite' K. Avatar answered Sep 26 '22 21:09

Jan 'splite' K.