提交 ed354572 编写于 作者: C Cyrus Najmabadi

Revert json features. They will be added in the jsonFeatures branch

上级 93d265a2
// 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.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Implementation.BraceMatching;
namespace Microsoft.CodeAnalysis.Editor.CSharp.BraceMatching
{
[ExportBraceMatcher(LanguageNames.CSharp)]
internal class CSharpJsonBraceMatcher : IBraceMatcher
{
public Task<BraceMatchingResult?> FindBracesAsync(Document document, int position, CancellationToken cancellationToken)
=> CommonJsonBraceMatcher.FindBracesAsync(document, position, cancellationToken);
}
}
// 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.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Editor.Implementation.BraceMatching;
namespace Microsoft.CodeAnalysis.Editor.CSharp.BraceMatching
{
[ExportBraceMatcher(LanguageNames.CSharp)]
internal class CSharpRegexBraceMatcher : IBraceMatcher
{
public Task<BraceMatchingResult?> FindBracesAsync(Document document, int position, CancellationToken cancellationToken)
=> CommonRegexBraceMatcher.FindBracesAsync(document, position, cancellationToken);
}
}
// 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.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.JsonStringDetector;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.JsonStringDetector
{
public class JsonStringDetectorTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest
{
internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
=> (new CSharpJsonStringDetectorDiagnosticAnalyzer(), new CSharpEnableIDEJsonFeaturesCodeFixProvider());
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsDetectJsonString)]
public async Task TestStrict()
{
await TestInRegularAndScriptAsync(
@"
class C
{
void Goo()
{
var j = [||]""{ \""a\"": 0 }"";
}
}",
@"
class C
{
void Goo()
{
var j = /*lang=json,strict*/ ""{ \""a\"": 0 }"";
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsDetectJsonString)]
public async Task TestNonStrict()
{
await TestInRegularAndScriptAsync(
@"
class C
{
void Goo()
{
var j = [||]""{ 'a': 00 }"";
}
}",
@"
class C
{
void Goo()
{
var j = /*lang=json*/ ""{ 'a': 00 }"";
}
}");
}
}
}
// 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.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.ValidateJsonString;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Json;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ValidateJsonString
{
public class ValidateJsonStringTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest
{
internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
=> (new CSharpValidateJsonStringDiagnosticAnalyzer(), null);
private IDictionary<OptionKey, object> OptionOn()
{
var optionsSet = new Dictionary<OptionKey, object>();
optionsSet.Add(new OptionKey(JsonOptions.ReportInvalidJsonPatterns, LanguageNames.CSharp), true);
optionsSet.Add(new OptionKey(JsonOptions.ReportInvalidJsonPatterns, LanguageNames.VisualBasic), true);
return optionsSet;
}
[Fact, Trait(Traits.Feature, Traits.Features.ValidateJsonString)]
public async Task TestWarning1()
{
await TestDiagnosticInfoAsync(@"
class Program
{
void Main()
{
var r = /*lang=json,strict*/ ""[|new|] Json()"";
}
}",
options: OptionOn(),
diagnosticId: IDEDiagnosticIds.JsonPatternDiagnosticId,
diagnosticSeverity: DiagnosticSeverity.Warning,
diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0, WorkspacesResources.Constructors_not_allowed));
}
[Fact, Trait(Traits.Feature, Traits.Features.ValidateJsonString)]
public async Task TestWarning2()
{
await TestDiagnosticInfoAsync(@"
class Program
{
void Main()
{
var r = /*lang=json*/ ""[|}|]"";
}
}",
options: OptionOn(),
diagnosticId: IDEDiagnosticIds.JsonPatternDiagnosticId,
diagnosticSeverity: DiagnosticSeverity.Warning,
diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0,
string.Format(WorkspacesResources._0_unexpected, '}')));
}
}
}
// 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.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.ValidateRegexString;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.RegularExpressions;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ValidateRegexString
{
public class ValidateRegexStringTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest
{
internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
=> (new CSharpValidateRegexStringDiagnosticAnalyzer(), null);
private IDictionary<OptionKey, object> OptionOn()
{
var optionsSet = new Dictionary<OptionKey, object>();
optionsSet.Add(new OptionKey(RegularExpressionsOptions.ReportInvalidRegexPatterns, LanguageNames.CSharp), true);
optionsSet.Add(new OptionKey(RegularExpressionsOptions.ReportInvalidRegexPatterns, LanguageNames.VisualBasic), true);
return optionsSet;
}
private IDictionary<OptionKey, object> OptionOff()
{
var optionsSet = new Dictionary<OptionKey, object>();
optionsSet.Add(new OptionKey(RegularExpressionsOptions.ReportInvalidRegexPatterns, LanguageNames.CSharp), false);
optionsSet.Add(new OptionKey(RegularExpressionsOptions.ReportInvalidRegexPatterns, LanguageNames.VisualBasic), false);
return optionsSet;
}
[Fact, Trait(Traits.Feature, Traits.Features.ValidateRegexString)]
public async Task TestWarning1()
{
await TestDiagnosticInfoAsync(@"
using System.Text.RegularExpressions;
class Program
{
void Main()
{
var r = new Regex(@""[|)|]"");
}
}",
options: OptionOn(),
diagnosticId: IDEDiagnosticIds.RegexPatternDiagnosticId,
diagnosticSeverity: DiagnosticSeverity.Warning,
diagnosticMessage: string.Format(FeaturesResources.Regex_issue_0, WorkspacesResources.Too_many_close_parens));
}
[Fact, Trait(Traits.Feature, Traits.Features.ValidateRegexString)]
public async Task TestWarning2()
{
await TestDiagnosticInfoAsync(@"
using System.Text.RegularExpressions;
class Program
{
void Main()
{
var r = new Regex(""[|\u0029|]"");
}
}",
options: OptionOn(),
diagnosticId: IDEDiagnosticIds.RegexPatternDiagnosticId,
diagnosticSeverity: DiagnosticSeverity.Warning,
diagnosticMessage: string.Format(FeaturesResources.Regex_issue_0, WorkspacesResources.Too_many_close_parens));
}
[Fact, Trait(Traits.Feature, Traits.Features.ValidateRegexString)]
public async Task TestWarningMissing1()
{
await TestDiagnosticMissingAsync(@"
using System.Text.RegularExpressions;
class Program
{
void Main()
{
var r = new Regex(@""[|\u0029|]"");
}
}");
}
}
}
// 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.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Json;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.VirtualChars;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor.Implementation.BraceMatching
{
internal static class CommonJsonBraceMatcher
{
internal static async Task<BraceMatchingResult?> FindBracesAsync(
Document document, int position, CancellationToken cancellationToken)
{
var option = document.Project.Solution.Workspace.Options.GetOption(JsonOptions.HighlightRelatedJsonComponentsUnderCursor, document.Project.Language);
if (!option)
{
return default;
}
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var token = root.FindToken(position);
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
if (JsonPatternDetector.IsDefinitelyNotJson(token, syntaxFacts))
{
return default;
}
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var detector = JsonPatternDetector.GetOrCreate(
semanticModel, syntaxFacts, document.GetLanguageService<ISemanticFactsService>(), document.GetLanguageService<IVirtualCharService>());
if (!detector.IsDefinitelyJson(token, cancellationToken))
{
return default;
}
var tree = detector.TryParseJson(token, cancellationToken);
if (tree == null)
{
return default;
}
return GetMatchingBraces(tree, position);
}
private static BraceMatchingResult? GetMatchingBraces(JsonTree tree, int position)
{
var virtualChar = tree.Text.FirstOrNullable(vc => vc.Span.Contains(position));
if (virtualChar == null)
{
return null;
}
var ch = virtualChar.Value;
if (ch == '{' || ch == '[' || ch == '(' ||
ch == '}' || ch == ']' || ch == ')')
{
return FindBraceHighlights(tree, ch);
}
return null;
}
private static BraceMatchingResult? FindBraceHighlights(JsonTree tree, VirtualChar ch)
{
var node = FindObjectOrArrayNode(tree.Root, ch);
switch (node)
{
case JsonObjectNode obj: return Create(obj.OpenBraceToken, obj.CloseBraceToken);
case JsonArrayNode array: return Create(array.OpenBracketToken, array.CloseBracketToken);
case JsonConstructorNode cons: return Create(cons.OpenParenToken, cons.CloseParenToken);
}
return default;
}
private static BraceMatchingResult? Create(JsonToken open, JsonToken close)
{
if (open.IsMissing || close.IsMissing)
{
return default;
}
return new BraceMatchingResult(
JsonHelpers.GetSpan(open),
JsonHelpers.GetSpan(close));
}
private static JsonValueNode FindObjectOrArrayNode(JsonNode node, VirtualChar ch)
{
switch (node)
{
case JsonArrayNode array when Matches(array.OpenBracketToken, array.CloseBracketToken, ch):
return array;
case JsonObjectNode obj when Matches(obj.OpenBraceToken, obj.CloseBraceToken, ch):
return obj;
case JsonConstructorNode cons when Matches(cons.OpenParenToken, cons.CloseParenToken, ch):
return cons;
}
foreach (var child in node)
{
if (child.IsNode)
{
var result = FindObjectOrArrayNode(child.Node, ch);
if (result != null)
{
return result;
}
}
}
return null;
}
private static bool Matches(JsonToken openToken, JsonToken closeToken, VirtualChar ch)
=> openToken.VirtualChars.Contains(ch) || closeToken.VirtualChars.Contains(ch);
}
}
// 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.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.RegularExpressions;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.VirtualChars;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor.Implementation.BraceMatching
{
internal static class CommonRegexBraceMatcher
{
internal static async Task<BraceMatchingResult?> FindBracesAsync(
Document document, int position, CancellationToken cancellationToken)
{
var option = document.Project.Solution.Workspace.Options.GetOption(
RegularExpressionsOptions.HighlightRelatedRegexComponentsUnderCursor, document.Project.Language);
if (!option)
{
return default;
}
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var token = root.FindToken(position);
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
if (RegexPatternDetector.IsDefinitelyNotPattern(token, syntaxFacts))
{
return null;
}
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var detector = RegexPatternDetector.TryGetOrCreate(semanticModel, syntaxFacts, document.GetLanguageService<ISemanticFactsService>());
var tree = detector?.TryParseRegexPattern(token, document.GetLanguageService<IVirtualCharService>(), cancellationToken);
if (tree == null)
{
return null;
}
return GetMatchingBraces(tree, position);
}
private static BraceMatchingResult? GetMatchingBraces(RegexTree tree, int position)
{
var virtualChar = tree.Text.FirstOrNullable(vc => vc.Span.Contains(position));
if (virtualChar == null)
{
return null;
}
var ch = virtualChar.Value;
if (ch != '(' && ch != ')')
{
return null;
}
return FindBraceHighlights(tree, ch);
}
private static BraceMatchingResult? FindBraceHighlights(RegexTree tree, VirtualChar ch)
{
var node = FindGroupingNode(tree.Root, ch);
if (node == null)
{
return null;
}
if (node.OpenParenToken.IsMissing || node.CloseParenToken.IsMissing)
{
return null;
}
return new BraceMatchingResult(
node.OpenParenToken.VirtualChars[0].Span,
node.CloseParenToken.VirtualChars[0].Span);
}
private static RegexGroupingNode FindGroupingNode(RegexNode node, VirtualChar ch)
{
if (node is RegexGroupingNode grouping &&
(grouping.OpenParenToken.VirtualChars.Contains(ch) || grouping.CloseParenToken.VirtualChars.Contains(ch)))
{
return grouping;
}
foreach (var child in node)
{
if (child.IsNode)
{
var result = FindGroupingNode(child.Node, ch);
if (result != null)
{
return result;
}
}
}
return null;
}
}
}
// 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.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using System.Threading;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.VirtualChars;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.RegularExpressions
{
/// <summary>
/// Helper class to detect regex pattern tokens in a document efficiently.
/// </summary>
internal class RegexPatternDetector
{
private const string _patternName = "pattern";
private static readonly ConditionalWeakTable<SemanticModel, RegexPatternDetector> _modelToDetector =
new ConditionalWeakTable<SemanticModel, RegexPatternDetector>();
private readonly SemanticModel _semanticModel;
private readonly ISyntaxFactsService _syntaxFacts;
private readonly ISemanticFactsService _semanticFacts;
private readonly INamedTypeSymbol _regexType;
private readonly HashSet<string> _methodNamesOfInterest;
/// <summary>
/// Helps match patterns of the form: language=regex,option1,option2,option3
///
/// All matching is case insensitive, with spaces allowed between the punctuation.
/// 'regex' or 'regexp' are both allowed. Option values will be or'ed together
/// to produce final options value. If an unknown option is encountered, processing
/// will stop with whatever value has accumulated so far.
///
/// Option names are the values from the <see cref="RegexOptions"/> enum.
/// </summary>
private static readonly Regex s_languageCommentDetector =
new Regex(@"lang(uage)?\s*=\s*regex(p)?((\s*,\s*)(?<option>[a-zA-Z]+))*",
RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Dictionary<string, RegexOptions> s_nameToOption =
typeof(RegexOptions).GetTypeInfo().DeclaredFields
.Where(f => f.FieldType == typeof(RegexOptions))
.ToDictionary(f => f.Name, f => (RegexOptions)f.GetValue(null), StringComparer.OrdinalIgnoreCase);
public RegexPatternDetector(
SemanticModel semanticModel,
ISyntaxFactsService syntaxFacts,
ISemanticFactsService semanticFacts,
INamedTypeSymbol regexType,
HashSet<string> methodNamesOfInterest)
{
_semanticModel = semanticModel;
_syntaxFacts = syntaxFacts;
_semanticFacts = semanticFacts;
_regexType = regexType;
_methodNamesOfInterest = methodNamesOfInterest;
}
public static RegexPatternDetector TryGetOrCreate(
SemanticModel semanticModel,
ISyntaxFactsService syntaxFacts,
ISemanticFactsService semanticFacts)
{
// Do a quick non-allocating check first.
if (_modelToDetector.TryGetValue(semanticModel, out var detector))
{
return detector;
}
return _modelToDetector.GetValue(
semanticModel, _ => TryCreate(semanticModel, syntaxFacts, semanticFacts));
}
private static RegexPatternDetector TryCreate(
SemanticModel semanticModel,
ISyntaxFactsService syntaxFacts,
ISemanticFactsService semanticFacts)
{
var regexType = semanticModel.Compilation.GetTypeByMetadataName(typeof(Regex).FullName);
if (regexType == null)
{
return null;
}
var methodNamesOfInterest = GetMethodNamesOfInterest(regexType, syntaxFacts);
return new RegexPatternDetector(
semanticModel, syntaxFacts, semanticFacts,
regexType, methodNamesOfInterest);
}
public static bool IsDefinitelyNotPattern(SyntaxToken token, ISyntaxFactsService syntaxFacts)
{
// We only support string literals passed in arguments to something.
// In the future we could support any string literal, as long as it has
// some marker (like a comment on it) stating it's a regex.
if (!syntaxFacts.IsStringLiteral(token))
{
return true;
}
if (!IsMethodOrConstructorArgument(token, syntaxFacts) &&
!HasRegexLanguageComment(token, syntaxFacts, out _))
{
return true;
}
return false;
}
private static bool HasRegexLanguageComment(
SyntaxToken token, ISyntaxFactsService syntaxFacts, out RegexOptions options)
{
if (HasRegexLanguageComment(token.GetPreviousToken().TrailingTrivia, syntaxFacts, out options))
{
return true;
}
for (var node = token.Parent; node != null; node = node.Parent)
{
if (HasRegexLanguageComment(node.GetLeadingTrivia(), syntaxFacts, out options))
{
return true;
}
}
options = default;
return false;
}
private static bool HasRegexLanguageComment(
SyntaxTriviaList list, ISyntaxFactsService syntaxFacts, out RegexOptions options)
{
foreach (var trivia in list)
{
if (HasRegexLanguageComment(trivia, syntaxFacts, out options))
{
return true;
}
}
options = default;
return false;
}
private static bool HasRegexLanguageComment(
SyntaxTrivia trivia, ISyntaxFactsService syntaxFacts, out RegexOptions options)
{
if (syntaxFacts.IsRegularComment(trivia))
{
var text = trivia.ToString();
var match = s_languageCommentDetector.Match(text);
if (match.Success)
{
options = RegexOptions.None;
var optionGroup = match.Groups["option"];
foreach (Capture capture in optionGroup.Captures)
{
if (s_nameToOption.TryGetValue(capture.Value, out var specificOption))
{
options |= specificOption;
}
else
{
break;
}
}
return true;
}
}
options = default;
return false;
}
private static bool IsMethodOrConstructorArgument(SyntaxToken token, ISyntaxFactsService syntaxFacts)
=> syntaxFacts.IsLiteralExpression(token.Parent) &&
syntaxFacts.IsArgument(token.Parent.Parent);
private static HashSet<string> GetMethodNamesOfInterest(INamedTypeSymbol regexType, ISyntaxFactsService syntaxFacts)
{
var result = syntaxFacts.IsCaseSensitive
? new HashSet<string>()
: new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var methods = from method in regexType.GetMembers().OfType<IMethodSymbol>()
where method.DeclaredAccessibility == Accessibility.Public
where method.IsStatic
where method.Parameters.Any(p => p.Name == _patternName)
select method.Name;
result.AddRange(methods);
return result;
}
public bool IsRegexPattern(SyntaxToken token, CancellationToken cancellationToken, out RegexOptions options)
{
options = default;
if (IsDefinitelyNotPattern(token, _syntaxFacts))
{
return false;
}
if (HasRegexLanguageComment(token, _syntaxFacts, out options))
{
return true;
}
var stringLiteral = token;
var literalNode = stringLiteral.Parent;
var argumentNode = literalNode.Parent;
Debug.Assert(_syntaxFacts.IsArgument(argumentNode));
var argumentList = argumentNode.Parent;
var invocationOrCreation = argumentList.Parent;
if (_syntaxFacts.IsInvocationExpression(invocationOrCreation))
{
var invokedExpression = _syntaxFacts.GetExpressionOfInvocationExpression(invocationOrCreation);
var name = GetNameOfInvokedExpression(invokedExpression);
if (_methodNamesOfInterest.Contains(name))
{
// Is a string argument to a method that looks like it could be a Regex method.
// Need to do deeper analysis
var method = _semanticModel.GetSymbolInfo(invocationOrCreation, cancellationToken).GetAnySymbol();
if (method != null &&
method.DeclaredAccessibility == Accessibility.Public &&
method.IsStatic &&
_regexType.Equals(method.ContainingType))
{
return AnalyzeStringLiteral(
stringLiteral, argumentNode, cancellationToken, out options);
}
}
}
else if (_syntaxFacts.IsObjectCreationExpression(invocationOrCreation))
{
var typeNode = _syntaxFacts.GetObjectCreationType(invocationOrCreation);
var name = GetNameOfType(typeNode, _syntaxFacts);
if (name != null)
{
if (_syntaxFacts.StringComparer.Compare(nameof(Regex), name) == 0)
{
var constructor = _semanticModel.GetSymbolInfo(invocationOrCreation, cancellationToken).GetAnySymbol();
if (_regexType.Equals(constructor?.ContainingType))
{
// Argument to "new Regex". Need to do deeper analysis
return AnalyzeStringLiteral(
stringLiteral, argumentNode, cancellationToken, out options);
}
}
}
}
return false;
}
public RegexTree TryParseRegexPattern(SyntaxToken token, IVirtualCharService virtualCharService, CancellationToken cancellationToken)
{
if (!this.IsRegexPattern(token, cancellationToken, out var options))
{
return null;
}
var chars = virtualCharService.TryConvertToVirtualChars(token);
if (chars.IsDefaultOrEmpty)
{
return null;
}
return RegexParser.TryParse(chars, options);
}
private bool AnalyzeStringLiteral(
SyntaxToken stringLiteral, SyntaxNode argumentNode,
CancellationToken cancellationToken, out RegexOptions options)
{
options = default;
var parameter = _semanticFacts.FindParameterForArgument(_semanticModel, argumentNode, cancellationToken);
if (parameter?.Name != _patternName)
{
return false;
}
options = GetRegexOptions(argumentNode, cancellationToken);
return true;
}
private RegexOptions GetRegexOptions(SyntaxNode argumentNode, CancellationToken cancellationToken)
{
var argumentList = argumentNode.Parent;
var arguments = _syntaxFacts.GetArgumentsOfArgumentList(argumentList);
foreach (var siblingArg in arguments)
{
if (siblingArg != argumentNode)
{
var expr = _syntaxFacts.GetExpressionOfArgument(siblingArg);
if (expr != null)
{
var exprType = _semanticModel.GetTypeInfo(expr, cancellationToken);
if (exprType.Type?.Name == nameof(RegexOptions))
{
var constVal = _semanticModel.GetConstantValue(expr, cancellationToken);
if (constVal.HasValue)
{
return (RegexOptions)(int)constVal.Value;
}
}
}
}
}
return RegexOptions.None;
}
private string GetNameOfType(SyntaxNode typeNode, ISyntaxFactsService syntaxFacts)
{
if (syntaxFacts.IsQualifiedName(typeNode))
{
return GetNameOfType(syntaxFacts.GetRightSideOfDot(typeNode), syntaxFacts);
}
else if (syntaxFacts.IsIdentifierName(typeNode))
{
return syntaxFacts.GetIdentifierOfSimpleName(typeNode).ValueText;
}
return null;
}
private string GetNameOfInvokedExpression(SyntaxNode invokedExpression)
{
if (_syntaxFacts.IsSimpleMemberAccessExpression(invokedExpression))
{
return _syntaxFacts.GetIdentifierOfSimpleName(_syntaxFacts.GetNameOfMemberAccessExpression(invokedExpression)).ValueText;
}
else if (_syntaxFacts.IsIdentifierName(invokedExpression))
{
return _syntaxFacts.GetIdentifierOfSimpleName(invokedExpression).ValueText;
}
return null;
}
}
}
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Collections.Immutable
Imports System.Threading
Imports Microsoft.CodeAnalysis.Classification
Imports Microsoft.CodeAnalysis.VisualBasic.VirtualChars
Imports Microsoft.CodeAnalysis.PooledObjects
Namespace Microsoft.CodeAnalysis.VisualBasic.Classification.Classifiers
Friend Class JsonPatternTokenClassifier
Inherits AbstractSyntaxClassifier
Public Overrides ReadOnly Property SyntaxTokenKinds As ImmutableArray(Of Integer) = ImmutableArray.Create(Of Integer)(SyntaxKind.StringLiteralToken)
Public Overrides Sub AddClassifications(workspace As Workspace, token As SyntaxToken, semanticModel As SemanticModel, result As ArrayBuilder(Of ClassifiedSpan), cancellationToken As CancellationToken)
Debug.Assert(token.Kind() = SyntaxKind.StringLiteralToken)
CommonJsonPatternTokenClassifier.AddClassifications(
workspace, token, semanticModel, result,
VisualBasicSyntaxFactsService.Instance,
VisualBasicSemanticFactsService.Instance,
VisualBasicVirtualCharService.Instance,
cancellationToken)
End Sub
End Class
End Namespace
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Collections.Immutable
Imports System.Threading
Imports Microsoft.CodeAnalysis.Classification
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.VisualBasic.VirtualChars
Namespace Microsoft.CodeAnalysis.VisualBasic.Classification.Classifiers
Friend Class RegexPatternTokenClassifier
Inherits AbstractSyntaxClassifier
Public Overrides ReadOnly Property SyntaxTokenKinds As ImmutableArray(Of Integer) = ImmutableArray.Create(Of Integer)(SyntaxKind.StringLiteralToken)
Public Overrides Sub AddClassifications(workspace As Workspace, token As SyntaxToken, semanticModel As SemanticModel, result As ArrayBuilder(Of ClassifiedSpan), cancellationToken As CancellationToken)
Debug.Assert(token.Kind() = SyntaxKind.StringLiteralToken)
CommonRegexPatternTokenClassifier.AddClassifications(
workspace, token, semanticModel, result,
VisualBasicSyntaxFactsService.Instance,
VisualBasicSemanticFactsService.Instance,
VisualBasicVirtualCharService.Instance,
cancellationToken)
End Sub
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册