提交 fc11e8ad 编写于 作者: T Tom Meschter 提交者: GitHub

Merge pull request #19744 from dotnet/merges/master-to-dev15.6-20170524-070012

Merge master to dev15.6
......@@ -9,12 +9,14 @@
<SamplesSolution>$(MSBuildThisFileDirectory)src\Samples\Samples.sln</SamplesSolution>
<TestVsi Condition="'$(testVsiNetCore)' == 'true'">true</TestVsi>
<Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
<RunTestArgs>$(RunTestArgs) -timeout:50</RunTestArgs>
<RunTestArgs Condition="'$(ManualTest)' == ''">$(RunTestArgs) -xml</RunTestArgs>
<RunTestArgs Condition="'$(Test64)' == 'true'">$(RunTestArgs) -test64</RunTestArgs>
<RunTestArgs Condition="'$(TestVsi)' == 'true'">$(RunTestArgs) -testVsi</RunTestArgs>
<RunTestArgs Condition="'$(TestVsiNetCore)' == 'true'">$(RunTestArgs) -trait:Feature=NetCore</RunTestArgs>
<RunTestArgs Condition="'$(Trait)' != ''">$(RunTestArgs) -trait:$(Trait)</RunTestArgs>
<RunTestArgs Condition="'$(NoTrait)' != ''">$(RunTestArgs) -notrait:$(NoTrait)</RunTestArgs>
<RunTestArgs Condition="'$(ProcDumpDir)' != ''">$(RunTestArgs) -procDumpPath:$(ProcDumpDir)</RunTestArgs>
<DeployExtensionViaBuild Condition="'$(DeployExtensionViaBuild)' == ''">false</DeployExtensionViaBuild>
<IncludePattern Condition="'$(IncludePattern)' == '' AND '$(TestVsi)' != 'true'">*.UnitTests.dll</IncludePattern>
<IncludePattern Condition="'$(IncludePattern)' == '' AND '$(TestVsi)' == 'true'">*.IntegrationTests.dll</IncludePattern>
......
......@@ -45,8 +45,8 @@
<MicrosoftInternalVisualStudioShellInterop140DesignTimeVersion>14.3.25407-alpha</MicrosoftInternalVisualStudioShellInterop140DesignTimeVersion>
<MicrosoftMetadataVisualizerVersion>1.0.0-beta1-61531-03</MicrosoftMetadataVisualizerVersion>
<MicrosoftMSXMLVersion>8.0.0.0-alpha</MicrosoftMSXMLVersion>
<MicrosoftNetCompilersVersion>2.0.1</MicrosoftNetCompilersVersion>
<MicrosoftNetCompilersnetcoreVersion>2.0.0-rc2-61102-09</MicrosoftNetCompilersnetcoreVersion>
<MicrosoftNetCompilersVersion>2.3.0-beta2-61716-09</MicrosoftNetCompilersVersion>
<MicrosoftNetCompilersnetcoreVersion>2.3.0-beta2-61716-09</MicrosoftNetCompilersnetcoreVersion>
<MicrosoftNetRoslynDiagnosticsVersion>2.0.0-beta1-61628-06</MicrosoftNetRoslynDiagnosticsVersion>
<MicrosoftNetCoreILAsmVersion>1.1.0</MicrosoftNetCoreILAsmVersion>
<MicrosoftNETCoreCompilersVersion>2.3.0-dev-56735-00</MicrosoftNETCoreCompilersVersion>
......
......@@ -166,6 +166,7 @@
<When Condition="'$(MSBuildProjectExtension)' == '.csproj' OR '$(Language)' == 'C#' OR '$(ProjectLanguage)' == 'CSharp'">
<PropertyGroup>
<ProjectLanguage>CSharp</ProjectLanguage>
<LangVersion>7.1</LangVersion>
<WarningLevel>4</WarningLevel>
<ErrorReport>prompt</ErrorReport>
......
......@@ -16,6 +16,7 @@
moniker listed below -->
<RoslynNuGetMoniker Condition="'$(RoslynNuGetMoniker)' == ''">dev</RoslynNuGetMoniker>
<RoslynNuGetMoniker Condition="'$(OfficialBuild)' == 'true'">beta1</RoslynNuGetMoniker>
<!-- This is the base of the NuGet versioning for prerelease packages -->
<NuGetPreReleaseVersion>$(RoslynFileVersionBase)-$(RoslynNuGetMoniker)</NuGetPreReleaseVersion>
......
......@@ -52,6 +52,31 @@ function Terminate-BuildProcesses() {
Get-Process vbcscompiler -ErrorAction SilentlyContinue | kill
}
# Ensure that procdump is available on the machine. Returns the path to the directory that contains
# the procdump binaries (both 32 and 64 bit)
function Ensure-ProcDump() {
# Jenkins images default to having procdump installed in the root. Use that if available to avoid
# an unnecessary download.
if (Test-Path "c:\SysInternals\procdump.exe") {
return "c:\SysInternals";
}
$toolsDir = Join-Path $binariesDir "Tools"
$outDir = Join-Path $toolsDir "ProcDump"
$filePath = Join-Path $outDir "procdump.exe"
if (-not (Test-Path $filePath)) {
Remove-Item -Re $filePath -ErrorAction SilentlyContinue
Create-Directory $outDir
$zipFilePath = Join-Path $toolsDir "procdump.zip"
Invoke-WebRequest "https://download.sysinternals.com/files/Procdump.zip" -outfile $zipFilePath | Out-Null
Add-Type -AssemblyName System.IO.Compression.FileSystem
[IO.Compression.ZipFile]::ExtractToDirectory($zipFilePath, $outDir)
}
return $outDir
}
# The Jenkins images used to execute our tests can live for a very long time. Over the course
# of hundreds of runs this can cause the %TEMP% folder to fill up. To avoid this we redirect
# %TEMP% into the binaries folder which is deleted at the end of every run as a part of cleaning
......@@ -161,6 +186,7 @@ try {
$testVsiArg = if ($testVsi) { "true" } else { "false" }
$testVsiNetCoreArg = if ($testVsiNetCore) { "true" } else { "false" }
$buildLog = Join-Path $binariesdir "Build.log"
$procDumpDir = Ensure-ProcDump
# To help the VS SDK team track down their issues around install via build temporarily
# re-enabling the build based deployment
......@@ -172,7 +198,7 @@ try {
Write-Host "The testVsiNetCore option can't be combined with other test arguments"
}
Run-MSBuild /p:BootstrapBuildPath="$bootstrapDir" BuildAndTest.proj /p:Configuration=$buildConfiguration /p:Test64=$test64Arg /p:TestVsi=$testVsiArg /p:TestDesktop=$testDesktop /p:TestCoreClr=$testCoreClr /p:TestVsiNetCore=$testVsiNetCoreArg /p:PathMap="$($repoDir)=q:\roslyn" /p:Feature=pdb-path-determinism /fileloggerparameters:LogFile="$buildLog"`;verbosity=diagnostic /p:DeployExtension=false /p:RoslynRuntimeIdentifier=win7-x64 /p:DeployExtensionViaBuild=$deployExtensionViaBuild /p:TreatWarningsAsErrors=true
Run-MSBuild /p:BootstrapBuildPath="$bootstrapDir" BuildAndTest.proj /p:Configuration=$buildConfiguration /p:Test64=$test64Arg /p:TestVsi=$testVsiArg /p:TestDesktop=$testDesktop /p:TestCoreClr=$testCoreClr /p:TestVsiNetCore=$testVsiNetCoreArg /p:PathMap="$($repoDir)=q:\roslyn" /p:Feature=pdb-path-determinism /fileloggerparameters:LogFile="$buildLog"`;verbosity=diagnostic /p:DeployExtension=false /p:RoslynRuntimeIdentifier=win7-x64 /p:DeployExtensionViaBuild=$deployExtensionViaBuild /p:TreatWarningsAsErrors=true /p:ProcDumpDir=$procDumpDir
exit 0
}
......
......@@ -13,7 +13,7 @@ Using the command line Roslyn can be developed using the following pattern:
1. [Visual Studio 2017](https://www.visualstudio.com/downloads/)
- Ensure C#, VB, MSBuild and Visual Studio Extensibility are included in the selected work loads
- Ensure Visual Studio is on at least update 1
- Ensure Visual Studio is on at least version 15.1
1. Run Restore.cmd
1. Open Roslyn.sln
......@@ -25,6 +25,8 @@ do the following:
- Click on the hamburger menu, click Modify
- Choose the workloads listed above and click Modify
During the last few weeks of a development cycle for a quarterly release (versions 15.3, 15.6, etc.), it is possible for the Roslyn codebase to make use of new language features, which will not be suppored by the last released version. During that period, it is recommended to use the [preview version of Visual Studio](https://www.visualstudio.com/vs/preview/) or [Roslyn nightlies](https://github.com/dotnet/roslyn/issues/18783#issuecomment-299064434). Alternatively, you can just ignore some red squiggles produced by the IDE that do not correspond to build errors (on portions of the code using the latest language features).
## Running Tests
There are a number of options for running the core Roslyn unit tests
......
......@@ -37,19 +37,6 @@ private bool UseV7SwitchBinder
}
}
private static bool HasPatternSwitchSyntax(SwitchStatementSyntax switchSyntax)
{
foreach (var section in switchSyntax.Sections)
{
if (section.Labels.Any(SyntaxKind.CasePatternSwitchLabel))
{
return true;
}
}
return false;
}
internal override BoundStatement BindSwitchExpressionAndSections(SwitchStatementSyntax node, Binder originalBinder, DiagnosticBag diagnostics)
{
// If it is a valid C# 6 switch statement, we use the old binder to bind it.
......
......@@ -36,11 +36,25 @@ internal static SwitchBinder Create(Binder next, SwitchStatementSyntax switchSyn
// lead to a translation that fully supports edit-and-continue, so it delegates to the C# 6
// binder when it can. The "testV7SwitchBinder" feature flag forces the use of the C# 7 switch binder
// for all operations; we use it to enhance test coverage.
(parseOptions?.IsFeatureEnabled(MessageID.IDS_FeaturePatternMatching) != false || parseOptions?.Features.ContainsKey("testV7SwitchBinder") != false)
(parseOptions?.IsFeatureEnabled(MessageID.IDS_FeaturePatternMatching) != false ||
parseOptions?.Features.ContainsKey("testV7SwitchBinder") != false ||
switchSyntax.HasErrors && HasPatternSwitchSyntax(switchSyntax))
? new PatternSwitchBinder(next, switchSyntax)
: new SwitchBinder(next, switchSyntax);
}
internal static bool HasPatternSwitchSyntax(SwitchStatementSyntax switchSyntax)
{
foreach (var section in switchSyntax.Sections)
{
if (section.Labels.Any(SyntaxKind.CasePatternSwitchLabel))
{
return true;
}
}
return false;
}
protected bool PatternsEnabled =>
((CSharpParseOptions)SwitchSyntax.SyntaxTree.Options)?.IsFeatureEnabled(MessageID.IDS_FeaturePatternMatching) != false;
......@@ -619,7 +633,7 @@ private BoundSwitchLabel BindSwitchSectionLabel(SwitchLabelSyntax node, Binder s
case SyntaxKind.CasePatternSwitchLabel:
if (!node.HasErrors)
{
// This should not occur, because it would have been a syntax error
// This should not occur, because we would be using a pattern switch binder
throw ExceptionUtilities.UnexpectedValue(node.Kind());
}
break;
......
......@@ -5756,10 +5756,7 @@ static void M(out int x)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "_").WithArguments("tuples", "7").WithLocation(21, 15),
// (12,17): warning CS0162: Unreachable code detected
// break;
Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(12, 17),
// (17,17): warning CS0162: Unreachable code detected
// break;
Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(17, 17)
Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(12, 17)
);
}
......
......@@ -9012,6 +9012,59 @@ struct B : I1
expectedOutput: "FalseFalseTrueTrue");
}
[Fact, WorkItem(16195, "https://github.com/dotnet/roslyn/issues/16195")]
public void TestMatchWithTypeParameter_07()
{
var source =
@"using System;
class Program
{
public static void Main(string[] args)
{
Console.Write(M1<B>(new A()));
Console.Write(M2<B>(new A()));
Console.Write(M1<A>(new A()));
Console.Write(M2<A>(new A()));
}
public static bool M1<T>(A o) where T : new()
{
return o is T t;
}
public static bool M2<T>(A o) where T : new()
{
switch (o)
{
case T t:
return true;
default:
return false;
}
}
}
struct A
{
}
struct B
{
}
";
CreateStandardCompilation(source, parseOptions: TestOptions.Regular7).VerifyDiagnostics(
// (13,21): error CS9003: An expression of type 'A' cannot be handled by a pattern of type 'T' in C# 7. Please use language version 7.1 or greater.
// return o is T t;
Diagnostic(ErrorCode.ERR_PatternWrongGenericTypeInVersion, "T").WithArguments("A", "T", "7", "7.1").WithLocation(13, 21),
// (19,18): error CS9003: An expression of type 'A' cannot be handled by a pattern of type 'T' in C# 7. Please use language version 7.1 or greater.
// case T t:
Diagnostic(ErrorCode.ERR_PatternWrongGenericTypeInVersion, "T").WithArguments("A", "T", "7", "7.1").WithLocation(19, 18)
);
var compilation = CreateStandardCompilation(source,
options: TestOptions.DebugDll.WithOutputKind(OutputKind.ConsoleApplication),
parseOptions: TestOptions.Regular7_1)
.VerifyDiagnostics();
var compVerifier = CompileAndVerify(compilation,
expectedOutput: "FalseFalseTrueTrue");
compVerifier.VerifyDiagnostics();
}
[Fact, WorkItem(16195, "https://github.com/dotnet/roslyn/issues/16195")]
public void TestIgnoreDynamicVsObjectAndTupleElementNames_01()
{
......
......@@ -2351,7 +2351,7 @@ .locals init (int V_0)
}");
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/19682")]
[Fact]
public void Switch_Patterns()
{
var source = @"
......@@ -2395,7 +2395,6 @@ static void M()
<slot kind=""0"" offset=""323"" />
<slot kind=""1"" offset=""11"" />
<slot kind=""temp"" />
<slot kind=""temp"" />
</encLocalSlotMap>
</customDebugInfo>
</method>
......@@ -2404,7 +2403,7 @@ static void M()
v0.VerifyIL("C.M", @"
{
// Code size 235 (0xeb)
// Code size 232 (0xe8)
.maxstack 2
.locals init (object V_0,
int V_1,
......@@ -2414,8 +2413,7 @@ .maxstack 2
int V_5, //j
object V_6, //o
object V_7,
int? V_8,
byte? V_9)
object V_8)
IL_0000: nop
IL_0001: call ""object C.F()""
IL_0006: stloc.s V_7
......@@ -2423,99 +2421,110 @@ .maxstack 2
IL_000a: stloc.0
IL_000b: ldloc.0
IL_000c: brtrue.s IL_0010
IL_000e: br.s IL_0086
IL_000e: br.s IL_0083
IL_0010: ldloc.0
IL_0011: isinst ""int?""
IL_0016: unbox.any ""int?""
IL_001b: stloc.s V_8
IL_001d: ldloca.s V_8
IL_001f: call ""int int?.GetValueOrDefault()""
IL_0024: stloc.1
IL_0025: ldloca.s V_8
IL_0027: call ""bool int?.HasValue.get""
IL_002c: brfalse.s IL_0036
IL_002e: ldloc.1
IL_002f: ldc.i4.1
IL_0030: beq.s IL_0034
IL_0032: br.s IL_0036
IL_0034: br.s IL_0088
IL_0036: ldloc.0
IL_0037: isinst ""byte?""
IL_003c: unbox.any ""byte?""
IL_0041: stloc.s V_9
IL_0043: ldloca.s V_9
IL_0045: call ""byte byte?.GetValueOrDefault()""
IL_004a: stloc.2
IL_004b: ldloca.s V_9
IL_004d: call ""bool byte?.HasValue.get""
IL_0052: brfalse.s IL_0060
IL_0054: br.s IL_0095
IL_0011: stloc.s V_8
IL_0013: ldloc.s V_8
IL_0015: isinst ""int""
IL_001a: ldnull
IL_001b: cgt.un
IL_001d: dup
IL_001e: brtrue.s IL_0023
IL_0020: ldc.i4.0
IL_0021: br.s IL_002a
IL_0023: ldloc.s V_8
IL_0025: unbox.any ""int""
IL_002a: stloc.1
IL_002b: brfalse.s IL_0035
IL_002d: ldloc.1
IL_002e: ldc.i4.1
IL_002f: beq.s IL_0033
IL_0031: br.s IL_0035
IL_0033: br.s IL_0085
IL_0035: ldloc.0
IL_0036: stloc.s V_8
IL_0038: ldloc.s V_8
IL_003a: isinst ""byte""
IL_003f: ldnull
IL_0040: cgt.un
IL_0042: dup
IL_0043: brtrue.s IL_0048
IL_0045: ldc.i4.0
IL_0046: br.s IL_004f
IL_0048: ldloc.s V_8
IL_004a: unbox.any ""byte""
IL_004f: stloc.2
IL_0050: brfalse.s IL_005e
IL_0052: br.s IL_0092
IL_0054: ldloc.2
IL_0055: stloc.2
IL_0056: ldloc.2
IL_0057: stloc.2
IL_0058: ldloc.2
IL_0059: ldc.i4.1
IL_005a: beq.s IL_005e
IL_005c: br.s IL_0060
IL_005e: br.s IL_00bf
IL_0060: ldloc.0
IL_0061: isinst ""int?""
IL_0066: unbox.any ""int?""
IL_006b: stloc.s V_8
IL_006d: ldloca.s V_8
IL_006f: call ""int int?.GetValueOrDefault()""
IL_0074: stloc.1
IL_0075: ldloca.s V_8
IL_0077: call ""bool int?.HasValue.get""
IL_007c: brfalse.s IL_0082
IL_007e: br.s IL_00a9
IL_0080: br.s IL_00cc
IL_0082: ldloc.0
IL_0083: stloc.0
IL_0084: br.s IL_00db
IL_0086: br.s IL_00ea
IL_0088: ldstr ""int 1""
IL_008d: call ""void System.Console.WriteLine(string)""
IL_0092: nop
IL_0093: br.s IL_00ea
IL_0095: ldloc.2
IL_0096: stloc.3
IL_0097: call ""bool C.P()""
IL_009c: brtrue.s IL_00a0
IL_009e: br.s IL_0056
IL_00a0: ldloc.3
IL_00a1: call ""void System.Console.WriteLine(int)""
IL_00a6: nop
IL_00a7: br.s IL_00ea
IL_00a9: ldloc.1
IL_00aa: stloc.s V_4
IL_00ac: call ""bool C.P()""
IL_00b1: brtrue.s IL_00b5
IL_00b3: br.s IL_0080
IL_00b5: ldloc.s V_4
IL_00b7: call ""void System.Console.WriteLine(int)""
IL_00bc: nop
IL_00bd: br.s IL_00ea
IL_00bf: ldstr ""byte 1""
IL_00c4: call ""void System.Console.WriteLine(string)""
IL_00c9: nop
IL_00ca: br.s IL_00ea
IL_00cc: ldloc.1
IL_00cd: stloc.s V_5
IL_00cf: br.s IL_00d1
IL_00d1: ldloc.s V_5
IL_00d3: call ""void System.Console.WriteLine(int)""
IL_00d8: nop
IL_00d9: br.s IL_00ea
IL_00db: ldloc.0
IL_00dc: stloc.s V_6
IL_00de: br.s IL_00e0
IL_00e0: ldloc.s V_6
IL_00e2: call ""void System.Console.WriteLine(object)""
IL_00e7: nop
IL_00e8: br.s IL_00ea
IL_00ea: ret
IL_0057: ldc.i4.1
IL_0058: beq.s IL_005c
IL_005a: br.s IL_005e
IL_005c: br.s IL_00bc
IL_005e: ldloc.0
IL_005f: stloc.s V_8
IL_0061: ldloc.s V_8
IL_0063: isinst ""int""
IL_0068: ldnull
IL_0069: cgt.un
IL_006b: dup
IL_006c: brtrue.s IL_0071
IL_006e: ldc.i4.0
IL_006f: br.s IL_0078
IL_0071: ldloc.s V_8
IL_0073: unbox.any ""int""
IL_0078: stloc.1
IL_0079: brfalse.s IL_007f
IL_007b: br.s IL_00a6
IL_007d: br.s IL_00c9
IL_007f: ldloc.0
IL_0080: stloc.0
IL_0081: br.s IL_00d8
IL_0083: br.s IL_00e7
IL_0085: ldstr ""int 1""
IL_008a: call ""void System.Console.WriteLine(string)""
IL_008f: nop
IL_0090: br.s IL_00e7
IL_0092: ldloc.2
IL_0093: stloc.3
IL_0094: call ""bool C.P()""
IL_0099: brtrue.s IL_009d
IL_009b: br.s IL_0054
IL_009d: ldloc.3
IL_009e: call ""void System.Console.WriteLine(int)""
IL_00a3: nop
IL_00a4: br.s IL_00e7
IL_00a6: ldloc.1
IL_00a7: stloc.s V_4
IL_00a9: call ""bool C.P()""
IL_00ae: brtrue.s IL_00b2
IL_00b0: br.s IL_007d
IL_00b2: ldloc.s V_4
IL_00b4: call ""void System.Console.WriteLine(int)""
IL_00b9: nop
IL_00ba: br.s IL_00e7
IL_00bc: ldstr ""byte 1""
IL_00c1: call ""void System.Console.WriteLine(string)""
IL_00c6: nop
IL_00c7: br.s IL_00e7
IL_00c9: ldloc.1
IL_00ca: stloc.s V_5
IL_00cc: br.s IL_00ce
IL_00ce: ldloc.s V_5
IL_00d0: call ""void System.Console.WriteLine(int)""
IL_00d5: nop
IL_00d6: br.s IL_00e7
IL_00d8: ldloc.0
IL_00d9: stloc.s V_6
IL_00db: br.s IL_00dd
IL_00dd: ldloc.s V_6
IL_00df: call ""void System.Console.WriteLine(object)""
IL_00e4: nop
IL_00e5: br.s IL_00e7
IL_00e7: ret
}");
var methodData0 = v0.TestData.GetMethodData("C.M");
var method0 = compilation0.GetMember<MethodSymbol>("C.M");
var method1 = compilation1.GetMember<MethodSymbol>("C.M");
......@@ -2527,7 +2536,7 @@ .maxstack 2
diff1.VerifyIL("C.M", @"
{
// Code size 235 (0xeb)
// Code size 232 (0xe8)
.maxstack 2
.locals init (object V_0,
int V_1,
......@@ -2537,10 +2546,8 @@ .maxstack 2
int V_5, //j
object V_6, //o
object V_7,
[unchanged] V_8,
[unchanged] V_9,
int? V_10,
byte? V_11)
[object] V_8,
object V_9)
IL_0000: nop
IL_0001: call ""object C.F()""
IL_0006: stloc.s V_7
......@@ -2548,99 +2555,110 @@ .maxstack 2
IL_000a: stloc.0
IL_000b: ldloc.0
IL_000c: brtrue.s IL_0010
IL_000e: br.s IL_0086
IL_000e: br.s IL_0083
IL_0010: ldloc.0
IL_0011: isinst ""int?""
IL_0016: unbox.any ""int?""
IL_001b: stloc.s V_10
IL_001d: ldloca.s V_10
IL_001f: call ""int int?.GetValueOrDefault()""
IL_0024: stloc.1
IL_0025: ldloca.s V_10
IL_0027: call ""bool int?.HasValue.get""
IL_002c: brfalse.s IL_0036
IL_002e: ldloc.1
IL_002f: ldc.i4.1
IL_0030: beq.s IL_0034
IL_0032: br.s IL_0036
IL_0034: br.s IL_0088
IL_0036: ldloc.0
IL_0037: isinst ""byte?""
IL_003c: unbox.any ""byte?""
IL_0041: stloc.s V_11
IL_0043: ldloca.s V_11
IL_0045: call ""byte byte?.GetValueOrDefault()""
IL_004a: stloc.2
IL_004b: ldloca.s V_11
IL_004d: call ""bool byte?.HasValue.get""
IL_0052: brfalse.s IL_0060
IL_0054: br.s IL_0095
IL_0011: stloc.s V_9
IL_0013: ldloc.s V_9
IL_0015: isinst ""int""
IL_001a: ldnull
IL_001b: cgt.un
IL_001d: dup
IL_001e: brtrue.s IL_0023
IL_0020: ldc.i4.0
IL_0021: br.s IL_002a
IL_0023: ldloc.s V_9
IL_0025: unbox.any ""int""
IL_002a: stloc.1
IL_002b: brfalse.s IL_0035
IL_002d: ldloc.1
IL_002e: ldc.i4.1
IL_002f: beq.s IL_0033
IL_0031: br.s IL_0035
IL_0033: br.s IL_0085
IL_0035: ldloc.0
IL_0036: stloc.s V_9
IL_0038: ldloc.s V_9
IL_003a: isinst ""byte""
IL_003f: ldnull
IL_0040: cgt.un
IL_0042: dup
IL_0043: brtrue.s IL_0048
IL_0045: ldc.i4.0
IL_0046: br.s IL_004f
IL_0048: ldloc.s V_9
IL_004a: unbox.any ""byte""
IL_004f: stloc.2
IL_0050: brfalse.s IL_005e
IL_0052: br.s IL_0092
IL_0054: ldloc.2
IL_0055: stloc.2
IL_0056: ldloc.2
IL_0057: stloc.2
IL_0058: ldloc.2
IL_0059: ldc.i4.1
IL_005a: beq.s IL_005e
IL_005c: br.s IL_0060
IL_005e: br.s IL_00bf
IL_0060: ldloc.0
IL_0061: isinst ""int?""
IL_0066: unbox.any ""int?""
IL_006b: stloc.s V_10
IL_006d: ldloca.s V_10
IL_006f: call ""int int?.GetValueOrDefault()""
IL_0074: stloc.1
IL_0075: ldloca.s V_10
IL_0077: call ""bool int?.HasValue.get""
IL_007c: brfalse.s IL_0082
IL_007e: br.s IL_00a9
IL_0080: br.s IL_00cc
IL_0082: ldloc.0
IL_0083: stloc.0
IL_0084: br.s IL_00db
IL_0086: br.s IL_00ea
IL_0088: ldstr ""int 1""
IL_008d: call ""void System.Console.WriteLine(string)""
IL_0092: nop
IL_0093: br.s IL_00ea
IL_0095: ldloc.2
IL_0096: stloc.3
IL_0097: call ""bool C.P()""
IL_009c: brtrue.s IL_00a0
IL_009e: br.s IL_0056
IL_00a0: ldloc.3
IL_00a1: call ""void System.Console.WriteLine(int)""
IL_00a6: nop
IL_00a7: br.s IL_00ea
IL_00a9: ldloc.1
IL_00aa: stloc.s V_4
IL_00ac: call ""bool C.P()""
IL_00b1: brtrue.s IL_00b5
IL_00b3: br.s IL_0080
IL_00b5: ldloc.s V_4
IL_00b7: call ""void System.Console.WriteLine(int)""
IL_00bc: nop
IL_00bd: br.s IL_00ea
IL_00bf: ldstr ""byte 1""
IL_00c4: call ""void System.Console.WriteLine(string)""
IL_00c9: nop
IL_00ca: br.s IL_00ea
IL_00cc: ldloc.1
IL_00cd: stloc.s V_5
IL_00cf: br.s IL_00d1
IL_00d1: ldloc.s V_5
IL_00d3: call ""void System.Console.WriteLine(int)""
IL_00d8: nop
IL_00d9: br.s IL_00ea
IL_00db: ldloc.0
IL_00dc: stloc.s V_6
IL_00de: br.s IL_00e0
IL_00e0: ldloc.s V_6
IL_00e2: call ""void System.Console.WriteLine(object)""
IL_00e7: nop
IL_00e8: br.s IL_00ea
IL_00ea: ret
}
");
IL_0057: ldc.i4.1
IL_0058: beq.s IL_005c
IL_005a: br.s IL_005e
IL_005c: br.s IL_00bc
IL_005e: ldloc.0
IL_005f: stloc.s V_9
IL_0061: ldloc.s V_9
IL_0063: isinst ""int""
IL_0068: ldnull
IL_0069: cgt.un
IL_006b: dup
IL_006c: brtrue.s IL_0071
IL_006e: ldc.i4.0
IL_006f: br.s IL_0078
IL_0071: ldloc.s V_9
IL_0073: unbox.any ""int""
IL_0078: stloc.1
IL_0079: brfalse.s IL_007f
IL_007b: br.s IL_00a6
IL_007d: br.s IL_00c9
IL_007f: ldloc.0
IL_0080: stloc.0
IL_0081: br.s IL_00d8
IL_0083: br.s IL_00e7
IL_0085: ldstr ""int 1""
IL_008a: call ""void System.Console.WriteLine(string)""
IL_008f: nop
IL_0090: br.s IL_00e7
IL_0092: ldloc.2
IL_0093: stloc.3
IL_0094: call ""bool C.P()""
IL_0099: brtrue.s IL_009d
IL_009b: br.s IL_0054
IL_009d: ldloc.3
IL_009e: call ""void System.Console.WriteLine(int)""
IL_00a3: nop
IL_00a4: br.s IL_00e7
IL_00a6: ldloc.1
IL_00a7: stloc.s V_4
IL_00a9: call ""bool C.P()""
IL_00ae: brtrue.s IL_00b2
IL_00b0: br.s IL_007d
IL_00b2: ldloc.s V_4
IL_00b4: call ""void System.Console.WriteLine(int)""
IL_00b9: nop
IL_00ba: br.s IL_00e7
IL_00bc: ldstr ""byte 1""
IL_00c1: call ""void System.Console.WriteLine(string)""
IL_00c6: nop
IL_00c7: br.s IL_00e7
IL_00c9: ldloc.1
IL_00ca: stloc.s V_5
IL_00cc: br.s IL_00ce
IL_00ce: ldloc.s V_5
IL_00d0: call ""void System.Console.WriteLine(int)""
IL_00d5: nop
IL_00d6: br.s IL_00e7
IL_00d8: ldloc.0
IL_00d9: stloc.s V_6
IL_00db: br.s IL_00dd
IL_00dd: ldloc.s V_6
IL_00df: call ""void System.Console.WriteLine(object)""
IL_00e4: nop
IL_00e5: br.s IL_00e7
IL_00e7: ret
}");
}
[Fact]
......
......@@ -1015,6 +1015,7 @@ private static void VerifyModelForOutVarInNotExecutableCode(SemanticModel model,
var typeInfo = model.GetTypeInfo(decl);
Assert.Equal(expectedType, typeInfo.Type);
Assert.Equal(expectedType, model.GetOperationInternal(decl)?.Type);
// Note: the following assertion is not, in general, correct for declaration expressions,
// even though this helper is used to handle declaration expressions.
......@@ -5162,6 +5162,45 @@ public static void Main(string[] args)
3");
}
[Fact, WorkItem(16195, "https://github.com/dotnet/roslyn/issues/16195")]
public void TypeParameterSubsumption05()
{
var program = @"
public class Program
{
static void M<T, U>(T t, U u) where T : U
{
switch(""test"")
{
case U uu:
break;
case T tt: // Produces a diagnostic about subsumption/unreachability
break;
}
}
}
";
CreateStandardCompilation(program, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular7).VerifyDiagnostics(
// (8,18): error CS8314: An expression of type 'string' cannot be handled by a pattern of type 'U' in C# 7. Please use language version 7.1 or greater.
// case U uu:
Diagnostic(ErrorCode.ERR_PatternWrongGenericTypeInVersion, "U").WithArguments("string", "U", "7", "7.1").WithLocation(8, 18),
// (10,18): error CS8314: An expression of type 'string' cannot be handled by a pattern of type 'T' in C# 7. Please use language version 7.1 or greater.
// case T tt: // Produces a diagnostic about subsumption/unreachability
Diagnostic(ErrorCode.ERR_PatternWrongGenericTypeInVersion, "T").WithArguments("string", "T", "7", "7.1").WithLocation(10, 18),
// (11,17): warning CS0162: Unreachable code detected
// break;
Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(11, 17)
);
CreateStandardCompilation(program, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular7_1).VerifyDiagnostics(
// (10,18): error CS8120: The switch case has already been handled by a previous case.
// case T tt: // Produces a diagnostic about subsumption/unreachability
Diagnostic(ErrorCode.ERR_PatternIsSubsumed, "T tt").WithLocation(10, 18),
// (11,17): warning CS0162: Unreachable code detected
// break;
Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(11, 17)
);
}
[Fact, WorkItem(17103, "https://github.com/dotnet/roslyn/issues/17103")]
public void IsConstantPatternConversion_Positive()
{
......@@ -5926,5 +5965,184 @@ void M1(int? i)
Diagnostic(ErrorCode.ERR_NameNotInContext, "b").WithArguments("b").WithLocation(14, 17)
);
}
[Fact, WorkItem(19038, "https://github.com/dotnet/roslyn/issues/19038")]
public void GenericDynamicIsObject()
{
var program = @"
using System;
public class Program
{
static void Main(string[] args)
{
M<dynamic>(new object());
M<dynamic>(null);
M<dynamic>(""xyzzy"");
}
static void M<T>(object x)
{
switch (x)
{
case T t:
Console.Write(""T"");
break;
case null:
Console.Write(""n"");
break;
}
}
}
";
var compilation = CreateStandardCompilation(program, options: TestOptions.DebugExe);
compilation.VerifyDiagnostics(
);
var comp = CompileAndVerify(compilation, expectedOutput: @"TnT");
}
[Fact, WorkItem(19038, "https://github.com/dotnet/roslyn/issues/19038")]
public void MatchNullableTypeParameter()
{
var program = @"
using System;
public class Program
{
static void Main(string[] args)
{
M<int>(1);
M<int>(null);
M<float>(3.14F);
}
static void M<T>(T? x) where T : struct
{
switch (x)
{
case T t:
Console.Write(""T"");
break;
case null:
Console.Write(""n"");
break;
}
}
}
";
var compilation = CreateStandardCompilation(program, options: TestOptions.DebugExe);
compilation.VerifyDiagnostics(
);
var comp = CompileAndVerify(compilation, expectedOutput: @"TnT");
}
[Fact, WorkItem(16195, "https://github.com/dotnet/roslyn/issues/16195")]
public void MatchRecursiveGenerics()
{
var program =
@"using System;
class Packet { }
class Packet<U> : Packet { }
public class C {
static void Main()
{
Console.Write(M<Packet>(null));
Console.Write(M<Packet>(new Packet<Packet>()));
Console.Write(M<Packet>(new Packet<int>()));
Console.Write(M<Packet<int>>(new Packet<int>()));
}
static bool M<T>(T p) where T : Packet => p is Packet<T> p1;
}";
CreateStandardCompilation(program, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7).VerifyDiagnostics(
// (12,52): error CS8314: An expression of type 'T' cannot be handled by a pattern of type 'Packet<T>' in C# 7. Please use language version 7.1 or greater.
// static bool M<T>(T p) where T : Packet => p is Packet<T> p1;
Diagnostic(ErrorCode.ERR_PatternWrongGenericTypeInVersion, "Packet<T>").WithArguments("T", "Packet<T>", "7", "7.1").WithLocation(12, 52)
);
var compilation = CreateStandardCompilation(program, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_1);
compilation.VerifyDiagnostics(
);
var comp = CompileAndVerify(compilation, expectedOutput: @"FalseTrueFalseFalse");
}
[Fact, WorkItem(19038, "https://github.com/dotnet/roslyn/issues/19038")]
public void MatchRestrictedTypes_Fail()
{
var program =
@"using System;
unsafe public class C {
static bool M(TypedReference x, int* p, ref int z)
{
var n1 = x is TypedReference x0; // ok
var p1 = p is int* p0; // syntax error 1
var r1 = z is ref int z0; // syntax error 2
var b1 = x is object o1; // not allowed 1
var b2 = p is object o2; // not allowed 2
var b3 = z is object o3; // ok
return b1 && b2 && b3;
}
}";
var compilation = CreateStandardCompilation(program, options: TestOptions.DebugDll.WithAllowUnsafe(true));
compilation.VerifyDiagnostics(
// (6,23): error CS1525: Invalid expression term 'int'
// var p1 = p is int* p0; // syntax error 1
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(6, 23),
// (7,23): error CS1525: Invalid expression term 'ref'
// var r1 = z is ref int z0; // syntax error 2
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref").WithArguments("ref").WithLocation(7, 23),
// (7,23): error CS1002: ; expected
// var r1 = z is ref int z0; // syntax error 2
Diagnostic(ErrorCode.ERR_SemicolonExpected, "ref").WithLocation(7, 23),
// (6,28): error CS0103: The name 'p0' does not exist in the current context
// var p1 = p is int* p0; // syntax error 1
Diagnostic(ErrorCode.ERR_NameNotInContext, "p0").WithArguments("p0").WithLocation(6, 28),
// (7,31): error CS8174: A declaration of a by-reference variable must have an initializer
// var r1 = z is ref int z0; // syntax error 2
Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "z0").WithLocation(7, 31),
// (9,23): error CS8121: An expression of type 'TypedReference' cannot be handled by a pattern of type 'object'.
// var b1 = x is object o1; // not allowed 1
Diagnostic(ErrorCode.ERR_PatternWrongType, "object").WithArguments("System.TypedReference", "object").WithLocation(9, 23),
// (10,23): error CS0244: Neither 'is' nor 'as' is valid on pointer types
// var b2 = p is object o2; // not allowed 2
Diagnostic(ErrorCode.ERR_PointerInAsOrIs, "object o2").WithLocation(10, 23),
// (7,31): warning CS0168: The variable 'z0' is declared but never used
// var r1 = z is ref int z0; // syntax error 2
Diagnostic(ErrorCode.WRN_UnreferencedVar, "z0").WithArguments("z0").WithLocation(7, 31)
);
}
[Fact, WorkItem(19038, "https://github.com/dotnet/roslyn/issues/19038")]
public void MatchRestrictedTypes_Success()
{
var program =
@"using System;
using System.Reflection;
unsafe public class C {
public int Value;
static void Main()
{
C a = new C { Value = 12 };
FieldInfo info = typeof(C).GetField(""Value"");
TypedReference reference = __makeref(a);
if (!(reference is TypedReference reference0)) throw new Exception(""TypedReference"");
info.SetValueDirect(reference0, 34);
if (a.Value != 34) throw new Exception(""SetValueDirect"");
int z = 56;
if (CopyRefInt(ref z) != 56) throw new Exception(""ref z"");
Console.WriteLine(""ok"");
}
static int CopyRefInt(ref int z)
{
if (!(z is int z0)) throw new Exception(""CopyRefInt"");
return z0;
}
}";
var compilation = CreateStandardCompilation(program, options: TestOptions.DebugExe.WithAllowUnsafe(true));
compilation.VerifyDiagnostics(
);
var comp = CompileAndVerify(compilation, expectedOutput: "ok");
}
}
}
......@@ -834,9 +834,9 @@ public static void Main()
// (15,17): error CS0159: No such label 'case 3:' within the scope of the goto statement
// goto case 3; // warning CS0469: The 'goto case' value is not implicitly convertible to type 'Color'
Diagnostic(ErrorCode.ERR_LabelNotFound, "goto case 3;").WithArguments("case 3:").WithLocation(15, 17),
// (18,13): error CS8070: Control cannot fall out of switch from final case label ('case Color x when false:')
// case Color x when false:
Diagnostic(ErrorCode.ERR_SwitchFallOut, "case Color x when false:").WithArguments("case Color x when false:").WithLocation(18, 13)
// (15,17): warning CS0162: Unreachable code detected
// goto case 3; // warning CS0469: The 'goto case' value is not implicitly convertible to type 'Color'
Diagnostic(ErrorCode.WRN_UnreachableCode, "goto").WithLocation(15, 17)
);
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe);
compilation.VerifyDiagnostics(
......@@ -3184,5 +3184,86 @@ public static async Task<T> SwitchWithAwaitInPatternFails<T>(Task self, T defaul
compilation.VerifyDiagnostics();
var comp = CompileAndVerify(compilation);
}
[Fact, WorkItem(388743, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?_a=edit&id=388743")]
public void SemanticModelForBrokenSwitch_01()
{
// a syntax error that happens to look like a pattern switch if you squint
var source =
@"class Sample
{
void M()
{
bool x = true;
switch (x) {
case
var q = 3;
var y = q/*BIND*/;
}
}";
var compilation = CreateStandardCompilation(source, options: TestOptions.ReleaseDll, parseOptions: TestOptions.Regular6);
compilation.VerifyDiagnostics(
// (8,13): error CS8059: Feature 'pattern matching' is not available in C# 6. Please use language version 7 or greater.
// case
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, @"case
var q ").WithArguments("pattern matching", "7").WithLocation(8, 13),
// (10,15): error CS1003: Syntax error, ':' expected
// var q = 3;
Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments(":", "=").WithLocation(10, 15),
// (10,15): error CS1525: Invalid expression term '='
// var q = 3;
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(10, 15),
// (13,2): error CS1513: } expected
// }
Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(13, 2),
// (10,9): error CS8070: Control cannot fall out of switch from final case label ('var q')
// var q = 3;
Diagnostic(ErrorCode.ERR_SwitchFallOut, "var q").WithArguments("var q").WithLocation(10, 9)
);
var tree = compilation.SyntaxTrees[0];
var model = compilation.GetSemanticModel(tree);
var node = tree.GetRoot().DescendantNodes()
.OfType<IdentifierNameSyntax>()
.Where(n => n.Identifier.ValueText == "q" && n.ToFullString().Contains("/*BIND*/"))
.Single();
var type = model.GetTypeInfo(node);
}
[Fact, WorkItem(388743, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?_a=edit&id=388743")]
public void SemanticModelForBrokenSwitch_02()
{
// a simple legal pattern switch but run in language version 6
var source =
@"class Sample
{
void M()
{
bool b = true;
switch (b) {
case var q:
System.Console.WriteLine(q/*BIND*/);
break;
}
}
}";
var compilation = CreateStandardCompilation(source, options: TestOptions.ReleaseDll, parseOptions: TestOptions.Regular6);
compilation.VerifyDiagnostics(
// (7,13): error CS8059: Feature 'pattern matching' is not available in C# 6. Please use language version 7 or greater.
// case var q:
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "case var q:").WithArguments("pattern matching", "7").WithLocation(7, 13)
);
var tree = compilation.SyntaxTrees[0];
var model = compilation.GetSemanticModel(tree);
var node = tree.GetRoot().DescendantNodes()
.OfType<IdentifierNameSyntax>()
.Where(n => n.Identifier.ValueText == "q" && n.ToFullString().Contains("/*BIND*/"))
.Single();
var type = model.GetTypeInfo(node);
Assert.Equal(SpecialType.System_Boolean, type.Type.SpecialType);
Assert.Equal(SpecialType.System_Boolean, type.ConvertedType.SpecialType);
}
}
}
......@@ -45,7 +45,13 @@ public static void Main(string[] args)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "case string s:").WithArguments("pattern matching", "7").WithLocation(11, 13),
// (15,18): error CS8059: Feature 'pattern matching' is not available in C# 6. Please use language version 7 or greater.
// bool b = args[0] is string s;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "args[0] is string s").WithArguments("pattern matching", "7").WithLocation(15, 18)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "args[0] is string s").WithArguments("pattern matching", "7").WithLocation(15, 18),
// (11,18): error CS8121: An expression of type 'int' cannot be handled by a pattern of type 'string'.
// case string s:
Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("int", "string").WithLocation(11, 18),
// (11,25): error CS0136: A local or parameter named 's' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
// case string s:
Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "s").WithArguments("s").WithLocation(11, 25)
);
}
......
......@@ -42,7 +42,7 @@ public AdditionalTextFile(CommandLineSourceFile sourceFile, CommonCompiler compi
/// Returns a <see cref="SourceText"/> with the contents of this file, or <c>null</c> if
/// there were errors reading the file.
/// </summary>
public override SourceText GetText(CancellationToken cancellationToken = default(CancellationToken))
public override SourceText GetText(CancellationToken cancellationToken = default)
{
lock (_lockObject)
{
......
......@@ -34,7 +34,7 @@ public static class FileSystemExtensions
string xmlDocPath = null,
string win32ResourcesPath = null,
IEnumerable<ResourceDescription> manifestResources = null,
CancellationToken cancellationToken = default(CancellationToken))
CancellationToken cancellationToken = default)
{
if (compilation == null)
{
......
......@@ -665,6 +665,7 @@ Microsoft.CodeAnalysis.Semantics.UnaryOperationKind.UnsignedPrefixIncrement = 77
abstract Microsoft.CodeAnalysis.Diagnostics.OperationBlockStartAnalysisContext.RegisterOperationAction(System.Action<Microsoft.CodeAnalysis.Diagnostics.OperationAnalysisContext> action, System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.OperationKind> operationKinds) -> void
abstract Microsoft.CodeAnalysis.Diagnostics.OperationBlockStartAnalysisContext.RegisterOperationBlockEndAction(System.Action<Microsoft.CodeAnalysis.Diagnostics.OperationBlockAnalysisContext> action) -> void
abstract Microsoft.CodeAnalysis.SemanticModel.GetOperationCore(Microsoft.CodeAnalysis.SyntaxNode node, System.Threading.CancellationToken cancellationToken) -> Microsoft.CodeAnalysis.IOperation
const Microsoft.CodeAnalysis.LanguageNames.FSharp = "F#" -> string
override Microsoft.CodeAnalysis.Semantics.OperationWalker.Visit(Microsoft.CodeAnalysis.IOperation operation) -> void
override Microsoft.CodeAnalysis.Semantics.OperationWalker.VisitAddressOfExpression(Microsoft.CodeAnalysis.Semantics.IAddressOfExpression operation) -> void
override Microsoft.CodeAnalysis.Semantics.OperationWalker.VisitArgument(Microsoft.CodeAnalysis.Semantics.IArgument operation) -> void
......
// 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.Text;
namespace Microsoft.CodeAnalysis
{
/// <summary>
......@@ -18,5 +16,10 @@ public static class LanguageNames
/// The common name used for the Visual Basic language.
/// </summary>
public const string VisualBasic = "Visual Basic";
/// <summary>
/// The common name used for the F# language.
/// </summary>
public const string FSharp = "F#";
}
}
......@@ -3,6 +3,7 @@
using System;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Completion.Providers;
using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders;
......@@ -440,5 +441,17 @@ void foo()
";
await VerifyNoItemsExistAsync(markup);
}
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async void TestDescription()
{
var markup = @"
public class MyClass
{
MyClass $$
}
";
await VerifyItemExistsAsync(markup, "MyClass", glyph: (int)Glyph.MethodPublic, expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
}
}
......@@ -516,6 +516,26 @@ static void N(ParameterSyntax parameter)
parent = parent.Parent;
}
}
}");
}
[WorkItem(429612, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/429612")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInlineTypeCheck)]
public async Task TestMissingWithNullableType()
{
await TestMissingInRegularAndScriptAsync(
@"
class C
{
public object Convert(object value)
{
if (value is bool?)
{
[|bool?|] tmp = (bool?)value;
}
return null;
}
}");
}
}
......
......@@ -258,18 +258,16 @@ private static bool IsPotentialFilterCharacter(TypeCharCommandArgs args)
private Document GetDocument()
{
return this.SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges();
// Crash if we don't find a document, we're already in a bad state.
var document = this.SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges();
Contract.ThrowIfNull(document, nameof(document));
return document;
}
private CompletionHelper GetCompletionHelper()
{
var document = GetDocument();
if (document != null)
{
return CompletionHelper.GetHelper(document);
}
return null;
return CompletionHelper.GetHelper(document);
}
private bool IsTextualTriggerCharacter(CompletionService completionService, char ch, OptionSet options)
......
......@@ -5,9 +5,11 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.SolutionCrawler;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Composition;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
......@@ -138,6 +140,71 @@ public async Task TestOpenFileOnlyAnalyzerDiagnostics()
await listener.CreateWaitTask().ConfigureAwait(false);
}
[Fact]
public async Task TestSynchronizeWithBuild()
{
var workspace = new AdhocWorkspace(MefV1HostServices.Create(TestExportProvider.ExportProviderWithCSharpAndVisualBasic.AsExportProvider()));
var language = Workspaces.NoCompilationConstants.LanguageName;
var project = workspace.AddProject(
ProjectInfo.Create(
ProjectId.CreateNewId(),
VersionStamp.Create(),
"NoNameProject",
"NoNameProject",
language));
var filePath = "NoNameDoc.other";
var document = workspace.AddDocument(
DocumentInfo.Create(
DocumentId.CreateNewId(project.Id),
"Empty",
loader: TextLoader.From(TextAndVersion.Create(SourceText.From(""), VersionStamp.Create(), filePath)),
filePath: filePath));
// create listener/service/analyzer
var listener = new AsynchronousOperationListener();
var service = new MyDiagnosticAnalyzerService(new NoNameAnalyzer(), listener, language);
var analyzer = service.CreateIncrementalAnalyzer(workspace);
bool syntax = false;
// listen to events
service.DiagnosticsUpdated += (s, a) =>
{
switch (a.Diagnostics.Length)
{
case 0:
return;
case 1:
syntax |= a.Diagnostics[0].Id == NoNameAnalyzer.s_syntaxRule.Id;
return;
default:
AssertEx.Fail("shouldn't reach here");
return;
}
};
// cause analysis
await service.SynchronizeWithBuildAsync(
workspace,
ImmutableDictionary<ProjectId, ImmutableArray<DiagnosticData>>.Empty.Add(
document.Project.Id,
ImmutableArray.Create(
Diagnostic.Create(
NoNameAnalyzer.s_syntaxRule,
Location.Create(document.FilePath, TextSpan.FromBounds(0, 0), new LinePositionSpan(new LinePosition(0, 0), new LinePosition(0, 0)))).ToDiagnosticData(project))));
// wait for all events to raised
await listener.CreateWaitTask().ConfigureAwait(false);
// two should have been called.
Assert.True(syntax);
// we should reach here without crashing
}
private static Document GetDocumentFromIncompleteProject(AdhocWorkspace workspace)
{
var project = workspace.AddProject(
......@@ -160,11 +227,11 @@ private static async Task RunAllAnalysisAsync(IIncrementalAnalyzer analyzer, Doc
private class MyDiagnosticAnalyzerService : DiagnosticAnalyzerService
{
internal MyDiagnosticAnalyzerService(DiagnosticAnalyzer analyzer, IAsynchronousOperationListener listener)
internal MyDiagnosticAnalyzerService(DiagnosticAnalyzer analyzer, IAsynchronousOperationListener listener, string language = LanguageNames.CSharp)
: base(new HostAnalyzerManager(
ImmutableArray.Create<AnalyzerReference>(
new TestAnalyzerReferenceByLanguage(
ImmutableDictionary<string, ImmutableArray<DiagnosticAnalyzer>>.Empty.Add(LanguageNames.CSharp, ImmutableArray.Create(analyzer)))),
ImmutableDictionary<string, ImmutableArray<DiagnosticAnalyzer>>.Empty.Add(language, ImmutableArray.Create(analyzer)))),
hostDiagnosticUpdateSource: null),
hostDiagnosticUpdateSource: null,
registrationService: new MockDiagnosticUpdateSourceRegistrationService(),
......@@ -210,5 +277,23 @@ public bool OpenFileOnly(Workspace workspace)
return true;
}
}
private class NoNameAnalyzer : DocumentDiagnosticAnalyzer
{
internal static readonly DiagnosticDescriptor s_syntaxRule = new DiagnosticDescriptor("syntax", "test", "test", "test", DiagnosticSeverity.Error, isEnabledByDefault: true);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(s_syntaxRule);
public override async Task<ImmutableArray<Diagnostic>> AnalyzeSyntaxAsync(Document document, CancellationToken cancellationToken)
{
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
return ImmutableArray.Create(Diagnostic.Create(s_syntaxRule, Location.Create(document.FilePath, TextSpan.FromBounds(0, 0), new LinePositionSpan(new LinePosition(0, 0), new LinePosition(0, 0)))));
}
public override Task<ImmutableArray<Diagnostic>> AnalyzeSemanticsAsync(Document document, CancellationToken cancellationToken)
{
return SpecializedTasks.Default<ImmutableArray<Diagnostic>>();
}
}
}
}
......@@ -199,7 +199,7 @@ public async Task TestPreviewDiagnosticTagger()
}
}
[WpfFact(Skip = "https://github.com/dotnet/roslyn/issues/14444")]
[WpfFact]
public async Task TestPreviewDiagnosticTaggerInPreviewPane()
{
using (var workspace = TestWorkspace.CreateCSharp("class { }", exportProvider: EditorServicesUtil.ExportProvider))
......
......@@ -46,7 +46,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.GoToImplementation
End Using
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
Public Async Function TestEmptyFile() As Task
Dim workspace =
<Workspace>
......@@ -60,7 +60,7 @@ $$
Await TestAsync(workspace, shouldSucceed:=False)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
Public Async Function TestWithSingleClass() As Task
Dim workspace =
<Workspace>
......@@ -74,7 +74,7 @@ class [|$$C|] { }
Await TestAsync(workspace)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
Public Async Function TestWithAbstractClass() As Task
' Since the class is abstract, it cannot be an implementation of itself. Compare to TestWithSingleClass
' above (where we count a class as an implementation of itself) or TestWithAbstractMethodImplementation
......@@ -97,7 +97,7 @@ class [|D|] : C
Await TestAsync(workspace)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
Public Async Function TestWithSealedClass() As Task
Dim workspace =
<Workspace>
......@@ -113,7 +113,7 @@ sealed class [|$$C|]
Await TestAsync(workspace)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
Public Async Function TestWithStruct() As Task
Dim workspace =
<Workspace>
......@@ -129,7 +129,7 @@ struct [|$$C|]
Await TestAsync(workspace)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
Public Async Function TestWithEnum() As Task
Dim workspace =
<Workspace>
......@@ -145,7 +145,7 @@ enum [|$$C|]
Await TestAsync(workspace)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
Public Async Function TestWithNonAbstractClass() As Task
Dim workspace =
<Workspace>
......@@ -165,7 +165,7 @@ class [|D|] : C
Await TestAsync(workspace)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
Public Async Function TestWithSingleClassImplementation() As Task
Dim workspace =
<Workspace>
......@@ -180,7 +180,7 @@ interface $$I { }
Await TestAsync(workspace)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
Public Async Function TestWithTwoClassImplementations() As Task
Dim workspace =
<Workspace>
......@@ -196,7 +196,7 @@ interface $$I { }
Await TestAsync(workspace)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
Public Async Function TestWithOneMethodImplementation() As Task
Dim workspace =
<Workspace>
......@@ -211,7 +211,7 @@ interface I { void $$M(); }
Await TestAsync(workspace)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
Public Async Function TestWithOneEventImplementation() As Task
Dim workspace =
<Workspace>
......@@ -228,7 +228,7 @@ interface I { event EventHandler $$E; }
Await TestAsync(workspace)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
Public Async Function TestWithTwoMethodImplementations() As Task
Dim workspace =
<Workspace>
......@@ -244,7 +244,7 @@ interface I { void $$M(); }
Await TestAsync(workspace)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
Public Async Function TestWithNonInheritedImplementation() As Task
Dim workspace =
<Workspace>
......@@ -260,7 +260,7 @@ interface I { void $$M(); }
Await TestAsync(workspace)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<WorkItem(6752, "https://github.com/dotnet/roslyn/issues/6752")>
Public Async Function TestWithVirtualMethodImplementationWithInterfaceOnBaseClass() As Task
Dim workspace =
......@@ -277,7 +277,7 @@ interface I { void $$M(); }
Await TestAsync(workspace)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<WorkItem(6752, "https://github.com/dotnet/roslyn/issues/6752")>
Public Async Function TestWithVirtualMethodImplementationWithInterfaceOnDerivedClass() As Task
Dim workspace =
......@@ -294,7 +294,7 @@ interface I { void $$M(); }
Await TestAsync(workspace)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<WorkItem(6752, "https://github.com/dotnet/roslyn/issues/6752")>
Public Async Function TestWithVirtualMethodImplementationAndInterfaceImplementedOnDerivedType() As Task
Dim workspace =
......@@ -311,7 +311,7 @@ interface I { void $$M(); }
Await TestAsync(workspace)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<WorkItem(6752, "https://github.com/dotnet/roslyn/issues/6752")>
Public Async Function TestWithAbstractMethodImplementation() As Task
Dim workspace =
......@@ -328,7 +328,7 @@ interface I { void $$M(); }
Await TestAsync(workspace)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
Public Async Function TestWithInterfaceMemberFromMetdataAtUseSite() As Task
Dim workspace =
<Workspace>
......@@ -351,7 +351,7 @@ class C : IDisposable
Await TestAsync(workspace)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
Public Async Function TestWithSimpleMethod() As Task
Dim workspace =
<Workspace>
......@@ -368,7 +368,7 @@ class C
Await TestAsync(workspace)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
Public Async Function TestWithOverridableMethodOnBase() As Task
Dim workspace =
<Workspace>
......@@ -390,7 +390,7 @@ class D : C
Await TestAsync(workspace)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
Public Async Function TestWithOverridableMethodOnImplementation() As Task
' Our philosophy is to only show derived in this case, since we know the implementation of
' D could never call C.M here
......@@ -413,5 +413,31 @@ class D : C
Await TestAsync(workspace)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
<WorkItem(19700, "https://github.com/dotnet/roslyn/issues/19700")>
Public Async Function TestWithIntermediateAbstractOverrides() As Task
Dim workspace =
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
abstract class A {
public virtual void $$[|M|]() { }
}
abstract class B : A {
public abstract override void M();
}
sealed class C1 : B {
public override void [|M|]() { }
}
sealed class C2 : A {
public override void [|M|]() => base.M();
}
</Document>
</Project>
</Workspace>
Await TestAsync(workspace)
End Function
End Class
End Namespace
\ No newline at end of file
......@@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.CSharp {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class CSharpFeaturesResources {
......@@ -980,6 +980,15 @@ internal class CSharpFeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to (Suggested name).
/// </summary>
internal static string Suggested_name {
get {
return ResourceManager.GetString("Suggested_name", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The name &apos;{0}&apos; does not exist in the current context..
/// </summary>
......
......@@ -521,4 +521,7 @@
<data name="Autoselect_disabled_due_to_member_declaration" xml:space="preserve">
<value>Autoselect disabled due to member declaration</value>
</data>
<data name="Suggested_name" xml:space="preserve">
<value>(Suggested name)</value>
</data>
</root>
\ No newline at end of file
......@@ -191,7 +191,12 @@ private ITypeSymbol UnwrapType(ITypeSymbol type, Compilation compilation)
CompletionItem CreateCompletionItem(string name, Glyph glyph, string sortText)
{
return CommonCompletionItem.Create(name, CompletionItemRules.Default, glyph: glyph, sortText: sortText);
return CommonCompletionItem.Create(
name,
CompletionItemRules.Default,
glyph: glyph,
sortText: sortText,
description: CSharpFeaturesResources.Suggested_name.ToSymbolDisplayParts());
}
}
}
......@@ -8,6 +8,7 @@
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.CSharp.UsePatternMatching
{
......@@ -144,6 +145,13 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext)
var semanticModel = syntaxContext.SemanticModel;
var localSymbol = (ILocalSymbol)semanticModel.GetDeclaredSymbol(declarator);
var isType = semanticModel.GetTypeInfo(castExpression.Type).Type;
if (isType.IsNullable())
{
// not legal to write "if (x is int? y)"
return;
}
if (!localSymbol.Type.Equals(isType))
{
// we have something like:
......
......@@ -5,6 +5,7 @@
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Experimentation;
using Microsoft.CodeAnalysis.Shared.Options;
using Microsoft.CodeAnalysis.Workspaces.Diagnostics;
using Roslyn.Utilities;
......@@ -223,6 +224,8 @@ public async Task SaveAsync(Project project, DiagnosticAnalysisResult result)
}
await SerializeAsync(serializer, project, result.ProjectId, _owner.NonLocalStateName, result.Others).ConfigureAwait(false);
AnalyzerABTestLogger.LogProjectDiagnostics(project, result);
}
public void ResetVersion()
......@@ -241,6 +244,8 @@ public async Task MergeAsync(ActiveFileState state, Document document)
var syntax = state.GetAnalysisData(AnalysisKind.Syntax);
var semantic = state.GetAnalysisData(AnalysisKind.Semantic);
AnalyzerABTestLogger.LogDocumentDiagnostics(document, syntax.Items, semantic.Items);
var project = document.Project;
// if project didn't successfully loaded, then it is same as FSA off
......
......@@ -122,6 +122,14 @@ public StateSet GetOrCreateStateSet(Project project, DiagnosticAnalyzer analyzer
/// </summary>
public ImmutableArray<StateSet> CreateBuildOnlyProjectStateSet(Project project)
{
if (!project.SupportsCompilation)
{
// languages which don't use our compilation model but diagnostic framework,
// all their analyzer should be host analyzers. return all host analyzers
// for the language
return _hostStates.GetOrCreateStateSets(project.Language).ToImmutableArray();
}
// create project analyzer reference identity map
var referenceIdentities = project.AnalyzerReferences.Select(r => _analyzerManager.GetAnalyzerReferenceIdentity(r)).ToSet();
......
// 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.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Shared.Options;
using Microsoft.CodeAnalysis.Workspaces.Diagnostics;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Experimentation
{
internal static class AnalyzerABTestLogger
{
private static bool s_reportErrors = false;
private static readonly ConcurrentDictionary<object, object> s_reported = new ConcurrentDictionary<object, object>(concurrencyLevel: 2, capacity: 10);
private const string Name = "LiveCodeAnalysisVsix";
public static void Log(string action)
{
Logger.Log(FunctionId.Experiment_ABTesting, KeyValueLogMessage.Create(LogType.UserAction, m =>
{
m[nameof(Name)] = Name;
m[nameof(action)] = action;
}));
}
public static void LogInstallationStatus(Workspace workspace, LiveCodeAnalysisInstallStatus installStatus)
{
var vsixInstalled = workspace.Options.GetOption(AnalyzerABTestOptions.VsixInstalled);
if (!vsixInstalled && installStatus == LiveCodeAnalysisInstallStatus.Installed)
{
// first time after vsix installed
workspace.Options = workspace.Options.WithChangedOption(AnalyzerABTestOptions.VsixInstalled, true);
workspace.Options = workspace.Options.WithChangedOption(AnalyzerABTestOptions.ParticipatedInExperiment, true);
Log("Installed");
// set the system to report the errors.
s_reportErrors = true;
}
if (vsixInstalled && installStatus == LiveCodeAnalysisInstallStatus.NotInstalled)
{
// first time after vsix is uninstalled
workspace.Options = workspace.Options.WithChangedOption(AnalyzerABTestOptions.VsixInstalled, false);
Log("Uninstalled");
}
}
public static void LogCandidacyRequirementsTracking(long lastTriggeredTimeBinary)
{
if (lastTriggeredTimeBinary == AnalyzerABTestOptions.LastDateTimeUsedSuggestionAction.DefaultValue)
{
Log("StartCandidacyRequirementsTracking");
}
}
public static void LogProjectDiagnostics(Project project, DiagnosticAnalysisResult result)
{
if (!s_reportErrors || !s_reported.TryAdd(project.Id, null))
{
// doesn't meet the bar to report the issue.
return;
}
// logs count of errors for this project. this won't log anything if FSA off since
// we don't collect any diagnostics for a project if FSA is off.
var map = new Dictionary<string, int>();
foreach (var documentId in result.DocumentIdsOrEmpty)
{
CountErrors(map, result.GetResultOrEmpty(result.SyntaxLocals, documentId));
CountErrors(map, result.GetResultOrEmpty(result.SemanticLocals, documentId));
CountErrors(map, result.GetResultOrEmpty(result.NonLocals, documentId));
}
CountErrors(map, result.Others);
LogErrors(project, "ProjectDignostics", project.Id.Id, map);
}
public static void LogDocumentDiagnostics(Document document, ImmutableArray<DiagnosticData> syntax, ImmutableArray<DiagnosticData> semantic)
{
if (!s_reportErrors || !s_reported.TryAdd(document.Id, null))
{
// doesn't meet the bar to report the issue.
return;
}
// logs count of errors for this document. this only logs errors for
// this particular document. we do this since when FSA is off, this is
// only errors we get. otherwise, we don't get any info when FSA is off and
// that is default for C#.
var map = new Dictionary<string, int>();
CountErrors(map, syntax);
CountErrors(map, semantic);
LogErrors(document.Project, "DocumentDignostics", document.Id.Id, map);
}
private static void LogErrors(Project project, string action, Guid target, Dictionary<string, int> map)
{
if (map.Count == 0)
{
// nothing to report
return;
}
var fsa = ServiceFeatureOnOffOptions.IsClosedFileDiagnosticsEnabled(project);
Logger.Log(FunctionId.Experiment_ABTesting, KeyValueLogMessage.Create(LogType.UserAction, m =>
{
m[nameof(Name)] = Name;
m[nameof(action)] = action;
m[nameof(target)] = target.ToString();
m["FSA"] = fsa;
m["errors"] = string.Join("|", map.Select(kv => $"{kv.Key}={kv.Value}"));
}));
}
private static void CountErrors(Dictionary<string, int> map, ImmutableArray<DiagnosticData> diagnostics)
{
if (diagnostics.IsDefaultOrEmpty)
{
return;
}
foreach (var group in diagnostics.GroupBy(d => d.Id))
{
map[group.Key] = IDictionaryExtensions.GetValueOrDefault(map, group.Key) + group.Count();
}
}
}
}
......@@ -3,7 +3,7 @@
using System;
using Microsoft.CodeAnalysis.Options;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Experimentation
namespace Microsoft.CodeAnalysis.Experimentation
{
internal static class AnalyzerABTestOptions
{
......@@ -13,7 +13,7 @@ internal static class AnalyzerABTestOptions
nameof(LastDateTimeUsedSuggestionAction), defaultValue: DateTime.MinValue.ToBinary(),
storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(LastDateTimeUsedSuggestionAction)));
public static readonly Option<uint> UsedSuggestedActionCount = new Option<uint>(nameof(AnalyzerABTestOptions), nameof(UsedSuggestedActionCount),
public static readonly Option<int> UsedSuggestedActionCount = new Option<int>(nameof(AnalyzerABTestOptions), nameof(UsedSuggestedActionCount),
defaultValue: 0, storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(UsedSuggestedActionCount)));
public static readonly Option<bool> NeverShowAgain = new Option<bool>(nameof(AnalyzerABTestOptions), nameof(NeverShowAgain),
......@@ -25,5 +25,13 @@ internal static class AnalyzerABTestOptions
public static readonly Option<long> LastDateTimeInfoBarShown = new Option<long>(nameof(AnalyzerABTestOptions), nameof(LastDateTimeInfoBarShown),
defaultValue: DateTime.MinValue.ToBinary(),
storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(LastDateTimeInfoBarShown)));
public static readonly Option<bool> VsixInstalled = new Option<bool>(nameof(AnalyzerABTestOptions),
nameof(VsixInstalled), defaultValue: false,
storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(VsixInstalled)));
public static readonly Option<bool> ParticipatedInExperiment = new Option<bool>(nameof(AnalyzerABTestOptions),
nameof(ParticipatedInExperiment), defaultValue: false,
storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(ParticipatedInExperiment)));
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Experimentation
namespace Microsoft.CodeAnalysis.Experimentation
{
internal enum LiveCodeAnalysisInstallStatus
{
......
......@@ -134,6 +134,9 @@
<Compile Include="Diagnostics\SymbolAnalysisContextExtensions.cs" />
<Compile Include="DocumentHighlighting\DocumentHighlightingOptions.cs" />
<Compile Include="EncapsulateField\EncapsulateFieldRefactoringProvider.cs" />
<Compile Include="Experimentation\AnalyzerABTestLogger.cs" />
<Compile Include="Experimentation\AnalyzerABTestOptions.cs" />
<Compile Include="Experimentation\LiveCodeAnalysisInstallStatus.cs" />
<Compile Include="ExtractInterface\ExtractInterfaceCodeRefactoringProvider.cs" />
<Compile Include="CodeFixes\FixAllOccurrences\FixSomeCodeAction.cs" />
<Compile Include="AddPackage\InstallPackageDirectlyCodeAction.cs" />
......
......@@ -124,7 +124,7 @@ private async Task CacheTestResult(ContentFile contentFile, TestResult testResul
}
catch (Exception ex)
{
Logger.Log($"Failed to create cached {ex}");
Logger.Log("Failed to create cached", ex);
}
}
}
......
......@@ -80,7 +80,7 @@ public bool TryGetCachedTestResult(string checksum, out CachedTestResult testRes
catch (Exception e)
{
// Okay for exception to occur here on I/O
Logger.Log($"Failed to read cache {checksum} {e.Message}");
Logger.Log($"Failed to read cache {checksum}", e);
}
return false;
......@@ -107,7 +107,7 @@ public Task AddCachedTestResult(AssemblyInfo assemblyInfo, ContentFile contentFi
catch (Exception e)
{
// I/O errors are expected and okay here.
Logger.Log($"Failed to log {checksum} {e.Message}");
Logger.Log($"Failed to log {checksum}", e);
FileUtil.DeleteDirectory(storagePath);
}
......@@ -159,7 +159,7 @@ private void CleanupStorage()
}
catch (Exception ex)
{
Logger.Log($"Unable to cleanup storage {ex.Message}");
Logger.Log("Unable to cleanup storage", ex);
}
}
}
......
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RunTests
{
public static class CrashDumps
{
public static bool TryMonitorProcess(Process processToMonitor, string outputPath)
{
var procDumpPath = TryGetProcDumpPath();
// Make sure everything is fully qualified as we are passing this to other processes
outputPath = Path.GetFullPath(outputPath);
if (procDumpPath == null)
{
return false;
}
var processStart = new ProcessStartInfo();
processStart.Arguments = GetProcDumpArgumentsForMonitoring(processToMonitor.Id, outputPath);
processStart.CreateNoWindow = true;
processStart.FileName = procDumpPath;
processStart.UseShellExecute = false;
var process = Process.Start(processStart);
return true;
}
private static string GetProcDumpArgumentsForMonitoring(int pid, string outputPath)
{
// Here's what these arguments mean:
//
// -g: run as a native debugger in a managed process (no interop).
// -e: dump when an unhandled exception happens
// -b: dump when a breakpoint (__int 3 / Debugger.Break()) is encountered
// -ma: create a full memory dump
//
// without -g, procdump will not catch unhandled managed exception since CLR will always
// handle unhandled exception. for procdump point of view, there is no such thing as unhandled
// exception for managed app.
return $"-accepteula -g -e -b -ma {pid} {outputPath}";
}
private const string DotNetContinuousIntegrationProcDumpLocation = @"C:\Sysinternals\Procdump.exe";
private static string TryGetProcDumpPath()
{
if (File.Exists(DotNetContinuousIntegrationProcDumpLocation))
{
return DotNetContinuousIntegrationProcDumpLocation;
}
return null;
}
}
}
......@@ -26,6 +26,25 @@ internal static void LogError(Exception ex, string line)
}
}
internal static void Log(string message, Exception ex)
{
lock (s_lines)
{
s_lines.Add(message);
s_lines.Add(ex.Message);
s_lines.Add(ex.StackTrace);
}
}
internal static void Log(Exception ex)
{
lock (s_lines)
{
s_lines.Add(ex.Message);
s_lines.Add(ex.StackTrace);
}
}
internal static void Log(string line)
{
lock (s_lines)
......
......@@ -58,6 +58,13 @@ internal class Options
/// </summary>
public List<string> Assemblies { get; set; }
/// <summary>
/// Time after which the runner should kill the xunit process and exit with a failure.
/// </summary>
public TimeSpan? Timeout { get; set; }
public string ProcDumpPath { get; set; }
public string XunitPath { get; set; }
/// <summary>
......@@ -144,6 +151,25 @@ bool isOption(string argument, string optionName, out string value)
opt.NoTrait = value;
index++;
}
else if (isOption(current, "-timeout", out value))
{
if (int.TryParse(value, out var minutes))
{
opt.Timeout = TimeSpan.FromMinutes(minutes);
}
else
{
Console.WriteLine($"{value} is not a valid minute value for timeout");
allGood = false;
}
index++;
}
else if (isOption(current, "-procdumpPath", out value))
{
opt.ProcDumpPath = value;
index++;
}
else
{
break;
......
......@@ -11,30 +11,15 @@ namespace RunTests
{
public sealed class ProcessOutput
{
private readonly int _exitCode;
private readonly IList<string> _outputLines;
private readonly IList<string> _errorLines;
public int ExitCode
{
get { return _exitCode; }
}
public IList<string> OutputLines
{
get { return _outputLines; }
}
public IList<string> ErrorLines
{
get { return _errorLines; }
}
public int ExitCode { get; }
public IList<string> OutputLines { get; }
public IList<string> ErrorLines { get; }
public ProcessOutput(int exitCode, IList<string> outputLines, IList<string> errorLines)
{
_exitCode = exitCode;
_outputLines = outputLines;
_errorLines = errorLines;
ExitCode = exitCode;
OutputLines = outputLines;
ErrorLines = errorLines;
}
}
......@@ -51,65 +36,32 @@ public static void OpenFile(string file)
public static Task<ProcessOutput> RunProcessAsync(
string executable,
string arguments,
bool lowPriority,
CancellationToken cancellationToken,
bool lowPriority = false,
string workingDirectory = null,
bool captureOutput = false,
bool displayWindow = true,
Dictionary<string, string> environmentVariables = null,
Action<Process> processMonitor = null)
Dictionary<string, string> environmentVariables = null)
{
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<ProcessOutput>();
var process = new Process();
process.EnableRaisingEvents = true;
process.StartInfo = CreateProcessStartInfo(executable, arguments, workingDirectory, captureOutput, displayWindow);
var task = CreateTask(process, taskCompletionSource, cancellationToken);
process.Start();
processMonitor?.Invoke(process);
if (lowPriority)
{
process.PriorityClass = ProcessPriorityClass.BelowNormal;
}
if (process.StartInfo.RedirectStandardOutput)
{
process.BeginOutputReadLine();
}
if (process.StartInfo.RedirectStandardError)
{
process.BeginErrorReadLine();
}
return task;
var processStartInfo = CreateProcessStartInfo(executable, arguments, workingDirectory, captureOutput, displayWindow);
return CreateProcessTask(processStartInfo, lowPriority, taskCompletionSource, cancellationToken);
}
private static Task<ProcessOutput> CreateTask(
Process process,
private static Task<ProcessOutput> CreateProcessTask(
ProcessStartInfo processStartInfo,
bool lowPriority,
TaskCompletionSource<ProcessOutput> taskCompletionSource,
CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (taskCompletionSource == null)
{
throw new ArgumentException("taskCompletionSource");
}
if (process == null)
{
return taskCompletionSource.Task;
}
var errorLines = new List<string>();
var outputLines = new List<string>();
var process = new Process();
process.EnableRaisingEvents = true;
process.StartInfo = processStartInfo;
process.OutputDataReceived += (s, e) =>
{
......@@ -159,6 +111,23 @@ public static void OpenFile(string file)
}
});
process.Start();
if (lowPriority)
{
process.PriorityClass = ProcessPriorityClass.BelowNormal;
}
if (processStartInfo.RedirectStandardOutput)
{
process.BeginOutputReadLine();
}
if (processStartInfo.RedirectStandardError)
{
process.BeginErrorReadLine();
}
return taskCompletionSource.Task;
}
......
......@@ -91,8 +91,7 @@ public async Task<TestResult> RunTestAsync(AssemblyInfo assemblyInfo, Cancellati
lowPriority: false,
displayWindow: false,
captureOutput: true,
cancellationToken: cancellationToken,
processMonitor: p => CrashDumps.TryMonitorProcess(p, dumpOutputFilePath)).ConfigureAwait(false);
cancellationToken: cancellationToken);
var span = DateTime.UtcNow - start;
if (processOutput.ExitCode != 0)
......
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Management;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace RunTests
{
internal static class ProcessUtil
{
internal static int? TryGetParentProcessId(Process p)
{
try
{
ManagementObject mo = new ManagementObject("win32_process.handle='" + p.Id + "'");
mo.Get();
return Convert.ToInt32(mo["ParentProcessId"]);
}
catch
{
return null;
}
}
/// <summary>
/// Return the list of processes which are direct children of the provided <paramref name="process"/>
/// instance.
/// </summary>
/// <remarks>
/// This is a best effort API. It can be thwarted by process instances starting / stopping during
/// the building of this list.
/// </remarks>
internal static List<Process> GetProcessChildren(Process process) => GetProcessChildrenCore(process, Process.GetProcesses());
private static List<Process> GetProcessChildrenCore(Process parentProcess, IEnumerable<Process> processes)
{
var list = new List<Process>();
foreach (var process in processes)
{
var parentId = TryGetParentProcessId(process);
if (parentId == parentProcess.Id)
{
list.Add(process);
}
}
return list;
}
/// <summary>
/// Return the list of processes which are direct or indirect children of the provided <paramref name="process"/>
/// instance.
/// </summary>
/// <remarks>
/// This is a best effort API. It can be thwarted by process instances starting / stopping during
/// the building of this list.
/// </remarks>
internal static List<Process> GetProcessTree(Process process)
{
var processes = Process.GetProcesses();
var list = new List<Process>();
var toVisit = new Queue<Process>();
toVisit.Enqueue(process);
while (toVisit.Count > 0)
{
var cur = toVisit.Dequeue();
var children = GetProcessChildrenCore(cur, processes);
foreach (var child in children)
{
toVisit.Enqueue(child);
list.Add(child);
}
}
return list;
}
}
}
......@@ -14,6 +14,7 @@
using System.Collections.Immutable;
using Newtonsoft.Json;
using System.Reflection;
using System.Diagnostics;
namespace RunTests
{
......@@ -41,7 +42,46 @@ internal static int Main(string[] args)
cts.Cancel();
};
return RunCore(options, cts.Token).GetAwaiter().GetResult();
return Run(options, cts.Token).GetAwaiter().GetResult();
}
private static async Task<int> Run(Options options, CancellationToken cancellationToken)
{
if (options.Timeout == null)
{
return await RunCore(options, cancellationToken);
}
var timeoutTask = Task.Delay(options.Timeout.Value);
var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
var runTask = RunCore(options, cts.Token);
if (cancellationToken.IsCancellationRequested)
{
return ExitFailure;
}
var finishedTask = await Task.WhenAny(timeoutTask, runTask);
if (finishedTask == timeoutTask)
{
await HandleTimeout(options, cancellationToken);
cts.Cancel();
try
{
// Need to await here to ensure that all of the child processes are properly
// killed before we exit.
await runTask;
}
catch
{
// Cancellation exceptions expected here.
}
return ExitFailure;
}
return await runTask;
}
private static async Task<int> RunCore(Options options, CancellationToken cancellationToken)
......@@ -106,6 +146,69 @@ private static void WriteLogFile(Options options)
Logger.Clear();
}
/// <summary>
/// Invoked when a timeout occurs and we need to dump all of the test processes and shut down
/// the runnner.
/// </summary>
private static async Task HandleTimeout(Options options, CancellationToken cancellationToken)
{
var procDumpFilePath = Path.Combine(options.ProcDumpPath, "procdump.exe");
async Task DumpProcess(Process targetProcess, string dumpFilePath)
{
Console.Write($"Dumping {targetProcess.ProcessName} {targetProcess.Id} to {dumpFilePath} ... ");
try
{
var args = $"-accepteula -ma {targetProcess.Id} {dumpFilePath}";
var processTask = ProcessRunner.RunProcessAsync(procDumpFilePath, args, cancellationToken);
var processOutput = await processTask;
// The exit code for procdump doesn't obey standard windows rules. It will return non-zero
// for succesful cases (possibly returning the count of dumps that were written). Best
// backup is to test for the dump file being present.
if (File.Exists(dumpFilePath))
{
Console.WriteLine("succeeded");
}
else
{
Console.WriteLine($"FAILED with {processOutput.ExitCode}");
Console.WriteLine($"{procDumpFilePath} {args}");
Console.WriteLine(string.Join(Environment.NewLine, processOutput.OutputLines));
}
}
catch (Exception ex) when (!cancellationToken.IsCancellationRequested)
{
Console.WriteLine("FAILED");
Console.WriteLine(ex.Message);
Logger.Log("Failed to dump process", ex);
}
}
Console.WriteLine("Roslyn Error: test timeout exceeded, dumping remaining processes");
if (!string.IsNullOrEmpty(options.ProcDumpPath))
{
var dumpDir = options.LogFilePath != null
? Path.GetDirectoryName(options.LogFilePath)
: Directory.GetCurrentDirectory();
var counter = 0;
foreach (var proc in ProcessUtil.GetProcessTree(Process.GetCurrentProcess()).OrderBy(x => x.ProcessName))
{
var dumpFilePath = Path.Combine(dumpDir, $"{proc.ProcessName}-{counter}.dmp");
await DumpProcess(proc, dumpFilePath);
counter++;
}
}
else
{
Console.WriteLine("Could not locate procdump");
}
WriteLogFile(options);
}
/// <summary>
/// Quick sanity check to look over the set of assemblies to make sure they are valid and something was
/// specified.
......
......@@ -20,6 +20,7 @@
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Management" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml" />
<PackageReference Include="Newtonsoft.Json">
......@@ -48,7 +49,6 @@
<Compile Include="Cache\WebDataStorage.Json.cs" />
<Compile Include="Cache\WebDataStorage.cs" />
<Compile Include="Constants.cs" />
<Compile Include="CrashDumps.cs" />
<Compile Include="FileUtil.cs" />
<Compile Include="Cache\IDataStorage.cs" />
<Compile Include="ITestExecutor.cs" />
......@@ -57,6 +57,7 @@
<Compile Include="Options.cs" />
<Compile Include="ProcessRunner.cs" />
<Compile Include="ProcessTestExecutor.cs" />
<Compile Include="ProcessUtil.cs" />
<Compile Include="Program.cs" />
<Compile Include="TestRunner.cs" />
<Compile Include="ConsoleUtil.cs" />
......
......@@ -103,7 +103,11 @@ internal async Task<RunAllResult> RunAllAsync(IEnumerable<AssemblyInfo> assembly
Console.Write($", {failures, 2} failures");
}
Console.WriteLine();
Task.WaitAny(running.ToArray());
if (running.Count > 0)
{
await Task.WhenAny(running.ToArray());
}
} while (running.Count > 0);
Print(completed);
......
......@@ -6,6 +6,7 @@
using Microsoft.CodeAnalysis.Editor.Implementation.Suggestions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Experimentation;
using Microsoft.CodeAnalysis.Experiments;
using Microsoft.CodeAnalysis.Extensions;
using Microsoft.VisualStudio.Shell;
......@@ -13,8 +14,7 @@
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Experimentation
{
// Disabling until https://github.com/dotnet/roslyn/issues/19629 is fixed.
// [Export(typeof(ISuggestedActionCallback))]
[Export(typeof(ISuggestedActionCallback))]
internal class AnalyzerVsixSuggestedActionCallback : ForegroundThreadAffinitizedObject, ISuggestedActionCallback
{
private const string AnalyzerEnabledFlight = @"LiveCA/LiveCAcf";
......@@ -51,7 +51,6 @@ public void OnSuggestedActionExecuted(SuggestedAction action)
// thread to get it
AssertIsForeground();
// If the user has previously clicked don't show again, then we bail out immediately
if (_workspace.Options.GetOption(AnalyzerABTestOptions.NeverShowAgain))
{
......@@ -97,6 +96,7 @@ private bool IsVsixInstalled()
else
{
_installStatus = installed != 0 ? LiveCodeAnalysisInstallStatus.Installed : LiveCodeAnalysisInstallStatus.NotInstalled;
AnalyzerABTestLogger.LogInstallationStatus(_workspace, _installStatus);
}
}
......@@ -105,6 +105,13 @@ private bool IsVsixInstalled()
private bool IsCandidate()
{
// if this user ever participated in the experiement and then uninstall the vsix, then
// this user will never be candidate again.
if (_workspace.Options.GetOption(AnalyzerABTestOptions.ParticipatedInExperiment))
{
return false;
}
// Filter for valid A/B test candidates. Candidates fill the following critera:
// 1: Are a Dotnet user (as evidenced by the fact that this code is being run)
// 2: Have triggered a lightbulb on 3 separate days
......@@ -116,21 +123,26 @@ private bool IsCandidate()
if (!isCandidate)
{
// We store in UTC to avoid any timezone offset weirdness
var lastTriggeredTime = DateTime.FromBinary(options.GetOption(AnalyzerABTestOptions.LastDateTimeUsedSuggestionAction));
var lastTriggeredTimeBinary = options.GetOption(AnalyzerABTestOptions.LastDateTimeUsedSuggestionAction);
AnalyzerABTestLogger.LogCandidacyRequirementsTracking(lastTriggeredTimeBinary);
var lastTriggeredTime = DateTime.FromBinary(lastTriggeredTimeBinary);
var currentTime = DateTime.UtcNow;
var span = currentTime - lastTriggeredTime;
if (span.TotalDays >= 1)
{
options = options.WithChangedOption(AnalyzerABTestOptions.LastDateTimeUsedSuggestionAction, currentTime.ToBinary());
var usageCount = options.GetOption(AnalyzerABTestOptions.UsedSuggestedActionCount);
usageCount++;
options = options.WithChangedOption(AnalyzerABTestOptions.UsedSuggestedActionCount, usageCount);
options = options.WithChangedOption(AnalyzerABTestOptions.UsedSuggestedActionCount, ++usageCount);
if (usageCount >= 3)
{
isCandidate = true;
options = options.WithChangedOption(AnalyzerABTestOptions.HasMetCandidacyRequirements, true);
AnalyzerABTestLogger.Log(nameof(AnalyzerABTestOptions.HasMetCandidacyRequirements));
}
_workspace.Options = options;
}
}
......@@ -144,6 +156,8 @@ private void ShowInfoBarIfNecessary()
_infoBarChecked = true;
if (_experimentationService.IsExperimentEnabled(AnalyzerEnabledFlight))
{
AnalyzerABTestLogger.Log(nameof(AnalyzerEnabledFlight));
// If we got true from the experimentation service, then we're in the treatment
// group, and the experiment is enabled. We determine if the infobar has been
// displayed in the past 24 hours. If it hasn't been displayed, then we do so now.
......@@ -154,6 +168,7 @@ private void ShowInfoBarIfNecessary()
if (timeSinceLastShown.TotalDays >= 1)
{
_workspace.Options = _workspace.Options.WithChangedOption(AnalyzerABTestOptions.LastDateTimeInfoBarShown, utcNow.ToBinary());
AnalyzerABTestLogger.Log("InfoBarShown");
var infoBarService = _workspace.Services.GetRequiredService<IInfoBarService>();
infoBarService.ShowInfoBarInGlobalView(
......@@ -173,11 +188,13 @@ private void ShowInfoBarIfNecessary()
private void OpenInstallHyperlink()
{
System.Diagnostics.Process.Start(AnalyzerVsixHyperlink);
AnalyzerABTestLogger.Log(nameof(AnalyzerVsixHyperlink));
}
private void DoNotShowAgain()
{
_workspace.Options = _workspace.Options.WithChangedOption(AnalyzerABTestOptions.NeverShowAgain, true);
AnalyzerABTestLogger.Log(nameof(AnalyzerABTestOptions.NeverShowAgain));
}
}
}
// 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.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
using Microsoft.VisualStudio.LanguageServices.Implementation.Extensions;
using Microsoft.VisualStudio.Text;
using Roslyn.Utilities;
using IVsLanguageBlock = Microsoft.VisualStudio.TextManager.Interop.IVsLanguageBlock;
using IVsTextLines = Microsoft.VisualStudio.TextManager.Interop.IVsTextLines;
using VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan;
......@@ -27,8 +25,6 @@ internal abstract partial class AbstractLanguageService<TPackage, TLanguageServi
out string pbstrDescription,
out int pfBlockAvailable)
{
Tuple<string, TextSpan> foundBlock = null;
var snapshot = this.EditorAdaptersFactoryService.GetDataBuffer(pTextLines).CurrentSnapshot;
var position = snapshot?.TryGetPosition(iCurrentLine, iCurrentChar);
if (position == null)
......@@ -38,6 +34,8 @@ internal abstract partial class AbstractLanguageService<TPackage, TLanguageServi
return VSConstants.S_OK;
}
(string description, TextSpan span)? foundBlock = null;
var waitIndicator = this.Package.ComponentModel.GetService<IWaitIndicator>();
waitIndicator.Wait(
ServicesVSResources.Current_block,
......@@ -45,15 +43,15 @@ internal abstract partial class AbstractLanguageService<TPackage, TLanguageServi
allowCancel: true,
action: context =>
{
foundBlock = VsLanguageBlock.GetCurrentBlockAsync(snapshot, position.Value, context.CancellationToken).WaitAndGetResult(context.CancellationToken);
foundBlock = VsLanguageBlock.GetCurrentBlock(snapshot, position.Value, context.CancellationToken);
});
pfBlockAvailable = foundBlock != null ? 1 : 0;
pbstrDescription = foundBlock?.Item1;
pbstrDescription = foundBlock?.description;
if (foundBlock != null && ptsBlockSpan != null && ptsBlockSpan.Length >= 1)
{
ptsBlockSpan[0] = foundBlock.Item2.ToSnapshotSpan(snapshot).ToVsTextSpan();
ptsBlockSpan[0] = foundBlock.Value.span.ToSnapshotSpan(snapshot).ToVsTextSpan();
}
return VSConstants.S_OK;
......@@ -62,7 +60,7 @@ internal abstract partial class AbstractLanguageService<TPackage, TLanguageServi
internal static class VsLanguageBlock
{
public static async Task<Tuple<string, TextSpan>> GetCurrentBlockAsync(
public static (string description, TextSpan span)? GetCurrentBlock(
ITextSnapshot snapshot,
int position,
CancellationToken cancellationToken)
......@@ -74,7 +72,7 @@ internal static class VsLanguageBlock
}
var syntaxFactsService = document.Project.LanguageServices.GetService<ISyntaxFactsService>();
var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var syntaxRoot = document.GetSyntaxRootSynchronously(cancellationToken);
var node = syntaxFactsService.GetContainingMemberDeclaration(syntaxRoot, position, useFullSpan: false);
if (node == null)
{
......@@ -87,7 +85,7 @@ internal static class VsLanguageBlock
DisplayNameOptions.IncludeType |
DisplayNameOptions.IncludeTypeParameters);
return Tuple.Create(description, node.Span);
return (description, node.Span);
}
}
}
}
\ No newline at end of file
......@@ -75,6 +75,44 @@ bool IOptionPersister.TryFetch(OptionKey optionKey, out object value)
value = subKey.GetValue(key, defaultValue: (bool)optionKey.Option.DefaultValue ? 1 : 0).Equals(1);
return true;
}
else if (optionKey.Option.Type == typeof(long))
{
var untypedValue = subKey.GetValue(key, defaultValue: optionKey.Option.DefaultValue);
switch (untypedValue)
{
case string stringValue:
{
// Due to a previous bug we were accidentally serializing longs as strings.
// Gracefully convert those back.
var suceeded = long.TryParse(stringValue, out long longValue);
value = longValue;
return suceeded;
}
case long longValue:
value = longValue;
return true;
}
}
else if (optionKey.Option.Type == typeof(int))
{
var untypedValue = subKey.GetValue(key, defaultValue: optionKey.Option.DefaultValue);
switch (untypedValue)
{
case string stringValue:
{
// Due to a previous bug we were accidentally serializing ints as strings.
// Gracefully convert those back.
var suceeded = int.TryParse(stringValue, out int intValue);
value = intValue;
return suceeded;
}
case int intValue:
value = intValue;
return true;
}
}
else
{
// Otherwise we can just store normally
......@@ -83,6 +121,9 @@ bool IOptionPersister.TryFetch(OptionKey optionKey, out object value)
}
}
}
value = null;
return false;
}
bool IOptionPersister.TryPersist(OptionKey optionKey, object value)
......@@ -108,6 +149,11 @@ bool IOptionPersister.TryPersist(OptionKey optionKey, object value)
subKey.SetValue(key, (bool)value ? 1 : 0, RegistryValueKind.DWord);
return true;
}
else if (optionKey.Option.Type == typeof(long))
{
subKey.SetValue(key, value, RegistryValueKind.QWord);
return true;
}
else
{
subKey.SetValue(key, value);
......
......@@ -63,8 +63,6 @@
<Compile Include="Implementation\AnalyzerDependency\IIgnorableAssemblyList.cs" />
<Compile Include="Implementation\AnalyzerDependency\IBindingRedirectionService.cs" />
<Compile Include="Implementation\Experimentation\AnalyzerVsixSuggestedActionCallback.cs" />
<Compile Include="Implementation\Experimentation\AnalyzerABTestOptions.cs" />
<Compile Include="Implementation\Experimentation\LiveCodeAnalysisInstallStatus.cs" />
<Compile Include="Implementation\Extensions\ServiceProviderExtensions.cs" />
<Compile Include="ID.InteractiveCommands.cs" />
<Compile Include="Implementation\FindReferences\VisualStudioDefinitionsAndReferencesFactory.cs" />
......
......@@ -12,7 +12,6 @@
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.TextManager.Interop;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.CPS
{
......@@ -28,6 +27,7 @@ internal partial class CPSProjectFactory : ForegroundThreadAffinitizedObject, IW
{
new KeyValuePair<string, string> (LanguageNames.CSharp, "CS"),
new KeyValuePair<string, string> (LanguageNames.VisualBasic, "BC"),
new KeyValuePair<string, string> (LanguageNames.FSharp, "FS"),
});
[ImportingConstructor]
......
' 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.Threading
Imports System.Threading.Tasks
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService
Imports Roslyn.Test.Utilities
Namespace Tests
Public Class LanguageBlockTests
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1043580")>
Public Async Function TestGetCurrentBlock_NotInImports_VB() As Task
Await VerifyNoBlockAsync("
Public Sub TestGetCurrentBlock_NotInImports_VB()
VerifyNoBlock("
I$$mports System
Module Program
......@@ -21,11 +19,11 @@ Module Program
End Sub
End Module
", LanguageNames.VisualBasic)
End Function
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1043580")>
Public Async Function TestGetCurrentBlock_NotLeadingTriviaOfRootClass_VB() As Task
Await VerifyNoBlockAsync("
Public Sub TestGetCurrentBlock_NotLeadingTriviaOfRootClass_VB()
VerifyNoBlock("
Imports System
$$
......@@ -36,11 +34,11 @@ Module Program
End Sub
End Module
", LanguageNames.VisualBasic)
End Function
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1043580")>
Public Async Function TestGetCurrentBlock_InNamespace_VB() As Task
Await VerifyBlockAsync("
Public Sub TestGetCurrentBlock_InNamespace_VB()
VerifyBlock("
[|Namespace N
$$
Module Program
......@@ -50,11 +48,11 @@ $$
End Module
End Namespace|]
", LanguageNames.VisualBasic, "N")
End Function
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1043580")>
Public Async Function TestGetCurrentBlock_InModule_VB() As Task
Await VerifyBlockAsync("
Public Sub TestGetCurrentBlock_InModule_VB()
VerifyBlock("
Namespace N
[|Module Program
$$
......@@ -64,11 +62,11 @@ Namespace N
End Module|]
End Namespace
", LanguageNames.VisualBasic, "Program")
End Function
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1043580")>
Public Async Function TestGetCurrentBlock_InSub() As Task
Await VerifyBlockAsync("
Public Sub TestGetCurrentBlock_InSub()
VerifyBlock("
Namespace N
Module Program
[|Sub M()
......@@ -77,11 +75,11 @@ Namespace N
End Module
End Namespace
", LanguageNames.VisualBasic, "Sub Program.M()")
End Function
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1043580")>
Public Async Function TestGetCurrentBlock_InFunction() As Task
Await VerifyBlockAsync("
Public Sub TestGetCurrentBlock_InFunction()
VerifyBlock("
Namespace N
Module Program
[|Function F() As Integer
......@@ -90,11 +88,11 @@ Namespace N
End Module
End Namespace
", LanguageNames.VisualBasic, "Function Program.F() As Integer")
End Function
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1043580")>
Public Async Function TestGetCurrentBlock_InProperty_VB() As Task
Await VerifyBlockAsync("
Public Sub TestGetCurrentBlock_InProperty_VB()
VerifyBlock("
Namespace N
Module Program
[|ReadOnly Property P() As Integer
......@@ -105,11 +103,11 @@ Namespace N
End Module
End Namespace
", LanguageNames.VisualBasic, "Property Program.P() As Integer")
End Function
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1043580")>
Public Async Function TestGetCurrentBlock_NotInUsings_CS() As Task
Await VerifyNoBlockAsync("
Public Sub TestGetCurrentBlock_NotInUsings_CS()
VerifyNoBlock("
u$$sing System;
class Program
......@@ -117,11 +115,11 @@ class Program
void M() { }
}
", LanguageNames.CSharp)
End Function
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1043580")>
Public Async Function TestGetCurrentBlock_NotLeadingTriviaOfRootClass_CS() As Task
Await VerifyNoBlockAsync("
Public Sub TestGetCurrentBlock_NotLeadingTriviaOfRootClass_CS()
VerifyNoBlock("
using System;
$$
......@@ -131,11 +129,11 @@ class Program
void M() { }
}
", LanguageNames.CSharp)
End Function
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1043580")>
Public Async Function TestGetCurrentBlock_InNamespace_CS() As Task
Await VerifyBlockAsync("
Public Sub TestGetCurrentBlock_InNamespace_CS()
VerifyBlock("
[|namespace N
{
$$
......@@ -145,11 +143,11 @@ $$
}
}|]
", LanguageNames.CSharp, "N")
End Function
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1043580")>
Public Async Function TestGetCurrentBlock_InClass_CS() As Task
Await VerifyBlockAsync("
Public Sub TestGetCurrentBlock_InClass_CS()
VerifyBlock("
namespace N
{
[|class Program
......@@ -159,11 +157,11 @@ namespace N
}|]
}
", LanguageNames.CSharp, "Program")
End Function
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1043580")>
Public Async Function TestGetCurrentBlock_InMethod() As Task
Await VerifyBlockAsync("
Public Sub TestGetCurrentBlock_InMethod()
VerifyBlock("
namespace N
{
class Program
......@@ -175,11 +173,11 @@ namespace N
}
}
", LanguageNames.CSharp, "void Program.M()")
End Function
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1043580")>
Public Async Function TestGetCurrentBlock_InProperty_CS() As Task
Await VerifyBlockAsync("
Public Sub TestGetCurrentBlock_InProperty_CS()
VerifyBlock("
namespace N
{
class Program
......@@ -194,43 +192,43 @@ namespace N
}
}
", LanguageNames.CSharp, "int Program.P")
End Function
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1043580")>
Public Async Function TestGetCurrentBlock_DocumentDoesNotSupportSyntax() As Task
Public Sub TestGetCurrentBlock_DocumentDoesNotSupportSyntax()
' NoCompilation is the special Language-Name we use to indicate that a language does not
' support SyntaxTrees/SemanticModels. This test validates that we do not crash in that
' case and we gracefully bail out with 'false' for VsLanguageBlock.GetCurrentBlock.
Await VerifyNoBlockAsync("$$", languageName:="NoCompilation")
End Function
VerifyNoBlock("$$", languageName:="NoCompilation")
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock)>
Public Async Function TestGetCurrentBlock_NotInGlobalCode_CS() As Task
Await VerifyNoBlockAsync("
Public Sub TestGetCurrentBlock_NotInGlobalCode_CS()
VerifyNoBlock("
var message = ""Hello"";
System.Console$$.WriteLine(message);
", LanguageNames.CSharp, SourceCodeKind.Script)
Await VerifyNoBlockAsync("
VerifyNoBlock("
var message = ""Hello"";
System.Console$$.WriteLine(message);
", LanguageNames.CSharp, SourceCodeKind.Regular)
End Function
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock)>
Public Async Function TestGetCurrentBlock_NotInGlobalCode_VB() As Task
Await VerifyNoBlockAsync("
Public Sub TestGetCurrentBlock_NotInGlobalCode_VB()
VerifyNoBlock("
Dim message = ""Hello""
System.Console$$.WriteLine(message)
", LanguageNames.VisualBasic, SourceCodeKind.Script)
Await VerifyNoBlockAsync("
VerifyNoBlock("
Dim message = ""Hello""
System.Console$$.WriteLine(message)
", LanguageNames.VisualBasic, SourceCodeKind.Regular)
End Function
End Sub
Private Async Function VerifyNoBlockAsync(markup As String, languageName As String, Optional sourceCodeKind As SourceCodeKind = SourceCodeKind.Regular) As Tasks.Task
Private Sub VerifyNoBlock(markup As String, languageName As String, Optional sourceCodeKind As SourceCodeKind = SourceCodeKind.Regular)
Dim xml = <Workspace>
<Project Language=<%= languageName %> CommonReferences="True">
<Document>
......@@ -242,14 +240,14 @@ System.Console$$.WriteLine(message)
Using workspace = TestWorkspace.Create(xml)
Dim hostDocument = workspace.Documents.Single()
Assert.Null(Await VsLanguageBlock.GetCurrentBlockAsync(
hostDocument.TextBuffer.CurrentSnapshot,
hostDocument.CursorPosition.Value,
CancellationToken.None))
Assert.Null(VsLanguageBlock.GetCurrentBlock(
hostDocument.TextBuffer.CurrentSnapshot,
hostDocument.CursorPosition.Value,
CancellationToken.None))
End Using
End Function
End Sub
Private Async Function VerifyBlockAsync(markup As String, languageName As String, expectedDescription As String) As Tasks.Task
Private Sub VerifyBlock(markup As String, languageName As String, expectedDescription As String)
Dim xml = <Workspace>
<Project Language=<%= languageName %> CommonReferences="True">
<Document>
......@@ -260,14 +258,14 @@ System.Console$$.WriteLine(message)
Using workspace = TestWorkspace.Create(xml)
Dim hostDocument = workspace.Documents.Single()
Dim tuple = Await VsLanguageBlock.GetCurrentBlockAsync(
hostDocument.TextBuffer.CurrentSnapshot,
hostDocument.CursorPosition.Value,
CancellationToken.None)
Dim tuple = VsLanguageBlock.GetCurrentBlock(
hostDocument.TextBuffer.CurrentSnapshot,
hostDocument.CursorPosition.Value,
CancellationToken.None)
Assert.Equal(expectedDescription, tuple.Item1)
Assert.Equal(hostDocument.SelectedSpans.Single(), tuple.Item2)
Assert.Equal(expectedDescription, tuple.Value.description)
Assert.Equal(hostDocument.SelectedSpans.Single(), tuple.Value.span)
End Using
End Function
End Sub
End Class
End Namespace
\ No newline at end of file
......@@ -81,7 +81,11 @@ public static bool TryParseNotification(string value, out NotificationOption not
{
switch (value.Trim())
{
case EditorConfigSeverityStrings.Silent: notification = NotificationOption.None; return true;
case EditorConfigSeverityStrings.None:
case EditorConfigSeverityStrings.Silent:
notification = NotificationOption.None;
return true;
case EditorConfigSeverityStrings.Suggestion: notification = NotificationOption.Suggestion; return true;
case EditorConfigSeverityStrings.Warning: notification = NotificationOption.Warning; return true;
case EditorConfigSeverityStrings.Error: notification = NotificationOption.Error; return true;
......
......@@ -32,41 +32,48 @@ public static partial class SymbolFinder
internal static async Task<ImmutableArray<SymbolAndProjectId>> FindOverridesAsync(
SymbolAndProjectId symbolAndProjectId, Solution solution, IImmutableSet<Project> projects = null, CancellationToken cancellationToken = default(CancellationToken))
{
// Method can only have overrides if its a virtual, abstract or override and is not
// sealed.
var symbol = symbolAndProjectId.Symbol;
var results = ArrayBuilder<SymbolAndProjectId>.GetInstance();
var symbol = symbolAndProjectId.Symbol?.OriginalDefinition;
if (symbol.IsOverridable())
{
// To find the overrides, we need to walk down the type hierarchy and check all
// derived types. TODO(cyrusn): This seems extremely costly. Is there any way to
// speed this up?
var containingType = symbol.ContainingType.OriginalDefinition;
// derived types.
var containingType = symbol.ContainingType;
var derivedTypes = await FindDerivedClassesAsync(
symbolAndProjectId.WithSymbol(containingType),
solution, projects, cancellationToken).ConfigureAwait(false);
var results = ArrayBuilder<SymbolAndProjectId>.GetInstance();
foreach (var type in derivedTypes)
{
foreach (var m in GetMembers(type, symbol.Name))
foreach (var m in type.Symbol.GetMembers(symbol.Name))
{
var sourceMember = await FindSourceDefinitionAsync(m, solution, cancellationToken).ConfigureAwait(false);
var bestMember = sourceMember.Symbol != null ? sourceMember : m;
var member = bestMember.Symbol;
if (member != null &&
member.IsOverride &&
member.OverriddenMember() != null &&
OriginalSymbolsMatch(member.OverriddenMember().OriginalDefinition, symbol.OriginalDefinition, solution, cancellationToken))
var bestMember = sourceMember ?? m;
if (IsOverride(solution, bestMember, symbol, cancellationToken))
{
results.Add(bestMember);
results.Add(new SymbolAndProjectId(bestMember, type.ProjectId));
}
}
}
}
return results.ToImmutableAndFree();
return results.ToImmutableAndFree();
}
private static bool IsOverride(
Solution solution, ISymbol member, ISymbol symbol, CancellationToken cancellationToken)
{
for (var current = member; current != null; current = current.OverriddenMember())
{
if (OriginalSymbolsMatch(current.OverriddenMember(), symbol.OriginalDefinition, solution, cancellationToken))
{
return true;
}
}
return ImmutableArray<SymbolAndProjectId>.Empty;
return false;
}
/// <summary>
......
......@@ -392,5 +392,6 @@ internal enum FunctionId
CompilationService_GetCompilationAsync,
SolutionCreator_AssetDifferences,
Extension_InfoBar,
Experiment_ABTesting,
}
}
......@@ -49,7 +49,10 @@ private static DiagnosticSeverity ParseEnforcementLevel(string ruleSeverity)
{
switch (ruleSeverity)
{
case EditorConfigSeverityStrings.Silent: return DiagnosticSeverity.Hidden;
case EditorConfigSeverityStrings.None:
case EditorConfigSeverityStrings.Silent:
return DiagnosticSeverity.Hidden;
case EditorConfigSeverityStrings.Suggestion: return DiagnosticSeverity.Info;
case EditorConfigSeverityStrings.Warning: return DiagnosticSeverity.Warning;
case EditorConfigSeverityStrings.Error: return DiagnosticSeverity.Error;
......
......@@ -4,6 +4,7 @@ namespace Microsoft.CodeAnalysis
{
internal static class EditorConfigSeverityStrings
{
public const string None = "none";
public const string Silent = "silent";
public const string Suggestion = "suggestion";
public const string Warning = "warning";
......
......@@ -102,12 +102,11 @@ public static ImmutableArray<ISymbol> ExplicitInterfaceImplementations(this ISym
public static bool IsOverridable(this ISymbol symbol)
{
return
symbol != null &&
symbol.ContainingType != null &&
symbol.ContainingType.TypeKind == TypeKind.Class &&
(symbol.IsVirtual || symbol.IsAbstract || symbol.IsOverride) &&
!symbol.IsSealed;
// Members can only have overrides if they are virtual, abstract or override and is not
// sealed.
return symbol?.ContainingType?.TypeKind == TypeKind.Class &&
(symbol.IsVirtual || symbol.IsAbstract || symbol.IsOverride) &&
!symbol.IsSealed;
}
public static bool IsImplementableMember(this ISymbol symbol)
......
......@@ -11,11 +11,13 @@ namespace Microsoft.CodeAnalysis.UnitTests.CodeStyle
public class EditorConfigCodeStyleParserTests
{
[Theory]
[InlineData("true:none", true, DiagnosticSeverity.Hidden)]
[InlineData("true:silent", true, DiagnosticSeverity.Hidden)]
[InlineData("true:suggestion", true, DiagnosticSeverity.Info)]
[InlineData("true:warning", true, DiagnosticSeverity.Warning)]
[InlineData("true:error", true, DiagnosticSeverity.Error)]
[InlineData("true", false, DiagnosticSeverity.Hidden)]
[InlineData("false:none", false, DiagnosticSeverity.Hidden)]
[InlineData("false:silent", false, DiagnosticSeverity.Hidden)]
[InlineData("false:suggestion", false, DiagnosticSeverity.Info)]
[InlineData("false:warning", false, DiagnosticSeverity.Warning)]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册