提交 ea61a2da 编写于 作者: S Sam Harwell

Simplify CreateWithLocationTags API

上级 d3551026
......@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
......@@ -11,7 +10,6 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.InvokeDelegateWithConditionalAccess
{
......@@ -173,9 +171,8 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext)
Descriptor,
fadeLocation,
ReportDiagnostic.Default,
additionalLocations.Add(fadeLocation),
tagIndices: ImmutableDictionary<string, IEnumerable<int>>.Empty
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), SpecializedCollections.SingletonEnumerable(additionalLocations.Length)),
additionalLocations,
additionalUnnecessaryLocations: ImmutableArray.Create(fadeLocation),
properties));
// Put a diagnostic with the appropriate severity on the expression-statement itself.
......@@ -193,9 +190,8 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext)
Descriptor,
fadeLocation,
ReportDiagnostic.Default,
additionalLocations.Add(fadeLocation),
tagIndices: ImmutableDictionary<string, IEnumerable<int>>.Empty
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), SpecializedCollections.SingletonEnumerable(additionalLocations.Length)),
additionalLocations,
additionalUnnecessaryLocations: ImmutableArray.Create(fadeLocation),
properties));
}
}
......
......@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CodeStyle;
......@@ -114,14 +113,16 @@ private void AnalyzeSemanticModel(SemanticModelAnalysisContext context)
// 'additionalLocations' is how we always pass along the locaiton of the first unreachable
// statement in this group.
var additionalLocations = SpecializedCollections.SingletonEnumerable(firstStatementLocation);
var additionalLocations = ImmutableArray.Create(firstStatementLocation);
if (fadeOutCode)
{
var tagIndices = ImmutableDictionary<string, IEnumerable<int>>.Empty
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), new int[] { 0 });
context.ReportDiagnostic(
DiagnosticHelper.CreateWithLocationTags(Descriptor, firstStatementLocation, ReportDiagnostic.Default, additionalLocations, tagIndices));
context.ReportDiagnostic(DiagnosticHelper.CreateWithLocationTags(
Descriptor,
firstStatementLocation,
ReportDiagnostic.Default,
additionalLocations: ImmutableArray<Location>.Empty,
additionalUnnecessaryLocations: additionalLocations));
}
else
{
......@@ -134,22 +135,18 @@ private void AnalyzeSemanticModel(SemanticModelAnalysisContext context)
{
var span = TextSpan.FromBounds(section[0].FullSpan.Start, section.Last().FullSpan.End);
var location = root.SyntaxTree.GetLocation(span);
var additionalUnnecessaryLocations = ImmutableArray<Location>.Empty;
// Mark subsequent sections as being 'cascaded'. We don't need to actually process them
// when doing a fix-all as they'll be scooped up when we process the fix for the first
// section.
if (fadeOutCode)
{
var tagIndices = ImmutableDictionary<string, IEnumerable<int>>.Empty
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), new int[] { additionalLocations.Count() });
context.ReportDiagnostic(
DiagnosticHelper.CreateWithLocationTags(Descriptor, location, ReportDiagnostic.Default, additionalLocations.Concat(location), tagIndices, s_subsequentSectionProperties));
}
else
{
context.ReportDiagnostic(
Diagnostic.Create(Descriptor, location, additionalLocations, s_subsequentSectionProperties));
additionalUnnecessaryLocations = ImmutableArray.Create(location);
}
context.ReportDiagnostic(
DiagnosticHelper.CreateWithLocationTags(Descriptor, location, ReportDiagnostic.Default, additionalLocations, additionalUnnecessaryLocations, s_subsequentSectionProperties));
}
}
}
......
......@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
......@@ -52,9 +51,8 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
Descriptor,
defaultExpression.GetLocation(),
preference.Notification.Severity,
additionalLocations: new[] { defaultExpression.SyntaxTree.GetLocation(fadeSpan) },
tagIndices: ImmutableDictionary<string, IEnumerable<int>>.Empty
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), new int[] { 0 })));
additionalLocations: ImmutableArray<Location>.Empty,
additionalUnnecessaryLocations: ImmutableArray.Create(defaultExpression.SyntaxTree.GetLocation(fadeSpan))));
}
}
}
......@@ -4,7 +4,6 @@
#nullable enable
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using Microsoft.CodeAnalysis.CodeStyle;
......@@ -61,9 +60,8 @@ private void ReportDiagnosticsIfNeeded(NameColonSyntax nameColon, SyntaxNodeAnal
Descriptor,
nameColon.GetLocation(),
preference.Notification.Severity,
additionalLocations: new[] { syntaxTree.GetLocation(fadeSpan) },
tagIndices: ImmutableDictionary<string, IEnumerable<int>>.Empty
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), new int[] { 0 })));
additionalLocations: ImmutableArray<Location>.Empty,
additionalUnnecessaryLocations: ImmutableArray.Create(syntaxTree.GetLocation(fadeSpan))));
}
private void ReportDiagnosticsIfNeeded(NameEqualsSyntax nameEquals, SyntaxNodeAnalysisContext context, AnalyzerOptions options, SyntaxTree syntaxTree, CancellationToken cancellationToken)
......@@ -89,9 +87,8 @@ private void ReportDiagnosticsIfNeeded(NameEqualsSyntax nameEquals, SyntaxNodeAn
Descriptor,
nameEquals.GetLocation(),
preference.Notification.Severity,
additionalLocations: new[] { syntaxTree.GetLocation(fadeSpan) },
tagIndices: ImmutableDictionary<string, IEnumerable<int>>.Empty
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), new int[] { 0 })));
additionalLocations: ImmutableArray<Location>.Empty,
additionalUnnecessaryLocations: ImmutableArray.Create(syntaxTree.GetLocation(fadeSpan))));
}
}
}
......@@ -33,7 +33,7 @@ internal abstract class AbstractBuiltInCodeStyleDiagnosticAnalyzer : AbstractCod
/// Message for the diagnostic descriptor.
/// <see langword="null"/> if the message is identical to the title.
/// </param>
/// <param name="isUnnecessary"></param>
/// <param name="isUnnecessary"><see langword="true"/> if the diagnostic is reported on unnecessary code; otherwise, <see langword="false"/>.</param>
/// <param name="configurable">Flag indicating if the reported diagnostics are configurable by the end users</param>
protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(
string diagnosticId,
......@@ -62,7 +62,7 @@ internal abstract class AbstractBuiltInCodeStyleDiagnosticAnalyzer : AbstractCod
/// Message for the diagnostic descriptor.
/// <see langword="null"/> if the message is identical to the title.
/// </param>
/// <param name="isUnnecessary"></param>
/// <param name="isUnnecessary"><see langword="true"/> if the diagnostic is reported on unnecessary code; otherwise, <see langword="false"/>.</param>
/// <param name="configurable">Flag indicating if the reported diagnostics are configurable by the end users</param>
protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(
string diagnosticId,
......@@ -90,7 +90,7 @@ internal abstract class AbstractBuiltInCodeStyleDiagnosticAnalyzer : AbstractCod
/// Message for the diagnostic descriptor.
/// Null if the message is identical to the title.
/// </param>
/// <param name="isUnnecessary"></param>
/// <param name="isUnnecessary"><see langword="true"/> if the diagnostic is reported on unnecessary code; otherwise, <see langword="false"/>.</param>
/// <param name="configurable">Flag indicating if the reported diagnostics are configurable by the end users</param>
protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(
string diagnosticId,
......@@ -120,7 +120,7 @@ internal abstract class AbstractBuiltInCodeStyleDiagnosticAnalyzer : AbstractCod
/// Message for the diagnostic descriptor.
/// Null if the message is identical to the title.
/// </param>
/// <param name="isUnnecessary"></param>
/// <param name="isUnnecessary"><see langword="true"/> if the diagnostic is reported on unnecessary code; otherwise, <see langword="false"/>.</param>
/// <param name="configurable">Flag indicating if the reported diagnostics are configurable by the end users</param>
protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(
string diagnosticId,
......
......@@ -69,11 +69,13 @@ internal static class DiagnosticHelper
/// <param name="additionalLocations">
/// An optional set of additional locations related to the diagnostic.
/// Typically, these are locations of other items referenced in the message.
/// If null, <see cref="Diagnostic.AdditionalLocations"/> will return an empty list.
/// These locations are joined with <paramref name="additionalUnnecessaryLocations"/> to produce the value for
/// <see cref="Diagnostic.AdditionalLocations"/>.
/// </param>
/// <param name="tagIndices">
/// a map of location tag to index in additional locations.
/// "AbstractRemoveUnnecessaryParenthesesDiagnosticAnalyzer" for an example of usage.
/// <param name="additionalUnnecessaryLocations">
/// An optional set of additional locations indicating unnecessary code related to the diagnostic.
/// These locations are joined with <paramref name="additionalLocations"/> to produce the value for
/// <see cref="Diagnostic.AdditionalLocations"/>.
/// </param>
/// <param name="messageArgs">Arguments to the message of the diagnostic.</param>
/// <returns>The <see cref="Diagnostic"/> instance.</returns>
......@@ -81,11 +83,74 @@ internal static class DiagnosticHelper
DiagnosticDescriptor descriptor,
Location location,
ReportDiagnostic effectiveSeverity,
IEnumerable<Location> additionalLocations,
IDictionary<string, IEnumerable<int>> tagIndices,
ImmutableArray<Location> additionalLocations,
ImmutableArray<Location> additionalUnnecessaryLocations,
params object[] messageArgs)
{
return CreateWithLocationTags(descriptor, location, effectiveSeverity, additionalLocations, tagIndices, ImmutableDictionary<string, string>.Empty, messageArgs);
if (additionalUnnecessaryLocations.IsEmpty)
{
return Create(descriptor, location, effectiveSeverity, additionalLocations, ImmutableDictionary<string, string>.Empty, messageArgs);
}
var tagIndices = ImmutableDictionary<string, IEnumerable<int>>.Empty
.Add(WellKnownDiagnosticTags.Unnecessary, Enumerable.Range(additionalLocations.Length, additionalUnnecessaryLocations.Length));
return CreateWithLocationTags(
descriptor,
location,
effectiveSeverity,
additionalLocations.AddRange(additionalUnnecessaryLocations),
tagIndices,
ImmutableDictionary<string, string>.Empty,
messageArgs);
}
/// <summary>
/// Create a diagnostic that adds properties specifying a tag for a set of locations.
/// </summary>
/// <param name="descriptor">A <see cref="DiagnosticDescriptor"/> describing the diagnostic.</param>
/// <param name="location">An optional primary location of the diagnostic. If null, <see cref="Location"/> will return <see cref="Location.None"/>.</param>
/// <param name="effectiveSeverity">Effective severity of the diagnostic.</param>
/// <param name="additionalLocations">
/// An optional set of additional locations related to the diagnostic.
/// Typically, these are locations of other items referenced in the message.
/// These locations are joined with <paramref name="additionalUnnecessaryLocations"/> to produce the value for
/// <see cref="Diagnostic.AdditionalLocations"/>.
/// </param>
/// <param name="additionalUnnecessaryLocations">
/// An optional set of additional locations indicating unnecessary code related to the diagnostic.
/// These locations are joined with <paramref name="additionalLocations"/> to produce the value for
/// <see cref="Diagnostic.AdditionalLocations"/>.
/// </param>
/// <param name="properties">
/// An optional set of name-value pairs by means of which the analyzer that creates the diagnostic
/// can convey more detailed information to the fixer.
/// </param>
/// <param name="messageArgs">Arguments to the message of the diagnostic.</param>
/// <returns>The <see cref="Diagnostic"/> instance.</returns>
public static Diagnostic CreateWithLocationTags(
DiagnosticDescriptor descriptor,
Location location,
ReportDiagnostic effectiveSeverity,
ImmutableArray<Location> additionalLocations,
ImmutableArray<Location> additionalUnnecessaryLocations,
ImmutableDictionary<string, string> properties,
params object[] messageArgs)
{
if (additionalUnnecessaryLocations.IsEmpty)
{
return Create(descriptor, location, effectiveSeverity, additionalLocations, ImmutableDictionary<string, string>.Empty, messageArgs);
}
var tagIndices = ImmutableDictionary<string, IEnumerable<int>>.Empty
.Add(WellKnownDiagnosticTags.Unnecessary, Enumerable.Range(additionalLocations.Length, additionalUnnecessaryLocations.Length));
return CreateWithLocationTags(
descriptor,
location,
effectiveSeverity,
additionalLocations.AddRange(additionalUnnecessaryLocations),
tagIndices,
properties,
messageArgs);
}
/// <summary>
......@@ -97,7 +162,6 @@ internal static class DiagnosticHelper
/// <param name="additionalLocations">
/// An optional set of additional locations related to the diagnostic.
/// Typically, these are locations of other items referenced in the message.
/// If null, <see cref="Diagnostic.AdditionalLocations"/> will return an empty list.
/// </param>
/// <param name="tagIndices">
/// a map of location tag to index in additional locations.
......@@ -109,7 +173,7 @@ internal static class DiagnosticHelper
/// </param>
/// <param name="messageArgs">Arguments to the message of the diagnostic.</param>
/// <returns>The <see cref="Diagnostic"/> instance.</returns>
public static Diagnostic CreateWithLocationTags(
private static Diagnostic CreateWithLocationTags(
DiagnosticDescriptor descriptor,
Location location,
ReportDiagnostic effectiveSeverity,
......
......@@ -5,7 +5,6 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Threading;
......@@ -34,12 +33,6 @@ internal abstract class AbstractRemoveUnnecessaryParenthesesDiagnosticAnalyzer<
new LocalizableResourceString(nameof(AnalyzersResources.Parentheses_can_be_removed), AnalyzersResources.ResourceManager, typeof(AnalyzersResources)),
isUnnecessary: true);
/// <summary>
/// This analyzer inserts the fade locations into indices 1 and 2 inside additional locations.
/// </summary>
private static readonly ImmutableDictionary<string, IEnumerable<int>> s_fadeLocations = ImmutableDictionary<string, IEnumerable<int>>.Empty
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), new int[] { 1, 2 });
protected AbstractRemoveUnnecessaryParenthesesDiagnosticAnalyzer()
: base(ImmutableArray.Create(s_diagnosticDescriptor))
{
......@@ -120,7 +113,8 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
var severity = preference.Notification.Severity;
var additionalLocations = ImmutableArray.Create(
parenthesizedExpression.GetLocation(),
parenthesizedExpression.GetLocation());
var additionalUnnecessaryLocations = ImmutableArray.Create(
parenthesizedExpression.GetFirstToken().GetLocation(),
parenthesizedExpression.GetLastToken().GetLocation());
......@@ -129,7 +123,7 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
GetDiagnosticSquiggleLocation(parenthesizedExpression, context.CancellationToken),
severity,
additionalLocations,
s_fadeLocations));
additionalUnnecessaryLocations));
}
/// <summary>
......
......@@ -2,9 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars;
......@@ -67,13 +65,17 @@ private void AnalyzeInterpolation(OperationAnalysisContext context)
return;
}
// The diagnostic itself fades the first unnecessary location, and the remaining locations are passed as
// additional unnecessary locations.
var firstUnnecessaryLocation = unnecessaryLocations[0];
var remainingUnnecessaryLocations = unnecessaryLocations.RemoveAt(0);
context.ReportDiagnostic(DiagnosticHelper.CreateWithLocationTags(
Descriptor,
unnecessaryLocations.First(),
firstUnnecessaryLocation,
option.Notification.Severity,
additionalLocations: ImmutableArray.Create(interpolation.Syntax.GetLocation()).AddRange(unnecessaryLocations.Skip(1)),
tagIndices: ImmutableDictionary<string, IEnumerable<int>>.Empty
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), Enumerable.Range(1, unnecessaryLocations.Length - 1))));
additionalLocations: ImmutableArray.Create(interpolation.Syntax.GetLocation()),
additionalUnnecessaryLocations: remainingUnnecessaryLocations));
}
}
}
......@@ -5,13 +5,11 @@
#nullable enable
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.UseCollectionInitializer
{
......@@ -146,18 +144,20 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context, INamedTypeSymbol ien
if (syntaxFacts.IsInvocationExpression(expression))
{
var arguments = syntaxFacts.GetArgumentsOfInvocationExpression(expression);
var location1 = Location.Create(syntaxTree, TextSpan.FromBounds(
match.SpanStart, arguments[0].SpanStart));
var additionalUnnecessaryLocations = ImmutableArray.Create(
syntaxTree.GetLocation(TextSpan.FromBounds(match.SpanStart, arguments[0].SpanStart)),
syntaxTree.GetLocation(TextSpan.FromBounds(arguments.Last().FullSpan.End, match.Span.End)));
// Report the diagnostic at the first unnecessary location. This is the location where the code fix
// will be offered.
var location1 = additionalUnnecessaryLocations[0];
context.ReportDiagnostic(DiagnosticHelper.CreateWithLocationTags(
Descriptor,
location1,
ReportDiagnostic.Default,
additionalLocations: locations
.Add(location1)
.Add(syntaxTree.GetLocation(TextSpan.FromBounds(arguments.Last().FullSpan.End, match.Span.End))),
tagIndices: ImmutableDictionary<string, IEnumerable<int>>.Empty
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), new int[] { locations.Length - 1, locations.Length })));
additionalLocations: locations,
additionalUnnecessaryLocations: additionalUnnecessaryLocations));
}
}
}
......
......@@ -4,14 +4,12 @@
#nullable enable
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.UseObjectInitializer
{
......@@ -132,11 +130,9 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context)
Descriptor,
location1,
ReportDiagnostic.Default,
additionalLocations: locations.Add(Location.Create(syntaxTree, TextSpan.FromBounds(
match.Initializer.FullSpan.End,
match.Statement.Span.End))),
tagIndices: ImmutableDictionary<string, IEnumerable<int>>.Empty
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), new int[] { locations.Length })));
additionalLocations: locations,
additionalUnnecessaryLocations: ImmutableArray.Create(
syntaxTree.GetLocation(TextSpan.FromBounds(match.Initializer.FullSpan.End, match.Statement.Span.End)))));
}
else
{
......
......@@ -65,8 +65,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseInferredMemberName
Descriptor,
nameColonEquals.GetLocation(),
preference.Notification.Severity,
additionalLocations:={syntaxTree.GetLocation(fadeSpan)},
tagIndices:=ImmutableDictionary(Of String, IEnumerable(Of Integer)).Empty.Add(NameOf(WellKnownDiagnosticTags.Unnecessary), {0})))
additionalLocations:=ImmutableArray(Of Location).Empty,
additionalUnnecessaryLocations:=ImmutableArray.Create(syntaxTree.GetLocation(fadeSpan))))
End Sub
Private Sub ReportDiagnosticsIfNeeded(
......@@ -95,8 +95,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseInferredMemberName
Descriptor,
syntaxTree.GetLocation(fadeSpan),
preference.Notification.Severity,
additionalLocations:={syntaxTree.GetLocation(fadeSpan)},
tagIndices:=ImmutableDictionary(Of String, IEnumerable(Of Integer)).Empty.Add(NameOf(WellKnownDiagnosticTags.Unnecessary), {0})))
additionalLocations:=ImmutableArray(Of Location).Empty,
additionalUnnecessaryLocations:=ImmutableArray.Create(syntaxTree.GetLocation(fadeSpan))))
End Sub
End Class
End Namespace
......@@ -59,12 +59,6 @@ public async Task Test_FadingSpans()
private class Analyzer : DiagnosticAnalyzer
{
// Mark elements 1, and 2 in the locations as the fading locations.
private static readonly ImmutableDictionary<string, IEnumerable<int>> s_fadeLocations = new Dictionary<string, IEnumerable<int>>
{
{ nameof(WellKnownDiagnosticTags.Unnecessary), new int[] { 1, 2 } },
}.ToImmutableDictionary();
private readonly DiagnosticDescriptor _rule = new DiagnosticDescriptor(
"test", "test", "test", "test", DiagnosticSeverity.Error, true,
customTags: DiagnosticCustomTags.Create(isUnnecessary: true, isConfigurable: false));
......@@ -76,15 +70,16 @@ public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxTreeAction(c =>
{
var additionalLocations = ImmutableArray.Create(Location.Create(c.Tree, new TextSpan(0, 10)));
var additionalUnnecessaryLocations = ImmutableArray.Create(
Location.Create(c.Tree, new TextSpan(0, 1)),
Location.Create(c.Tree, new TextSpan(9, 1)));
c.ReportDiagnostic(DiagnosticHelper.CreateWithLocationTags(
_rule, Location.Create(c.Tree, new TextSpan(0, 10)),
ReportDiagnostic.Error,
new Location[] {
Location.Create(c.Tree, new TextSpan(0, 10)),
Location.Create(c.Tree, new TextSpan(0, 1)),
Location.Create(c.Tree, new TextSpan(9, 1)),
},
s_fadeLocations));
additionalLocations,
additionalUnnecessaryLocations));
});
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册