Пользовательские предупреждения компилятора - PullRequest
107 голосов
/ 30 сентября 2008

При использовании атрибута ObsoleteAtribute в .Net он выдает предупреждения компилятора о том, что объект / метод / свойство устарело и что-то еще следует использовать. В настоящее время я работаю над проектом, который требует много рефакторинга кода бывших сотрудников. Я хочу написать собственный атрибут, который я могу использовать для пометки методов или свойств, которые будут генерировать предупреждения компилятора, которые дают сообщения, которые я пишу. Как то так

[MyAttribute("This code sux and should be looked at")]
public void DoEverything()
{
}
<MyAttribute("This code sux and should be looked at")>
Public Sub DoEverything()
End Sub

Я хочу, чтобы это сгенерировало предупреждение компилятора, которое говорит: «Этот код достаточно и должен быть просмотрен». Я знаю, как создать пользовательский атрибут, вопрос в том, как заставить его генерировать предупреждения компилятора в Visual Studio.

Ответы [ 10 ]

92 голосов
/ 30 сентября 2008

Не знаю, сработает ли это, но стоит попробовать.

Вы не можете расширить устаревшее, потому что оно окончательно, но, возможно, вы можете создать свой собственный атрибут и пометить этот класс как устаревший:

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

Затем, когда вы помечаете свои методы атрибутом "MustRefactor", могут отображаться предупреждения о компиляции.

Я сказал "возможно" и "мог", потому что я не пробовал это. Пожалуйста, скажите мне, если это не сработает, поэтому я удалю ответ.

Привет!

ОБНОВЛЕНИЕ: Протестировано. Он генерирует предупреждение о времени компиляции, но сообщение об ошибке выглядит забавно, вы должны увидеть его сами и выбрать. Это очень близко к тому, чего вы хотели достичь.

UPDATE2: С этот код генерирует это предупреждение (не очень хорошо, но я не думаю, что есть что-то лучше).

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
{

}
42 голосов
/ 30 сентября 2008

В некоторых компиляторах вы можете использовать #warning для выдачи предупреждения:

#warning "Do not use ABC, which is deprecated. Use XYZ instead."

В компиляторах Microsoft вы обычно можете использовать прагму сообщения:

#pragma message ( "text" )

Вы упомянули .Net, но не указали, программируете ли вы на C / C ++ или C #. Если вы программируете на C #, вы должны знать, что C # поддерживает формат #warning .

32 голосов
/ 30 сентября 2008

В настоящее время мы занимаемся рефакторингом, в котором мы не могли сразу все исправить. Мы просто используем команду #warning preproc, где нам нужно вернуться и посмотреть на код. Это отображается в выводе компилятора. Я не думаю, что вы можете поместить его в метод, но вы можете поместить его только внутри метода, и его все равно легко найти.

public void DoEverything() {
   #warning "This code sucks"
}
25 голосов
/ 30 сентября 2008

Обновление

Теперь это возможно с Roslyn (Visual Studio 2015). Вы можете построить анализатор кода , чтобы проверить пользовательский атрибут


Я не верю, что это возможно. ObsoleteAttribute специально обрабатывается компилятором и определяется в стандарте C #. Почему устаревший атрибут неприемлем? Мне кажется, что это именно та ситуация, для которой она была разработана, и она достигает именно того, что вам нужно!

Также обратите внимание, что Visual Studio на лету получает предупреждения, сгенерированные ObsoleteAttribute, что очень полезно.

Не хочу быть бесполезным, просто интересно, почему вы не заинтересованы в его использовании ...

К сожалению, ObsoleteAttribute запечатан (возможно, частично из-за особой обработки), поэтому вы не можете выделить из него свой собственный атрибут.

Из стандарта C #: -

Атрибут Устаревший используется для пометки типы и члены типов, которые должны больше не будет использоваться.

