提交 27d3b9d6 编写于 作者: C Charles Stoner 提交者: GitHub

Merge pull request #15261 from cston/bp-vb

VisualBasic function breakpoint binding
......@@ -99,6 +99,7 @@
<InternalsVisibleToTest Include="Roslyn.Compilers.VisualBasic.Semantic.UnitTests" />
<InternalsVisibleToTest Include="Roslyn.Compilers.VisualBasic.Symbol.UnitTests" />
<InternalsVisibleToTest Include="Roslyn.Compilers.VisualBasic.Syntax.UnitTests" />
<InternalsVisibleToTest Include="Roslyn.ExpressionEvaluator.FunctionResolver.UnitTests" />
<InternalsVisibleToTest Include="Roslyn.ExpressionEvaluator.VisualBasic.ExpressionCompiler.UnitTests" />
<InternalsVisibleToTest Include="Roslyn.ExpressionEvaluator.VisualBasic.ResultProvider.UnitTests" />
<InternalsVisibleToTest Include="Microsoft.CodeAnalysis.VisualBasic.Scripting.UnitTests" />
......
......@@ -819,6 +819,123 @@ public void TupleElementNames_IncorrectCount()
}
}
// Different number of tuple elements
// in value and declared type.
[WorkItem(13420, "https://github.com/dotnet/roslyn/issues/13420")]
[Fact(Skip = "13420")]
public void ValueAndTypeDifferentElementCount()
{
var source =
@"class C<T>
{
}
struct S<T, U>
{
}
class C
{
(object One, System.ValueType Two, (int A, int B) Three) F1 = ((1, 2), (3, 4), (5, 6)); // base types
((int A, int B)[] One, (int C, int D)[] Two, (int E, int F) Three) F2 = (null, new[] { (1, 2), (3, 4) }, (5, 6)); // arrays
((int A, int B)? One, (int C, int D)? Two) F3 = (null, (1, 2)); // Nullable<T>
(C<(int A, int B)> One, C<(int C, int D)> Two, (int E, int F) Three) F4 = (null, new C<(int, int)>(), (5, 6)); // class type arguments
(S<(int A, (int B, int C) D), object>? One, S<object, (int E, int F)>? Two, (int G, int H) Three) F5 = (null, new S<object, (int, int)>(), (5, 6)); // struct type arguments
}";
var assembly0 = GenerateTupleAssembly();
var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference();
var compilation1 = CSharpTestBaseBase.CreateCompilationWithMscorlib45AndCSruntime(source, additionalRefs: new[] { reference0 });
var assembly1 = compilation1.EmitToArray();
var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1)));
using (runtime.Load())
{
var type = runtime.GetType("C");
var value = type.Instantiate();
var evalResult = FormatResult("o", value);
var children = GetChildren(evalResult);
Verify(children,
EvalResult(
"F1",
"(One: (1, 2), Two: (3, 4), Three: (A: 5, B: 6))",
"(object One, System.ValueType Two, (int A, int B) Three)",
"o.F1",
DkmEvaluationResultFlags.Expandable),
EvalResult(
"F2",
"(One: null, Two: {(int, int)[2]}, Three: (E: 5, F: 6))",
"((int A, int B)[] One, (int C, int D)[] Two, (int E, int F) Three)",
"o.F2",
DkmEvaluationResultFlags.Expandable),
EvalResult(
"F3",
"(One: null, Two: (C: 1, D: 2))",
"((int A, int B)? One, (int C, int D)? Two)",
"o.F3",
DkmEvaluationResultFlags.Expandable),
EvalResult(
"F4",
"(One: null, Two: {C<(int, int)>}, Three: (E: 5, F: 6))",
"(C<(int A, int B)> One, C<(int C, int D)> Two, (int E, int F) Three)",
"o.F4",
DkmEvaluationResultFlags.Expandable),
EvalResult(
"F5",
"(One: null, Two: {S<object, (int, int)>}, Three: (G: 5, H: 6))",
"(S<(int A, (int B, int C) D), object>? One, S<object, (int E, int F)>? Two, (int G, int H) Three)",
"o.F5",
DkmEvaluationResultFlags.Expandable));
}
}
[WorkItem(13420, "https://github.com/dotnet/roslyn/issues/13420")]
[Fact(Skip = "13420")]
public void ValueAndTypeDifferentElementCount_LongTuple()
{
var source =
@"class C
{
(
object One,
object Two,
(int A, int B) Three,
(int C, int D) Four,
(int E, int F)[] Five,
(int G, int H)[] Six,
(int I, int J)? Seven,
(int K, int L)? Eight,
object Nine
) F =
(
One: null,
Two: (M: 21, N: 22),
Three: (31, 32),
Four: (41, 42),
Five: new[] { (71, 72), (73, 74) },
Six: null,
Seven: null,
Eight: (61, 62),
Nine: (O: 91, P: 92)
);
}";
var assembly0 = GenerateTupleAssembly();
var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference();
var compilation1 = CSharpTestBaseBase.CreateCompilationWithMscorlib45AndCSruntime(source, additionalRefs: new[] { reference0 });
var assembly1 = compilation1.EmitToArray();
var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1)));
using (runtime.Load())
{
var type = runtime.GetType("C");
var value = type.Instantiate();
var evalResult = FormatResult("o", value);
var children = GetChildren(evalResult);
Verify(children,
EvalResult(
"F",
"(One: null, Two: (21, 22), Three: (A: 31, B: 32), Four: (C: 41, D: 42), Five: {(int, int)[2]}, Six: null, Seven: null, Eight: (K: 61, L: 62), Nine: (91, 92))",
"(object One, object Two, (int A, int B) Three, (int C, int D) Four, (int E, int F)[] Five, (int G, int H)[] Six, (int I, int J)? Seven, (int K, int L)? Eight, object Nine)",
"o.F",
DkmEvaluationResultFlags.Expandable));
}
}
[Fact]
public void InvalidElementName()
{
......
......@@ -2,6 +2,7 @@
using System;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
using Microsoft.VisualStudio.Debugger.Evaluation;
using Microsoft.VisualStudio.Debugger.FunctionResolution;
namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
......@@ -17,5 +18,9 @@ internal override RequestSignature GetParsedSignature(DkmRuntimeFunctionResoluti
{
return MemberSignatureParser.Parse(request.FunctionName);
}
internal override bool IgnoreCase => false;
internal override Guid LanguageId => DkmLanguageId.CSharp;
}
}
......@@ -42,11 +42,6 @@ private MemberSignatureParser(ImmutableArray<Token> tokens)
private Token CurrentToken => _tokens[_tokenIndex];
private Token PeekToken(int offset)
{
return _tokens[_tokenIndex + offset];
}
private Token EatToken()
{
var token = CurrentToken;
......@@ -281,11 +276,6 @@ private ImmutableArray<ParameterSignature> ParseParameters()
}
}
private static bool IsKeyword(string text)
{
return SyntaxFacts.GetKeywordKind(text) != SyntaxKind.None;
}
private static SpecialType GetSpecialType(SyntaxKind kind)
{
switch (kind)
......@@ -327,7 +317,6 @@ private static SpecialType GetSpecialType(SyntaxKind kind)
}
}
private static Exception InvalidSignature()
{
return new InvalidSignatureException();
......
......@@ -25,7 +25,6 @@ private enum TokenKind
End,
Identifier,
Keyword,
ColonColon,
}
[DebuggerDisplay("{GetDebuggerDisplay(), nq}")]
......
......@@ -3,7 +3,6 @@
using Microsoft.VisualStudio.Debugger;
using Microsoft.VisualStudio.Debugger.Clr;
using Microsoft.VisualStudio.Debugger.ComponentInterfaces;
using Microsoft.VisualStudio.Debugger.Evaluation;
using Microsoft.VisualStudio.Debugger.FunctionResolution;
using Microsoft.VisualStudio.Debugger.Symbols;
using System;
......@@ -28,17 +27,6 @@ void IDkmRuntimeFunctionResolver.EnableResolution(DkmRuntimeFunctionResolutionRe
return;
}
var languageId = request.CompilerId.LanguageId;
if (languageId == DkmLanguageId.MethodId)
{
return;
}
else if (languageId != default(Guid))
{
// Verify module matches language before binding
// (see https://github.com/dotnet/roslyn/issues/15119).
}
EnableResolution(request.Process, request, OnFunctionResolved(workList));
}
......@@ -85,7 +73,7 @@ private void OnModuleLoad(DkmModuleInstance moduleInstance, DkmWorkList workList
OnModuleLoad(module.Process, module, OnFunctionResolved(workList));
}
internal override bool ShouldEnableFunctionResolver(DkmProcess process)
internal sealed override bool ShouldEnableFunctionResolver(DkmProcess process)
{
var dataItem = process.GetDataItem<FunctionResolverDataItem>();
if (dataItem == null)
......@@ -97,7 +85,7 @@ internal override bool ShouldEnableFunctionResolver(DkmProcess process)
return dataItem.Enabled;
}
internal override IEnumerable<DkmClrModuleInstance> GetAllModules(DkmProcess process)
internal sealed override IEnumerable<DkmClrModuleInstance> GetAllModules(DkmProcess process)
{
foreach (var runtimeInstance in process.GetRuntimeInstances())
{
......@@ -118,12 +106,12 @@ internal override IEnumerable<DkmClrModuleInstance> GetAllModules(DkmProcess pro
}
}
internal override string GetModuleName(DkmClrModuleInstance module)
internal sealed override string GetModuleName(DkmClrModuleInstance module)
{
return module.Name;
}
internal override MetadataReader GetModuleMetadata(DkmClrModuleInstance module)
internal sealed override MetadataReader GetModuleMetadata(DkmClrModuleInstance module)
{
uint length;
IntPtr ptr;
......@@ -142,16 +130,21 @@ internal override MetadataReader GetModuleMetadata(DkmClrModuleInstance module)
}
}
internal override DkmRuntimeFunctionResolutionRequest[] GetRequests(DkmProcess process)
internal sealed override DkmRuntimeFunctionResolutionRequest[] GetRequests(DkmProcess process)
{
return process.GetRuntimeFunctionResolutionRequests();
}
internal override string GetRequestModuleName(DkmRuntimeFunctionResolutionRequest request)
internal sealed override string GetRequestModuleName(DkmRuntimeFunctionResolutionRequest request)
{
return request.ModuleName;
}
internal sealed override Guid GetLanguageId(DkmRuntimeFunctionResolutionRequest request)
{
return request.CompilerId.LanguageId;
}
private static OnFunctionResolvedDelegate<DkmClrModuleInstance, DkmRuntimeFunctionResolutionRequest> OnFunctionResolved(DkmWorkList workList)
{
return (DkmClrModuleInstance module,
......
......@@ -47,7 +47,13 @@
<Compile Include="RequestSignature.cs" />
<Compile Include="SpecialTypeExtensions.cs" />
<Compile Include="TypeSignature.cs" />
<VsdConfigXml Include="FunctionResolver.vsdconfigxml" />
<Compile Include="VisualBasic\Keywords.cs" />
<Compile Include="VisualBasic\MemberSignatureParser.cs" />
<Compile Include="VisualBasic\Scanner.cs" />
<Compile Include="VisualBasic\SyntaxKind.cs" />
<Compile Include="VisualBasic\VisualBasicFunctionResolver.cs" />
<VsdConfigXml Include="CSharp\FunctionResolver.vsdconfigxml" />
<VsdConfigXml Include="VisualBasic\FunctionResolver.vsdconfigxml" />
</ItemGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\Concord\Concord.csproj">
......
......@@ -18,9 +18,17 @@ internal abstract class FunctionResolverBase<TProcess, TModule, TRequest>
internal abstract TRequest[] GetRequests(TProcess process);
internal abstract string GetRequestModuleName(TRequest request);
internal abstract RequestSignature GetParsedSignature(TRequest request);
internal abstract bool IgnoreCase { get; }
internal abstract Guid GetLanguageId(TRequest request);
internal abstract Guid LanguageId { get; }
internal void EnableResolution(TProcess process, TRequest request, OnFunctionResolvedDelegate<TModule, TRequest> onFunctionResolved)
{
if (!ShouldHandleRequest(request))
{
return;
}
var moduleName = GetRequestModuleName(request);
var signature = GetParsedSignature(request);
if (signature == null)
......@@ -49,7 +57,7 @@ internal void EnableResolution(TProcess process, TRequest request, OnFunctionRes
{
continue;
}
var resolver = new MetadataResolver<TProcess, TModule, TRequest>(process, module, reader, onFunctionResolved);
var resolver = CreateMetadataResolver(process, module, reader, onFunctionResolved);
resolver.Resolve(request, signature);
}
}
......@@ -66,6 +74,11 @@ internal void OnModuleLoad(TProcess process, TModule module, OnFunctionResolvedD
foreach (var request in requests)
{
if (!ShouldHandleRequest(request))
{
continue;
}
var moduleName = GetRequestModuleName(request);
if (!ShouldModuleHandleRequest(module, moduleName))
{
......@@ -85,13 +98,32 @@ internal void OnModuleLoad(TProcess process, TModule module, OnFunctionResolvedD
{
return;
}
resolver = new MetadataResolver<TProcess, TModule, TRequest>(process, module, reader, onFunctionResolved);
resolver = CreateMetadataResolver(process, module, reader, onFunctionResolved);
}
resolver.Resolve(request, signature);
}
}
private MetadataResolver<TProcess, TModule, TRequest> CreateMetadataResolver(
TProcess process,
TModule module,
MetadataReader reader,
OnFunctionResolvedDelegate<TModule, TRequest> onFunctionResolved)
{
return new MetadataResolver<TProcess, TModule, TRequest>(process, module, reader, IgnoreCase, onFunctionResolved);
}
private bool ShouldHandleRequest(TRequest request)
{
var languageId = GetLanguageId(request);
if (languageId == Guid.Empty)
{
return true;
}
return languageId == LanguageId;
}
private bool ShouldModuleHandleRequest(TModule module, string moduleName)
{
if (string.IsNullOrEmpty(moduleName))
......
......@@ -18,22 +18,25 @@ internal sealed class MetadataResolver<TProcess, TModule, TRequest>
where TModule : class
where TRequest : class
{
private static readonly StringComparer s_stringComparer = StringComparer.Ordinal;
private readonly TProcess _process;
private readonly TModule _module;
private readonly MetadataReader _reader;
private readonly StringComparer _stringComparer; // for comparing strings
private readonly bool _ignoreCase; // for comparing strings to strings represented with StringHandles
private readonly OnFunctionResolvedDelegate<TModule, TRequest> _onFunctionResolved;
internal MetadataResolver(
TProcess process,
TModule module,
MetadataReader reader,
bool ignoreCase,
OnFunctionResolvedDelegate<TModule, TRequest> onFunctionResolved)
{
_process = process;
_module = module;
_reader = reader;
_stringComparer = ignoreCase ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal;
_ignoreCase = ignoreCase;
_onFunctionResolved = onFunctionResolved;
}
......@@ -158,7 +161,7 @@ private bool MatchesNamespace(TypeDefinition typeDef, Name signature)
return false;
}
var part = parts[index];
if (!s_stringComparer.Equals(qualifiedName.Name, part))
if (!_stringComparer.Equals(qualifiedName.Name, part))
{
return false;
}
......@@ -171,7 +174,7 @@ private bool MatchesNamespace(TypeDefinition typeDef, Name signature)
private bool MatchesTypeName(TypeDefinition typeDef, string name)
{
var typeName = RemoveAritySeparatorIfAny(_reader.GetString(typeDef.Name));
return s_stringComparer.Equals(typeName, name);
return _stringComparer.Equals(typeName, name);
}
private bool MatchesMethod(
......@@ -186,7 +189,7 @@ private bool MatchesTypeName(TypeDefinition typeDef, string name)
{
if ((methodDef.Attributes & MethodAttributes.RTSpecialName) != 0)
{
if (!_reader.StringComparer.Equals(methodDef.Name, ".ctor"))
if (!_reader.StringComparer.Equals(methodDef.Name, ".ctor", ignoreCase: false))
{
// Unhandled special name.
return false;
......@@ -196,7 +199,7 @@ private bool MatchesTypeName(TypeDefinition typeDef, string name)
return false;
}
}
else if (!_reader.StringComparer.Equals(methodDef.Name, methodName))
else if (!_reader.StringComparer.Equals(methodDef.Name, methodName, _ignoreCase))
{
return false;
}
......@@ -220,7 +223,7 @@ private bool MatchesTypeName(TypeDefinition typeDef, string name)
int containingArity,
ImmutableArray<ParameterSignature> propertyParameters)
{
if (!_reader.StringComparer.Equals(propertyDef.Name, propertyName))
if (!_reader.StringComparer.Equals(propertyDef.Name, propertyName, _ignoreCase))
{
return false;
}
......@@ -319,14 +322,14 @@ private static bool MatchesTypeParameterCount(ImmutableArray<string> typeArgumen
}
// parameterA from string signature, parameterB from metadata.
private static bool MatchesParameter(ParameterSignature parameterA, ParameterSignature parameterB)
private bool MatchesParameter(ParameterSignature parameterA, ParameterSignature parameterB)
{
return MatchesType(parameterA.Type, parameterB.Type) &&
parameterA.IsByRef == parameterB.IsByRef;
}
// typeA from string signature, typeB from metadata.
private static bool MatchesType(TypeSignature typeA, TypeSignature typeB)
private bool MatchesType(TypeSignature typeA, TypeSignature typeB)
{
if (typeA.Kind != typeB.Kind)
{
......@@ -350,7 +353,7 @@ private static bool MatchesType(TypeSignature typeA, TypeSignature typeB)
// string signature but still considered a match
// (e.g.: "B<U>.C" should match N.A<T>.B<U>.C).
return (qualifiedA.Qualifier == null || (qualifiedB.Qualifier != null && MatchesType(qualifiedA.Qualifier, qualifiedB.Qualifier))) &&
s_stringComparer.Equals(qualifiedA.Name, qualifiedB.Name);
_stringComparer.Equals(qualifiedA.Name, qualifiedB.Name);
}
case TypeSignatureKind.ArrayType:
{
......
......@@ -39,6 +39,7 @@ internal static QualifiedTypeSignature GetTypeSignature(this SpecialType type)
builder.Add(SpecialType.System_UIntPtr, new QualifiedTypeSignature(systemNamespace, "UIntPtr"));
builder.Add(SpecialType.System_TypedReference, new QualifiedTypeSignature(systemNamespace, "TypedReference"));
builder.Add(SpecialType.System_Nullable_T, new QualifiedTypeSignature(systemNamespace, "Nullable"));
builder.Add(SpecialType.System_DateTime, new QualifiedTypeSignature(systemNamespace, "DateTime"));
return builder.ToImmutable();
}
}
......
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-->
<Configuration xmlns="http://schemas.microsoft.com/vstudio/vsdconfig/2008">
<DefineGuid Name="VisualBasicFunctionResolverId" Value="5901F6C2-5681-4371-8DF5-143821E1E4A1"/>
<ManagedComponent
ComponentId="VisualBasicFunctionResolverId"
ComponentLevel="65100"
Synchronized="true"
AssemblyName="Microsoft.CodeAnalysis.ExpressionEvaluator.FunctionResolver">
<Class Name="Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator.VisualBasicFunctionResolver">
<Implements>
<InterfaceGroup Priority="Normal">
<Filter>
<LanguageId RequiredValue="DkmLanguageId.VB"/>
<BaseDebugMonitorId RequiredValue="DkmBaseDebugMonitorId.InProcessManagedNativeInterop"/>
<BaseDebugMonitorId RequiredValue="DkmBaseDebugMonitorId.ClrVirtualMachine"/>
</Filter>
<Interface Name="IDkmRuntimeFunctionResolver"/>
</InterfaceGroup>
<InterfaceGroup CallOnlyWhenLoaded="true" Priority="Normal">
<Filter>
<RuntimeId RequiredValue="DkmRuntimeId.Clr"/>
<RuntimeId RequiredValue="DkmRuntimeId.ClrNativeCompilation"/>
</Filter>
<Interface Name="IDkmModuleInstanceLoadNotification"/>
<Interface Name="IDkmModuleInstanceUnloadNotification"/>
<Interface Name="IDkmModuleModifiedNotification"/>
<Interface Name="IDkmModuleSymbolsLoadedNotification"/>
</InterfaceGroup>
</Implements>
</Class>
</ManagedComponent>
</Configuration>
\ No newline at end of file
// 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.Immutable;
namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
{
internal sealed partial class MemberSignatureParser
{
// From SyntaxFacts.GetReservedKeywordKinds(). (See
// VisualBasicParsingTests.Keywords() which verifies the lists are in sync.)
private static ImmutableHashSet<string> GetKeywords(StringComparer comparer)
{
return ImmutableHashSet.CreateRange(
comparer,
new[]
{
"AddressOf",
"AddHandler",
"Alias",
"And",
"AndAlso",
"As",
"Boolean",
"ByRef",
"Byte",
"ByVal",
"Call",
"Case",
"Catch",
"CBool",
"CByte",
"CChar",
"CDate",
"CDec",
"CDbl",
"Char",
"CInt",
"Class",
"CLng",
"CObj",
"Const",
"Continue",
"CSByte",
"CShort",
"CSng",
"CStr",
"CType",
"CUInt",
"CULng",
"CUShort",
"Date",
"Decimal",
"Declare",
"Default",
"Delegate",
"Dim",
"DirectCast",
"Do",
"Double",
"Each",
"Else",
"ElseIf",
"End",
"Enum",
"Erase",
"Error",
"Event",
"Exit",
"False",
"Finally",
"For",
"Friend",
"Function",
"Get",
"GetType",
"GetXmlNamespace",
"Global",
"GoTo",
"Handles",
"If",
"Implements",
"Imports",
"In",
"Inherits",
"Integer",
"Interface",
"Is",
"IsNot",
"Let",
"Lib",
"Like",
"Long",
"Loop",
"Me",
"Mod",
"Module",
"MustInherit",
"MustOverride",
"MyBase",
"MyClass",
"NameOf",
"Namespace",
"Narrowing",
"Next",
"New",
"Not",
"Nothing",
"NotInheritable",
"NotOverridable",
"Object",
"Of",
"On",
"Operator",
"Option",
"Optional",
"Or",
"OrElse",
"Overloads",
"Overridable",
"Overrides",
"ParamArray",
"Partial",
"Private",
"Property",
"Protected",
"Public",
"RaiseEvent",
"ReadOnly",
"ReDim",
"REM",
"RemoveHandler",
"Resume",
"Return",
"SByte",
"Select",
"Set",
"Shadows",
"Shared",
"Short",
"Single",
"Static",
"Step",
"Stop",
"String",
"Structure",
"Sub",
"SyncLock",
"Then",
"Throw",
"To",
"True",
"Try",
"TryCast",
"TypeOf",
"UInteger",
"ULong",
"UShort",
"Using",
"When",
"While",
"Widening",
"With",
"WithEvents",
"WriteOnly",
"Xor",
"EndIf",
"Gosub",
"Variant",
"Wend",
});
}
}
}
// 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 Microsoft.CodeAnalysis.ExpressionEvaluator;
using System;
using System.Collections.Immutable;
using System.Diagnostics;
namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
{
internal sealed partial class MemberSignatureParser
{
internal static readonly StringComparer StringComparer = StringComparer.OrdinalIgnoreCase;
internal static readonly ImmutableHashSet<string> Keywords = GetKeywords(StringComparer);
internal static readonly ImmutableDictionary<string, SyntaxKind> KeywordKinds = GetKeywordKinds(StringComparer);
internal static RequestSignature Parse(string signature)
{
var scanner = new Scanner(signature);
var builder = ImmutableArray.CreateBuilder<Token>();
Token token;
do
{
scanner.MoveNext();
token = scanner.CurrentToken;
builder.Add(token);
} while (token.Kind != TokenKind.End);
var parser = new MemberSignatureParser(builder.ToImmutable());
try
{
return parser.Parse();
}
catch (InvalidSignatureException)
{
return null;
}
}
private readonly ImmutableArray<Token> _tokens;
private int _tokenIndex;
private MemberSignatureParser(ImmutableArray<Token> tokens)
{
_tokens = tokens;
_tokenIndex = 0;
}
private Token CurrentToken => _tokens[_tokenIndex];
private Token PeekToken(int offset)
{
return _tokens[_tokenIndex + offset];
}
private Token EatToken()
{
var token = CurrentToken;
Debug.Assert(token.Kind != TokenKind.End);
_tokenIndex++;
return token;
}
private RequestSignature Parse()
{
var methodName = ParseName();
var parameters = default(ImmutableArray<ParameterSignature>);
if (CurrentToken.Kind == TokenKind.OpenParen)
{
parameters = ParseParameters();
}
if (CurrentToken.Kind != TokenKind.End)
{
throw InvalidSignature();
}
return new RequestSignature(methodName, parameters);
}
private Name ParseName()
{
Name signature = null;
while (true)
{
switch (CurrentToken.Kind)
{
case TokenKind.Identifier:
break;
case TokenKind.Keyword:
if (signature == null)
{
throw InvalidSignature();
}
break;
default:
throw InvalidSignature();
}
var name = EatToken().Text;
signature = new QualifiedName(signature, name);
if (IsStartOfTypeArguments())
{
var typeParameters = ParseTypeParameters();
signature = new GenericName((QualifiedName)signature, typeParameters);
}
if (CurrentToken.Kind != TokenKind.Dot)
{
return signature;
}
EatToken();
}
}
private ImmutableArray<string> ParseTypeParameters()
{
Debug.Assert(IsStartOfTypeArguments());
EatToken();
EatToken();
var builder = ImmutableArray.CreateBuilder<string>();
while (true)
{
if (CurrentToken.Kind != TokenKind.Identifier)
{
throw InvalidSignature();
}
var name = EatToken().Text;
builder.Add(name);
switch (CurrentToken.Kind)
{
case TokenKind.CloseParen:
EatToken();
return builder.ToImmutable();
case TokenKind.Comma:
EatToken();
break;
default:
throw InvalidSignature();
}
}
}
private TypeSignature ParseTypeName()
{
TypeSignature signature = null;
while (true)
{
switch (CurrentToken.Kind)
{
case TokenKind.Identifier:
{
var token = EatToken();
var name = token.Text;
signature = new QualifiedTypeSignature(signature, name);
}
break;
case TokenKind.Keyword:
if (signature == null)
{
// Expand special type keywords (Object, Integer, etc.) to qualified names.
// This is only done for the first identifier in a qualified name.
var specialType = GetSpecialType(CurrentToken.KeywordKind);
if (specialType != SpecialType.None)
{
EatToken();
signature = specialType.GetTypeSignature();
Debug.Assert(signature != null);
}
if (signature == null)
{
throw InvalidSignature();
}
}
else
{
var token = EatToken();
var name = token.Text;
signature = new QualifiedTypeSignature(signature, name);
}
break;
default:
throw InvalidSignature();
}
if (IsStartOfTypeArguments())
{
var typeArguments = ParseTypeArguments();
signature = new GenericTypeSignature((QualifiedTypeSignature)signature, typeArguments);
}
if (CurrentToken.Kind != TokenKind.Dot)
{
return signature;
}
EatToken();
}
}
private ImmutableArray<TypeSignature> ParseTypeArguments()
{
Debug.Assert(IsStartOfTypeArguments());
EatToken();
EatToken();
var builder = ImmutableArray.CreateBuilder<TypeSignature>();
while (true)
{
var name = ParseType();
builder.Add(name);
switch (CurrentToken.Kind)
{
case TokenKind.CloseParen:
EatToken();
return builder.ToImmutable();
case TokenKind.Comma:
EatToken();
break;
default:
throw InvalidSignature();
}
}
}
private TypeSignature ParseType()
{
TypeSignature type = ParseTypeName();
while (true)
{
switch (CurrentToken.Kind)
{
case TokenKind.OpenParen:
EatToken();
int rank = 1;
while (CurrentToken.Kind == TokenKind.Comma)
{
EatToken();
rank++;
}
if (CurrentToken.Kind != TokenKind.CloseParen)
{
throw InvalidSignature();
}
EatToken();
type = new ArrayTypeSignature(type, rank);
break;
case TokenKind.QuestionMark:
EatToken();
type = new GenericTypeSignature(
SpecialType.System_Nullable_T.GetTypeSignature(),
ImmutableArray.Create(type));
break;
default:
return type;
}
}
}
private bool IsStartOfTypeArguments()
{
return CurrentToken.Kind == TokenKind.OpenParen &&
PeekToken(1).KeywordKind == SyntaxKind.OfKeyword;
}
private enum ParameterModifier
{
None,
ByVal,
ByRef,
}
private ParameterModifier ParseParameterModifier()
{
var modifier = ParameterModifier.None;
while (true)
{
var m = ParameterModifier.None;
switch (CurrentToken.KeywordKind)
{
case SyntaxKind.ByValKeyword:
m = ParameterModifier.ByVal;
break;
case SyntaxKind.ByRefKeyword:
m = ParameterModifier.ByRef;
break;
default:
return modifier;
}
if (modifier != ParameterModifier.None)
{
// Duplicate modifiers.
throw InvalidSignature();
}
modifier = m;
EatToken();
}
}
private ImmutableArray<ParameterSignature> ParseParameters()
{
Debug.Assert(CurrentToken.Kind == TokenKind.OpenParen);
EatToken();
if (CurrentToken.Kind == TokenKind.CloseParen)
{
EatToken();
return ImmutableArray<ParameterSignature>.Empty;
}
var builder = ImmutableArray.CreateBuilder<ParameterSignature>();
while (true)
{
var modifier = ParseParameterModifier();
var parameterType = ParseType();
builder.Add(new ParameterSignature(parameterType, isByRef: modifier == ParameterModifier.ByRef));
switch (CurrentToken.Kind)
{
case TokenKind.CloseParen:
EatToken();
return builder.ToImmutable();
case TokenKind.Comma:
EatToken();
break;
default:
throw InvalidSignature();
}
}
}
private static SpecialType GetSpecialType(SyntaxKind kind)
{
switch (kind)
{
case SyntaxKind.BooleanKeyword:
return SpecialType.System_Boolean;
case SyntaxKind.CharKeyword:
return SpecialType.System_Char;
case SyntaxKind.SByteKeyword:
return SpecialType.System_SByte;
case SyntaxKind.ByteKeyword:
return SpecialType.System_Byte;
case SyntaxKind.ShortKeyword:
return SpecialType.System_Int16;
case SyntaxKind.UShortKeyword:
return SpecialType.System_UInt16;
case SyntaxKind.IntegerKeyword:
return SpecialType.System_Int32;
case SyntaxKind.UIntegerKeyword:
return SpecialType.System_UInt32;
case SyntaxKind.LongKeyword:
return SpecialType.System_Int64;
case SyntaxKind.ULongKeyword:
return SpecialType.System_UInt64;
case SyntaxKind.SingleKeyword:
return SpecialType.System_Single;
case SyntaxKind.DoubleKeyword:
return SpecialType.System_Double;
case SyntaxKind.StringKeyword:
return SpecialType.System_String;
case SyntaxKind.ObjectKeyword:
return SpecialType.System_Object;
case SyntaxKind.DecimalKeyword:
return SpecialType.System_Decimal;
case SyntaxKind.DateKeyword:
return SpecialType.System_DateTime;
default:
return SpecialType.None;
}
}
private static Exception InvalidSignature()
{
return new InvalidSignatureException();
}
private sealed class InvalidSignatureException : Exception
{
}
}
}
// 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 Roslyn.Utilities;
using System;
using System.Diagnostics;
namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
{
internal sealed partial class MemberSignatureParser
{
private enum TokenKind
{
OpenParen = '(',
CloseParen = ')',
Dot = '.',
Comma = ',',
QuestionMark = '?',
Start = char.MaxValue + 1,
End,
Identifier,
Keyword,
}
[DebuggerDisplay("{GetDebuggerDisplay(), nq}")]
private struct Token
{
internal readonly TokenKind Kind;
internal readonly string Text;
internal readonly SyntaxKind KeywordKind;
internal Token(TokenKind kind, string text = null, SyntaxKind keywordKind = SyntaxKind.None)
{
Kind = kind;
Text = text;
KeywordKind = keywordKind;
}
private string GetDebuggerDisplay()
{
return (Text == null) ?
Kind.ToString() :
$"{Kind}: \"{Text}\"";
}
}
private sealed class Scanner
{
private readonly string _text;
private int _offset;
private Token _currentToken;
internal Scanner(string text)
{
_text = text;
_offset = 0;
_currentToken = default(Token);
}
internal Token CurrentToken
{
get
{
if (_currentToken.Kind == TokenKind.Start)
{
throw new InvalidOperationException();
}
return _currentToken;
}
}
internal void MoveNext()
{
_currentToken = Scan();
}
private Token Scan()
{
int length = _text.Length;
while (_offset < length && char.IsWhiteSpace(_text[_offset]))
{
_offset++;
}
if (_offset == length)
{
return new Token(TokenKind.End);
}
int n = ScanIdentifier();
if (n > 0)
{
var text = _text.Substring(_offset, n);
_offset += n;
if (Keywords.Contains(text))
{
var keywordKind = SyntaxKind.None;
KeywordKinds.TryGetValue(text, out keywordKind);
return new Token(TokenKind.Keyword, text, keywordKind);
}
return new Token(TokenKind.Identifier, text);
}
var c = _text[_offset++];
if (c == '[')
{
n = ScanIdentifier();
if (n > 0 && _offset + n < length && _text[_offset + n] == ']')
{
// A verbatim identifier. Treat the '[' and ']' as part
// of the token, but not part of the text.
var text = _text.Substring(_offset, n);
_offset += n + 1;
return new Token(TokenKind.Identifier, text);
}
}
return new Token((TokenKind)c);
}
// Returns the number of characters in the
// identifier starting at the current offset.
private int ScanIdentifier()
{
int length = _text.Length - _offset;
if (length > 0 && UnicodeCharacterUtilities.IsIdentifierStartCharacter(_text[_offset]))
{
int n = 1;
while (n < length && UnicodeCharacterUtilities.IsIdentifierPartCharacter(_text[_offset + n]))
{
n++;
}
return n;
}
return 0;
}
}
}
}
// 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.Immutable;
namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
{
internal sealed partial class MemberSignatureParser
{
// A subset of the VB compiler SyntaxKind enum, containing
// just those values recognized by the signature parser.
internal enum SyntaxKind
{
None,
OfKeyword,
ByValKeyword,
ByRefKeyword,
BooleanKeyword,
CharKeyword,
SByteKeyword,
ByteKeyword,
ShortKeyword,
UShortKeyword,
IntegerKeyword,
UIntegerKeyword,
LongKeyword,
ULongKeyword,
SingleKeyword,
DoubleKeyword,
StringKeyword,
ObjectKeyword,
DecimalKeyword,
DateKeyword,
}
private static ImmutableDictionary<string, SyntaxKind> GetKeywordKinds(StringComparer comparer)
{
var builder = ImmutableDictionary.CreateBuilder<string, SyntaxKind>(comparer);
builder.Add("of", SyntaxKind.OfKeyword);
builder.Add("byval", SyntaxKind.ByValKeyword);
builder.Add("byref", SyntaxKind.ByRefKeyword);
builder.Add("boolean", SyntaxKind.BooleanKeyword);
builder.Add("char", SyntaxKind.CharKeyword);
builder.Add("sbyte", SyntaxKind.SByteKeyword);
builder.Add("byte", SyntaxKind.ByteKeyword);
builder.Add("short", SyntaxKind.ShortKeyword);
builder.Add("ushort", SyntaxKind.UShortKeyword);
builder.Add("integer", SyntaxKind.IntegerKeyword);
builder.Add("uinteger", SyntaxKind.UIntegerKeyword);
builder.Add("long", SyntaxKind.LongKeyword);
builder.Add("ulong", SyntaxKind.ULongKeyword);
builder.Add("single", SyntaxKind.SingleKeyword);
builder.Add("double", SyntaxKind.DoubleKeyword);
builder.Add("string", SyntaxKind.StringKeyword);
builder.Add("object", SyntaxKind.ObjectKeyword);
builder.Add("decimal", SyntaxKind.DecimalKeyword);
builder.Add("date", SyntaxKind.DateKeyword);
return builder.ToImmutable();
}
}
}
// 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 Microsoft.CodeAnalysis.ExpressionEvaluator;
using Microsoft.VisualStudio.Debugger.Evaluation;
using Microsoft.VisualStudio.Debugger.FunctionResolution;
namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
{
[DkmReportNonFatalWatsonException(ExcludeExceptionType = typeof(NotImplementedException)), DkmContinueCorruptingException]
internal sealed class VisualBasicFunctionResolver : FunctionResolver
{
public VisualBasicFunctionResolver()
{
}
internal override RequestSignature GetParsedSignature(DkmRuntimeFunctionResolutionRequest request)
{
return MemberSignatureParser.Parse(request.FunctionName);
}
internal override bool IgnoreCase => true;
internal override Guid LanguageId => DkmLanguageId.VB;
}
}
// 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 Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Roslyn.Test.Utilities;
using System.Collections.Immutable;
using System.Linq;
using Xunit;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator.UnitTests
{
public class CSharpParsingTests : CSharpTestBase
public class CSharpParsingTests : ParsingTestBase
{
[Fact]
public void Parsing()
......@@ -140,6 +136,22 @@ public void ParseErrors()
Assert.Null(MemberSignatureParser.Parse("()"));
Assert.Null(MemberSignatureParser.Parse("<T>"));
Assert.Null(MemberSignatureParser.Parse("1"));
Assert.Null(MemberSignatureParser.Parse("F(C c)"));
Assert.Null(MemberSignatureParser.Parse("F(C c = null)"));
Assert.Null(MemberSignatureParser.Parse("F(C = null)"));
Assert.Null(MemberSignatureParser.Parse("F(params C[])"));
}
// global:: not supported.
[Fact]
public void Global()
{
Assert.Null(MemberSignatureParser.Parse("global:C.F"));
Assert.Null(MemberSignatureParser.Parse("global:"));
Assert.Null(MemberSignatureParser.Parse(":C.F"));
Assert.Null(MemberSignatureParser.Parse("global::C.F"));
Assert.Null(MemberSignatureParser.Parse("global::"));
Assert.Null(MemberSignatureParser.Parse("::C.F"));
}
[Fact]
......@@ -317,102 +329,10 @@ public void EscapedNames()
Assert.Null(MemberSignatureParser.Parse("F<T, @>"));
}
private static RequestSignature SignatureNameOnly(Name name)
{
return new RequestSignature(name, default(ImmutableArray<ParameterSignature>));
}
private static RequestSignature Signature(Name name)
{
return new RequestSignature(name, ImmutableArray<ParameterSignature>.Empty);
}
private static RequestSignature Signature(Name name, params TypeSignature[] parameterTypes)
{
return Signature(name, parameterTypes.Select(t => new ParameterSignature(t, isByRef: false)).ToArray());
}
private static RequestSignature Signature(Name name, params ParameterSignature[] parameters)
{
return new RequestSignature(name, ImmutableArray.CreateRange(parameters));
}
private static QualifiedName Name(string name)
{
return new QualifiedName(null, name);
}
private static GenericName Generic(QualifiedName name, params string[] typeArguments)
{
Assert.True(typeArguments.Length > 0);
return new GenericName(name, ImmutableArray.CreateRange(typeArguments));
}
private static QualifiedName Qualified(Name left, string right)
{
return new QualifiedName(left, right);
}
private static QualifiedTypeSignature Identifier(string name)
{
return new QualifiedTypeSignature(null, name);
}
private static GenericTypeSignature Generic(QualifiedTypeSignature name, params TypeSignature[] typeArguments)
{
Assert.True(typeArguments.Length > 0);
return new GenericTypeSignature(name, ImmutableArray.CreateRange(typeArguments));
}
private static QualifiedTypeSignature Qualified(TypeSignature left, string right)
{
return new QualifiedTypeSignature(left, right);
}
private static QualifiedTypeSignature Qualified(params string[] names)
{
QualifiedTypeSignature signature = null;
foreach (var name in names)
{
signature = new QualifiedTypeSignature(signature, name);
}
return signature;
}
private static ArrayTypeSignature Array(TypeSignature elementType, int rank)
{
return new ArrayTypeSignature(elementType, rank);
}
private static PointerTypeSignature Pointer(TypeSignature pointedAtType)
{
return new PointerTypeSignature(pointedAtType);
}
private static void VerifySignature(string str, RequestSignature expectedSignature)
{
var actualSignature = MemberSignatureParser.Parse(str);
if (expectedSignature == null)
{
Assert.Null(actualSignature);
}
else
{
Assert.NotNull(actualSignature);
Assert.Equal(expectedSignature.MemberName, actualSignature.MemberName, NameComparer.Instance);
if (expectedSignature.Parameters.IsDefault)
{
Assert.True(actualSignature.Parameters.IsDefault);
}
else
{
AssertEx.Equal(
expectedSignature.Parameters,
actualSignature.Parameters,
comparer: ParameterComparer.Instance,
itemInspector: p => p.Type.GetDebuggerDisplay());
}
}
VerifySignature(actualSignature, expectedSignature);
}
}
}
......@@ -18,6 +18,10 @@
<Project>{7a4b2176-7bfd-4b75-a61a-e25a1fdd0a1e}</Project>
<Name>CSharpCompilerTestUtilities.Desktop</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\Compilers\Test\Utilities\VisualBasic\BasicCompilerTestUtilities.vbproj">
<Project>{4371944A-D3BA-4B5B-8285-82E5FFC6D1F8}</Project>
<Name>BasicCompilerTestUtilities</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\Test\Utilities\Portable.FX45\TestUtilities.FX45.csproj">
<Project>{f7712928-1175-47b3-8819-ee086753dee2}</Project>
<Name>TestUtilities.FX45</Name>
......@@ -60,13 +64,17 @@
<ItemGroup>
<Compile Include="CSharpFunctionResolverTests.cs" />
<Compile Include="CSharpParsingTests.cs" />
<Compile Include="FunctionResolverTestBase.cs" />
<Compile Include="Module.cs" />
<Compile Include="NameComparer.cs" />
<Compile Include="ParameterComparer.cs" />
<Compile Include="ParsingTestBase.cs" />
<Compile Include="Process.cs" />
<Compile Include="Request.cs" />
<Compile Include="Resolver.cs" />
<Compile Include="TypeComparer.cs" />
<Compile Include="VisualBasicFunctionResolverTests.cs" />
<Compile Include="VisualBasicParsingTests.cs" />
</ItemGroup>
<ItemGroup>
<None Include="project.json" />
......
// 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 Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Roslyn.Test.Utilities;
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Text;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator.UnitTests
{
public abstract class FunctionResolverTestBase : CSharpTestBase
{
internal static void Resolve(Process process, Resolver resolver, RequestSignature signature, string[] expectedSignatures)
{
var request = new Request(null, signature);
resolver.EnableResolution(process, request);
VerifySignatures(request, expectedSignatures);
}
internal static void VerifySignatures(Request request, params string[] expectedSignatures)
{
var actualSignatures = request.GetResolvedAddresses().Select(a => GetMethodSignature(a.Module, a.Token));
AssertEx.Equal(expectedSignatures, actualSignatures);
}
private static string GetMethodSignature(Module module, int token)
{
var reader = module.GetMetadataInternal();
return GetMethodSignature(reader, MetadataTokens.MethodDefinitionHandle(token));
}
private static string GetMethodSignature(MetadataReader reader, MethodDefinitionHandle handle)
{
var methodDef = reader.GetMethodDefinition(handle);
var builder = new StringBuilder();
var typeDef = reader.GetTypeDefinition(methodDef.GetDeclaringType());
var allTypeParameters = typeDef.GetGenericParameters();
AppendTypeName(builder, reader, typeDef);
builder.Append('.');
builder.Append(reader.GetString(methodDef.Name));
var methodTypeParameters = methodDef.GetGenericParameters();
AppendTypeParameters(builder, DecodeTypeParameters(reader, offset: 0, typeParameters: methodTypeParameters));
var decoder = new MetadataDecoder(
reader,
GetTypeParameterNames(reader, allTypeParameters),
0,
GetTypeParameterNames(reader, methodTypeParameters));
try
{
AppendParameters(builder, decoder.DecodeParameters(methodDef));
}
catch (NotSupportedException)
{
builder.Append("([notsupported])");
}
return builder.ToString();
}
private static ImmutableArray<string> GetTypeParameterNames(MetadataReader reader, GenericParameterHandleCollection handles)
{
return ImmutableArray.CreateRange(handles.Select(h => reader.GetString(reader.GetGenericParameter(h).Name)));
}
private static void AppendTypeName(StringBuilder builder, MetadataReader reader, TypeDefinition typeDef)
{
var declaringTypeHandle = typeDef.GetDeclaringType();
int declaringTypeArity;
if (declaringTypeHandle.IsNil)
{
declaringTypeArity = 0;
var namespaceName = reader.GetString(typeDef.Namespace);
if (!string.IsNullOrEmpty(namespaceName))
{
builder.Append(namespaceName);
builder.Append('.');
}
}
else
{
var declaringType = reader.GetTypeDefinition(declaringTypeHandle);
declaringTypeArity = declaringType.GetGenericParameters().Count;
AppendTypeName(builder, reader, declaringType);
builder.Append('.');
}
var typeName = reader.GetString(typeDef.Name);
int index = typeName.IndexOf('`');
if (index >= 0)
{
typeName = typeName.Substring(0, index);
}
builder.Append(typeName);
AppendTypeParameters(builder, DecodeTypeParameters(reader, declaringTypeArity, typeDef.GetGenericParameters()));
}
private static void AppendTypeParameters(StringBuilder builder, ImmutableArray<string> typeParameters)
{
if (typeParameters.Length > 0)
{
builder.Append('<');
AppendCommaSeparatedList(builder, typeParameters, (b, t) => b.Append(t));
builder.Append('>');
}
}
private static void AppendParameters(StringBuilder builder, ImmutableArray<ParameterSignature> parameters)
{
builder.Append('(');
AppendCommaSeparatedList(builder, parameters, AppendParameter);
builder.Append(')');
}
private static void AppendParameter(StringBuilder builder, ParameterSignature signature)
{
if (signature.IsByRef)
{
builder.Append("ref ");
}
AppendType(builder, signature.Type);
}
private static void AppendType(StringBuilder builder, TypeSignature signature)
{
switch (signature.Kind)
{
case TypeSignatureKind.GenericType:
{
var genericName = (GenericTypeSignature)signature;
AppendType(builder, genericName.QualifiedName);
AppendTypeArguments(builder, genericName.TypeArguments);
}
break;
case TypeSignatureKind.QualifiedType:
{
var qualifiedName = (QualifiedTypeSignature)signature;
var qualifier = qualifiedName.Qualifier;
if (qualifier != null)
{
AppendType(builder, qualifier);
builder.Append('.');
}
builder.Append(qualifiedName.Name);
}
break;
case TypeSignatureKind.ArrayType:
{
var arrayType = (ArrayTypeSignature)signature;
AppendType(builder, arrayType.ElementType);
builder.Append('[');
builder.Append(',', arrayType.Rank - 1);
builder.Append(']');
}
break;
case TypeSignatureKind.PointerType:
AppendType(builder, ((PointerTypeSignature)signature).PointedAtType);
builder.Append('*');
break;
default:
throw new System.NotImplementedException();
}
}
private static void AppendTypeArguments(StringBuilder builder, ImmutableArray<TypeSignature> typeArguments)
{
if (typeArguments.Length > 0)
{
builder.Append('<');
AppendCommaSeparatedList(builder, typeArguments, AppendType);
builder.Append('>');
}
}
private static void AppendCommaSeparatedList<T>(StringBuilder builder, ImmutableArray<T> items, Action<StringBuilder, T> appendItem)
{
bool any = false;
foreach (var item in items)
{
if (any)
{
builder.Append(", ");
}
appendItem(builder, item);
any = true;
}
}
private static ImmutableArray<string> DecodeTypeParameters(MetadataReader reader, int offset, GenericParameterHandleCollection typeParameters)
{
int arity = typeParameters.Count - offset;
Debug.Assert(arity >= 0);
if (arity == 0)
{
return ImmutableArray<string>.Empty;
}
var builder = ImmutableArray.CreateBuilder<string>(arity);
for (int i = 0; i < arity; i++)
{
var handle = typeParameters[offset + i];
var typeParameter = reader.GetGenericParameter(handle);
builder.Add(reader.GetString(typeParameter.Name));
}
return builder.ToImmutable();
}
}
}
// 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 Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Roslyn.Test.Utilities;
using System.Collections.Immutable;
using System.Linq;
using Xunit;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator.UnitTests
{
public abstract class ParsingTestBase : CSharpTestBase
{
internal static RequestSignature SignatureNameOnly(Name name)
{
return new RequestSignature(name, default(ImmutableArray<ParameterSignature>));
}
internal static RequestSignature Signature(Name name)
{
return new RequestSignature(name, ImmutableArray<ParameterSignature>.Empty);
}
internal static RequestSignature Signature(Name name, params TypeSignature[] parameterTypes)
{
return Signature(name, parameterTypes.Select(t => new ParameterSignature(t, isByRef: false)).ToArray());
}
internal static RequestSignature Signature(Name name, params ParameterSignature[] parameters)
{
return new RequestSignature(name, ImmutableArray.CreateRange(parameters));
}
internal static QualifiedName Name(string name)
{
return new QualifiedName(null, name);
}
internal static GenericName Generic(QualifiedName name, params string[] typeArguments)
{
Assert.True(typeArguments.Length > 0);
return new GenericName(name, ImmutableArray.CreateRange(typeArguments));
}
internal static QualifiedName Qualified(Name left, string right)
{
return new QualifiedName(left, right);
}
internal static QualifiedTypeSignature Identifier(string name)
{
return new QualifiedTypeSignature(null, name);
}
internal static GenericTypeSignature Generic(QualifiedTypeSignature name, params TypeSignature[] typeArguments)
{
Assert.True(typeArguments.Length > 0);
return new GenericTypeSignature(name, ImmutableArray.CreateRange(typeArguments));
}
internal static QualifiedTypeSignature Qualified(TypeSignature left, string right)
{
return new QualifiedTypeSignature(left, right);
}
internal static QualifiedTypeSignature Qualified(params string[] names)
{
QualifiedTypeSignature signature = null;
foreach (var name in names)
{
signature = new QualifiedTypeSignature(signature, name);
}
return signature;
}
internal static ArrayTypeSignature Array(TypeSignature elementType, int rank)
{
return new ArrayTypeSignature(elementType, rank);
}
internal static PointerTypeSignature Pointer(TypeSignature pointedAtType)
{
return new PointerTypeSignature(pointedAtType);
}
internal static void VerifySignature(RequestSignature actualSignature, RequestSignature expectedSignature)
{
if (expectedSignature == null)
{
Assert.Null(actualSignature);
}
else
{
Assert.NotNull(actualSignature);
Assert.Equal(expectedSignature.MemberName, actualSignature.MemberName, NameComparer.Instance);
if (expectedSignature.Parameters.IsDefault)
{
Assert.True(actualSignature.Parameters.IsDefault);
}
else
{
AssertEx.Equal(
expectedSignature.Parameters,
actualSignature.Parameters,
comparer: ParameterComparer.Instance,
itemInspector: p => p.Type.GetDebuggerDisplay());
}
}
}
}
}
......@@ -26,15 +26,17 @@ internal sealed class Request
{
private readonly List<Address> _resolvedAddresses;
internal Request(string moduleName, RequestSignature signature)
internal Request(string moduleName, RequestSignature signature, Guid languageId = default(Guid))
{
ModuleName = moduleName;
Signature = signature;
LanguageId = languageId;
_resolvedAddresses = new List<Address>();
}
internal readonly string ModuleName;
internal readonly RequestSignature Signature;
internal readonly Guid LanguageId;
internal void OnFunctionResolved(Module module, int token, int version, int ilOffset)
{
......
......@@ -8,10 +8,22 @@ namespace Microsoft.CodeAnalysis.ExpressionEvaluator.UnitTests
{
internal sealed class Resolver : FunctionResolverBase<Process, Module, Request>
{
internal static readonly Resolver CSharpResolver = CreateFrom(new Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.CSharpFunctionResolver());
internal static readonly Resolver VisualBasicResolver = CreateFrom(new Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator.VisualBasicFunctionResolver());
private readonly bool _ignoreCase;
private readonly Guid _languageId;
private readonly Dictionary<Process, List<Request>> _requests;
internal Resolver()
private static Resolver CreateFrom(FunctionResolver resolver)
{
return new Resolver(resolver.IgnoreCase, resolver.LanguageId);
}
private Resolver(bool ignoreCase, Guid languageId)
{
_ignoreCase = ignoreCase;
_languageId = languageId;
_requests = new Dictionary<Process, List<Request>>();
}
......@@ -72,6 +84,15 @@ internal override RequestSignature GetParsedSignature(Request request)
return request.Signature;
}
internal override bool IgnoreCase => _ignoreCase;
internal override Guid GetLanguageId(Request request)
{
return request.LanguageId;
}
internal override Guid LanguageId => _languageId;
private static void OnFunctionResolved(Module module, Request request, int token, int version, int ilOffset)
{
request.OnFunctionResolved(module, token, version, ilOffset);
......
// 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 Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator;
using Microsoft.VisualStudio.Debugger.Evaluation;
using Roslyn.Test.Utilities;
using System;
using Xunit;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator.UnitTests
{
// Binding is shared between C# and VB, so these tests
// only cover the differences between the languages.
public class VisualBasicFunctionResolverTests : FunctionResolverTestBase
{
/// <summary>
/// Should only handle requests with expected
/// language id or default language id.
/// </summary>
[WorkItem(15119, "https://github.com/dotnet/roslyn/issues/15119")]
[Fact]
public void LanguageId()
{
var source =
@"class C
{
static void F() { }
}";
var bytes = CreateCompilationWithMscorlib(source).EmitToArray();
var resolver = Resolver.VisualBasicResolver;
var csharpLanguageId = Guid.Parse("3f5162f8-07c6-11d3-9053-00c04fa302a1");
var vbLanguageId = Guid.Parse("3a12d0b8-c26c-11d0-b442-00a0244a1dd2");
var cppLanguageId = Guid.Parse("3a12d0b7-c26c-11d0-b442-00a0244a1dd2");
// Module loaded before requests.
var module = new Module(bytes);
using (var process = new Process(module))
{
var requestDefaultId = new Request(null, MemberSignatureParser.Parse("F"), Guid.Empty);
var requestMethodId = new Request(null, MemberSignatureParser.Parse("F"), DkmLanguageId.MethodId);
var requestCSharp = new Request(null, MemberSignatureParser.Parse("F"), csharpLanguageId);
var requestVB = new Request(null, MemberSignatureParser.Parse("F"), vbLanguageId);
var requestCPP = new Request(null, MemberSignatureParser.Parse("F"), cppLanguageId);
resolver.EnableResolution(process, requestDefaultId);
VerifySignatures(requestDefaultId, "C.F()");
resolver.EnableResolution(process, requestMethodId);
VerifySignatures(requestMethodId);
resolver.EnableResolution(process, requestCSharp);
VerifySignatures(requestCSharp);
resolver.EnableResolution(process, requestVB);
VerifySignatures(requestVB, "C.F()");
resolver.EnableResolution(process, requestCPP);
VerifySignatures(requestCPP);
}
// Module loaded after requests.
module = new Module(bytes);
using (var process = new Process())
{
var requestDefaultId = new Request(null, MemberSignatureParser.Parse("F"), Guid.Empty);
var requestMethodId = new Request(null, MemberSignatureParser.Parse("F"), DkmLanguageId.MethodId);
var requestCSharp = new Request(null, MemberSignatureParser.Parse("F"), csharpLanguageId);
var requestVB = new Request(null, MemberSignatureParser.Parse("F"), vbLanguageId);
var requestCPP = new Request(null, MemberSignatureParser.Parse("F"), cppLanguageId);
resolver.EnableResolution(process, requestCPP);
resolver.EnableResolution(process, requestVB);
resolver.EnableResolution(process, requestCSharp);
resolver.EnableResolution(process, requestMethodId);
resolver.EnableResolution(process, requestDefaultId);
process.AddModule(module);
resolver.OnModuleLoad(process, module);
VerifySignatures(requestDefaultId, "C.F()");
VerifySignatures(requestMethodId);
VerifySignatures(requestCSharp);
VerifySignatures(requestVB, "C.F()");
VerifySignatures(requestCPP);
}
}
[Fact]
public void Properties()
{
var source =
@"abstract class A
{
abstract internal object P { get; set; }
}
class B
{
object P { get; set; }
}
class C
{
static object P { get; }
}
class D
{
int P { set { } }
}
interface I
{
object P { get; set; }
}";
var compilation = CreateCompilationWithMscorlib(source);
using (var process = new Process(new Module(compilation.EmitToArray())))
{
var resolver = Resolver.VisualBasicResolver;
Resolve(process, resolver, "P", "B.get_P()", "B.set_P(System.Object)", "C.get_P()", "D.set_P(System.Int32)");
Resolve(process, resolver, "A.P");
Resolve(process, resolver, "B.P", "B.get_P()", "B.set_P(System.Object)");
Resolve(process, resolver, "B.P()");
Resolve(process, resolver, "B.P(Object)");
Resolve(process, resolver, "B.P(Of T)");
Resolve(process, resolver, "C.P", "C.get_P()");
Resolve(process, resolver, "C.P()");
Resolve(process, resolver, "D.P", "D.set_P(System.Int32)");
Resolve(process, resolver, "D.P()");
Resolve(process, resolver, "D.P(Object)");
Resolve(process, resolver, "get_P", "B.get_P()", "C.get_P()");
Resolve(process, resolver, "set_P", "B.set_P(System.Object)", "D.set_P(System.Int32)");
Resolve(process, resolver, "B.get_P()", "B.get_P()");
Resolve(process, resolver, "B.set_P", "B.set_P(System.Object)");
}
}
[Fact]
public void DifferentCase_MethodsAndProperties()
{
var source =
@"class A
{
static void method() { }
static void Method(object o) { }
object property => null;
}
class B
{
static void Method() { }
object Property { get; set; }
}";
var compilation = CreateCompilationWithMscorlib(source);
using (var process = new Process(new Module(compilation.EmitToArray())))
{
var resolver = Resolver.VisualBasicResolver;
Resolve(process, resolver, "method", "A.method()", "A.Method(System.Object)", "B.Method()");
Resolve(process, resolver, "Method", "A.method()", "A.Method(System.Object)", "B.Method()");
Resolve(process, resolver, "[property]", "A.get_property()", "B.get_Property()", "B.set_Property(System.Object)");
Resolve(process, resolver, "[Property]", "A.get_property()", "B.get_Property()", "B.set_Property(System.Object)");
Resolve(process, resolver, "[PROPERTY]", "A.get_property()", "B.get_Property()", "B.set_Property(System.Object)");
Resolve(process, resolver, "GET_PROPERTY", "A.get_property()", "B.get_Property()");
}
}
[Fact]
public void DifferentCase_NamespacesAndTypes()
{
var source =
@"namespace one.two
{
class THREE
{
static void Method(THREE t) { }
}
}
namespace One.Two
{
class Three
{
static void Method(Three t) { }
}
}";
var compilation = CreateCompilationWithMscorlib(source);
using (var process = new Process(new Module(compilation.EmitToArray())))
{
var resolver = Resolver.VisualBasicResolver;
Resolve(process, resolver, "Method", "One.Two.Three.Method(One.Two.Three)", "one.two.THREE.Method(one.two.THREE)");
Resolve(process, resolver, "Three.Method", "One.Two.Three.Method(One.Two.Three)", "one.two.THREE.Method(one.two.THREE)");
Resolve(process, resolver, "three.Method(three)", "One.Two.Three.Method(One.Two.Three)", "one.two.THREE.Method(one.two.THREE)");
Resolve(process, resolver, "THREE.Method(THREE)", "One.Two.Three.Method(One.Two.Three)", "one.two.THREE.Method(one.two.THREE)");
Resolve(process, resolver, "ONE.TWO.THREE.Method", "One.Two.Three.Method(One.Two.Three)", "one.two.THREE.Method(one.two.THREE)");
Resolve(process, resolver, "one.two.three.Method(one.two.three)", "One.Two.Three.Method(One.Two.Three)", "one.two.THREE.Method(one.two.THREE)");
Resolve(process, resolver, "THREE", "One.Two.Three..ctor()", "one.two.THREE..ctor()");
}
}
private static void Resolve(Process process, Resolver resolver, string str, params string[] expectedSignatures)
{
var signature = MemberSignatureParser.Parse(str);
Assert.NotNull(signature);
Resolve(process, resolver, signature, expectedSignatures);
}
}
}
// 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 Microsoft.CodeAnalysis.VisualBasic;
using Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator;
using Roslyn.Test.Utilities;
using System;
using System.Collections.Immutable;
using System.Linq;
using Xunit;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator.UnitTests
{
public class VisualBasicParsingTests : ParsingTestBase
{
// Verify the set of keywords in the parser matches the VB compiler.
[Fact]
public void Keywords()
{
var builder = ImmutableHashSet.CreateBuilder<SyntaxKind>();
// SyntaxFacts.GetReservedKeywordKinds() contains ReferenceKeyword
// although "Reference" should not be considered a keyword.
// (see https://github.com/dotnet/roslyn/issues/15242).
builder.Add(SyntaxKind.ReferenceKeyword);
foreach (var text in MemberSignatureParser.Keywords)
{
var kind = SyntaxFacts.GetKeywordKind(text);
Assert.NotEqual(SyntaxKind.None, kind);
bool added = builder.Add(kind);
Assert.True(added);
}
var actualKeywordKinds = builder.ToImmutable();
var expectedKeywordKinds = ImmutableHashSet.CreateRange(SyntaxFacts.GetReservedKeywordKinds());
AssertEx.SetEqual(actualKeywordKinds, expectedKeywordKinds);
}
// Verify the set of keywords used in the parser are valid.
[Fact]
public void KeywordKinds()
{
// Verify the labels are consistent with the VB compiler.
foreach (var pair in MemberSignatureParser.KeywordKinds)
{
var expectedKind = SyntaxFacts.GetKeywordKind(pair.Key).ToString();
var actualKind = pair.Value.ToString();
Assert.Equal(expectedKind, actualKind);
}
// Verify all values are also in Keywords.
foreach (var keyword in MemberSignatureParser.KeywordKinds.Keys)
{
Assert.True(MemberSignatureParser.Keywords.Contains(keyword));
}
// Verify all values of SyntaxKind are recognized.
const string keywordSuffix = "Keyword";
foreach (var value in typeof(MemberSignatureParser.SyntaxKind).GetEnumValues())
{
var kind = (MemberSignatureParser.SyntaxKind)value;
if (kind == MemberSignatureParser.SyntaxKind.None)
{
continue;
}
var pair = MemberSignatureParser.KeywordKinds.First(p => p.Value == kind);
var kindText = kind.ToString();
Assert.EndsWith(keywordSuffix, kindText);
var expectedText = kindText.Substring(0, kindText.Length - keywordSuffix.Length);
Assert.Equal(expectedText, pair.Key, StringComparer.OrdinalIgnoreCase);
}
}
[Fact]
public void Parsing()
{
// Method name only.
VerifySignature("F",
SignatureNameOnly(
Name("F")));
// Method name and empty parameters.
VerifySignature("F()",
Signature(
Name("F")));
// Method name and parameters.
VerifySignature("F(A, B)",
Signature(
Name("F"),
Identifier("A"),
Identifier("B")));
// Type and method name.
VerifySignature("C.F",
SignatureNameOnly(
Qualified(Name("C"), "F")));
// Qualified type and method name.
VerifySignature("A.B.F",
SignatureNameOnly(
Qualified(
Qualified(
Name("A"),
"B"),
"F")));
// Generic types and method names.
VerifySignature("A(Of T).B(Of U).F(Of V)",
SignatureNameOnly(
Generic(
Qualified(
Generic(
Qualified(
Generic(
Name("A"),
"T"),
"B"),
"U"),
"F"),
"V")));
}
[Fact]
public void Spaces()
{
VerifySignature(" \tC . F ( System.Object\t,object) ",
Signature(
Qualified(Name("C"), "F"),
Qualified("System", "Object"),
Qualified("System", "Object")));
}
[Fact]
public void Arrays()
{
VerifySignature("F(C(,,,))",
Signature(
Name("F"),
Array(
Identifier("C"),
4)));
VerifySignature("F(C(,)())",
Signature(
Name("F"),
Array(
Array(
Identifier("C"),
2),
1)));
VerifySignature("F(C(Of T(,)))",
Signature(
Name("F"),
Generic(
Identifier("C"),
Array(
Identifier("T"),
2))));
}
[Fact]
public void ParseErrors()
{
Assert.Null(MemberSignatureParser.Parse("A(Of)"));
Assert.Null(MemberSignatureParser.Parse("A(Of Of)"));
Assert.Null(MemberSignatureParser.Parse("A(Of T)B"));
Assert.Null(MemberSignatureParser.Parse("A(Of (Of T))"));
Assert.Null(MemberSignatureParser.Parse("A(Of T)(Of U)"));
Assert.Null(MemberSignatureParser.Parse("A(Of T, Of U)"));
Assert.Null(MemberSignatureParser.Parse("A.(Of T)"));
Assert.Null(MemberSignatureParser.Parse("A(Of T).(Of U)"));
Assert.Null(MemberSignatureParser.Parse("A+B"));
Assert.Null(MemberSignatureParser.Parse("F("));
Assert.Null(MemberSignatureParser.Parse("F())"));
Assert.Null(MemberSignatureParser.Parse("F(]"));
Assert.Null(MemberSignatureParser.Parse("F(,B)"));
Assert.Null(MemberSignatureParser.Parse("F(A,)"));
Assert.Null(MemberSignatureParser.Parse("F(Of "));
Assert.Null(MemberSignatureParser.Parse("F(Of ()"));
Assert.Null(MemberSignatureParser.Parse("F(Of T))"));
Assert.Null(MemberSignatureParser.Parse("F(Of T()"));
Assert.Null(MemberSignatureParser.Parse("F(Of T()"));
Assert.Null(MemberSignatureParser.Parse("F?"));
Assert.Null(MemberSignatureParser.Parse("F[]"));
Assert.Null(MemberSignatureParser.Parse("F*"));
Assert.Null(MemberSignatureParser.Parse(".F"));
Assert.Null(MemberSignatureParser.Parse("()"));
Assert.Null(MemberSignatureParser.Parse("(Of T)"));
Assert.Null(MemberSignatureParser.Parse("1"));
Assert.Null(MemberSignatureParser.Parse("F(C*)"));
Assert.Null(MemberSignatureParser.Parse("F(C[])"));
Assert.Null(MemberSignatureParser.Parse("global:C.F"));
}
[Fact]
public void ByRef()
{
VerifySignature("F(ByVal A, ByRef B)",
Signature(
Name("F"),
Identifier("A"),
Identifier("B")));
Assert.Null(MemberSignatureParser.Parse("F(ByVal, B)"));
Assert.Null(MemberSignatureParser.Parse("F(A, ByRef)"));
Assert.Null(MemberSignatureParser.Parse("F(ByVal ByRef A, B)"));
Assert.Null(MemberSignatureParser.Parse("F(A, ByRef ByVal B)"));
Assert.Null(MemberSignatureParser.Parse("F(ByRef ByRef A)"));
Assert.Null(MemberSignatureParser.Parse("F(A, ByVal ByVal B)"));
Assert.Null(MemberSignatureParser.Parse("F(Of ByVal)"));
Assert.Null(MemberSignatureParser.Parse("F(Of ByRef C)"));
Assert.Null(MemberSignatureParser.Parse("F(C(Of ByRef))"));
Assert.Null(MemberSignatureParser.Parse("F(C(Of ByRef C))"));
}
// Special types are treated as keywords in names,
// but not recognized as special types.
[Fact]
public void SpecialTypes_Names()
{
// Method name only.
Assert.Null(MemberSignatureParser.Parse("Integer"));
Assert.Null(MemberSignatureParser.Parse("paramarray"));
VerifySignature("[Integer]",
SignatureNameOnly(
Name("Integer")));
// Type and method name.
VerifySignature("[Object].Integer",
SignatureNameOnly(
Qualified(
Name("Object"),
"Integer")));
// Type parameters.
VerifySignature("F(Of Void)",
SignatureNameOnly(
Generic(Name("F"),
"Void")));
Assert.Null(MemberSignatureParser.Parse("F(Of boolean)"));
Assert.Null(MemberSignatureParser.Parse("F(Of char)"));
Assert.Null(MemberSignatureParser.Parse("F(Of SBYTE)"));
Assert.Null(MemberSignatureParser.Parse("F(Of BYTE)"));
Assert.Null(MemberSignatureParser.Parse("F(Of Short)"));
Assert.Null(MemberSignatureParser.Parse("F(Of UShort)"));
VerifySignature("F(Of [Boolean], [Char], [sbyte], [byte], [SHORT], [USHORT], [Integer], [UInteger], [Long], [ULong], [Single], [Double], [String], [Object], [Decimal], [Date])()",
Signature(
Generic(Name("F"),
"Boolean",
"Char",
"sbyte",
"byte",
"SHORT",
"USHORT",
"Integer",
"UInteger",
"Long",
"ULong",
"Single",
"Double",
"String",
"Object",
"Decimal",
"Date")));
}
// Special types are recognized in type references.
[Fact]
public void SpecialTypes_TypeReferences()
{
// Parameters.
VerifySignature("F(boolean, char, sbyte, byte, short, ushort, integer, uinteger, long, ulong, single, double, string, object, decimal, date)",
Signature(
Name("F"),
Qualified("System", "Boolean"),
Qualified("System", "Char"),
Qualified("System", "SByte"),
Qualified("System", "Byte"),
Qualified("System", "Int16"),
Qualified("System", "UInt16"),
Qualified("System", "Int32"),
Qualified("System", "UInt32"),
Qualified("System", "Int64"),
Qualified("System", "UInt64"),
Qualified("System", "Single"),
Qualified("System", "Double"),
Qualified("System", "String"),
Qualified("System", "Object"),
Qualified("System", "Decimal"),
Qualified("System", "DateTime")));
// Type arguments.
VerifySignature("F(C(OF DECIMAL, INTEGER, STRING, OBJECT))",
Signature(
Name("F"),
Generic(
Identifier("C"),
Qualified("System", "Decimal"),
Qualified("System", "Int32"),
Qualified("System", "String"),
Qualified("System", "Object"))));
// Not special types.
VerifySignature("F(Void, Int, [Object], A.[Integer], B.Single)",
Signature(
Name("F"),
Identifier("Void"),
Identifier("Int"),
Identifier("Object"),
Qualified("A", "Integer"),
Qualified("B", "Single")));
}
[Fact]
public void EscapedNames()
{
VerifySignature("[F3]",
SignatureNameOnly(
Name("F3")));
VerifySignature("[_]",
SignatureNameOnly(
Name("_")));
VerifySignature("[Integer]",
SignatureNameOnly(
Name("Integer")));
VerifySignature("A.B.[Integer]",
SignatureNameOnly(
Qualified(
Qualified(
Name("A"),
"B"),
"Integer")));
VerifySignature("F([Integer])",
Signature(
Name("F"),
Identifier("Integer")));
VerifySignature("F(System.[Integer])",
Signature(
Name("F"),
Qualified(
Identifier("System"),
"Integer")));
VerifySignature("A(Of [Object]).B(Of [Integer]).F(Of [Of])",
SignatureNameOnly(
Generic(
Qualified(
Generic(
Qualified(
Generic(
Name("A"),
"Object"),
"B"),
"Integer"),
"F"),
"Of")));
VerifySignature("F(C(Of Integer, [Date]))",
Signature(
Name("F"),
Generic(
Identifier("C"),
Qualified("System", "Int32"),
Identifier("Date"))));
Assert.Null(MemberSignatureParser.Parse("@"));
Assert.Null(MemberSignatureParser.Parse("@Integer"));
Assert.Null(MemberSignatureParser.Parse("["));
Assert.Null(MemberSignatureParser.Parse("[]"));
Assert.Null(MemberSignatureParser.Parse("[3"));
Assert.Null(MemberSignatureParser.Parse("[3]"));
Assert.Null(MemberSignatureParser.Parse("[[F"));
Assert.Null(MemberSignatureParser.Parse("[F"));
Assert.Null(MemberSignatureParser.Parse("[F["));
Assert.Null(MemberSignatureParser.Parse("F]"));
Assert.Null(MemberSignatureParser.Parse("[(T)"));
Assert.Null(MemberSignatureParser.Parse("[Object]]"));
Assert.Null(MemberSignatureParser.Parse("[Object+]"));
Assert.Null(MemberSignatureParser.Parse("[Object ]"));
Assert.Null(MemberSignatureParser.Parse("[.F"));
Assert.Null(MemberSignatureParser.Parse("[()"));
Assert.Null(MemberSignatureParser.Parse("F([)"));
Assert.Null(MemberSignatureParser.Parse("F(A, [)"));
}
private static void VerifySignature(string str, RequestSignature expectedSignature)
{
var actualSignature = MemberSignatureParser.Parse(str);
VerifySignature(actualSignature, expectedSignature);
}
}
}
......@@ -5,7 +5,7 @@
Inputs="@(VsdConfigXml);$(IntermediateOutputPath)\$(AssemblyName).dll"
Outputs="$(OutDir)\$(AssemblyName).vsdconfig"
Condition="'$(BuildingProject)' == 'true' AND '$(SkipGenerateVsdconfig)' != 'true'">
<Exec Command="&quot;$(DevEnvDir)\..\..\VSSDK\VisualStudioIntegration\Tools\Bin\vsdconfigtool.exe&quot; &quot;@(VsdConfigXml)&quot; &quot;$(IntermediateOutputPath)\$(AssemblyName).dll&quot; &quot;$(OutDir)\$(AssemblyName).vsdconfig&quot;" />
<Exec Command="&quot;$(DevEnvDir)\..\..\VSSDK\VisualStudioIntegration\Tools\Bin\vsdconfigtool.exe&quot; @(VsdConfigXml->'%(RelativeDir)%(FileName)%(Extension)', ' ') &quot;$(IntermediateOutputPath)\$(AssemblyName).dll&quot; &quot;$(OutDir)\$(AssemblyName).vsdconfig&quot;" />
</Target>
<Target Name="VsdConfigOutputGroup" Outputs="@(VsdConfigOutputGroupOutput)">
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册