提交 ebd9e8be 编写于 作者: C CyrusNajmabadi

Merge remote-tracking branch 'upstream/master' into optionresilience

......@@ -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>
......
......@@ -15,7 +15,7 @@
<!-- The release moniker for our packages. Developers should use "dev" and official builds pick the branch
moniker listed below -->
<RoslynNuGetMoniker Condition="'$(RoslynNuGetMoniker)' == ''">dev</RoslynNuGetMoniker>
<RoslynNuGetMoniker Condition="'$(OfficialBuild)' == 'true'">beta2</RoslynNuGetMoniker>
<RoslynNuGetMoniker Condition="'$(OfficialBuild)' == 'true'">beta3</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
......
......@@ -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]
......
......@@ -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");
}
}
}
......@@ -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)
{
......
......@@ -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);
}
}
}
......@@ -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());
}
}
}
......@@ -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
......
// 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
......@@ -78,7 +78,6 @@ bool IOptionPersister.TryFetch(OptionKey optionKey, out object value)
else if (optionKey.Option.Type == typeof(long))
{
var untypedValue = subKey.GetValue(key, defaultValue: optionKey.Option.DefaultValue);
if (untypedValue is string stringValue)
{
// Due to a previous bug we were accidentally serializing longs as strings. Gracefully convert
......@@ -150,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" />
......
' 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.
先完成此消息的编辑!
想要评论请 注册