Если программа использует тип или член что украшено устаревшим атрибут, компилятор выдает предупреждение или ошибка. В частности, Компилятор выдает предупреждение, если нет ошибки параметр предоставлен, или если ошибка параметр предоставляется и имеет значение false. Компилятор выдает ошибка, если параметр ошибки указано и имеет значение true.

Разве это не суммирует ваши нужды? ... вы не добьетесь большего успеха, чем я думаю.

7 голосов
/ 11 января 2010

В VS 2008 (+ sp1) # предупреждения не отображаются должным образом в списке ошибок после решения Clean Soultion & Rebuild, не все из них. Некоторые предупреждения отображаются в списке ошибок только после открытия определенного файла класса. Поэтому я был вынужден использовать пользовательский атрибут:

[Obsolete("Mapping ToDo")]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property)]
public class MappingToDo : System.Attribute
{
    public string Comment = "";

    public MappingToDo(string comment)
    {
        Comment = comment;
    }

    public MappingToDo()
    {}
}

Поэтому, когда я отмечаю какой-то код

[MappingToDo("Some comment")]
public class MembershipHour : Entity
{
    // .....
}

Выдает такие предупреждения:

Namespace.MappingToDo устарело: 'Mapping ToDo'.

Я не могу изменить текст предупреждения, «Некоторый комментарий» не отображается в списке ошибок. Но он перейдет в нужное место в файле. Поэтому, если вам нужно изменить такие предупреждающие сообщения, создайте различные атрибуты.

5 голосов
/ 29 сентября 2014

То, что вы пытаетесь сделать, - это неправильное использование атрибутов. Вместо этого используйте список задач Visual Studio. Вы можете ввести комментарий в свой код следующим образом:

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

Затем откройте View / Task List из меню. Список задач имеет две категории: пользовательские задачи и комментарии. Переключитесь на Комментарии, и вы увидите все ваши // Todo: там. Двойной щелчок по TODO приведет к переходу к комментарию в вашем коде.

Al

2 голосов
/ 30 сентября 2008

Глядя на источник для ObsoleteAttribute , не похоже, что он делает что-то особенное, чтобы сгенерировать предупреждение компилятора, поэтому я бы предпочел пойти с @ technophile и сказать, что он жестко запрограммирован в компиляторе. Есть ли причина, по которой вы не хотите просто использовать ObsoleteAttribute для создания предупреждений?

2 голосов
/ 30 сентября 2008

Не думаю, что ты можешь. Насколько я знаю, поддержка ObsoleteAttribute по существу жестко запрограммирована в компиляторе C #; Вы не можете делать ничего подобного напрямую.

Что вы могли бы сделать, это использовать задачу MSBuild (или событие после сборки), которая запускает пользовательский инструмент для только что скомпилированной сборки. Пользовательский инструмент будет отражать все типы / методы в сборке и использовать ваш пользовательский атрибут, после чего он может печатать в System.Console по умолчанию или с ошибкой TextWriters.

1 голос
/ 31 июля 2017

Вот реализация Roslyn, так что вы можете создавать свои собственные атрибуты, которые выдают предупреждения или ошибки на лету.

Я создал атрибут Type Called IdeMessage, который будет атрибутом, генерирующим предупреждения:

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

    public IDEMessageAttribute(string message);
}

Для этого вам нужно сначала установить Roslyn SDK и запустить новый проект VSIX с анализатором. Я опустил некоторые менее значимые фрагменты, такие как сообщения, вы можете понять, как это сделать. В вашем анализаторе вы делаете это

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);
}

Для этого нет CodeFixProvider, вы можете удалить его из решения.

1 голос
/ 12 ноября 2014

Есть несколько комментариев, которые предлагают вставить предупреждения или прагму. Устаревшие работы совсем по-другому! Отмечая устаревшую функцию библиотеки L, устаревшее сообщение возникает, когда программа вызывает функцию, даже если вызывающая программа отсутствует в библиотеке L. Предупреждение вызывает сообщение ТОЛЬКО, когда компилируется L.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...