From 1d4da1ae301a6e11e5bdc3702749b5bdccb8a97c Mon Sep 17 00:00:00 2001 From: Evangelink Date: Fri, 7 Aug 2020 17:25:01 +0200 Subject: [PATCH] Update resource analyzers to flag leading and trailing whitespaces --- .../CodeAnalysisDiagnosticsResources.resx | 6 +- .../DiagnosticDescriptorCreationAnalyzer.cs | 29 +- .../CodeAnalysisDiagnosticsResources.cs.xlf | 8 +- .../CodeAnalysisDiagnosticsResources.de.xlf | 8 +- .../CodeAnalysisDiagnosticsResources.es.xlf | 8 +- .../CodeAnalysisDiagnosticsResources.fr.xlf | 8 +- .../CodeAnalysisDiagnosticsResources.it.xlf | 8 +- .../CodeAnalysisDiagnosticsResources.ja.xlf | 8 +- .../CodeAnalysisDiagnosticsResources.ko.xlf | 8 +- .../CodeAnalysisDiagnosticsResources.pl.xlf | 8 +- ...CodeAnalysisDiagnosticsResources.pt-BR.xlf | 8 +- .../CodeAnalysisDiagnosticsResources.ru.xlf | 8 +- .../CodeAnalysisDiagnosticsResources.tr.xlf | 8 +- ...deAnalysisDiagnosticsResources.zh-Hans.xlf | 8 +- ...deAnalysisDiagnosticsResources.zh-Hant.xlf | 8 +- ...agnosticDescriptorCreationAnalyzerTests.cs | 511 ++++++++++++++++++ 16 files changed, 591 insertions(+), 59 deletions(-) diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnalysisDiagnosticsResources.resx b/src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnalysisDiagnosticsResources.resx index 93a2acd3c8..52936a7c8e 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnalysisDiagnosticsResources.resx +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnalysisDiagnosticsResources.resx @@ -497,19 +497,19 @@ Enabling release tracking for analyzer packages helps in tracking and documenting the analyzer diagnostics that ship and/or change with each analyzer release. See details at https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md. - The diagnostic title should not contain a period or any line return character + The diagnostic title should not contain a period, nor any line return character, nor any leading or trailing whitespaces Define diagnostic title correctly - The diagnostic message should not contain any line return character and should either be a single sentence without a trailing period or a multi-sentences with a trailing period + The diagnostic message should not contain any line return character nor any leading or trailing whitespaces and should either be a single sentence without a trailing period or a multi-sentences with a trailing period Define diagnostic message correctly - The diagnostic description should be one or multiple sentences ending with a punctuation sign + The diagnostic description should be one or multiple sentences ending with a punctuation sign and should not have any leading or trailing whitespaces Define diagnostic description correctly diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/DiagnosticDescriptorCreationAnalyzer.cs b/src/Microsoft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/DiagnosticDescriptorCreationAnalyzer.cs index b9517e380d..d9e5b8a4a0 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/DiagnosticDescriptorCreationAnalyzer.cs +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/DiagnosticDescriptorCreationAnalyzer.cs @@ -504,11 +504,14 @@ private static void AnalyzeTitleCore(string title, IArgumentOperation argumentOp var isMultiSentences = IsMultiSentences(title); var endsWithPeriod = EndsWithPeriod(title); var containsLineReturn = ContainsLineReturn(title); - if (isMultiSentences || endsWithPeriod || containsLineReturn) + var hasLeadingOrTrailingWhitespaces = HasLeadingOrTrailingWhitespaces(title); + + if (isMultiSentences || endsWithPeriod || containsLineReturn || hasLeadingOrTrailingWhitespaces) { var fixedTitle = endsWithPeriod ? RemoveTrailingPeriod(title) : title; fixedTitle = isMultiSentences ? FixMultiSentences(fixedTitle) : fixedTitle; fixedTitle = containsLineReturn ? FixLineReturns(fixedTitle, allowMultisentences: false) : fixedTitle; + fixedTitle = hasLeadingOrTrailingWhitespaces ? RemoveLeadingAndTrailingWhitespaces(fixedTitle) : fixedTitle; Debug.Assert(title != fixedTitle); ReportDefineDiagnosticArgumentCorrectlyDiagnostic(DefineDiagnosticTitleCorrectlyRule, @@ -594,7 +597,9 @@ private static void AnalyzeMessageCore(string message, IArgumentOperation argume var isMultiSentences = IsMultiSentences(message); var endsWithPeriod = EndsWithPeriod(message); var containsLineReturn = ContainsLineReturn(message); - if (isMultiSentences ^ endsWithPeriod || containsLineReturn) + var hasLeadingOrTrailingWhitespaces = HasLeadingOrTrailingWhitespaces(message); + + if (isMultiSentences ^ endsWithPeriod || containsLineReturn || hasLeadingOrTrailingWhitespaces) { var fixedMessage = containsLineReturn ? FixLineReturns(message, allowMultisentences: true) : message; isMultiSentences = IsMultiSentences(fixedMessage); @@ -605,6 +610,8 @@ private static void AnalyzeMessageCore(string message, IArgumentOperation argume fixedMessage = endsWithPeriod ? RemoveTrailingPeriod(fixedMessage) : fixedMessage + "."; } + fixedMessage = hasLeadingOrTrailingWhitespaces ? RemoveLeadingAndTrailingWhitespaces(fixedMessage) : fixedMessage; + ReportDefineDiagnosticArgumentCorrectlyDiagnostic(DefineDiagnosticMessageCorrectlyRule, argumentOperation, fixedMessage, fixLocation, reportDiagnostic); } @@ -630,9 +637,14 @@ private static void AnalyzeMessageCore(string message, IArgumentOperation argume private static void AnalyzeDescriptionCore(string description, IArgumentOperation argumentOperation, Location fixLocation, Action reportDiagnostic) { - if (!EndsWithPunctuation(description)) + var hasLeadingOrTrailingWhitespaces = HasLeadingOrTrailingWhitespaces(description); + var endsWithPunctuation = EndsWithPunctuation(description); + + if (!endsWithPunctuation || hasLeadingOrTrailingWhitespaces) { - var fixedDescription = description + "."; + var fixedDescription = !endsWithPunctuation ? description + "." : description; + fixedDescription = hasLeadingOrTrailingWhitespaces ? RemoveLeadingAndTrailingWhitespaces(fixedDescription) : fixedDescription; + ReportDefineDiagnosticArgumentCorrectlyDiagnostic(DefineDiagnosticDescriptionCorrectlyRule, argumentOperation, fixedDescription, fixLocation, reportDiagnostic); } @@ -859,6 +871,15 @@ private static string RemoveTrailingPunctuation(string s) return s[0..^1]; } + private static bool HasLeadingOrTrailingWhitespaces(string s) + => s.Trim().Length != s.Length; + + private static string RemoveLeadingAndTrailingWhitespaces(string s) + { + Debug.Assert(HasLeadingOrTrailingWhitespaces(s)); + return s.Trim(); + } + private static void AnalyzeHelpLinkUri( OperationAnalysisContext operationAnalysisContext, ImmutableArray creationArguments, diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.cs.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.cs.xlf index d4d6e4812a..37531d2130 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.cs.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.cs.xlf @@ -68,7 +68,7 @@ - The diagnostic description should be one or multiple sentences ending with a punctuation sign + The diagnostic description should be one or multiple sentences ending with a punctuation sign and should not have any leading or trailing whitespaces Diagnostický popis by měla být jedna věta nebo několik vět zakončených interpunkčním znaménkem. @@ -78,7 +78,7 @@ - The diagnostic message should not contain any line return character and should either be a single sentence without a trailing period or a multi-sentences with a trailing period + The diagnostic message should not contain any line return character nor any leading or trailing whitespaces and should either be a single sentence without a trailing period or a multi-sentences with a trailing period Diagnostická zpráva by neměla obsahovat žádný návratový znak (konec řádku) a měla by to být buď jedna věta bez tečky na konci nebo víc vět s tečkou na konci. @@ -88,8 +88,8 @@ - The diagnostic title should not contain a period or any line return character - Nadpis diagnostiky by neměl obsahovat tečku ani žádný znak konce řádku. + The diagnostic title should not contain a period, nor any line return character, nor any leading or trailing whitespaces + Nadpis diagnostiky by neměl obsahovat tečku ani žádný znak konce řádku. diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.de.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.de.xlf index 291b6fe2c9..28a432f3ef 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.de.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.de.xlf @@ -68,7 +68,7 @@ - The diagnostic description should be one or multiple sentences ending with a punctuation sign + The diagnostic description should be one or multiple sentences ending with a punctuation sign and should not have any leading or trailing whitespaces Die Diagnosebeschreibung sollte mindestens einen Satz umfassen und auf ein Satzzeichen enden. @@ -78,7 +78,7 @@ - The diagnostic message should not contain any line return character and should either be a single sentence without a trailing period or a multi-sentences with a trailing period + The diagnostic message should not contain any line return character nor any leading or trailing whitespaces and should either be a single sentence without a trailing period or a multi-sentences with a trailing period Die Diagnosemeldung darf keine Zeilenvorschubzeichen enthalten und muss entweder einen einzelnen Satz ohne Satzendepunkt oder mehrere Sätze mit Satzendepunkt umfassen. @@ -88,8 +88,8 @@ - The diagnostic title should not contain a period or any line return character - Der Titel der Diagnosemeldung darf keinen Satzendepunkt oder ein Zeilenvorschubzeichen enthalten. + The diagnostic title should not contain a period, nor any line return character, nor any leading or trailing whitespaces + Der Titel der Diagnosemeldung darf keinen Satzendepunkt oder ein Zeilenvorschubzeichen enthalten. diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.es.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.es.xlf index 8e838afbc9..6d3a5f48f2 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.es.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.es.xlf @@ -68,7 +68,7 @@ - The diagnostic description should be one or multiple sentences ending with a punctuation sign + The diagnostic description should be one or multiple sentences ending with a punctuation sign and should not have any leading or trailing whitespaces La descripción del diagnóstico debe ser una o varias oraciones que terminen con un signo de puntuación. @@ -78,7 +78,7 @@ - The diagnostic message should not contain any line return character and should either be a single sentence without a trailing period or a multi-sentences with a trailing period + The diagnostic message should not contain any line return character nor any leading or trailing whitespaces and should either be a single sentence without a trailing period or a multi-sentences with a trailing period El mensaje de diagnóstico no debe contener ningún carácter de retorno de línea y debe ser una sola oración sin punto final o varias oraciones con punto final. @@ -88,8 +88,8 @@ - The diagnostic title should not contain a period or any line return character - El título del diagnóstico no debe contener un punto ni un carácter de retorno de línea. + The diagnostic title should not contain a period, nor any line return character, nor any leading or trailing whitespaces + El título del diagnóstico no debe contener un punto ni un carácter de retorno de línea. diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.fr.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.fr.xlf index 03997c3a25..2fe383a1d9 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.fr.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.fr.xlf @@ -68,7 +68,7 @@ - The diagnostic description should be one or multiple sentences ending with a punctuation sign + The diagnostic description should be one or multiple sentences ending with a punctuation sign and should not have any leading or trailing whitespaces La description de diagnostic doit être une ou plusieurs phrases se terminant par un signe de ponctuation. @@ -78,7 +78,7 @@ - The diagnostic message should not contain any line return character and should either be a single sentence without a trailing period or a multi-sentences with a trailing period + The diagnostic message should not contain any line return character nor any leading or trailing whitespaces and should either be a single sentence without a trailing period or a multi-sentences with a trailing period Le message de diagnostic ne doit avoir aucun caractère de retour de ligne, et doit tenir en une seule phrase sans point final ou en plusieurs phrases avec un point final. @@ -88,8 +88,8 @@ - The diagnostic title should not contain a period or any line return character - Le titre de diagnostic ne doit pas avoir de point ou de caractère de retour de ligne + The diagnostic title should not contain a period, nor any line return character, nor any leading or trailing whitespaces + Le titre de diagnostic ne doit pas avoir de point ou de caractère de retour de ligne diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.it.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.it.xlf index 0efca4acbc..e1350dcffe 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.it.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.it.xlf @@ -68,7 +68,7 @@ - The diagnostic description should be one or multiple sentences ending with a punctuation sign + The diagnostic description should be one or multiple sentences ending with a punctuation sign and should not have any leading or trailing whitespaces La descrizione della diagnostica deve essere costituita da una o più frasi che terminano con un segno di punteggiatura. @@ -78,7 +78,7 @@ - The diagnostic message should not contain any line return character and should either be a single sentence without a trailing period or a multi-sentences with a trailing period + The diagnostic message should not contain any line return character nor any leading or trailing whitespaces and should either be a single sentence without a trailing period or a multi-sentences with a trailing period Il messaggio della diagnostica non deve contenere caratteri di ritorno a capo e deve essere costituito da una singola frase senza punto finale oppure da più frasi con un punto finale. @@ -88,8 +88,8 @@ - The diagnostic title should not contain a period or any line return character - Il titolo della diagnostica non deve contenere un punto o un carattere di ritorno a capo + The diagnostic title should not contain a period, nor any line return character, nor any leading or trailing whitespaces + Il titolo della diagnostica non deve contenere un punto o un carattere di ritorno a capo diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ja.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ja.xlf index c07e2881da..33b59f8589 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ja.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ja.xlf @@ -68,7 +68,7 @@ - The diagnostic description should be one or multiple sentences ending with a punctuation sign + The diagnostic description should be one or multiple sentences ending with a punctuation sign and should not have any leading or trailing whitespaces 診断の説明は、句読点で終わる 1 つまたは複数の文にする必要があります。 @@ -78,7 +78,7 @@ - The diagnostic message should not contain any line return character and should either be a single sentence without a trailing period or a multi-sentences with a trailing period + The diagnostic message should not contain any line return character nor any leading or trailing whitespaces and should either be a single sentence without a trailing period or a multi-sentences with a trailing period 診断メッセージには改行文字を含めないでください。また、末尾にピリオドが付いていない 1 つの文か、末尾にピリオドが付いた複数の文にする必要があります。 @@ -88,8 +88,8 @@ - The diagnostic title should not contain a period or any line return character - 診断タイトルには、ピリオドも改行文字も含めないでください + The diagnostic title should not contain a period, nor any line return character, nor any leading or trailing whitespaces + 診断タイトルには、ピリオドも改行文字も含めないでください diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ko.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ko.xlf index a50d47d6fb..6bdbe00dc1 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ko.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ko.xlf @@ -68,7 +68,7 @@ - The diagnostic description should be one or multiple sentences ending with a punctuation sign + The diagnostic description should be one or multiple sentences ending with a punctuation sign and should not have any leading or trailing whitespaces 진단 설명에는 문장 부호로 끝나는 하나 이상의 문장이 있어야 합니다. @@ -78,7 +78,7 @@ - The diagnostic message should not contain any line return character and should either be a single sentence without a trailing period or a multi-sentences with a trailing period + The diagnostic message should not contain any line return character nor any leading or trailing whitespaces and should either be a single sentence without a trailing period or a multi-sentences with a trailing period 진단 메시지에 줄 바꿈 문자를 포함할 수 없으며, 마침표가 없는 단일 문장이거나 마침표가 있는 여러 문장이어야 합니다. @@ -88,8 +88,8 @@ - The diagnostic title should not contain a period or any line return character - 진단 제목에는 마침표 또는 줄 바꿈 문자를 포함할 수 없습니다. + The diagnostic title should not contain a period, nor any line return character, nor any leading or trailing whitespaces + 진단 제목에는 마침표 또는 줄 바꿈 문자를 포함할 수 없습니다. diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pl.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pl.xlf index 67683dca00..3c0d2136f7 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pl.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pl.xlf @@ -68,7 +68,7 @@ - The diagnostic description should be one or multiple sentences ending with a punctuation sign + The diagnostic description should be one or multiple sentences ending with a punctuation sign and should not have any leading or trailing whitespaces Opis diagnostyki powinien składać się z jednego lub wielu zdań zakończonych znakiem interpunkcyjnym. @@ -78,7 +78,7 @@ - The diagnostic message should not contain any line return character and should either be a single sentence without a trailing period or a multi-sentences with a trailing period + The diagnostic message should not contain any line return character nor any leading or trailing whitespaces and should either be a single sentence without a trailing period or a multi-sentences with a trailing period Komunikat dotyczący diagnostyki nie powinien zawierać znaku nowego wiersza i powinien być pojedynczym zdaniem bez kropki na końcu lub wieloma zdaniami z kropkami na końcu. @@ -88,8 +88,8 @@ - The diagnostic title should not contain a period or any line return character - Tytuł diagnostyki nie powinien zawierać kropki ani żadnych znaków nowego wiersza + The diagnostic title should not contain a period, nor any line return character, nor any leading or trailing whitespaces + Tytuł diagnostyki nie powinien zawierać kropki ani żadnych znaków nowego wiersza diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pt-BR.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pt-BR.xlf index 81b7164767..25a00154b5 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pt-BR.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pt-BR.xlf @@ -68,7 +68,7 @@ - The diagnostic description should be one or multiple sentences ending with a punctuation sign + The diagnostic description should be one or multiple sentences ending with a punctuation sign and should not have any leading or trailing whitespaces A descrição do diagnóstico deve conter uma ou várias frases terminando com um sinal de pontuação. @@ -78,7 +78,7 @@ - The diagnostic message should not contain any line return character and should either be a single sentence without a trailing period or a multi-sentences with a trailing period + The diagnostic message should not contain any line return character nor any leading or trailing whitespaces and should either be a single sentence without a trailing period or a multi-sentences with a trailing period A mensagem de diagnóstico não deve conter nenhum caractere de retorno de linha e deve ser uma única frase sem um ponto à direita ou ser várias frases com um ponto à direita. @@ -88,8 +88,8 @@ - The diagnostic title should not contain a period or any line return character - O título do diagnóstico não deve conter um ponto nem nenhum caractere de retorno de linha + The diagnostic title should not contain a period, nor any line return character, nor any leading or trailing whitespaces + O título do diagnóstico não deve conter um ponto nem nenhum caractere de retorno de linha diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ru.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ru.xlf index 8e0ed094f0..28e270eb81 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ru.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ru.xlf @@ -68,7 +68,7 @@ - The diagnostic description should be one or multiple sentences ending with a punctuation sign + The diagnostic description should be one or multiple sentences ending with a punctuation sign and should not have any leading or trailing whitespaces Описание диагностики должно включать одно или несколько предложений, заканчивающихся знаком препинания. @@ -78,7 +78,7 @@ - The diagnostic message should not contain any line return character and should either be a single sentence without a trailing period or a multi-sentences with a trailing period + The diagnostic message should not contain any line return character nor any leading or trailing whitespaces and should either be a single sentence without a trailing period or a multi-sentences with a trailing period Сообщение диагностики не должно содержать символов возврата строки и должно представлять собой одно предложение без конечной точки или несколько предложений с конечной точкой. @@ -88,8 +88,8 @@ - The diagnostic title should not contain a period or any line return character - Название диагностики не может содержать точку и символы возврата строк. + The diagnostic title should not contain a period, nor any line return character, nor any leading or trailing whitespaces + Название диагностики не может содержать точку и символы возврата строк. diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.tr.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.tr.xlf index d210c9abe7..28bea08971 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.tr.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.tr.xlf @@ -68,7 +68,7 @@ - The diagnostic description should be one or multiple sentences ending with a punctuation sign + The diagnostic description should be one or multiple sentences ending with a punctuation sign and should not have any leading or trailing whitespaces Tanılama açıklaması, noktalama işaretiyle biten bir veya daha fazla cümleden oluşmalıdır. @@ -78,7 +78,7 @@ - The diagnostic message should not contain any line return character and should either be a single sentence without a trailing period or a multi-sentences with a trailing period + The diagnostic message should not contain any line return character nor any leading or trailing whitespaces and should either be a single sentence without a trailing period or a multi-sentences with a trailing period Tanılama iletisi, satır dönüş karakteri içermemelidir ve sonunda nokta olmayan tek bir cümle veya sonunda nokta olan birden çok cümleden oluşmalıdır. @@ -88,8 +88,8 @@ - The diagnostic title should not contain a period or any line return character - Tanılama başlığı, bir nokta veya satır dönüş karakteri içermemelidir + The diagnostic title should not contain a period, nor any line return character, nor any leading or trailing whitespaces + Tanılama başlığı, bir nokta veya satır dönüş karakteri içermemelidir diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hans.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hans.xlf index a0f58118b6..1a52a85dc9 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hans.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hans.xlf @@ -68,7 +68,7 @@ - The diagnostic description should be one or multiple sentences ending with a punctuation sign + The diagnostic description should be one or multiple sentences ending with a punctuation sign and should not have any leading or trailing whitespaces 诊断说明应为以一个标点符号结尾的一个或多个句子。 @@ -78,7 +78,7 @@ - The diagnostic message should not contain any line return character and should either be a single sentence without a trailing period or a multi-sentences with a trailing period + The diagnostic message should not contain any line return character nor any leading or trailing whitespaces and should either be a single sentence without a trailing period or a multi-sentences with a trailing period 诊断消息不应包含任何行回车符,应为不带尾随句点的单个句子或带有一个尾随句点的多个句子。 @@ -88,8 +88,8 @@ - The diagnostic title should not contain a period or any line return character - 诊断标题不应包含句点或任何行回车字符 + The diagnostic title should not contain a period, nor any line return character, nor any leading or trailing whitespaces + 诊断标题不应包含句点或任何行回车字符 diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hant.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hant.xlf index a7ccc7ffb2..775d7f32e6 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hant.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hant.xlf @@ -68,7 +68,7 @@ - The diagnostic description should be one or multiple sentences ending with a punctuation sign + The diagnostic description should be one or multiple sentences ending with a punctuation sign and should not have any leading or trailing whitespaces 診斷描述應為一或多個以標點符號結尾的句子。 @@ -78,7 +78,7 @@ - The diagnostic message should not contain any line return character and should either be a single sentence without a trailing period or a multi-sentences with a trailing period + The diagnostic message should not contain any line return character nor any leading or trailing whitespaces and should either be a single sentence without a trailing period or a multi-sentences with a trailing period 診斷訊息不應包含任何換行字元,而且應為沒有結尾句號的單一句子,或有結尾句號的多個句子。 @@ -88,8 +88,8 @@ - The diagnostic title should not contain a period or any line return character - 診斷標題不應包含句點或任何換行字元 + The diagnostic title should not contain a period, nor any line return character, nor any leading or trailing whitespaces + 診斷標題不應包含句點或任何換行字元 diff --git a/src/Microsoft.CodeAnalysis.Analyzers/UnitTests/MetaAnalyzers/DiagnosticDescriptorCreationAnalyzerTests.cs b/src/Microsoft.CodeAnalysis.Analyzers/UnitTests/MetaAnalyzers/DiagnosticDescriptorCreationAnalyzerTests.cs index 92a8b16462..9b4c8c9b69 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/UnitTests/MetaAnalyzers/DiagnosticDescriptorCreationAnalyzerTests.cs +++ b/src/Microsoft.CodeAnalysis.Analyzers/UnitTests/MetaAnalyzers/DiagnosticDescriptorCreationAnalyzerTests.cs @@ -2838,6 +2838,175 @@ End Class GetRS1007ExpectedDiagnostic(2)); } + [Fact, WorkItem(3958, "https://github.com/dotnet/roslyn-analyzers/issues/3958")] + public async Task RS1031_LeadingOrTailingWhitespace_Diagnostic() + { + var additionalFileName = "Resources.resx"; + var additionalFileText = @" + + + Title with trailing space + + + Title with leading space + + + " + "\t" + @" Title with leading and trailing spaces/tabs " + "\t" + @" + +"; + var fixedAdditionalFileText = @" + + + Title with trailing space + + + Title with leading space + + + Title with leading and trailing spaces/tabs + +"; + + await VerifyCSharpCodeFixAsync(@" +using System; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +class Resources { } + +[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] +class MyAnalyzer : DiagnosticAnalyzer +{ + private static readonly DiagnosticDescriptor descriptor1 = + new DiagnosticDescriptor(""MyDiagnosticId"", {|#0:new LocalizableResourceString(""AnalyzerTitle1"", null, typeof(Resources))|}, ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: """"); + + private static readonly DiagnosticDescriptor descriptor2 = + new DiagnosticDescriptor(""MyDiagnosticId"", {|#1:new LocalizableResourceString(""AnalyzerTitle2"", null, typeof(Resources))|}, ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: """"); + + private static readonly LocalizableResourceString Title = new LocalizableResourceString(""AnalyzerTitle3"", null, typeof(Resources)); + private static readonly DiagnosticDescriptor descriptor3 = + new DiagnosticDescriptor(""MyDiagnosticId"", {|#2:Title|}, ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: """"); + + public override ImmutableArray SupportedDiagnostics + { + get + { + return ImmutableArray.Create(descriptor1, descriptor2, descriptor3); + } + } + + public override void Initialize(AnalysisContext context) + { + } +}", + additionalFileName: additionalFileName, + additionalFileText: additionalFileText, + fixedAdditionalFileText: fixedAdditionalFileText, + fixedSource: @" +using System; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +class Resources { } + +[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] +class MyAnalyzer : DiagnosticAnalyzer +{ + private static readonly DiagnosticDescriptor descriptor1 = + new DiagnosticDescriptor(""MyDiagnosticId"", new LocalizableResourceString(""AnalyzerTitle1"", null, typeof(Resources)), ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: """"); + + private static readonly DiagnosticDescriptor descriptor2 = + new DiagnosticDescriptor(""MyDiagnosticId"", new LocalizableResourceString(""AnalyzerTitle2"", null, typeof(Resources)), ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: """"); + + private static readonly LocalizableResourceString Title = new LocalizableResourceString(""AnalyzerTitle3"", null, typeof(Resources)); + private static readonly DiagnosticDescriptor descriptor3 = + new DiagnosticDescriptor(""MyDiagnosticId"", Title, ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: """"); + + public override ImmutableArray SupportedDiagnostics + { + get + { + return ImmutableArray.Create(descriptor1, descriptor2, descriptor3); + } + } + + public override void Initialize(AnalysisContext context) + { + } +}", + expected: new[] { + VerifyCS.Diagnostic(DiagnosticDescriptorCreationAnalyzer.DefineDiagnosticTitleCorrectlyRule).WithLocation(0), + VerifyCS.Diagnostic(DiagnosticDescriptorCreationAnalyzer.DefineDiagnosticTitleCorrectlyRule).WithLocation(1), + VerifyCS.Diagnostic(DiagnosticDescriptorCreationAnalyzer.DefineDiagnosticTitleCorrectlyRule).WithLocation(2), + }); + + await VerifyBasicCodeFixAsync(@" +Imports System +Imports System.Collections.Immutable +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Diagnostics + +Class Resources +End Class + + +Class MyAnalyzer + Inherits DiagnosticAnalyzer + + Private Shared ReadOnly descriptor1 As DiagnosticDescriptor = new DiagnosticDescriptor(""MyDiagnosticId"", {|#0:New LocalizableResourceString(""AnalyzerTitle1"", Nothing, GetType(Resources))|}, ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, ""Description."", ""HelpLinkUrl"", ""Tag"") + Private Shared ReadOnly descriptor2 As DiagnosticDescriptor = new DiagnosticDescriptor(""MyDiagnosticId"", {|#1:New LocalizableResourceString(""AnalyzerTitle2"", Nothing, GetType(Resources))|}, ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, ""Description."", ""HelpLinkUrl"", ""Tag"") + Private Shared ReadOnly Title As New LocalizableResourceString(""AnalyzerTitle3"", Nothing, GetType(Resources)) + Private Shared ReadOnly descriptor3 As DiagnosticDescriptor = new DiagnosticDescriptor(""MyDiagnosticId"", {|#2:Title|}, ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, ""Description."", ""HelpLinkUrl"", ""Tag"") + + Public Overrides ReadOnly Property SupportedDiagnostics() As ImmutableArray(Of DiagnosticDescriptor) + Get + Return ImmutableArray.Create(descriptor1, descriptor2, descriptor3) + End Get + End Property + + Public Overrides Sub Initialize(context As AnalysisContext) + End Sub +End Class +", + additionalFileName: additionalFileName, + additionalFileText: additionalFileText, + fixedAdditionalFileText: fixedAdditionalFileText, + fixedSource: @" +Imports System +Imports System.Collections.Immutable +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Diagnostics + +Class Resources +End Class + + +Class MyAnalyzer + Inherits DiagnosticAnalyzer + + Private Shared ReadOnly descriptor1 As DiagnosticDescriptor = new DiagnosticDescriptor(""MyDiagnosticId"", New LocalizableResourceString(""AnalyzerTitle1"", Nothing, GetType(Resources)), ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, ""Description."", ""HelpLinkUrl"", ""Tag"") + Private Shared ReadOnly descriptor2 As DiagnosticDescriptor = new DiagnosticDescriptor(""MyDiagnosticId"", New LocalizableResourceString(""AnalyzerTitle2"", Nothing, GetType(Resources)), ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, ""Description."", ""HelpLinkUrl"", ""Tag"") + Private Shared ReadOnly Title As New LocalizableResourceString(""AnalyzerTitle3"", Nothing, GetType(Resources)) + Private Shared ReadOnly descriptor3 As DiagnosticDescriptor = new DiagnosticDescriptor(""MyDiagnosticId"", Title, ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, ""Description."", ""HelpLinkUrl"", ""Tag"") + + Public Overrides ReadOnly Property SupportedDiagnostics() As ImmutableArray(Of DiagnosticDescriptor) + Get + Return ImmutableArray.Create(descriptor1, descriptor2, descriptor3) + End Get + End Property + + Public Overrides Sub Initialize(context As AnalysisContext) + End Sub +End Class +", expected: new[] { + VerifyVB.Diagnostic(DiagnosticDescriptorCreationAnalyzer.DefineDiagnosticTitleCorrectlyRule).WithLocation(0), + VerifyVB.Diagnostic(DiagnosticDescriptorCreationAnalyzer.DefineDiagnosticTitleCorrectlyRule).WithLocation(1), + VerifyVB.Diagnostic(DiagnosticDescriptorCreationAnalyzer.DefineDiagnosticTitleCorrectlyRule).WithLocation(2), + }); + } + #endregion // RS1031 (DefineDiagnosticTitleCorrectlyRule) #region RS1032 (DefineDiagnosticMessageCorrectlyRule) @@ -3553,6 +3722,177 @@ End Class GetRS1007ExpectedDiagnostic(3)); } + [Fact, WorkItem(3958, "https://github.com/dotnet/roslyn-analyzers/issues/3958")] + public async Task RS1032_LeadingOrTrailingWhitespaces_Diagnostic() + { + var additionalFileName = "Resources.resx"; + var additionalFileText = @" + + + Message with trailing whitespace + + + Message with leading whitespace + Optional comment. + + + " + "\t" + @" Message with leading and trailing spaces/tabs " + "\t" + @" + +"; + var fixedAdditionalFileText = @" + + + Message with trailing whitespace + + + Message with leading whitespace + Optional comment. + + + Message with leading and trailing whitespace + +"; + + await VerifyCSharpCodeFixAsync(@" +using System; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +class Resources { } + +[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] +class MyAnalyzer : DiagnosticAnalyzer +{ + private static readonly DiagnosticDescriptor descriptor1 = + new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", {|#0:new LocalizableResourceString(""AnalyzerMessage1"", null, typeof(Resources))|}, ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: """"); + + private static readonly LocalizableString Message = new LocalizableResourceString(""AnalyzerMessage2"", null, typeof(Resources)); + private static readonly DiagnosticDescriptor descriptor2 = + new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", {|#1:Message|}, ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: """"); + + private static readonly DiagnosticDescriptor descriptor3 = + new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", {|#2:new LocalizableResourceString(""AnalyzerMessage3"", null, typeof(Resources))|}, ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: """"); + + public override ImmutableArray SupportedDiagnostics + { + get + { + return ImmutableArray.Create(descriptor1, descriptor2, descriptor3); + } + } + + public override void Initialize(AnalysisContext context) + { + } +}", + additionalFileName: additionalFileName, + additionalFileText: additionalFileText, + fixedAdditionalFileText: fixedAdditionalFileText, + fixedSource: @" +using System; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +class Resources { } + +[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] +class MyAnalyzer : DiagnosticAnalyzer +{ + private static readonly DiagnosticDescriptor descriptor1 = + new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", new LocalizableResourceString(""AnalyzerMessage1"", null, typeof(Resources)), ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: """"); + + private static readonly LocalizableString Message = new LocalizableResourceString(""AnalyzerMessage2"", null, typeof(Resources)); + private static readonly DiagnosticDescriptor descriptor2 = + new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", Message, ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: """"); + + private static readonly DiagnosticDescriptor descriptor3 = + new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", new LocalizableResourceString(""AnalyzerMessage3"", null, typeof(Resources)), ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: """"); + + public override ImmutableArray SupportedDiagnostics + { + get + { + return ImmutableArray.Create(descriptor1, descriptor2, descriptor3); + } + } + + public override void Initialize(AnalysisContext context) + { + } +}", + expected: new[] { + VerifyCS.Diagnostic(DiagnosticDescriptorCreationAnalyzer.DefineDiagnosticMessageCorrectlyRule).WithLocation(0), + VerifyCS.Diagnostic(DiagnosticDescriptorCreationAnalyzer.DefineDiagnosticMessageCorrectlyRule).WithLocation(1), + VerifyCS.Diagnostic(DiagnosticDescriptorCreationAnalyzer.DefineDiagnosticMessageCorrectlyRule).WithLocation(2), + }); + + await VerifyBasicCodeFixAsync(@" +Imports System +Imports System.Collections.Immutable +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Diagnostics + +Class Resources +End Class + + +Class MyAnalyzer + Inherits DiagnosticAnalyzer + + Private Shared ReadOnly descriptor1 As DiagnosticDescriptor = new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", {|#0:New LocalizableResourceString(""AnalyzerMessage1"", Nothing, GetType(Resources))|}, ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, ""Description."", ""HelpLinkUrl"", ""Tag"") + Private Shared ReadOnly Message As LocalizableString = New LocalizableResourceString(""AnalyzerMessage2"", Nothing, GetType(Resources)) + Private Shared ReadOnly descriptor2 As DiagnosticDescriptor = new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", {|#1:Message|}, ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, ""Description."", ""HelpLinkUrl"", ""Tag"") + Private Shared ReadOnly descriptor3 As DiagnosticDescriptor = new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", {|#2:New LocalizableResourceString(""AnalyzerMessage3"", Nothing, GetType(Resources))|}, ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, ""Description."", ""HelpLinkUrl"", ""Tag"") + + Public Overrides ReadOnly Property SupportedDiagnostics() As ImmutableArray(Of DiagnosticDescriptor) + Get + Return ImmutableArray.Create(descriptor1, descriptor2, descriptor3) + End Get + End Property + + Public Overrides Sub Initialize(context As AnalysisContext) + End Sub +End Class +", + additionalFileName: additionalFileName, + additionalFileText: additionalFileText, + fixedAdditionalFileText: fixedAdditionalFileText, + fixedSource: @" +Imports System +Imports System.Collections.Immutable +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Diagnostics + +Class Resources +End Class + + +Class MyAnalyzer + Inherits DiagnosticAnalyzer + + Private Shared ReadOnly descriptor1 As DiagnosticDescriptor = new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", New LocalizableResourceString(""AnalyzerMessage1"", Nothing, GetType(Resources)), ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, ""Description."", ""HelpLinkUrl"", ""Tag"") + Private Shared ReadOnly Message As LocalizableString = New LocalizableResourceString(""AnalyzerMessage2"", Nothing, GetType(Resources)) + Private Shared ReadOnly descriptor2 As DiagnosticDescriptor = new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", Message, ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, ""Description."", ""HelpLinkUrl"", ""Tag"") + Private Shared ReadOnly descriptor3 As DiagnosticDescriptor = new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", New LocalizableResourceString(""AnalyzerMessage3"", Nothing, GetType(Resources)), ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, ""Description."", ""HelpLinkUrl"", ""Tag"") + + Public Overrides ReadOnly Property SupportedDiagnostics() As ImmutableArray(Of DiagnosticDescriptor) + Get + Return ImmutableArray.Create(descriptor1, descriptor2, descriptor3) + End Get + End Property + + Public Overrides Sub Initialize(context As AnalysisContext) + End Sub +End Class +", expected: new[] { + VerifyVB.Diagnostic(DiagnosticDescriptorCreationAnalyzer.DefineDiagnosticMessageCorrectlyRule).WithLocation(0), + VerifyVB.Diagnostic(DiagnosticDescriptorCreationAnalyzer.DefineDiagnosticMessageCorrectlyRule).WithLocation(1), + VerifyVB.Diagnostic(DiagnosticDescriptorCreationAnalyzer.DefineDiagnosticMessageCorrectlyRule).WithLocation(2), + }); + } + #endregion // RS1032 (DefineDiagnosticMessageCorrectlyRule) #region RS1033 (DefineDiagnosticDescriptionCorrectlyRule) @@ -3901,6 +4241,177 @@ End Class GetRS1007ExpectedDiagnostic(2)); } + [Fact, WorkItem(3958, "https://github.com/dotnet/roslyn-analyzers/issues/3958")] + public async Task RS1033_LeadingOrTrailingWhitespaces_Diagnostic() + { + var additionalFileName = "Resources.resx"; + var additionalFileText = @" + + + Description with leading whitespace + + + Description with trailing whitespace + Optional comment. + + + " + "\t" + @" Description with leading and trailing spaces/tabs " + "\t" + @" + +"; + var fixedAdditionalFileText = @" + + + Description with leading whitespace + + + Description with trailing whitespace + Optional comment. + + + Description with leading and trailing spaces/tabs + +"; + + await VerifyCSharpCodeFixAsync(@" +using System; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +class Resources { } + +[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] +class MyAnalyzer : DiagnosticAnalyzer +{ + private static readonly DiagnosticDescriptor descriptor1 = + new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, {|#0:description: new LocalizableResourceString(""AnalyzerDescription1"", null, typeof(Resources))|}, helpLinkUri: ""HelpLink"", customTags: """"); + + private static readonly LocalizableResourceString Description = new LocalizableResourceString(""AnalyzerDescription2"", null, typeof(Resources)); + private static readonly DiagnosticDescriptor descriptor2 = + new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, {|#1:description: Description|}, helpLinkUri: ""HelpLink"", customTags: """"); + + private static readonly DiagnosticDescriptor descriptor3 = + new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, {|#2:description: new LocalizableResourceString(""AnalyzerDescription3"", null, typeof(Resources))|}, helpLinkUri: ""HelpLink"", customTags: """"); + + public override ImmutableArray SupportedDiagnostics + { + get + { + return ImmutableArray.Create(descriptor1, descriptor2, descriptor3); + } + } + + public override void Initialize(AnalysisContext context) + { + } +}", + additionalFileName: additionalFileName, + additionalFileText: additionalFileText, + fixedAdditionalFileText: fixedAdditionalFileText, + fixedSource: @" +using System; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +class Resources { } + +[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] +class MyAnalyzer : DiagnosticAnalyzer +{ + private static readonly DiagnosticDescriptor descriptor1 = + new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, description: new LocalizableResourceString(""AnalyzerDescription1"", null, typeof(Resources)), helpLinkUri: ""HelpLink"", customTags: """"); + + private static readonly LocalizableResourceString Description = new LocalizableResourceString(""AnalyzerDescription2"", null, typeof(Resources)); + private static readonly DiagnosticDescriptor descriptor2 = + new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description, helpLinkUri: ""HelpLink"", customTags: """"); + + private static readonly DiagnosticDescriptor descriptor3 = + new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, description: new LocalizableResourceString(""AnalyzerDescription3"", null, typeof(Resources)), helpLinkUri: ""HelpLink"", customTags: """"); + + public override ImmutableArray SupportedDiagnostics + { + get + { + return ImmutableArray.Create(descriptor1, descriptor2, descriptor3); + } + } + + public override void Initialize(AnalysisContext context) + { + } +}", + expected: new[] { + VerifyCS.Diagnostic(DiagnosticDescriptorCreationAnalyzer.DefineDiagnosticDescriptionCorrectlyRule).WithLocation(0), + VerifyCS.Diagnostic(DiagnosticDescriptorCreationAnalyzer.DefineDiagnosticDescriptionCorrectlyRule).WithLocation(1), + VerifyCS.Diagnostic(DiagnosticDescriptorCreationAnalyzer.DefineDiagnosticDescriptionCorrectlyRule).WithLocation(2), + }); + + await VerifyBasicCodeFixAsync(@" +Imports System +Imports System.Collections.Immutable +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Diagnostics + +Class Resources +End Class + + +Class MyAnalyzer + Inherits DiagnosticAnalyzer + + Private Shared ReadOnly descriptor1 As DiagnosticDescriptor = new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, {|#0:New LocalizableResourceString(""AnalyzerDescription1"", Nothing, GetType(Resources))|}, ""HelpLinkUrl"", ""Tag"") + Private Shared ReadOnly Description As LocalizableString = New LocalizableResourceString(""AnalyzerDescription2"", Nothing, GetType(Resources)) + Private Shared ReadOnly descriptor2 As DiagnosticDescriptor = new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, {|#1:Description|}, ""HelpLinkUrl"", ""Tag"") + Private Shared ReadOnly descriptor3 As DiagnosticDescriptor = new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, {|#2:New LocalizableResourceString(""AnalyzerDescription3"", Nothing, GetType(Resources))|}, ""HelpLinkUrl"", ""Tag"") + + Public Overrides ReadOnly Property SupportedDiagnostics() As ImmutableArray(Of DiagnosticDescriptor) + Get + Return ImmutableArray.Create(descriptor1, descriptor2, descriptor3) + End Get + End Property + + Public Overrides Sub Initialize(context As AnalysisContext) + End Sub +End Class +", + additionalFileName: additionalFileName, + additionalFileText: additionalFileText, + fixedAdditionalFileText: fixedAdditionalFileText, + fixedSource: @" +Imports System +Imports System.Collections.Immutable +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Diagnostics + +Class Resources +End Class + + +Class MyAnalyzer + Inherits DiagnosticAnalyzer + + Private Shared ReadOnly descriptor1 As DiagnosticDescriptor = new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, New LocalizableResourceString(""AnalyzerDescription1"", Nothing, GetType(Resources)), ""HelpLinkUrl"", ""Tag"") + Private Shared ReadOnly Description As LocalizableString = New LocalizableResourceString(""AnalyzerDescription2"", Nothing, GetType(Resources)) + Private Shared ReadOnly descriptor2 As DiagnosticDescriptor = new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, Description, ""HelpLinkUrl"", ""Tag"") + Private Shared ReadOnly descriptor3 As DiagnosticDescriptor = new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, New LocalizableResourceString(""AnalyzerDescription3"", Nothing, GetType(Resources)), ""HelpLinkUrl"", ""Tag"") + + Public Overrides ReadOnly Property SupportedDiagnostics() As ImmutableArray(Of DiagnosticDescriptor) + Get + Return ImmutableArray.Create(descriptor1, descriptor2, descriptor3) + End Get + End Property + + Public Overrides Sub Initialize(context As AnalysisContext) + End Sub +End Class +", expected: new[] { + VerifyVB.Diagnostic(DiagnosticDescriptorCreationAnalyzer.DefineDiagnosticDescriptionCorrectlyRule).WithLocation(0), + VerifyVB.Diagnostic(DiagnosticDescriptorCreationAnalyzer.DefineDiagnosticDescriptionCorrectlyRule).WithLocation(1), + VerifyVB.Diagnostic(DiagnosticDescriptorCreationAnalyzer.DefineDiagnosticDescriptionCorrectlyRule).WithLocation(2), + }); + } + #endregion // RS1033 (DefineDiagnosticDescriptionCorrectlyRule) #region Helpers