提交 dc04d6b2 编写于 作者: S Shyam N 提交者: GitHub

Merge pull request #20419 from dotnet/merges/master-to-dev15.6-20170623-070014

Merge master to dev15.6
......@@ -12,28 +12,29 @@ Syntax Grammar
This grammar is represented as a diff from the current spec grammar.
```diff
declaration-statement
: local-variable-declaration ';'
| local-constant-declaration ';'
+ | local-function-declaration
declaration_statement
: local_variable_declaration ';'
| local_constant_declaration ';'
+ | local_function_declaration
;
+local-function-declaration
+ : local-function-header local-function-body
+local_function_declaration
+ : local_function_header local_function_body
+ ;
+local-function-header
+ : local-function-modifiers? return-type identifier type-parameter-list?
+ ( formal-parameter-list? ) type-parameter-constraints-clauses
+local_function_header
+ : local_function_modifier* return_type identifier type_parameter_list?
+ '(' formal_parameter_list? ')' type_parameter_constraints_clauses
+ ;
+local-function-modifiers
+ : (async | unsafe)
+local_function_modifier
+ : 'async'
+ | 'unsafe'
+ ;
+local-function-body
+local_function_body
+ : block
+ | arrow-expression-body
+ | arrow_expression_body
+ ;
```
......
......@@ -916,6 +916,31 @@ public void TestReportingDiagnosticWithInvalidLocation()
}
}
[Fact]
public void TestReportingDiagnosticWithInvalidSpan()
{
var source1 = @"class C1 { void M() { int i = 0; i++; } }";
var compilation = CreateCompilationWithMscorlib45(source1, parseOptions: TestOptions.RegularWithIOperationFeature);
var treeInAnotherCompilation = compilation.SyntaxTrees.Single();
var badSpan = new Text.TextSpan(100000, 10000);
string message = new ArgumentException(
string.Format(CodeAnalysisResources.InvalidDiagnosticSpanReported, AnalyzerWithInvalidDiagnosticSpan.Descriptor.Id, badSpan, treeInAnotherCompilation.FilePath), "diagnostic").Message;
compilation.VerifyDiagnostics();
var analyzer = new AnalyzerWithInvalidDiagnosticSpan(badSpan);
var analyzers = new DiagnosticAnalyzer[] { analyzer };
compilation
.VerifyAnalyzerDiagnostics(analyzers, null, null, logAnalyzerExceptionAsDiagnostics: true,
expected:
Diagnostic("AD0001")
.WithArguments("Microsoft.CodeAnalysis.CommonDiagnosticAnalyzers+AnalyzerWithInvalidDiagnosticSpan", "System.ArgumentException", message)
.WithLocation(1, 1)
);
}
[Fact, WorkItem(13120, "https://github.com/dotnet/roslyn/issues/13120")]
public void TestRegisteringAsyncAnalyzerMethod()
{
......@@ -1903,7 +1928,7 @@ public class RegularClass
var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs");
var compilation = CreateCompilationWithMscorlib45(new[] { tree });
compilation.VerifyDiagnostics();
var analyzers = new DiagnosticAnalyzer[] { new GeneratedCodeAnalyzer(GeneratedCodeAnalysisFlags.None) };
compilation.VerifyAnalyzerDiagnostics(analyzers, null, null, true,
Diagnostic("GeneratedCodeAnalyzerWarning", "}").WithArguments("Source.cs").WithLocation(11, 1),
......
......@@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class CodeAnalysisResources {
......@@ -748,6 +748,15 @@ internal class CodeAnalysisResources {
}
}
/// <summary>
/// Looks up a localized string similar to Reported diagnostic &apos;{0}&apos; has a source location &apos;{1}&apos; in file &apos;{2}&apos;, which is outside of the given file..
/// </summary>
internal static string InvalidDiagnosticSpanReported {
get {
return ResourceManager.GetString("InvalidDiagnosticSpanReported", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Invalid hash..
/// </summary>
......@@ -1334,7 +1343,7 @@ internal class CodeAnalysisResources {
}
/// <summary>
/// Looks up a localized string similar to Windows PDB writer doesn&apos;t support deterministic compilation: &apos;{0}&apos;.
/// Looks up a localized string similar to Windows PDB writer doesn&apos;t support SourceLink feature: &apos;{0}&apos;.
/// </summary>
internal static string SymWriterDoesNotSupportSourceLink {
get {
......@@ -1343,7 +1352,7 @@ internal class CodeAnalysisResources {
}
/// <summary>
/// Looks up a localized string similar to Windows PDB writer is not available -- could not find Microsoft.DiaSymReader.Native.{0}.dll.
/// Looks up a localized string similar to Windows PDB writer doesn&apos;t support deterministic compilation: &apos;{0}&apos;.
/// </summary>
internal static string SymWriterNotDeterministic {
get {
......
......@@ -612,4 +612,7 @@
<data name="Stream_contains_invalid_data" xml:space="preserve">
<value>Stream contains invalid data</value>
</data>
<data name="InvalidDiagnosticSpanReported" xml:space="preserve">
<value>Reported diagnostic '{0}' has a source location '{1}' in file '{2}', which is outside of the given file.</value>
</data>
</root>
\ No newline at end of file
......@@ -73,7 +73,7 @@ internal static void VerifyDiagnosticLocationsInCompilation(Diagnostic diagnosti
}
}
}
internal static void VerifyIOperationFeatureFlag(bool isIOperationFeatureEnabled)
{
if (!isIOperationFeatureEnabled)
......@@ -84,11 +84,22 @@ internal static void VerifyIOperationFeatureFlag(bool isIOperationFeatureEnabled
private static void VerifyDiagnosticLocationInCompilation(string id, Location location, Compilation compilation)
{
if (location.IsInSource && !compilation.ContainsSyntaxTree(location.SourceTree))
if (!location.IsInSource)
{
return;
}
if (!compilation.ContainsSyntaxTree(location.SourceTree))
{
// Disallow diagnostics with source locations outside this compilation.
throw new ArgumentException(string.Format(CodeAnalysisResources.InvalidDiagnosticLocationReported, id, location.SourceTree.FilePath), "diagnostic");
}
if (location.SourceSpan.End > location.SourceTree.Length)
{
// Disallow diagnostics with source locations outside this compilation.
throw new ArgumentException(string.Format(CodeAnalysisResources.InvalidDiagnosticSpanReported, id, location.SourceSpan, location.SourceTree.FilePath), "diagnostic");
}
}
private static void VerifyAction<TContext>(Action<TContext> action)
......
......@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
......@@ -312,5 +313,34 @@ public void AnalyzeNode(SyntaxNodeAnalysisContext context)
}
}
}
[Fact]
public async Task TestDiagnosticSpan()
{
var source = @"// empty code";
var analyzer = new InvalidSpanAnalyzer();
using (var compilerEngineWorkspace = TestWorkspace.CreateCSharp(source))
{
var compilerEngineCompilation = (CSharpCompilation)(await compilerEngineWorkspace.CurrentSolution.Projects.Single().GetCompilationAsync());
var diagnostics = compilerEngineCompilation.GetAnalyzerDiagnostics(new[] { analyzer });
AssertEx.Any(diagnostics, d => d.Id == AnalyzerHelper.AnalyzerExceptionDiagnosticId);
}
}
private class InvalidSpanAnalyzer : DiagnosticAnalyzer
{
public static DiagnosticDescriptor Descriptor = DescriptorFactory.CreateSimpleDescriptor("DummyDiagnostic");
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
=> ImmutableArray.Create(Descriptor);
public override void Initialize(AnalysisContext context)
=> context.RegisterSyntaxTreeAction(Analyze);
private void Analyze(SyntaxTreeAnalysisContext context)
=> context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, TextSpan.FromBounds(1000, 2000))));
}
}
}
......@@ -8,6 +8,7 @@
using Microsoft.CodeAnalysis.Editor.Shared.Preview;
using Microsoft.CodeAnalysis.Editor.Shared.Tagging;
using Microsoft.CodeAnalysis.Editor.Tagging;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
......@@ -63,7 +64,7 @@ protected override ITaggerEventSource CreateEventSource(ITextView textViewOpt, I
// We act as a source of events ourselves. When the diagnostics service tells
// us about new diagnostics, we'll use that to kick of the asynchronous tagging
// work.
var eventSource = TaggerEventSources.Compose(
TaggerEventSources.OnWorkspaceRegistrationChanged(subjectBuffer, TaggerDelay.Medium),
this);
......@@ -83,69 +84,79 @@ protected override Task ProduceTagsAsync(TaggerContext<TTag> context, DocumentSn
private void ProduceTags(TaggerContext<TTag> context, DocumentSnapshotSpan spanToTag)
{
if (!_owner.IsEnabled)
try
{
return;
}
if (!_owner.IsEnabled)
{
return;
}
var document = spanToTag.Document;
if (document == null)
{
return;
}
var document = spanToTag.Document;
if (document == null)
{
return;
}
// See if we've marked any spans as those we want to suppress diagnostics for.
// This can happen for buffers used in the preview workspace where some feature
// is generating code that it doesn't want errors shown for.
var buffer = spanToTag.SnapshotSpan.Snapshot.TextBuffer;
var suppressedDiagnosticsSpans = default(NormalizedSnapshotSpanCollection);
buffer?.Properties.TryGetProperty(PredefinedPreviewTaggerKeys.SuppressDiagnosticsSpansKey, out suppressedDiagnosticsSpans);
// Producing tags is simple. We just grab the diagnostics we were already told about,
// and we convert them to tag spans.
object id;
ImmutableArray<DiagnosticData> diagnostics;
SourceText sourceText;
ITextSnapshot editorSnapshot;
lock (_gate)
{
id = _latestId;
diagnostics = _latestDiagnostics;
sourceText = _latestSourceText;
editorSnapshot = _latestEditorSnapshot;
}
// See if we've marked any spans as those we want to suppress diagnostics for.
// This can happen for buffers used in the preview workspace where some feature
// is generating code that it doesn't want errors shown for.
var buffer = spanToTag.SnapshotSpan.Snapshot.TextBuffer;
var suppressedDiagnosticsSpans = default(NormalizedSnapshotSpanCollection);
buffer?.Properties.TryGetProperty(PredefinedPreviewTaggerKeys.SuppressDiagnosticsSpansKey, out suppressedDiagnosticsSpans);
// Producing tags is simple. We just grab the diagnostics we were already told about,
// and we convert them to tag spans.
object id;
ImmutableArray<DiagnosticData> diagnostics;
SourceText sourceText;
ITextSnapshot editorSnapshot;
lock (_gate)
{
id = _latestId;
diagnostics = _latestDiagnostics;
sourceText = _latestSourceText;
editorSnapshot = _latestEditorSnapshot;
}
if (sourceText == null || editorSnapshot == null)
{
return;
}
if (sourceText == null || editorSnapshot == null)
{
return;
}
var project = document.Project;
var project = document.Project;
var requestedSnapshot = spanToTag.SnapshotSpan.Snapshot;
var requestedSpan = spanToTag.SnapshotSpan;
var isLiveUpdate = id is ISupportLiveUpdate;
var requestedSnapshot = spanToTag.SnapshotSpan.Snapshot;
var requestedSpan = spanToTag.SnapshotSpan;
var isLiveUpdate = id is ISupportLiveUpdate;
foreach (var diagnosticData in diagnostics)
{
if (_owner.IncludeDiagnostic(diagnosticData))
foreach (var diagnosticData in diagnostics)
{
var actualSpan = diagnosticData
.GetExistingOrCalculatedTextSpan(sourceText)
.ToSnapshotSpan(editorSnapshot)
.TranslateTo(requestedSnapshot, SpanTrackingMode.EdgeExclusive);
if (actualSpan.IntersectsWith(requestedSpan) &&
!IsSuppressed(suppressedDiagnosticsSpans, actualSpan))
if (_owner.IncludeDiagnostic(diagnosticData))
{
var tagSpan = _owner.CreateTagSpan(isLiveUpdate, actualSpan, diagnosticData);
if (tagSpan != null)
var actualSpan = diagnosticData
.GetExistingOrCalculatedTextSpan(sourceText)
.ToSnapshotSpan(editorSnapshot)
.TranslateTo(requestedSnapshot, SpanTrackingMode.EdgeExclusive);
if (actualSpan.IntersectsWith(requestedSpan) &&
!IsSuppressed(suppressedDiagnosticsSpans, actualSpan))
{
context.AddTag(tagSpan);
var tagSpan = _owner.CreateTagSpan(isLiveUpdate, actualSpan, diagnosticData);
if (tagSpan != null)
{
context.AddTag(tagSpan);
}
}
}
}
}
catch (ArgumentOutOfRangeException ex) when (FatalError.ReportWithoutCrash(ex))
{
// https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?id=428328&_a=edit&triage=false
// explicitly report NFW to find out what is causing us for out of range.
// stop crashing on such occations
return;
}
}
private bool IsSuppressed(NormalizedSnapshotSpanCollection suppressedSpans, SnapshotSpan span)
......
......@@ -377,7 +377,7 @@ public IEnumerable<DiagnosticData> ConvertToLocalDiagnostics(Document targetDocu
try
{
var diagnostics = await analyzer.AnalyzeProjectAsync(project, cancellationToken).ConfigureAwait(false);
var diagnostics = (await analyzer.AnalyzeProjectAsync(project, cancellationToken).ConfigureAwait(false)).NullToEmpty();
// Apply filtering from compilation options (source suppressions, ruleset, etc.)
if (compilationOpt != null)
......@@ -385,6 +385,13 @@ public IEnumerable<DiagnosticData> ConvertToLocalDiagnostics(Document targetDocu
diagnostics = CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, compilationOpt).ToImmutableArrayOrEmpty();
}
#if DEBUG
// since all ProjectDiagnosticAnalyzers are from internal users, we only do debug check. also this can be expensive at runtime
// since it requires await. if we find any offender through NFW, we should be able to fix those since all those should
// from intern teams.
await VerifyDiagnosticLocationsAsync(diagnostics, project, cancellationToken).ConfigureAwait(false);
#endif
return diagnostics;
}
catch (Exception e) when (!IsCanceled(e, cancellationToken))
......@@ -423,6 +430,13 @@ public IEnumerable<DiagnosticData> ConvertToLocalDiagnostics(Document targetDocu
return CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, compilationOpt);
}
#if DEBUG
// since all DocumentDiagnosticAnalyzers are from internal users, we only do debug check. also this can be expensive at runtime
// since it requires await. if we find any offender through NFW, we should be able to fix those since all those should
// from intern teams.
await VerifyDiagnosticLocationsAsync(diagnostics, document.Project, cancellationToken).ConfigureAwait(false);
#endif
return diagnostics;
}
catch (Exception e) when (!IsCanceled(e, cancellationToken))
......@@ -584,6 +598,86 @@ private IEnumerable<DiagnosticData> ConvertToLocalDiagnosticsWithCompilation(Doc
}
}
private static async Task VerifyDiagnosticLocationsAsync(ImmutableArray<Diagnostic> diagnostics, Project project, CancellationToken cancellationToken)
{
foreach (var diagnostic in diagnostics)
{
await VerifyDiagnosticLocationAsync(diagnostic.Id, diagnostic.Location, project, cancellationToken).ConfigureAwait(false);
if (diagnostic.AdditionalLocations != null)
{
foreach (var location in diagnostic.AdditionalLocations)
{
await VerifyDiagnosticLocationAsync(diagnostic.Id, diagnostic.Location, project, cancellationToken).ConfigureAwait(false);
}
}
}
}
private static async Task VerifyDiagnosticLocationAsync(string id, Location location, Project project, CancellationToken cancellationToken)
{
switch (location.Kind)
{
case LocationKind.None:
case LocationKind.MetadataFile:
case LocationKind.XmlFile:
// ignore these kinds
break;
case LocationKind.SourceFile:
{
if (project.GetDocument(location.SourceTree) == null)
{
// Disallow diagnostics with source locations outside this project.
throw new ArgumentException(string.Format(FeaturesResources.Reported_diagnostic_0_has_a_source_location_in_file_1_which_is_not_part_of_the_compilation_being_analyzed, id, location.SourceTree.FilePath), "diagnostic");
}
if (location.SourceSpan.End > location.SourceTree.Length)
{
// Disallow diagnostics with source locations outside this project.
throw new ArgumentException(string.Format(FeaturesResources.Reported_diagnostic_0_has_a_source_location_1_in_file_2_which_is_outside_of_the_given_file, id, location.SourceSpan, location.SourceTree.FilePath), "diagnostic");
}
}
break;
case LocationKind.ExternalFile:
{
var filePath = location.GetLineSpan().Path;
var document = TryGetDocumentWithFilePath(project, filePath);
if (document == null)
{
// this is not a roslyn file. we don't care about this file.
return;
}
// this can be potentially expensive since it will load text if it is not already loaded.
// but, this text is most likely already loaded since producer of this diagnostic (Document/ProjectDiagnosticAnalyzers)
// should have loaded it to produce the diagnostic at the first place. once loaded, it should stay in memory until
// project cache goes away. when text is already there, await should return right away.
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
if (location.SourceSpan.End > text.Length)
{
// Disallow diagnostics with locations outside this project.
throw new ArgumentException(string.Format(FeaturesResources.Reported_diagnostic_0_has_a_source_location_1_in_file_2_which_is_outside_of_the_given_file, id, location.SourceSpan, filePath), "diagnostic");
}
}
break;
default:
throw ExceptionUtilities.Unreachable;
}
}
private static Document TryGetDocumentWithFilePath(Project project, string path)
{
foreach (var documentId in project.Solution.GetDocumentIdsWithFilePath(path))
{
if (documentId.ProjectId == project.Id)
{
return project.GetDocument(documentId);
}
}
return null;
}
private static void GetLogFunctionIdAndTitle(AnalysisKind kind, out FunctionId functionId, out string title)
{
switch (kind)
......
......@@ -225,7 +225,7 @@ public async Task SaveAsync(Project project, DiagnosticAnalysisResult result)
await SerializeAsync(serializer, project, result.ProjectId, _owner.NonLocalStateName, result.Others).ConfigureAwait(false);
AnalyzerABTestLogger.LogProjectDiagnostics(project, result);
AnalyzerABTestLogger.LogProjectDiagnostics(project, _owner.StateName, result);
}
public void ResetVersion()
......@@ -244,7 +244,7 @@ public async Task MergeAsync(ActiveFileState state, Document document)
var syntax = state.GetAnalysisData(AnalysisKind.Syntax);
var semantic = state.GetAnalysisData(AnalysisKind.Semantic);
AnalyzerABTestLogger.LogDocumentDiagnostics(document, syntax.Items, semantic.Items);
AnalyzerABTestLogger.LogDocumentDiagnostics(document, _owner.StateName, syntax.Items, semantic.Items);
var project = document.Project;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Threading;
......@@ -15,6 +17,8 @@ internal partial class DiagnosticIncrementalAnalyzer
{
public async Task SynchronizeWithBuildAsync(Workspace workspace, ImmutableDictionary<ProjectId, ImmutableArray<DiagnosticData>> map)
{
DebugVerifyDiagnosticLocations(map);
if (!PreferBuildErrors(workspace))
{
// prefer live errors over build errors
......@@ -51,6 +55,18 @@ public async Task SynchronizeWithBuildAsync(Workspace workspace, ImmutableDictio
}
}
[Conditional("DEBUG")]
private void DebugVerifyDiagnosticLocations(ImmutableDictionary<ProjectId, ImmutableArray<DiagnosticData>> map)
{
foreach (var diagnostic in map.Values.SelectMany(v => v))
{
// errors from build shouldn't have any span set.
// this is debug check since it gets data from us only not from third party unlike one in compiler
// that checks span for third party reported diagnostics
Contract.Requires(!diagnostic.HasTextSpan);
}
}
private async Task<ProjectAnalysisData> CreateProjectAnalysisDataAsync(Project project, ImmutableArray<StateSet> stateSets, ImmutableArray<DiagnosticData> diagnostics)
{
// we always load data sicne we don't know right version.
......
......@@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.Experimentation
internal static class AnalyzerABTestLogger
{
private static bool s_reportErrors = false;
private static readonly ConcurrentDictionary<object, object> s_reported = new ConcurrentDictionary<object, object>(concurrencyLevel: 2, capacity: 10);
private static readonly ConcurrentDictionary<(object, string), object> s_reported = new ConcurrentDictionary<(object, string), object>(concurrencyLevel: 2, capacity: 10);
private const string Name = "LiveCodeAnalysisVsix";
......@@ -59,9 +59,9 @@ public static void LogCandidacyRequirementsTracking(long lastTriggeredTimeBinary
}
}
public static void LogProjectDiagnostics(Project project, DiagnosticAnalysisResult result)
public static void LogProjectDiagnostics(Project project, string analyzerName, DiagnosticAnalysisResult result)
{
if (!s_reportErrors || !s_reported.TryAdd(project.Id, null))
if (!s_reportErrors || !s_reported.TryAdd((project.Id, analyzerName), null))
{
// doesn't meet the bar to report the issue.
return;
......@@ -82,9 +82,9 @@ public static void LogProjectDiagnostics(Project project, DiagnosticAnalysisResu
LogErrors(project, "ProjectDignostics", project.Id.Id, map);
}
public static void LogDocumentDiagnostics(Document document, ImmutableArray<DiagnosticData> syntax, ImmutableArray<DiagnosticData> semantic)
public static void LogDocumentDiagnostics(Document document, string analyzerName, ImmutableArray<DiagnosticData> syntax, ImmutableArray<DiagnosticData> semantic)
{
if (!s_reportErrors || !s_reported.TryAdd(document.Id, null))
if (!s_reportErrors || !s_reported.TryAdd((document.Id, analyzerName), null))
{
// doesn't meet the bar to report the issue.
return;
......
......@@ -2583,6 +2583,26 @@ internal class FeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Reported diagnostic &apos;{0}&apos; has a source location &apos;{1}&apos; in file &apos;{2}&apos;, which is outside of the given file..
/// </summary>
internal static string Reported_diagnostic_0_has_a_source_location_1_in_file_2_which_is_outside_of_the_given_file {
get {
return ResourceManager.GetString("Reported_diagnostic_0_has_a_source_location_1_in_file_2_which_is_outside_of_the_g" +
"iven_file", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Reported diagnostic &apos;{0}&apos; has a source location in file &apos;{1}&apos;, which is not part of the compilation being analyzed..
/// </summary>
internal static string Reported_diagnostic_0_has_a_source_location_in_file_1_which_is_not_part_of_the_compilation_being_analyzed {
get {
return ResourceManager.GetString("Reported_diagnostic_0_has_a_source_location_in_file_1_which_is_not_part_of_the_co" +
"mpilation_being_analyzed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Reported diagnostic with ID &apos;{0}&apos; is not supported by the analyzer..
/// </summary>
......
......@@ -1247,6 +1247,12 @@ This version used in: {2}</value>
<data name="default_expression_can_be_simplified" xml:space="preserve">
<value>'default' expression can be simplified</value>
</data>
<data name="Reported_diagnostic_0_has_a_source_location_in_file_1_which_is_not_part_of_the_compilation_being_analyzed" xml:space="preserve">
<value>Reported diagnostic '{0}' has a source location in file '{1}', which is not part of the compilation being analyzed.</value>
</data>
<data name="Reported_diagnostic_0_has_a_source_location_1_in_file_2_which_is_outside_of_the_given_file" xml:space="preserve">
<value>Reported diagnostic '{0}' has a source location '{1}' in file '{2}', which is outside of the given file.</value>
</data>
<data name="Unreachable_code_detected" xml:space="preserve">
<value>Unreachable code detected</value>
</data>
......
......@@ -460,6 +460,25 @@ public override void Initialize(AnalysisContext context)
}
}
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class AnalyzerWithInvalidDiagnosticSpan : DiagnosticAnalyzer
{
private readonly TextSpan _badSpan;
public static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor(
"ID",
"Title1",
"Message",
"Category1",
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);
public AnalyzerWithInvalidDiagnosticSpan(TextSpan badSpan) => _badSpan = badSpan;
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Descriptor);
public override void Initialize(AnalysisContext context)
=> context.RegisterSyntaxTreeAction(c => c.ReportDiagnostic(Diagnostic.Create(Descriptor, SourceLocation.Create(c.Tree, _badSpan))));
}
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class AnalyzerWithInvalidDiagnosticLocation : DiagnosticAnalyzer
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册