[c#] Custom Compiler Warnings


4 Answers

Don't know if this will work but it's worth a try.

You can't extend Obsolete, because its final, but maybe you can create your own attribute, and mark that class as obsolete like this:

[Obsolete("Should be refactored")]
public class MustRefactor: System.Attribute{}

Then when you mark your methods with the "MustRefactor" attribute, the compile warnings might show.

I said "maybe" and "might" because I haven't tried this. Please tell me if it doesn't work so I'll remove the answer.

Regards!

UPDATE: Tested it. It generates a compile time warning, but the error message looks funny, you should see it for yourself and choose. This is very close to what you wanted to achieve.

UPDATE2: With this code It generates this warnings (not very nice, but I don't think there's something better).

public class User
{
    private String userName;

    [TooManyArgs] // Will show warning: Try removing some arguments
    public User(String userName)
    {
        this.userName = userName;   
    }

    public String UserName
    {
        get { return userName; }
    }
    [MustRefactor] // will show warning: Refactor is needed Here
    public override string ToString()
    {
        return "User: " + userName;
    }
}
[Obsolete("Refactor is needed Here")]
public class MustRefactor : System.Attribute
{

}
[Obsolete("Try removing some arguments")]
public class TooManyArgs : System.Attribute
{

}
Question

When using the ObsoleteAtribute in .Net it gives you compiler warnings telling you that the object/method/property is obsolete and somthing else should be used. I'm currently working on a project that requires a lot of refactoring an ex-employees code. I want to write a custom attribute that I can use to mark methods or properties that will generate compiler warnings that give messages that I write. Something like this

[MyAttribute("This code sux and should be looked at")]
public sub DoEverything(){}

I want this to generate a compiler warning that says, "This code sux and should be looked at". I know how to create a custom attribute, the question is how do I cause it to generate compiler warnings in visual studio.




What you are trying to do is a misuse of attributes. Instead use the Visual Studio Task List. You can enter a comment in your code like this:

//TODO:  This code sux and should be looked at
public class SuckyClass(){
  //TODO:  Do something really sucky here!
}

Then open View / Task List from the menu. The task list has two categories, user tasks and Comments. Switch to Comments and you will see all of your //Todo:'s there. Double clicking on a TODO will jump to the comment in your code.

Al




Here is the Roslyn Implementation, so you can create you're own attributes that give warnings or errors of the fly.

I've create an attribute Type Called IdeMessage which you will be the attribute which generates warnings:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class IDEMessageAttribute : Attribute
{
    public string Message;

    public IDEMessageAttribute(string message);
}

In order to do this you need to install the Roslyn SDK first and start a new VSIX project with analyzer, I've omitted some of the less relevant piece like the messages you can figure out how to do it, in your analyzer you do this

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

private static void AnalyzerInvocation(SyntaxNodeAnalysisContext context)
{
    var invocation = (InvocationExpressionSyntax)context.Node;

    var methodDeclaration = (context.SemanticModel.GetSymbolInfo(invocation, context.CancellationToken).Symbol as IMethodSymbol);

    //There are several reason why this may be null e.g invoking a delegate
    if (null == methodDeclaration)
    {
        return;
    }

    var methodAttributes = methodDeclaration.GetAttributes();
    var attributeData = methodAttributes.FirstOrDefault(attr => IsIDEMessageAttribute(context.SemanticModel, attr, typeof(IDEMessageAttribute)));
    if(null == attributeData)
    {
        return;
    }

    var message = GetMessage(attributeData); 
    var diagnostic = Diagnostic.Create(Rule, invocation.GetLocation(), methodDeclaration.Name, message);
    context.ReportDiagnostic(diagnostic);
}

static bool IsIDEMessageAttribute(SemanticModel semanticModel, AttributeData attribute, Type desiredAttributeType)
{
    var desiredTypeNamedSymbol = semanticModel.Compilation.GetTypeByMetadataName(desiredAttributeType.FullName);

    var result = attribute.AttributeClass.Equals(desiredTypeNamedSymbol);
    return result;
}

static string GetMessage(AttributeData attribute)
{
    if (attribute.ConstructorArguments.Length < 1)
    {
        return "This method is obsolete";
    }

    return (attribute.ConstructorArguments[0].Value as string);
}

There are no CodeFixProvider for this you can remove it from the solution.




Looking at the source for ObsoleteAttribute, it doesn't look like it's doing anything special to generate a compiler warning, so I would tend to go with @technophile and say that it is hard-coded into the compiler. Is there a reason you don't want to just use ObsoleteAttribute to generate your warning messages?




We're currently in the middle of a lot of refactoring where we couldn't fix everything right away. We just use the #warning preproc command where we need to go back and look at code. It shows up in the compiler output. I don't think you can put it on a method, but you could put it just inside the method, and it's still easy to find.

public void DoEverything() {
   #warning "This code sucks"
}



Related