提交 26beb0b0 编写于 作者: H Heejae Chang

Merge branch 'master' of https://github.com/dotnet/roslyn into deadcode2

......@@ -10,4 +10,5 @@
<package id="FakeSign" version="0.9.2" targetFramework="net45" />
<package id="dnx-coreclr-win-x86" version="1.0.0-beta5-12101" />
<package id="dnx-mono" version="1.0.0-beta5-12101" />
<package id="Microsoft.Build.Mono.Debug" version="14.1.0.0-prerelease" />
</packages>
......@@ -55,6 +55,17 @@
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" Condition="'$(ProjectLanguage)' == 'CSharp' And '$(TargetFrameworkIdentifier)' != '.NETPortable' And '$(TargetCoreClr)' != 'True'" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" Condition="'$(ProjectLanguage)' == 'C++'" />
<!-- It looks like MSBuild has a bug on *nix where they aggressively
directory separators from '\' to '/', even when the '\'
is being used as an escape character in a define constant in VB.
This change works around the bug by removing all quotes from
define constants after Microsoft.VisualBasic.CurrentVersion adds
them in our build. This should be OK since none of our constants
should require quoting. See https://github.com/Microsoft/msbuild/issues/137 -->
<PropertyGroup Condition="'$(OS)' != 'Windows_NT'">
<FinalDefineConstants>$(FinalDefineConstants.Replace('"', ''))</FinalDefineConstants>
</PropertyGroup>
<PropertyGroup>
<BuildDependsOn>
$(BuildDependsOn);
......
......@@ -52,7 +52,7 @@ done
run_xbuild()
{
xbuild /v:m /p:SignAssembly=false /p:DebugSymbols=false "$@"
mono packages/Microsoft.Build.Mono.Debug.14.1.0.0-prerelease/lib/MSBuild.exe /v:m /p:SignAssembly=false /p:DebugSymbols=false "$@"
if [ $? -ne 0 ]; then
echo Compilation failed
exit 1
......@@ -115,7 +115,7 @@ save_toolset()
clean_roslyn()
{
echo Cleaning the enlistment
xbuild /v:m /t:Clean build/Toolset.sln /p:Configuration=$BUILD_CONFIGURATION
mono packages/Microsoft.Build.Mono.Debug.14.1.0.0-prerelease/lib/MSBuild.exe /v:m /t:Clean build/Toolset.sln /p:Configuration=$BUILD_CONFIGURATION
rm -rf Binaries/$BUILD_CONFIGURATION
}
......
......@@ -238,7 +238,16 @@ private void CheckBinaryOperator(BoundBinaryOperator node)
private void CheckCompoundAssignmentOperator(BoundCompoundAssignmentOperator node)
{
CheckForBitwiseOrSignExtend(node, node.Operator.Kind, node.Left, node.Right);
BoundExpression left = node.Left;
if (!node.Operator.Kind.IsDynamic() && !node.LeftConversion.IsIdentity && node.LeftConversion.Exists)
{
// Need to represent the implicit conversion as a node in order to be able to produce correct diagnostics.
left = new BoundConversion(left.Syntax, left, node.LeftConversion, node.Operator.Kind.IsChecked(),
explicitCastInCode: false, constantValueOpt: null, type: node.Operator.LeftType);
}
CheckForBitwiseOrSignExtend(node, node.Operator.Kind, left, node.Right);
CheckLiftedCompoundAssignment(node);
if (_inExpressionLambda)
......
......@@ -53,8 +53,12 @@
</ProjectReference>
</ItemGroup>
<ItemGroup Label="File References">
<Reference Include="..\..\..\..\..\packages\System.Reflection.Metadata.$(SystemReflectionMetadataVersion)\lib\portable-net45+win8\System.Reflection.Metadata.dll" />
<Reference Include="..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll" />
<Reference Include="System.Reflection.Metadata.dll">
<HintPath>..\..\..\..\..\packages\System.Reflection.Metadata.$(SystemReflectionMetadataVersion)\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
</Reference>
<Reference Include="System.Collections.Immutable.dll">
<HintPath>..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="xunit">
<HintPath>..\..\..\..\..\packages\xunit.1.9.2\lib\net20\xunit.dll</HintPath>
</Reference>
......
......@@ -119,6 +119,6 @@
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="csc_rsp" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\..\csc\csc.rsp;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>../../csc/csc.rsp;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>
\ No newline at end of file
</root>
......@@ -52,9 +52,15 @@
</ProjectReference>
</ItemGroup>
<ItemGroup Label="File References">
<Reference Include="..\..\..\..\..\packages\System.Reflection.Metadata.$(SystemReflectionMetadataVersion)\lib\portable-net45+win8\System.Reflection.Metadata.dll" />
<Reference Include="..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll" />
<Reference Include="..\..\..\..\..\packages\Microsoft.DiaSymReader.1.0.5\lib\net45\Microsoft.DiaSymReader.dll" />
<Reference Include="System.Reflection.Metadata.dll">
<HintPath>..\..\..\..\..\packages\System.Reflection.Metadata.$(SystemReflectionMetadataVersion)\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
</Reference>
<Reference Include="System.Collections.Immutable.dll">
<HintPath>..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="Microsoft.DiaSymReader.dll">
<HintPath>..\..\..\..\..\packages\Microsoft.DiaSymReader.1.0.5\lib\net45\Microsoft.DiaSymReader.dll</HintPath>
</Reference>
<Reference Include="xunit">
<HintPath>..\..\..\..\..\packages\xunit.1.9.2\lib\net20\xunit.dll</HintPath>
</Reference>
......@@ -206,4 +212,4 @@
<Import Project="..\..\..\..\..\build\Targets\Roslyn.Toolsets.Xunit.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
\ No newline at end of file
</Project>
......@@ -48,7 +48,9 @@
</ProjectReference>
</ItemGroup>
<ItemGroup Label="File References">
<Reference Include="..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll" />
<Reference Include="System.Collections.Immutable">
<HintPath>..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="xunit">
<HintPath>..\..\..\..\..\packages\xunit.1.9.2\lib\net20\xunit.dll</HintPath>
</Reference>
......
......@@ -1105,6 +1105,20 @@ void Method()
TestGenericNameCore(source, new AnalyzerWithNoActions(), new CSharpGenericNameAnalyzer());
}
[Fact, WorkItem(4055, "https://github.com/dotnet/roslyn/issues/4055")]
public void TestAnalyzerWithNoSupportedDiagnostics()
{
var source = @"
class MyClass
{
}";
// Ensure that adding a dummy analyzer with no supported diagnostics doesn't bring down entire analysis.
var analyzers = new DiagnosticAnalyzer[] { new AnalyzerWithNoSupportedDiagnostics() };
CreateCompilationWithMscorlib45(source)
.VerifyDiagnostics()
.VerifyAnalyzerDiagnostics(analyzers);
}
private static void TestEffectiveSeverity(
DiagnosticSeverity defaultSeverity,
ReportDiagnostic expectedEffectiveSeverity,
......
......@@ -8728,5 +8728,26 @@ operator int (IntHolder ih)
operator IntHolder(int i)
'y' is 5");
}
[Fact, WorkItem(4027, "https://github.com/dotnet/roslyn/issues/4027")]
public void NotSignExtendedOperand()
{
string source = @"
class MainClass
{
public static void Main ()
{
short a = 0;
int b = 0;
a |= (short)b;
a = (short)(a | (short)b);
}
}
";
var compilation = CreateCompilationWithMscorlib(source, options: TestOptions.DebugDll);
compilation.VerifyDiagnostics();
}
}
}
......@@ -52,9 +52,15 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\packages\Microsoft.CodeAnalysis.Test.Resources.Proprietary.1.1.0-beta1-20150716-08\lib\net45\Microsoft.CodeAnalysis.Test.Resources.Proprietary.dll</HintPath>
</Reference>
<Reference Include="..\..\..\..\..\packages\System.Reflection.Metadata.$(SystemReflectionMetadataVersion)\lib\portable-net45+win8\System.Reflection.Metadata.dll" />
<Reference Include="..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll" />
<Reference Include="..\..\..\..\..\packages\Microsoft.DiaSymReader.1.0.5\lib\net45\Microsoft.DiaSymReader.dll" />
<Reference Include="System.Reflection.Metadata.dll">
<HintPath>..\..\..\..\..\packages\System.Reflection.Metadata.$(SystemReflectionMetadataVersion)\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
</Reference>
<Reference Include="System.Collections.Immutable">
<HintPath>..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="Microsoft.DiaSymReader.dll">
<HintPath>..\..\..\..\..\packages\Microsoft.DiaSymReader.1.0.5\lib\net45\Microsoft.DiaSymReader.dll</HintPath>
</Reference>
<Reference Include="xunit">
<HintPath>..\..\..\..\..\packages\xunit.1.9.2\lib\net20\xunit.dll</HintPath>
</Reference>
......
......@@ -22,7 +22,9 @@
<SyntaxTestDefinition Include="..\..\Portable\Syntax\Syntax.xml" />
</ItemGroup>
<ItemGroup Label="File References">
<Reference Include="..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll" />
<Reference Include="System.Collections.Immutable.dll">
<HintPath>..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="xunit">
<HintPath>..\..\..\..\..\packages\xunit.1.9.2\lib\net20\xunit.dll</HintPath>
</Reference>
......
......@@ -70,8 +70,12 @@
</ProjectReference>
</ItemGroup>
<ItemGroup Label="File References">
<Reference Include="..\..\..\..\packages\System.Reflection.Metadata.$(SystemReflectionMetadataVersion)\lib\portable-net45+win8\System.Reflection.Metadata.dll" />
<Reference Include="..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll" />
<Reference Include="System.Reflection.Metadata.dll">
<HintPath>..\..\..\..\packages\System.Reflection.Metadata.$(SystemReflectionMetadataVersion)\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
</Reference>
<Reference Include="System.Collections.Immutable.dll">
<HintPath>..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="xunit">
<HintPath>..\..\..\..\packages\xunit.1.9.2\lib\net20\xunit.dll</HintPath>
</Reference>
......@@ -174,10 +178,10 @@
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="Resources\default.win32manifest" />
<None Include="Resources\nativeWithStringIDsAndTypesAndIntTypes.res" />
<None Include="Resources\Roslyn.ico.blah" />
<None Include="Resources\VerResourceBuiltByRC.RES" />
<None Include="Resources/default.win32manifest" />
<None Include="Resources/nativeWithStringIDsAndTypesAndIntTypes.res" />
<None Include="Resources/Roslyn.ico.blah" />
<None Include="Resources/VerResourceBuiltByRC.RES" />
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
......@@ -187,4 +191,4 @@
<Import Project="..\..\..\..\build\Targets\Roslyn.Toolsets.Xunit.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
\ No newline at end of file
</Project>
......@@ -121,15 +121,15 @@
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="defaultWin32Manifest" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\default.win32manifest;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>Resources/default.win32manifest;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="VerResourceBuiltByRC" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\VerResourceBuiltByRC.RES;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>Resources/VerResourceBuiltByRC.RES;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="nativeWithStringIDsAndTypesAndIntTypes" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\nativeWithStringIDsAndTypesAndIntTypes.res;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>Resources/nativeWithStringIDsAndTypesAndIntTypes.res;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Roslyn_ico" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\Roslyn.ico.blah;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>Resources/Roslyn.ico.blah;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>
......@@ -308,6 +308,45 @@ private ImmutableArray<Cci.AssemblyReferenceAlias> CalculateAssemblyReferenceAli
#region Synthesized Members
#if DEBUG
/// <summary>
/// The queue of synthesized members of a type should be deterministic, as the members are
/// emitted in the order in which they are added to the queue. Therefore for debug purposes
/// we have a custom version of ConcurrentQueue that detects attempted concurrent adds.
/// </summary>
/// <typeparam name="T"></typeparam>
private class ConcurrentQueue<T> : System.Collections.Concurrent.ConcurrentQueue<T>
{
// A count of the number of concurrent queue operations in progress. Should always be zero or one,
// as synthetic members should be added by the compiler to a given type in a well-defined sequential
// order.
int queueing;
// A short delay to increase the chance that concurrent Enqueue operation will be diagnosed.
static readonly TimeSpan shortDelay = new TimeSpan(2);
/// <summary>
/// Adds an object to the end of the ConcurrentQueue.
/// </summary>
/// <param name="item">
/// The object to add to the end of the ConcurrentQueue.
/// The value can be a null reference for reference types.
/// </param>
public new void Enqueue(T item)
{
if (Interlocked.Increment(ref queueing) != 1)
{
throw new System.InvalidOperationException("Concurrent use of " + nameof(SynthesizedDefinitions));
}
base.Enqueue(item);
// To increase the chance of catching concurrency issues, we add a delay to each queued item
// so that another thread has a chance to add at the same time.
System.Threading.Tasks.Task.Delay(shortDelay).Wait();
Interlocked.Decrement(ref queueing);
}
}
#endif
/// <summary>
/// Captures the set of synthesized definitions that should be added to a type
/// during emit process.
......
......@@ -27,8 +27,12 @@
</ProjectReference>
</ItemGroup>
<ItemGroup Label="File References">
<Reference Include="..\..\..\..\..\packages\System.Reflection.Metadata.$(SystemReflectionMetadataVersion)\lib\portable-net45+win8\System.Reflection.Metadata.dll" />
<Reference Include="..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll" />
<Reference Include="System.Reflection.Metadata.dll">
<HintPath>..\..\..\..\..\packages\System.Reflection.Metadata.$(SystemReflectionMetadataVersion)\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
</Reference>
<Reference Include="System.Collections.Immutable.dll">
<HintPath>..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="xunit">
<HintPath>..\..\..\..\..\packages\xunit.1.9.2\lib\net20\xunit.dll</HintPath>
</Reference>
......
......@@ -21,7 +21,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
'''Creates a string representing the unformatted LocalizableErrorArgument instance.
''' </summary>
Public Overrides Function ToString() As String
Return ToString(Nothing)
Return ToString_IFormattable(Nothing, Nothing)
End Function
''' <summary>
......
......@@ -58,8 +58,12 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\packages\Microsoft.CodeAnalysis.Test.Resources.Proprietary.1.1.0-beta1-20150716-08\lib\net45\Microsoft.CodeAnalysis.Test.Resources.Proprietary.dll</HintPath>
</Reference>
<Reference Include="..\..\..\..\..\packages\System.Reflection.Metadata.$(SystemReflectionMetadataVersion)\lib\portable-net45+win8\System.Reflection.Metadata.dll" />
<Reference Include="..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll" />
<Reference Include="System.Reflection.Metadata.dll">
<HintPath>..\..\..\..\..\packages\System.Reflection.Metadata.$(SystemReflectionMetadataVersion)\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
</Reference>
<Reference Include="System.Collections.Immutable.dll">
<HintPath>..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="xunit">
<HintPath>..\..\..\..\..\packages\xunit.1.9.2\lib\net20\xunit.dll</HintPath>
</Reference>
......
......@@ -119,6 +119,6 @@
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="vbc_rsp" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\..\vbc\vbc.rsp;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>../../vbc/vbc.rsp;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>
\ No newline at end of file
</root>
......@@ -46,9 +46,15 @@
</ProjectReference>
</ItemGroup>
<ItemGroup Label="File References">
<Reference Include="..\..\..\..\..\packages\System.Reflection.Metadata.$(SystemReflectionMetadataVersion)\lib\portable-net45+win8\System.Reflection.Metadata.dll" />
<Reference Include="..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll" />
<Reference Include="..\..\..\..\..\packages\Microsoft.DiaSymReader.1.0.5\lib\net45\Microsoft.DiaSymReader.dll" />
<Reference Include="System.Reflection.Metadata.dll">
<HintPath>..\..\..\..\..\packages\System.Reflection.Metadata.$(SystemReflectionMetadataVersion)\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
</Reference>
<Reference Include="System.Colections.Immutable.dll">
<HintPath>..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="Microsoft.DiaSymReader.dll">
<HintPath>..\..\..\..\..\packages\Microsoft.DiaSymReader.1.0.5\lib\net45\Microsoft.DiaSymReader.dll</HintPath>
</Reference>
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
......
......@@ -21,6 +21,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests
Public Class CompilationAPITests
Inherits BasicTestBase
<Fact>
Public Sub LocalizableErrorArgumentToStringDoesntStackOverflow()
' Error ID is arbitrary
Dim arg = New LocalizableErrorArgument(ERRID.IDS_ProjectSettingsLocationName)
Assert.NotNull(arg.ToString())
End Sub
<WorkItem(538778, "DevDiv")>
<WorkItem(537623, "DevDiv")>
<Fact>
......
......@@ -119,37 +119,37 @@
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="Async_Overload_Change_3_vb" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Semantics\Async_Overload_Change_3.vb.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<value>Semantics/Async_Overload_Change_3.vb.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="BinaryOperatorsTestBaseline1" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Semantics\BinaryOperatorsTestBaseline1.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<value>Semantics/BinaryOperatorsTestBaseline1.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="BinaryOperatorsTestBaseline2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Semantics\BinaryOperatorsTestBaseline2.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<value>Semantics/BinaryOperatorsTestBaseline2.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="BinaryOperatorsTestBaseline3" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Semantics\BinaryOperatorsTestBaseline3.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<value>Semantics/BinaryOperatorsTestBaseline3.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="BinaryOperatorsTestBaseline4" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Semantics\BinaryOperatorsTestBaseline4.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<value>Semantics/BinaryOperatorsTestBaseline4.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="BinaryOperatorsTestBaseline5" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Semantics\BinaryOperatorsTestBaseline5.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<value>Semantics/BinaryOperatorsTestBaseline5.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="BinaryOperatorsTestSource1" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Semantics\BinaryOperatorsTestSource1.vb;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<value>Semantics/BinaryOperatorsTestSource1.vb;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="BinaryOperatorsTestSource2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Semantics\BinaryOperatorsTestSource2.vb;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<value>Semantics/BinaryOperatorsTestSource2.vb;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="BinaryOperatorsTestSource3" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Semantics\BinaryOperatorsTestSource3.vb;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<value>Semantics/BinaryOperatorsTestSource3.vb;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="BinaryOperatorsTestSource4" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Semantics\BinaryOperatorsTestSource4.vb;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<value>Semantics/BinaryOperatorsTestSource4.vb;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="BinaryOperatorsTestSource5" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Semantics\BinaryOperatorsTestSource5.vb;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<value>Semantics/BinaryOperatorsTestSource5.vb;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="EmitSimpleBaseLine1" xml:space="preserve">
<value>&lt;Global&gt;
......@@ -182,21 +182,21 @@
&lt;/Global&gt;</value>
</data>
<data name="LongTypeNameNative_vb" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Semantics\LongTypeNameNative.vb.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<value>Semantics/LongTypeNameNative.vb.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="LongTypeName_vb" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Semantics\LongTypeName.vb.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<value>Semantics/LongTypeName.vb.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="OverloadResolutionTestSource" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Semantics\OverloadResolutionTestSource.vb;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<value>Semantics/OverloadResolutionTestSource.vb;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="PrintResultTestSource" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Semantics\PrintResultTestSource.vb;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<value>Semantics/PrintResultTestSource.vb;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="T_1247520" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Binding\T_1247520.cs;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
<value>Binding/T_1247520.cs;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="T_68086" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Binding\T_68086.vb;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
<value>Binding/T_68086.vb;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
</root>
......@@ -46,8 +46,12 @@
</ProjectReference>
</ItemGroup>
<ItemGroup Label="File References">
<Reference Include="..\..\..\..\..\packages\System.Reflection.Metadata.$(SystemReflectionMetadataVersion)\lib\portable-net45+win8\System.Reflection.Metadata.dll" />
<Reference Include="..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll" />
<Reference Include="System.Reflection.Metadata.dll">
<HintPath>..\..\..\..\..\packages\System.Reflection.Metadata.$(SystemReflectionMetadataVersion)\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
</Reference>
<Reference Include="System.Collections.Immutable.dll">
<HintPath>..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="xunit">
<HintPath>..\..\..\..\..\packages\xunit.1.9.2\lib\net20\xunit.dll</HintPath>
</Reference>
......
......@@ -20,7 +20,9 @@
<SyntaxTestDefinition Include="..\..\Portable\Syntax\Syntax.xml" />
</ItemGroup>
<ItemGroup Label="File References">
<Reference Include="..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll" />
<Reference Include="System.Collections.Immutable.dll">
<HintPath>..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\..\..\..\Tools\Source\CompilerGeneratorTools\Source\VisualBasicSyntaxGenerator\VisualBasicSyntaxGenerator.vbproj">
......
......@@ -121,6 +121,6 @@
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="VBAllInOne" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\VBAllInOne.vb;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<value>Resources/VBAllInOne.vb;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
</root>
......@@ -29,27 +29,21 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="..\..\..\packages\Microsoft.DiaSymReader.1.0.5\lib\net45\Microsoft.DiaSymReader.dll" />
<Reference Include="..\..\..\packages\System.IO.FileSystem.4.0.0-beta-22816\lib\portable-wpa81+wp80+win80+net45+aspnetcore50\System.IO.FileSystem.dll">
<Reference Include="Microsoft.DiaSymReader.dll">
<HintPath>..\..\..\packages\Microsoft.DiaSymReader.1.0.5\lib\net45\Microsoft.DiaSymReader.dll</HintPath>
</Reference>
<Reference Include="System.IO.FileSystem.dll">
<HintPath>..\..\..\packages\System.IO.FileSystem.4.0.0-beta-22816\lib\portable-wpa81+wp80+win80+net45+aspnetcore50\System.IO.FileSystem.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="..\..\..\packages\System.IO.FileSystem.Primitives.4.0.0-beta-22816\lib\portable-wpa81+wp80+win80+net45+aspnetcore50\System.IO.FileSystem.Primitives.dll">
<Reference Include="System.IO.FileSystem.Primitives.dll">
<HintPath>..\..\..\packages\System.IO.FileSystem.Primitives.4.0.0-beta-22816\lib\portable-wpa81+wp80+win80+net45+aspnetcore50\System.IO.FileSystem.Primitives.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="..\..\..\packages\System.IO.MemoryMappedFiles.4.0.0-beta-22816\lib\portable-wpa81+wp80+win80+net45+aspnetcore50\System.IO.MemoryMappedFiles.dll">
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Content Include="..\..\..\packages\System.IO.FileSystem.4.0.0-beta-22816\lib\net45\System.IO.FileSystem.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>false</Visible>
</Content>
<Content Include="..\..\..\packages\System.IO.MemoryMappedFiles.4.0.0-beta-22816\lib\net45\System.IO.MemoryMappedFiles.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>false</Visible>
</Content>
</ItemGroup>
<ItemGroup>
<Compile Include="AsyncMethodData.cs" />
<Compile Include="Utilities\BlobWriter.cs" />
......@@ -85,4 +79,4 @@
<Import Project="..\..\..\build\Targets\VSL.Imports.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
\ No newline at end of file
</Project>
......@@ -794,6 +794,8 @@ class AnonymousFunctions
Using workspace = TestWorkspaceFactory.CreateWorkspace(test)
Dim project = workspace.CurrentSolution.Projects.Single()
' Test partial type diagnostic reported on user file.
Dim analyzer = New PartialTypeDiagnosticAnalyzer(indexOfDeclToReportDiagnostic:=1)
Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer))
project = project.AddAnalyzerReference(analyzerReference)
......@@ -813,6 +815,52 @@ class AnonymousFunctions
End Using
End Sub
<Fact, WorkItem(1042914), Trait(Traits.Feature, Traits.Features.Diagnostics)>
Public Sub TestDiagnosticsReportedOnAllPartialDefinitions()
Dim test = <Workspace>
<Project Language="C#" CommonReferences="true">
<Document FilePath="Test1.cs">
public partial class Foo { }
</Document>
<Document FilePath="Test2.cs">
public partial class Foo { }
</Document>
</Project>
</Workspace>
Using workspace = TestWorkspaceFactory.CreateWorkspace(test)
Dim project = workspace.CurrentSolution.Projects.Single()
' Test partial type diagnostic reported on all source files.
Dim analyzer = New PartialTypeDiagnosticAnalyzer(indexOfDeclToReportDiagnostic:=Nothing)
Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer))
project = project.AddAnalyzerReference(analyzerReference)
Dim diagnosticService = New TestDiagnosticAnalyzerService()
Dim descriptorsMap = diagnosticService.GetDiagnosticDescriptors(project)
Assert.Equal(1, descriptorsMap.Count)
' Verify project diagnostics contains diagnostics reported on both partial definitions.
Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace)
Dim diagnostics = diagnosticService.GetDiagnosticsAsync(project.Solution, project.Id).WaitAndGetResult(CancellationToken.None)
Assert.Equal(2, diagnostics.Count())
Dim file1HasDiag = False, file2HasDiag = False
For Each diagnostic In diagnostics
Assert.Equal(PartialTypeDiagnosticAnalyzer.DiagDescriptor.Id, diagnostic.Id)
Dim document = project.GetDocument(diagnostic.DocumentId)
If document.Name = "Test1.cs" Then
file1HasDiag = True
ElseIf document.Name = "Test2.cs"
file2HasDiag = True
End If
Next
Assert.True(file1HasDiag)
Assert.True(file2HasDiag)
End Using
End Sub
<Fact, WorkItem(1067286)>
Private Sub TestCodeBlockAnalyzersForExpressionBody()
Dim test = <Workspace>
......@@ -1228,8 +1276,8 @@ public class B
Private Class PartialTypeDiagnosticAnalyzer
Inherits DiagnosticAnalyzer
Private ReadOnly _indexOfDeclToReportDiagnostic As Integer
Public Sub New(indexOfDeclToReportDiagnostic As Integer)
Private ReadOnly _indexOfDeclToReportDiagnostic As Integer?
Public Sub New(indexOfDeclToReportDiagnostic As Integer?)
Me._indexOfDeclToReportDiagnostic = indexOfDeclToReportDiagnostic
End Sub
......@@ -1246,7 +1294,15 @@ public class B
End Sub
Private Sub AnalyzeSymbol(context As SymbolAnalysisContext)
context.ReportDiagnostic(Diagnostic.Create(DiagDescriptor, context.Symbol.Locations.ElementAt(Me._indexOfDeclToReportDiagnostic)))
Dim index = 0
For Each location In context.Symbol.Locations
If Not Me._indexOfDeclToReportDiagnostic.HasValue OrElse Me._indexOfDeclToReportDiagnostic.Value = index Then
context.ReportDiagnostic(Diagnostic.Create(DiagDescriptor, location))
End If
index += 1
Next
End Sub
End Class
......@@ -1685,5 +1741,43 @@ namespace ConsoleApplication1
' See https//github.com/dotnet/roslyn/issues/2980 for details.
TestGenericNameCore(test, CSharpGenericNameAnalyzer.Message, CSharpGenericNameAnalyzer.DiagnosticId, New AnalyzerWithNoActions, New CSharpGenericNameAnalyzer)
End Sub
<Fact, WorkItem(4055, "https://github.com/dotnet/roslyn/issues/4055")>
Public Sub TestAnalyzerWithNoSupportedDiagnostics()
Dim test = <Workspace>
<Project Language="C#" CommonReferences="true">
<Document><![CDATA[
class MyClass
{
}]]>
</Document>
</Project>
</Workspace>
' Ensure that adding a dummy analyzer with no supported diagnostics doesn't bring down entire analysis.
Using workspace = TestWorkspaceFactory.CreateWorkspace(test)
Dim project = workspace.CurrentSolution.Projects.Single()
' Add analyzer
Dim analyzer = New AnalyzerWithNoSupportedDiagnostics()
Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(analyzer))
project = project.AddAnalyzerReference(analyzerReference)
Dim diagnosticService = New TestDiagnosticAnalyzerService()
Dim incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace)
' Verify available diagnostic descriptors/analyzers
Dim descriptorsMap = diagnosticService.GetDiagnosticDescriptors(project)
Assert.Equal(1, descriptorsMap.Count)
Assert.Equal(0, descriptorsMap.First().Value.Length)
Dim document = project.Documents.Single()
Dim diagnostics = diagnosticService.GetDiagnosticsForSpanAsync(document,
document.GetSyntaxRootAsync().WaitAndGetResult(CancellationToken.None).FullSpan,
CancellationToken.None).WaitAndGetResult(CancellationToken.None)
Assert.Equal(0, diagnostics.Count())
End Using
End Sub
End Class
End Namespace
......@@ -8,16 +8,9 @@ internal static class CompletionOptions
{
public const string FeatureName = "Completion";
[ExportOption]
public static readonly PerLanguageOption<bool> HideAdvancedMembers = new PerLanguageOption<bool>(FeatureName, "HideAdvancedMembers", defaultValue: false);
[ExportOption]
public static readonly PerLanguageOption<bool> IncludeKeywords = new PerLanguageOption<bool>(FeatureName, "IncludeKeywords", defaultValue: true);
[ExportOption]
public static readonly PerLanguageOption<bool> TriggerOnTyping = new PerLanguageOption<bool>(FeatureName, "TriggerOnTyping", defaultValue: true);
[ExportOption]
public static readonly PerLanguageOption<bool> TriggerOnTypingLetters = new PerLanguageOption<bool>(FeatureName, "TriggerOnTypingLetters", defaultValue: true);
}
}
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Options.Providers;
namespace Microsoft.CodeAnalysis.Completion
{
[ExportOptionProvider, Shared]
internal class CompletionOptionsProvider : IOptionProvider
{
private readonly IEnumerable<IOption> _options = new List<IOption>
{
CompletionOptions.HideAdvancedMembers,
CompletionOptions.IncludeKeywords,
CompletionOptions.TriggerOnTyping,
CompletionOptions.TriggerOnTypingLetters
}.ToImmutableArray();
public IEnumerable<IOption> GetOptions()
{
return _options;
}
}
}
......@@ -8,28 +8,13 @@ internal static class InternalDiagnosticsOptions
{
public const string OptionName = "InternalDiagnosticsOptions";
[ExportOption]
public static readonly Option<bool> BlueSquiggleForBuildDiagnostic = new Option<bool>(OptionName, "Blue Squiggle For Build Diagnostic", defaultValue: false);
[ExportOption]
public static readonly Option<bool> UseDiagnosticEngineV2 = new Option<bool>(OptionName, "Use Diagnostic Engine V2", defaultValue: false);
[ExportOption]
public static readonly Option<bool> CompilationEndCodeFix = new Option<bool>(OptionName, "Enable Compilation End Code Fix", defaultValue: true);
[ExportOption]
public static readonly Option<bool> UseCompilationEndCodeFixHeuristic = new Option<bool>(OptionName, "Enable Compilation End Code Fix With Heuristic", defaultValue: true);
[ExportOption]
public static readonly Option<bool> BuildErrorIsTheGod = new Option<bool>(OptionName, "Make build errors to take over everything", defaultValue: false);
[ExportOption]
public static readonly Option<bool> ClearLiveErrorsForProjectBuilt = new Option<bool>(OptionName, "Clear all live errors of projects that got built", defaultValue: false);
[ExportOption]
public static readonly Option<bool> PreferLiveErrorsOnOpenedFiles = new Option<bool>(OptionName, "Live errors will be preferred over errors from build on opened files from same analyzer", defaultValue: true);
[ExportOption]
public static readonly Option<bool> PreferBuildErrorsOverLiveErrors = new Option<bool>(OptionName, "Errors from build will be preferred over live errors from same analyzer", defaultValue: true);
}
}
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Options.Providers;
namespace Microsoft.CodeAnalysis.Diagnostics
{
[ExportOptionProvider, Shared]
internal class InternalDiagnosticsOptionsProvider : IOptionProvider
{
private readonly IEnumerable<IOption> _options = new List<IOption>
{
InternalDiagnosticsOptions.BlueSquiggleForBuildDiagnostic,
InternalDiagnosticsOptions.UseDiagnosticEngineV2,
InternalDiagnosticsOptions.CompilationEndCodeFix,
InternalDiagnosticsOptions.UseCompilationEndCodeFixHeuristic,
InternalDiagnosticsOptions.BuildErrorIsTheGod,
InternalDiagnosticsOptions.ClearLiveErrorsForProjectBuilt,
InternalDiagnosticsOptions.PreferLiveErrorsOnOpenedFiles,
InternalDiagnosticsOptions.PreferBuildErrorsOverLiveErrors
}.ToImmutableArray();
public IEnumerable<IOption> GetOptions()
{
return _options;
}
}
}
......@@ -8,13 +8,8 @@ internal static class ExtractMethodOptions
{
public const string FeatureName = "ExtractMethod";
[ExportOption]
public static readonly PerLanguageOption<bool> AllowBestEffort = new PerLanguageOption<bool>(FeatureName, "Allow Best Effort", defaultValue: false);
[ExportOption]
public static readonly PerLanguageOption<bool> DontPutOutOrRefOnStruct = new PerLanguageOption<bool>(FeatureName, "Don't Put Out Or Ref On Strcut", defaultValue: true);
[ExportOption]
public static readonly PerLanguageOption<bool> AllowMovingDeclaration = new PerLanguageOption<bool>(FeatureName, "Allow Moving Declaration", defaultValue: false);
}
}
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Options.Providers;
namespace Microsoft.CodeAnalysis.ExtractMethod
{
[ExportOptionProvider, Shared]
internal class ExtractMethodOptionsProvider : IOptionProvider
{
private readonly IEnumerable<IOption> _options = new List<IOption>
{
ExtractMethodOptions.AllowBestEffort,
ExtractMethodOptions.DontPutOutOrRefOnStruct,
ExtractMethodOptions.AllowMovingDeclaration
}.ToImmutableArray();
public IEnumerable<IOption> GetOptions()
{
return _options;
}
}
}
......@@ -47,10 +47,6 @@
<Project>{1EE8CAD3-55F9-4D91-96B2-084641DA9A6C}</Project>
<Name>CodeAnalysis</Name>
</ProjectReference>
<ProjectReference Include="..\..\Workspaces\Core\Desktop\Workspaces.Desktop.csproj">
<Project>{2e87fa96-50bb-4607-8676-46521599f998}</Project>
<Name>Workspaces.Desktop</Name>
</ProjectReference>
<ProjectReference Include="..\..\Workspaces\Core\Portable\Workspaces.csproj">
<Project>{5F8D2414-064A-4B3A-9B42-8E2A04246BE5}</Project>
<Name>Workspaces</Name>
......@@ -159,6 +155,7 @@
<Compile Include="Completion\CompletionList.cs" />
<Compile Include="Completion\CompletionListContext.cs" />
<Compile Include="Completion\CompletionOptions.cs" />
<Compile Include="Completion\CompletionOptionsProvider.cs" />
<Compile Include="Completion\CompletionService.cs" />
<Compile Include="Completion\CompletionTriggerInfo.cs" />
<Compile Include="Completion\CompletionTriggerReason.cs" />
......@@ -187,6 +184,7 @@
<Compile Include="Diagnostics\AnalyzerUpdateArgsId.cs" />
<Compile Include="Diagnostics\EngineV1\DiagnosticIncrementalAnalyzer.SolutionCrawlerAnalysisState.cs" />
<Compile Include="Diagnostics\HostDiagnosticAnalyzerPackage.cs" />
<Compile Include="Diagnostics\InternalDiagnosticsOptionsProvider.cs" />
<Compile Include="Diagnostics\PredefinedBuildTools.cs" />
<Compile Include="Diagnostics\DiagnosticAnalyzerService_BuildSynchronization.cs" />
<Compile Include="Diagnostics\EngineV1\DiagnosticIncrementalAnalyzer.ProjectAnalyzerReferenceChangedEventArgs.cs" />
......@@ -235,6 +233,7 @@
<Compile Include="EditAndContinue\BidirectionalMap.cs" />
<Compile Include="EditAndContinue\StateMachineKind.cs" />
<Compile Include="EditAndContinue\TraceLog.cs" />
<Compile Include="ExtractMethod\ExtractMethodOptionsProvider.cs" />
<Compile Include="FeaturesResources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
......@@ -252,7 +251,10 @@
<Compile Include="IntroduceVariable\AbstractIntroduceVariableService.IntroduceVariableAllOccurrenceCodeAction.cs" />
<Compile Include="LanguageServices\ProjectInfoService\IProjectInfoService.cs" />
<Compile Include="QuickInfo\QuickInfoUtilities.cs" />
<Compile Include="Shared\Options\OrganizerOptionsProvider.cs" />
<Compile Include="Shared\Options\ServiceComponentOnOffOptionsProvider.cs" />
<Compile Include="Shared\Options\ServiceFeatureOnOffOptions.cs" />
<Compile Include="Shared\Options\ServiceFeatureOnOffOptionsProvider.cs" />
<Compile Include="Shared\Utilities\LinkedFilesSymbolEquivalenceComparer.cs" />
<Compile Include="Shared\Utilities\SupportedPlatformData.cs" />
<Compile Include="Completion\Providers\SymbolCompletionItem.cs" />
......@@ -512,6 +514,7 @@
<Compile Include="SolutionCrawler\IIncrementalAnalyzer.cs" />
<Compile Include="SolutionCrawler\IncrementalAnalyzerBase.cs" />
<Compile Include="SolutionCrawler\IncrementalAnalyzerProviderBase.cs" />
<Compile Include="SolutionCrawler\InternalSolutionCrawlerOptionsProvider.cs" />
<Compile Include="SolutionCrawler\InvocationReasons.cs" />
<Compile Include="SolutionCrawler\InvocationReasons_Constants.cs" />
<Compile Include="SolutionCrawler\ISolutionCrawlerProgressReporter.cs" />
......@@ -539,8 +542,6 @@
<Compile Include="SolutionCrawler\SolutionCrawlerRegistrationService.cs" />
<Compile Include="Workspace\BackgroundCompiler.cs" />
<Compile Include="Workspace\BackgroundParser.cs" />
<Compile Include="Workspace\FileTracker.cs" />
<Compile Include="Workspace\Kernel32File.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="FeaturesResources.resx">
......
......@@ -11,7 +11,7 @@ internal partial class OrganizerOptions
public static PerLanguageOption<bool> PlaceSystemNamespaceFirst
{
get { return Microsoft.CodeAnalysis.Editing.GenerationOptions.PlaceSystemNamespaceFirst; }
get { return Editing.GenerationOptions.PlaceSystemNamespaceFirst; }
}
/// <summary>
......@@ -20,7 +20,6 @@ public static PerLanguageOption<bool> PlaceSystemNamespaceFirst
/// maintain any customized value for this setting, even through versions that have not
/// implemented this feature yet.
/// </summary>
[ExportOption]
public static readonly PerLanguageOption<bool> WarnOnBuildErrors = new PerLanguageOption<bool>(FeatureName, "WarnOnBuildErrors", defaultValue: true);
}
}
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Options.Providers;
namespace Microsoft.CodeAnalysis.Shared.Options
{
[ExportOptionProvider, Shared]
internal class OrganizerOptionsProvider : IOptionProvider
{
private readonly IEnumerable<IOption> _options = new List<IOption>
{
OrganizerOptions.WarnOnBuildErrors
}.ToImmutableArray();
public IEnumerable<IOption> GetOptions()
{
return _options;
}
}
}
......@@ -11,7 +11,6 @@ internal static class ServiceComponentOnOffOptions
{
public const string OptionName = "FeatureManager/Components";
[ExportOption]
public static readonly Option<bool> DiagnosticProvider = new Option<bool>(OptionName, "Diagnostic Provider", defaultValue: true);
}
}
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Options.Providers;
namespace Microsoft.CodeAnalysis.Shared.Options
{
[ExportOptionProvider, Shared]
internal class ServiceComponentOnOffOptionsProvider : IOptionProvider
{
private readonly IEnumerable<IOption> _options = new List<IOption>
{
ServiceComponentOnOffOptions.DiagnosticProvider
}.ToImmutableArray();
public IEnumerable<IOption> GetOptions()
{
return _options;
}
}
}
......@@ -8,7 +8,6 @@ internal static class ServiceFeatureOnOffOptions
{
public const string OptionName = "ServiceFeaturesOnOff";
[ExportOption]
public static readonly PerLanguageOption<bool> ClosedFileDiagnostic = new PerLanguageOption<bool>(OptionName, "Closed File Diagnostic", defaultValue: true);
}
}
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Options.Providers;
namespace Microsoft.CodeAnalysis.Shared.Options
{
[ExportOptionProvider, Shared]
internal class ServiceFeatureOnOffOptionsProvider : IOptionProvider
{
private readonly IEnumerable<IOption> _options = new List<IOption>
{
ServiceFeatureOnOffOptions.ClosedFileDiagnostic
}.ToImmutableArray();
public IEnumerable<IOption> GetOptions()
{
return _options;
}
}
}
......@@ -8,25 +8,12 @@ internal static class InternalSolutionCrawlerOptions
{
public const string OptionName = "SolutionCrawler";
[ExportOption]
public static readonly Option<bool> SolutionCrawler = new Option<bool>("FeatureManager/Components", "Solution Crawler", defaultValue: true);
[ExportOption]
public static readonly Option<int> ActiveFileWorkerBackOffTimeSpanInMS = new Option<int>(OptionName, "Active file worker backoff timespan in ms", defaultValue: 800);
[ExportOption]
public static readonly Option<int> AllFilesWorkerBackOffTimeSpanInMS = new Option<int>(OptionName, "All files worker backoff timespan in ms", defaultValue: 1500);
[ExportOption]
public static readonly Option<int> EntireProjectWorkerBackOffTimeSpanInMS = new Option<int>(OptionName, "Entire project analysis worker backoff timespan in ms", defaultValue: 5000);
[ExportOption]
public static readonly Option<int> SemanticChangeBackOffTimeSpanInMS = new Option<int>(OptionName, "Semantic change backoff timespan in ms", defaultValue: 100);
[ExportOption]
public static readonly Option<int> ProjectPropagationBackOffTimeSpanInMS = new Option<int>(OptionName, "Project propagation backoff timespan in ms", defaultValue: 500);
[ExportOption]
public static readonly Option<int> PreviewBackOffTimeSpanInMS = new Option<int>(OptionName, "Preview backoff timespan in ms", defaultValue: 500);
}
}
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Options.Providers;
namespace Microsoft.CodeAnalysis.SolutionCrawler
{
[ExportOptionProvider, Shared]
internal class InternalSolutionCrawlerOptionsProvider : IOptionProvider
{
private readonly IEnumerable<IOption> _options = new List<IOption>
{
InternalSolutionCrawlerOptions.SolutionCrawler,
InternalSolutionCrawlerOptions.ActiveFileWorkerBackOffTimeSpanInMS,
InternalSolutionCrawlerOptions.AllFilesWorkerBackOffTimeSpanInMS,
InternalSolutionCrawlerOptions.EntireProjectWorkerBackOffTimeSpanInMS,
InternalSolutionCrawlerOptions.SemanticChangeBackOffTimeSpanInMS,
InternalSolutionCrawlerOptions.ProjectPropagationBackOffTimeSpanInMS,
InternalSolutionCrawlerOptions.PreviewBackOffTimeSpanInMS
}.ToImmutableArray();
public IEnumerable<IOption> GetOptions()
{
return _options;
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Host
{
/// <summary>
/// A class that tracks file changes on disk and invokes user actions
/// when changes happen.
/// </summary>
internal class FileTracker
{
// guards watchers and actions
private readonly NonReentrantLock _guard = new NonReentrantLock();
private readonly Dictionary<string, FileSystemWatcher> _watchers =
new Dictionary<string, FileSystemWatcher>();
private readonly Dictionary<string, FileActions> _fileActionsMap =
new Dictionary<string, FileActions>();
public FileTracker()
{
}
private FileActions GetFileActions_NoLock(string path)
{
_guard.AssertHasLock();
FileActions actions;
if (!_fileActionsMap.TryGetValue(path, out actions))
{
actions = new FileActions(this, path);
_fileActionsMap.Add(path, actions);
}
return actions;
}
public bool IsTracking(string path)
{
if (path == null)
{
return false;
}
using (_guard.DisposableWait())
{
return _fileActionsMap.ContainsKey(path);
}
}
public void Track(string path, Action action)
{
if (path == null)
{
throw new ArgumentNullException(nameof(path));
}
using (_guard.DisposableWait())
{
var fileActions = this.GetFileActions_NoLock(path);
fileActions.AddAction_NoLock(action);
var directory = Path.GetDirectoryName(path);
if (!_watchers.ContainsKey(directory))
{
var watcher = new FileSystemWatcher(directory);
watcher.Changed += OnFileChanged;
watcher.EnableRaisingEvents = true;
}
}
}
public void StopTracking(string path)
{
if (path != null)
{
using (_guard.DisposableWait())
{
_fileActionsMap.Remove(path);
}
}
}
private void OnFileChanged(object sender, FileSystemEventArgs args)
{
FileActions actions;
using (_guard.DisposableWait())
{
actions = this.GetFileActions_NoLock(args.FullPath);
}
actions.InvokeActions();
}
public void Dispose()
{
using (_guard.DisposableWait())
{
foreach (var watcher in _watchers.Values)
{
watcher.Dispose();
}
_watchers.Clear();
_fileActionsMap.Clear();
}
}
private class FileActions
{
private readonly FileTracker _tracker;
private readonly string _path;
private ImmutableArray<Action> _actions;
private Task _invokeTask;
public FileActions(FileTracker tracker, string path)
{
_tracker = tracker;
_path = path;
_actions = ImmutableArray.Create<Action>();
}
public void AddAction_NoLock(Action action)
{
_tracker._guard.AssertHasLock();
_actions = _actions.Add(action);
}
public void InvokeActions()
{
using (_tracker._guard.DisposableWait())
{
// only start invoke task if one is not already running
if (_invokeTask == null)
{
_invokeTask = Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Current);
_invokeTask.ContinueWithAfterDelay(() => TryInvokeActions(_actions), CancellationToken.None, 100, TaskContinuationOptions.None, TaskScheduler.Current);
}
}
}
private void TryInvokeActions(ImmutableArray<Action> actions)
{
if (actions.Length == 0)
{
return;
}
// only invoke actions if the writer that caused the event is done
// determine this by checking to see if we can read the file
using (var stream = Kernel32File.Open(_path, FileAccess.Read, FileMode.Open, throwException: false))
{
if (stream != null)
{
stream.Close();
foreach (var action in actions)
{
action();
}
// clear invoke task so any following changes get additional invocations
using (_tracker._guard.DisposableWait())
{
_invokeTask = null;
}
}
else
{
// try again after a short delay
using (_tracker._guard.DisposableWait())
{
_invokeTask.ContinueWithAfterDelay(() => TryInvokeActions(_actions), CancellationToken.None, 100, TaskContinuationOptions.None, TaskScheduler.Current);
}
}
}
}
}
}
}
// 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.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using IO = System.IO;
namespace Microsoft.CodeAnalysis.Host
{
internal static class Kernel32File
{
internal static IO.FileStream Open(string path, IO.FileAccess access, IO.FileMode mode, IO.FileShare share = IO.FileShare.None, bool throwException = true)
{
var fileHandle = CreateFile(path, GetFileAccess(access), GetFileShare(share), default(IntPtr), GetFileMode(mode));
if (fileHandle.IsInvalid)
{
if (throwException)
{
HandleCOMError(Marshal.GetLastWin32Error());
}
else
{
return null;
}
}
return new IO.FileStream(fileHandle, access);
}
[Flags]
private enum FileShare
{
FILE_SHARE_NONE = 0x00,
FILE_SHARE_READ = 0x01,
FILE_SHARE_WRITE = 0x02,
FILE_SHARE_DELETE = 0x04
}
private enum FileMode
{
CREATE_NEW = 1,
CREATE_ALWAYS = 2,
OPEN_EXISTING = 3,
OPEN_ALWAYS = 4,
TRUNCATE_EXISTING = 5
}
private enum FileAccess
{
GENERIC_READ = unchecked((int)0x80000000),
GENERIC_WRITE = 0x40000000
}
[DllImport("kernel32", SetLastError = true)]
private static extern SafeFileHandle CreateFile(string filename,
FileAccess desiredAccess,
FileShare shareMode,
IntPtr attributes,
FileMode creationDisposition,
uint flagsAndAttributes = 0,
IntPtr templateFile = default(IntPtr));
private static void HandleCOMError(int error)
{
throw new System.ComponentModel.Win32Exception(error);
}
private static FileMode GetFileMode(IO.FileMode mode)
{
if (mode != IO.FileMode.Append)
{
return (FileMode)(int)mode;
}
else
{
return (FileMode)(int)IO.FileMode.OpenOrCreate;
}
}
private static FileAccess GetFileAccess(IO.FileAccess access)
{
return access == IO.FileAccess.Read ?
FileAccess.GENERIC_READ :
FileAccess.GENERIC_WRITE;
}
private static FileShare GetFileShare(IO.FileShare share)
{
return (FileShare)(int)share;
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
namespace AsyncPackage
{
/// <summary>
/// Analyzer that examines async lambdas and checks if they are being passed or stored as void-returning delegate types.
/// </summary>
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class AsyncLambdaAnalyzer : DiagnosticAnalyzer
{
internal const string AsyncLambdaId1 = "Async003";
internal const string AsyncLambdaId2 = "Async004";
internal static DiagnosticDescriptor Rule1 = new DiagnosticDescriptor(id: AsyncLambdaId1,
title: "Don't Pass Async Lambdas as Void Returning Delegate Types",
messageFormat: "This async lambda is passed as a void-returning delegate type",
category: "Usage",
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);
internal static DiagnosticDescriptor Rule2 = new DiagnosticDescriptor(id: AsyncLambdaId2,
title: "Don't Store Async Lambdas as Void Returning Delegate Types",
messageFormat: "This async lambda is stored as a void-returning delegate type",
category: "Usage",
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ParenthesizedLambdaExpression, SyntaxKind.SimpleLambdaExpression, SyntaxKind.AnonymousMethodExpression);
}
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule1, Rule2); } }
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
var symbol = context.SemanticModel.GetSymbolInfo(context.Node).Symbol;
var methodLambda = symbol as IMethodSymbol;
if (methodLambda != null && methodLambda.IsAsync)
{
var type = context.SemanticModel.GetTypeInfo(context.Node);
if (this.CheckIfVoidReturningDelegateType(type.ConvertedType))
{
// check if the lambda is being assigned to a variable. This has a code fix.
var parent = context.Node.Parent;
while (parent != null && !(parent is InvocationExpressionSyntax))
{
if (parent is VariableDeclarationSyntax)
{
context.ReportDiagnostic(Diagnostic.Create(Rule2, parent.GetLocation()));
return;
}
parent = parent.Parent;
}
// if not, add the normal diagnostic
context.ReportDiagnostic(Diagnostic.Create(Rule1, context.Node.GetLocation()));
return;
}
}
return;
}
/// <summary>
/// Check if the method is a void returning delegate type
/// </summary>
/// <param name="convertedType"></param>
/// <returns>
/// Returns false if analysis failed or if not a void-returning delegate type
/// Returns true if the inputted node has a converted type that is a void-returning delegate type
/// </returns>
private bool CheckIfVoidReturningDelegateType(ITypeSymbol convertedType)
{
if (convertedType != null && convertedType.TypeKind.Equals(TypeKind.Delegate))
{
var invoke = convertedType.GetMembers("Invoke").FirstOrDefault() as IMethodSymbol;
if (invoke != null)
{
return invoke.ReturnsVoid;
}
}
return false;
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Simplification;
namespace AsyncPackage
{
/// <summary>
/// Codefix that changes the type of a variable to be Func of Task instead of a void-returning delegate type.
/// </summary>
[ExportCodeFixProvider(LanguageNames.CSharp, Name = AsyncLambdaAnalyzer.AsyncLambdaId1), Shared]
public class AsyncLambdaVariableCodeFix : CodeFixProvider
{
public sealed override ImmutableArray<string> FixableDiagnosticIds
{
get { return ImmutableArray.Create(AsyncLambdaAnalyzer.AsyncLambdaId1); }
}
public sealed override FixAllProvider GetFixAllProvider()
{
return null;
}
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
Debug.Assert(root != null);
var parent = root.FindToken(diagnosticSpan.Start).Parent;
if (parent != null)
{
// Find the type declaration identified by the diagnostic.
var variableDeclaration = parent.FirstAncestorOrSelf<VariableDeclarationSyntax>();
// Register a code action that will invoke the fix.
context.RegisterCodeFix(
new AsyncLambdaVariableCodeAction("Async lambdas should not be stored in void-returning delegates",
c => ChangeToFunc(context.Document, variableDeclaration, c)),
diagnostic);
}
}
private async Task<Document> ChangeToFunc(Document document, VariableDeclarationSyntax variableDeclaration, CancellationToken cancellationToken)
{
// Change the variable declaration
var newDeclaration = variableDeclaration.WithType(SyntaxFactory.ParseTypeName("System.Func<System.Threading.Tasks.Task>").WithAdditionalAnnotations(Simplifier.Annotation, Formatter.Annotation)
.WithLeadingTrivia(variableDeclaration.Type.GetLeadingTrivia()).WithTrailingTrivia(variableDeclaration.Type.GetTrailingTrivia()));
var oldRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var newRoot = oldRoot.ReplaceNode(variableDeclaration, newDeclaration);
var newDocument = document.WithSyntaxRoot(newRoot);
// Return document with transformed tree.
return newDocument;
}
private class AsyncLambdaVariableCodeAction : CodeAction
{
private Func<CancellationToken, Task<Document>> _generateDocument;
private string _title;
public AsyncLambdaVariableCodeAction(string title, Func<CancellationToken, Task<Document>> generateDocument)
{
_title = title;
_generateDocument = generateDocument;
}
public override string Title { get { return _title; } }
protected override Task<Document> GetChangedDocumentAsync(CancellationToken cancellationToken)
{
return _generateDocument(cancellationToken);
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="Settings">
<Import Project="..\..\..\..\build\Targets\VSL.Settings.targets" />
</ImportGroup>
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<SchemaVersion>2.0</SchemaVersion>
<ProjectTypeGuids>{82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<ProjectGuid>{68D3FDD2-DA02-453B-9DF9-022F65F9265E}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>AsyncPackage</RootNamespace>
<AssemblyName>AsyncPackage</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<GeneratePkgDefFile>false</GeneratePkgDefFile>
<IncludeAssemblyInVSIXContainer>true</IncludeAssemblyInVSIXContainer>
<IncludeDebugSymbolsInVSIXContainer>true</IncludeDebugSymbolsInVSIXContainer>
<IncludeDebugSymbolsInLocalVSIXDeployment>false</IncludeDebugSymbolsInLocalVSIXDeployment>
<VSSDKTargetPlatformRegRootSuffix>RoslynDev</VSSDKTargetPlatformRegRootSuffix>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<FileUpgradeFlags>
</FileUpgradeFlags>
<OldToolsVersion>4.0</OldToolsVersion>
<UpgradeBackupLocation />
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<ImportVSSDKTargets>true</ImportVSSDKTargets>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\..\</SolutionDir>
<SccProjectName>SAK</SccProjectName>
<SccLocalPath>SAK</SccLocalPath>
<SccAuxPath>SAK</SccAuxPath>
<SccProvider>SAK</SccProvider>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartAction>Program</StartAction>
<StartProgram>$(DevEnvDir)devenv.exe</StartProgram>
<StartArguments>/rootsuffix RoslynDev /log</StartArguments>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CodeAnalysis">
<HintPath>$(VSLOutDir)\Microsoft.CodeAnalysis.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Microsoft.CodeAnalysis.CSharp">
<HintPath>$(VSLOutDir)\Microsoft.CodeAnalysis.CSharp.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Microsoft.CodeAnalysis.CSharp.Workspaces">
<HintPath>$(VSLOutDir)\Microsoft.CodeAnalysis.CSharp.Workspaces.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Microsoft.CodeAnalysis.VisualBasic">
<HintPath>$(VSLOutDir)\Microsoft.CodeAnalysis.VisualBasic.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces">
<HintPath>$(VSLOutDir)\Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Microsoft.CodeAnalysis.Workspaces">
<HintPath>$(VSLOutDir)\Microsoft.CodeAnalysis.Workspaces.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.Collections.Immutable, Version=$(SystemCollectionsImmutableAssemblyVersion), Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Composition.AttributedModel">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Microsoft.Composition.$(MicrosoftCompositionVersion)\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll</HintPath>
</Reference>
<Reference Include="System.Composition.Convention">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Microsoft.Composition.$(MicrosoftCompositionVersion)\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll</HintPath>
</Reference>
<Reference Include="System.Composition.Hosting">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Microsoft.Composition.$(MicrosoftCompositionVersion)\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll</HintPath>
</Reference>
<Reference Include="System.Composition.Runtime">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Microsoft.Composition.$(MicrosoftCompositionVersion)\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll</HintPath>
</Reference>
<Reference Include="System.Composition.TypedParts">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Microsoft.Composition.$(MicrosoftCompositionVersion)\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll</HintPath>
</Reference>
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Reflection.Metadata, Version=$(SystemReflectionMetadataAssemblyVersion), Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\packages\System.Reflection.Metadata.$(SystemReflectionMetadataVersion)\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup>
<Compile Include="AsyncLambdaAnalyzer.cs" />
<Compile Include="BlockingAsyncAnalyzer.cs" />
<Compile Include="CancellationCodeFix.cs" />
<Compile Include="AsyncLambdaVariableCodeFix.cs" />
<Compile Include="CancellationAnalyzer.cs" />
<Compile Include="AsyncVoidCodeFix.cs" />
<Compile Include="AsyncVoidAnalyzer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RenameAsyncAnalyzer.cs" />
<Compile Include="RenameAsyncCodeFix.cs" />
<Compile Include="BlockingAsyncCodeFix.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
<None Include="source.extension.vsixmanifest">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="Diagnostic.nuspec">
<SubType>Designer</SubType>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="tools\install.ps1">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="tools\uninstall.ps1">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.5">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.5 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">11.0</VisualStudioVersion>
<MinimumVisualStudioVersion>$(VisualStudioVersion)</MinimumVisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<ImportGroup Label="Targets">
<Import Project="..\..\..\..\build\Targets\VSL.Imports.targets" />
</ImportGroup>
<Target Name="AfterBuild">
<Message Text="AfterBuild" />
<Exec Condition="'$(CIBuild)' != 'true'" Command="$(SolutionDir)..\..\packages\NuGet.CommandLine.$(NuGetCommandLineVersion)\tools\NuGet.exe pack Diagnostic.nuspec -NoPackageAnalysis -OutputDirectory $(OutDir)" />
</Target>
</Project>
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
namespace AsyncPackage
{
/// <summary>
/// This Analyzer determines if a method is Async and needs to be returning a Task instead of having a void return type.
/// </summary>
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public class AsyncVoidAnalyzer : DiagnosticAnalyzer
{
internal const string AsyncVoidId = "Async001";
internal static DiagnosticDescriptor VoidReturnType = new DiagnosticDescriptor(id: AsyncVoidId,
title: "Avoid Async Void",
messageFormat: "This method has the async keyword but it returns void",
category: "Usage",
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);
public override void Initialize(AnalysisContext context)
{
context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.Method);
}
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(VoidReturnType); } }
private void AnalyzeSymbol(SymbolAnalysisContext context)
{
// Filter out methods that do not use Async and that do not have exactly two parameters
var methodSymbol = (IMethodSymbol)context.Symbol;
var eventType = context.Compilation.GetTypeByMetadataName("System.EventArgs");
if (methodSymbol.ReturnsVoid && methodSymbol.IsAsync)
{
if (methodSymbol.Parameters.Length == 2)
{
var firstParam = methodSymbol.Parameters[0];
var secondParam = methodSymbol.Parameters[1];
if (firstParam is object)
{
// Check each parameter for EventHandler shape and return if it matches.
if (firstParam.Name.ToLower().Equals("sender") && secondParam.Type == eventType)
{
return;
}
else
{
// Check if the second parameter implements EventArgs. If it does; return.
var checkForEventType = secondParam.Type.BaseType;
while (checkForEventType.OriginalDefinition != context.Compilation.GetTypeByMetadataName("System.Object"))
{
if (checkForEventType == eventType)
{
return;
}
checkForEventType = checkForEventType.BaseType;
}
}
}
}
context.ReportDiagnostic(Diagnostic.Create(VoidReturnType, methodSymbol.Locations[0], methodSymbol.Name));
return;
}
return;
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Simplification;
namespace AsyncPackage
{
/// <summary>
/// This codefix replaces the void return type with Task in any method declaration the AsyncVoidAnalyzer catches
/// </summary>
[ExportCodeFixProvider(LanguageNames.CSharp, Name = AsyncVoidAnalyzer.AsyncVoidId), Shared]
public class AsyncVoidCodeFix : CodeFixProvider
{
public sealed override ImmutableArray<string> FixableDiagnosticIds
{
get { return ImmutableArray.Create(AsyncVoidAnalyzer.AsyncVoidId); }
}
public sealed override FixAllProvider GetFixAllProvider()
{
return null;
}
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
// Find the type declaration identified by the diagnostic.
var methodDeclaration = root.FindToken(diagnosticSpan.Start).Parent.FirstAncestorOrSelf<MethodDeclarationSyntax>();
// Register a code action that will invoke the fix.
context.RegisterCodeFix(
new AsyncVoidCodeAction("Async methods should not return void",
c => VoidToTaskAsync(context.Document, methodDeclaration, c)),
diagnostic);
}
private async Task<Document> VoidToTaskAsync(Document document, MethodDeclarationSyntax methodDeclaration, CancellationToken cancellationToken)
{
// The Task object must be parsed from a string using the Syntax Factory
var newType = SyntaxFactory.ParseTypeName("System.Threading.Tasks.Task").WithAdditionalAnnotations(Simplifier.Annotation).WithTrailingTrivia(methodDeclaration.ReturnType.GetTrailingTrivia());
var newMethodDeclaration = methodDeclaration.WithReturnType(newType);
var oldRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var newRoot = oldRoot.ReplaceNode(methodDeclaration, newMethodDeclaration);
var newDocument = document.WithSyntaxRoot(newRoot);
// Return document with transformed tree.
return newDocument;
}
private class AsyncVoidCodeAction : CodeAction
{
private Func<CancellationToken, Task<Document>> _createDocument;
private string _title;
public AsyncVoidCodeAction(string title, Func<CancellationToken, Task<Document>> createDocument)
{
_title = title;
_createDocument = createDocument;
}
public override string Title { get { return _title; } }
protected override Task<Document> GetChangedDocumentAsync(CancellationToken cancellationToken)
{
return _createDocument(cancellationToken);
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
namespace AsyncPackage
{
/// <summary>
/// This analyzer checks to see if asynchronous and synchronous code is mixed.
/// This causes blocking and deadlocks. The analyzer will check when async
/// methods are used and then checks if synchronous code is used within the method.
/// A codefix will then change that synchronous code to its asynchronous counterpart.
/// </summary>
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class BlockingAsyncAnalyzer : DiagnosticAnalyzer
{
internal const string BlockingAsyncId = "Async006";
internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(id: BlockingAsyncId,
title: "Don't Mix Blocking and Async",
messageFormat: "This method is blocking on async code",
category: "Usage",
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.SimpleMemberAccessExpression);
}
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
var method = context.SemanticModel.GetEnclosingSymbol(context.Node.SpanStart) as IMethodSymbol;
if (method != null && method.IsAsync)
{
var invokeMethod = context.SemanticModel.GetSymbolInfo(context.Node).Symbol as IMethodSymbol;
if (invokeMethod != null && !invokeMethod.IsExtensionMethod)
{
// Checks if the Wait method is called within an async method then creates the diagnostic.
if (invokeMethod.OriginalDefinition.Name.Equals("Wait"))
{
context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.Parent.GetLocation()));
return;
}
// Checks if the WaitAny method is called within an async method then creates the diagnostic.
if (invokeMethod.OriginalDefinition.Name.Equals("WaitAny"))
{
context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.Parent.GetLocation()));
return;
}
// Checks if the WaitAll method is called within an async method then creates the diagnostic.
if (invokeMethod.OriginalDefinition.Name.Equals("WaitAll"))
{
context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.Parent.GetLocation()));
return;
}
// Checks if the Sleep method is called within an async method then creates the diagnostic.
if (invokeMethod.OriginalDefinition.Name.Equals("Sleep"))
{
context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.Parent.GetLocation()));
return;
}
// Checks if the GetResult method is called within an async method then creates the diagnostic.
if (invokeMethod.OriginalDefinition.Name.Equals("GetResult"))
{
context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.Parent.GetLocation()));
return;
}
}
var property = context.SemanticModel.GetSymbolInfo(context.Node).Symbol as IPropertySymbol;
// Checks if the Result property is called within an async method then creates the diagnostic.
if (property != null && property.OriginalDefinition.Name.Equals("Result"))
{
context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.GetLocation()));
return;
}
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Simplification;
namespace AsyncPackage
{
/// <summary>
/// Codefix changes the synchronous operations to it's asynchronous equivalent.
/// </summary>
[ExportCodeFixProvider(LanguageNames.CSharp, Name = BlockingAsyncAnalyzer.BlockingAsyncId), Shared]
public class BlockingAsyncCodeFix : CodeFixProvider
{
public sealed override ImmutableArray<string> FixableDiagnosticIds
{
get { return ImmutableArray.Create(BlockingAsyncAnalyzer.BlockingAsyncId); }
}
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
// Find the type declaration identified by the diagnostic.
var invocation = root.FindToken(diagnosticSpan.Start).Parent.FirstAncestorOrSelf<InvocationExpressionSyntax>();
var invokemethod = root.FindToken(diagnosticSpan.Start).Parent.FirstAncestorOrSelf<MemberAccessExpressionSyntax>();
var semanticmodel = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);
var method = semanticmodel.GetEnclosingSymbol(invocation.SpanStart) as IMethodSymbol;
if (method != null && method.IsAsync)
{
if (invokemethod != null && invokemethod.Name.Identifier.Text.Equals("Wait"))
{
var name = invokemethod.Name.Identifier.Text;
// Register a code action that will invoke the fix.
context.RegisterCodeFix(
new CodeActionChangetoAwaitAsync("Change synchronous operation to asynchronous counterpart",
c => ChangetoAwaitAsync(context.Document, invocation, name, c)),
diagnostic);
return;
}
if (invokemethod != null && invokemethod.Name.Identifier.Text.Equals("GetAwaiter"))
{
// Register a code action that will invoke the fix.
context.RegisterCodeFix(
new CodeActionChangetoAwaitGetAwaiterAsync("Change synchronous operation to asynchronous counterpart",
c => ChangetoAwaitGetAwaiterAsync(context.Document, invocation, c)),
diagnostic);
return;
}
if (invokemethod != null && invokemethod.Name.Identifier.Text.Equals("Result"))
{
var name = invokemethod.Name.Identifier.Text;
// Register a code action that will invoke the fix.
context.RegisterCodeFix(
new CodeActionChangetoAwaitAsync("Change synchronous operation to asynchronous counterpart",
c => ChangetoAwaitAsync(context.Document, invocation, name, c)),
diagnostic);
return;
}
if (invokemethod != null && invokemethod.Name.Identifier.Text.Equals("WaitAny"))
{
var name = invokemethod.Name.Identifier.Text;
// Register a code action that will invoke the fix.
context.RegisterCodeFix(
new CodeActionToDelayWhenAnyWhenAllAsync("Change synchronous operation to asynchronous counterpart",
c => ToDelayWhenAnyWhenAllAsync(context.Document, invocation, name, c)),
diagnostic);
return;
}
if (invokemethod != null && invokemethod.Name.Identifier.Text.Equals("WaitAll"))
{
var name = invokemethod.Name.Identifier.Text;
// Register a code action that will invoke the fix.
context.RegisterCodeFix(
new CodeActionToDelayWhenAnyWhenAllAsync("Change synchronous operation to asynchronous counterpart",
c => ToDelayWhenAnyWhenAllAsync(context.Document, invocation, name, c)),
diagnostic);
return;
}
if (invokemethod != null && invokemethod.Name.Identifier.Text.Equals("Sleep"))
{
var name = invokemethod.Name.Identifier.Text;
// Register a code action that will invoke the fix.
context.RegisterCodeFix(
new CodeActionToDelayWhenAnyWhenAllAsync("Change synchronous operation to asynchronous counterpart",
c => ToDelayWhenAnyWhenAllAsync(context.Document, invocation, name, c)),
diagnostic);
return;
}
}
}
private async Task<Document> ToDelayWhenAnyWhenAllAsync(Document document, InvocationExpressionSyntax invocation, string name, CancellationToken cancellationToken)
{
var simpleExpression = SyntaxFactory.ParseName("");
if (name.Equals("WaitAny"))
{
simpleExpression = SyntaxFactory.ParseName("System.Threading.Tasks.Task.WhenAny").WithAdditionalAnnotations(Simplifier.Annotation);
}
else if (name.Equals("WaitAll"))
{
simpleExpression = SyntaxFactory.ParseName("System.Threading.Tasks.Task.WhenAll").WithAdditionalAnnotations(Simplifier.Annotation);
}
else if (name.Equals("Sleep"))
{
simpleExpression = SyntaxFactory.ParseName("System.Threading.Tasks.Task.Delay").WithAdditionalAnnotations(Simplifier.Annotation);
}
SyntaxNode oldExpression = invocation;
var expression = invocation.WithExpression(simpleExpression).WithLeadingTrivia(invocation.GetLeadingTrivia()).WithTrailingTrivia(invocation.GetTrailingTrivia());
var newExpression = SyntaxFactory.PrefixUnaryExpression(SyntaxKind.AwaitExpression, expression.WithLeadingTrivia(SyntaxFactory.Space)).WithTrailingTrivia(invocation.GetTrailingTrivia()).WithLeadingTrivia(invocation.GetLeadingTrivia());
var oldroot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var newroot = oldroot.ReplaceNode(oldExpression, newExpression);
var newDocument = document.WithSyntaxRoot(newroot);
return newDocument;
}
private async Task<Document> ChangetoAwaitAsync(Document document, InvocationExpressionSyntax invocation, string name, CancellationToken cancellationToken)
{
SyntaxNode oldExpression = invocation;
SyntaxNode newExpression = null;
if (name.Equals("Wait"))
{
oldExpression = invocation.FirstAncestorOrSelf<InvocationExpressionSyntax>();
var identifier = (invocation.Expression as MemberAccessExpressionSyntax).Expression as IdentifierNameSyntax;
newExpression = SyntaxFactory.PrefixUnaryExpression(
SyntaxKind.AwaitExpression,
identifier).WithAdditionalAnnotations(Formatter.Annotation);
}
if (name.Equals("Result"))
{
oldExpression = invocation.Parent.FirstAncestorOrSelf<MemberAccessExpressionSyntax>();
newExpression = SyntaxFactory.PrefixUnaryExpression(
SyntaxKind.AwaitExpression,
invocation).WithAdditionalAnnotations(Formatter.Annotation);
}
var oldroot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var newroot = oldroot.ReplaceNode(oldExpression, newExpression);
var newDocument = document.WithSyntaxRoot(newroot);
return newDocument;
}
private async Task<Document> ChangetoAwaitGetAwaiterAsync(Document document, InvocationExpressionSyntax invocation, CancellationToken cancellationTkn)
{
SyntaxNode expression = invocation;
while (!(expression is ExpressionStatementSyntax))
{
expression = expression.Parent;
}
var oldExpression = expression as ExpressionStatementSyntax;
var awaitedInvocation = SyntaxFactory.PrefixUnaryExpression(SyntaxKind.AwaitExpression, invocation.WithLeadingTrivia(SyntaxFactory.Space)).WithLeadingTrivia(invocation.GetLeadingTrivia());
var newExpression = oldExpression.WithExpression(awaitedInvocation);
var oldroot = await document.GetSyntaxRootAsync(cancellationTkn).ConfigureAwait(false);
var newroot = oldroot.ReplaceNode(oldExpression, newExpression);
var newDocument = document.WithSyntaxRoot(newroot);
return newDocument;
}
public sealed override FixAllProvider GetFixAllProvider()
{
return null;
}
private class CodeActionToDelayWhenAnyWhenAllAsync : CodeAction
{
private Func<CancellationToken, Task<Document>> _generateDocument;
private string _title;
public CodeActionToDelayWhenAnyWhenAllAsync(string title, Func<CancellationToken, Task<Document>> generateDocument)
{
_title = title;
_generateDocument = generateDocument;
}
public override string Title { get { return _title; } }
protected override Task<Document> GetChangedDocumentAsync(CancellationToken cancellationToken)
{
return _generateDocument(cancellationToken);
}
}
private class CodeActionChangetoAwaitAsync : CodeAction
{
private Func<CancellationToken, Task<Document>> _generateDocument;
private string _title;
public CodeActionChangetoAwaitAsync(string title, Func<CancellationToken, Task<Document>> generateDocument)
{
_title = title;
_generateDocument = generateDocument;
}
public override string Title { get { return _title; } }
protected override Task<Document> GetChangedDocumentAsync(CancellationToken cancellationToken)
{
return _generateDocument(cancellationToken);
}
}
private class CodeActionChangetoAwaitGetAwaiterAsync : CodeAction
{
private Func<CancellationToken, Task<Document>> _generateDocument;
private string _title;
public CodeActionChangetoAwaitGetAwaiterAsync(string title, Func<CancellationToken, Task<Document>> generateDocument)
{
_title = title;
_generateDocument = generateDocument;
}
public override string Title { get { return _title; } }
protected override Task<Document> GetChangedDocumentAsync(CancellationToken cancellationToken)
{
return _generateDocument(cancellationToken);
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
namespace AsyncPackage
{
/// <summary>
/// This analyzer check to see if there are Cancellation Tokens that can be propagated through async method calls
/// </summary>
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class CancellationAnalyzer : DiagnosticAnalyzer
{
internal const string CancellationId = "Async005";
internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(id: CancellationId,
title: "Propagate CancellationTokens When Possible",
messageFormat: "This method can take a CancellationToken",
category: "Library",
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);
public override void Initialize(AnalysisContext context)
{
context.RegisterCodeBlockStartAction<SyntaxKind>(CreateAnalyzerWithinCodeBlock);
}
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }
private void CreateAnalyzerWithinCodeBlock(CodeBlockStartAnalysisContext<SyntaxKind> context)
{
var methodDeclaration = context.OwningSymbol as IMethodSymbol;
if (methodDeclaration != null)
{
ITypeSymbol cancellationTokenType = context.SemanticModel.Compilation.GetTypeByMetadataName("System.Threading.CancellationToken");
var paramTypes = methodDeclaration.Parameters.Select(x => x.Type);
if (paramTypes.Contains(cancellationTokenType))
{
// Analyze the inside of the code block for invocationexpressions
context.RegisterSyntaxNodeAction(new CancellationAnalyzer_Inner().AnalyzeNode, SyntaxKind.InvocationExpression);
}
}
}
internal class CancellationAnalyzer_Inner
{
public void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
var invokeMethod = context.SemanticModel.GetSymbolInfo(context.Node).Symbol as IMethodSymbol;
if (invokeMethod != null)
{
ITypeSymbol cancellationTokenType = context.SemanticModel.Compilation.GetTypeByMetadataName("System.Threading.CancellationToken");
var invokeParams = invokeMethod.Parameters.Select(x => x.Type);
if (invokeParams.Contains(cancellationTokenType))
{
var passedToken = false;
foreach (var arg in ((InvocationExpressionSyntax)context.Node).ArgumentList.Arguments)
{
var thisArgType = context.SemanticModel.GetTypeInfo(arg.Expression).Type;
if (thisArgType != null && thisArgType.Equals(cancellationTokenType))
{
passedToken = true;
}
}
if (!passedToken)
{
context.ReportDiagnostic(Diagnostic.Create(CancellationAnalyzer.Rule, context.Node.GetLocation()));
}
}
}
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace AsyncPackage
{
/// <summary>
/// Codefix that changes the type of a variable to be Func of Task instead of a void-returning delegate type.
/// </summary>
[ExportCodeFixProvider(LanguageNames.CSharp, Name = CancellationAnalyzer.CancellationId), Shared]
public class CancellationCodeFix : CodeFixProvider
{
public sealed override ImmutableArray<string> FixableDiagnosticIds
{
get { return ImmutableArray.Create(CancellationAnalyzer.CancellationId); }
}
public sealed override FixAllProvider GetFixAllProvider()
{
return null;
}
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
// Find the type declaration identified by the diagnostic.
var invocation = root.FindToken(diagnosticSpan.Start).Parent.FirstAncestorOrSelf<InvocationExpressionSyntax>();
// Register a code action that will invoke the fix.
context.RegisterCodeFix(
new CancellationCodeAction("Propagate CancellationTokens when possible",
c => AddCancellationTokenAsync(context.Document, invocation, c)),
diagnostic);
}
private async Task<Document> AddCancellationTokenAsync(Document document, InvocationExpressionSyntax invocation, CancellationToken cancellationToken)
{
var semanticModel = await document.GetSemanticModelAsync().ConfigureAwait(false);
ITypeSymbol cancellationTokenType = semanticModel.Compilation.GetTypeByMetadataName("System.Threading.CancellationToken");
var invocationSymbol = semanticModel.GetSymbolInfo(invocation).Symbol as IMethodSymbol;
// Step up through the syntax tree to get the Method Declaration of the invocation
var parent = invocation.Parent;
parent = parent.FirstAncestorOrSelf<MethodDeclarationSyntax>();
var containingMethod = semanticModel.GetDeclaredSymbol(parent) as IMethodSymbol;
// Get the CancellationToken from the containing method
var tokens = containingMethod.Parameters.Where(x => x.Type.Equals(cancellationTokenType));
var firstToken = tokens.FirstOrDefault();
// Get what slot to put it in
var cancelSlots = invocationSymbol.Parameters.Where(x => x.Type.Equals(cancellationTokenType));
if (cancelSlots.FirstOrDefault() == null)
{
return document;
}
var firstSlotIndex = invocationSymbol.Parameters.IndexOf(cancelSlots.FirstOrDefault());
var newIdentifier = SyntaxFactory.IdentifierName(firstToken.Name.ToString());
var newArgs = invocation.ArgumentList.Arguments;
if (firstSlotIndex == 0)
{
newArgs = newArgs.Insert(firstSlotIndex, SyntaxFactory.Argument(newIdentifier).WithLeadingTrivia());
}
else
{
newArgs = invocation.ArgumentList.Arguments.Insert(firstSlotIndex, SyntaxFactory.Argument(newIdentifier).WithLeadingTrivia(SyntaxFactory.TriviaList(SyntaxFactory.ElasticSpace)));
}
var newArgsList = SyntaxFactory.ArgumentList(newArgs);
var newInvocation = invocation.WithArgumentList(newArgsList);
var oldRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var newRoot = oldRoot.ReplaceNode(invocation, newInvocation);
var newDocument = document.WithSyntaxRoot(newRoot);
// Return document with transformed tree.
return newDocument;
}
private class CancellationCodeAction : CodeAction
{
private Func<CancellationToken, Task<Document>> _createDocument;
private string _title;
public CancellationCodeAction(string title, Func<CancellationToken, Task<Document>> createDocument)
{
_title = title;
_createDocument = createDocument;
}
public override string Title { get { return _title; } }
protected override Task<Document> GetChangedDocumentAsync(CancellationToken cancellationToken)
{
return _createDocument(cancellationToken);
}
}
}
}
<?xml version="1.0"?>
<package>
<metadata>
<id>AsyncPackage</id>
<version>1.0.0.0</version>
<title>AsyncPackage</title>
<authors>AsyncPackage</authors>
<owners>AsyncPackage</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>AsyncPackage</description>
<releaseNotes>Summary of changes made in this release of the package.</releaseNotes>
<copyright>Copyright</copyright>
<tags>Tag1 Tag2</tags>
<frameworkAssemblies>
<frameworkAssembly assemblyName="System" targetFramework="" />
</frameworkAssemblies>
</metadata>
<files>
<file src="*.dll" target="tools\analyzers\" exclude="**\Microsoft.CodeAnalysis.*;**\System.Collections.Immutable.*;**\System.Reflection.Metadata.*" />
<file src="tools\*.ps1" target="tools\" />
</files>
</package>
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Reflection;
[assembly: AssemblyTitle("AsyncPackage")]

Building this project will produce an analyzer .dll, as well as the
following two ways you may wish to package that analyzer:
* A NuGet package (.nupkg file) that will add your assembly as a
project-local analyzer that participates in builds.
* A VSIX extension (.vsix file) that will apply your analyzer to all projects
and works just in the IDE.
Starting this project will deploy the analyzer as a VSIX into another copy of
Visual Studio, which is useful for debugging, even if you intend to produce a
NuGet package.
GETTING STARTED WITH NUGET
Before you can produce a NuGet package, you must enable NuGet Package Restore:
* Right-click the solution in Solution Explorer and choose Enable NuGet
Package Restore.
This downloads the NuGet binaries that will be used to pack your analyzer into
a NuGet package. For more information, see
http://go.microsoft.com/fwlink/?LinkID=322105.
If you do not wish to produce a NuGet package, you can delete the
Diagnostic.nuspec file to silence the Package Restore warning.
TRYING OUT YOUR NUGET PACKAGE
To try out the NuGet package:
1. Create a local NuGet feed by following the instructions here:
> http://docs.nuget.org/docs/creating-packages/hosting-your-own-nuget-feeds
2. Copy the .nupkg file into that folder.
3. Open the target project in Visual Studio "14".
4. Right-click on the project node in Solution Explorer and choose Manage
NuGet Packages.
5. Select the NuGet feed you created on the left.
6. Choose your analyzer from the list and click Install.
If you want to automatically deploy the .nupkg file to the local feed folder
when you build this project, follow these steps:
1. Right-click on this project in Solution Explorer and choose Properties.
2. Go to the Build Events tab.
3. In the "Post-build event command line" box, change the -OutputDirectory
path to point to your local NuGet feed folder.
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
namespace AsyncPackage
{
/// <summary>
/// This analyzer will run a codefix on any method that qualifies as async that renames it to follow naming conventions
/// </summary>
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public class RenameAsyncAnalyzer : DiagnosticAnalyzer
{
internal const string RenameAsyncId = "Async002";
internal static DiagnosticDescriptor RenameAsyncMethod = new DiagnosticDescriptor(id: RenameAsyncId,
title: "Async Method Names Should End in Async",
messageFormat: "This method is async but the method name does not end in Async",
category: "Naming",
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);
public override void Initialize(AnalysisContext context)
{
context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.Method);
}
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(RenameAsyncMethod); } }
private static void AnalyzeSymbol(SymbolAnalysisContext context)
{
// Filter out methods that do not use Async and make sure to include methods that return a Task
var methodSymbol = (IMethodSymbol)context.Symbol;
// Check if method name is an override or virtual class. If it is disregard it.
// (This assumes if a method is virtual the programmer will not want to change the name)
// Check if the method returns a Task or Task<TResult>
if ((methodSymbol.ReturnType == context.Compilation.GetTypeByMetadataName("System.Threading.Tasks.Task")
|| methodSymbol.ReturnType.OriginalDefinition == context.Compilation.GetTypeByMetadataName("System.Threading.Tasks.Task`1").OriginalDefinition)
&& !methodSymbol.Name.EndsWith("Async") && !methodSymbol.IsOverride && !methodSymbol.IsVirtual)
{
context.ReportDiagnostic(Diagnostic.Create(RenameAsyncMethod, methodSymbol.Locations[0], methodSymbol.Name));
return;
}
return;
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Rename;
namespace AsyncPackage
{
/// <summary>
/// This codefix adds "Async" to the end of the Method Identifier and does a basic spellcheck in case the user had already tried to type Async
/// </summary>
[ExportCodeFixProvider(LanguageNames.CSharp, Name = RenameAsyncAnalyzer.RenameAsyncId), Shared]
public class RenameAsyncCodeFix : CodeFixProvider
{
public sealed override ImmutableArray<string> FixableDiagnosticIds
{
get { return ImmutableArray.Create(RenameAsyncAnalyzer.RenameAsyncId); }
}
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
// Find the type declaration identified by the diagnostic.
var methodDeclaration = root.FindToken(diagnosticSpan.Start).Parent.FirstAncestorOrSelf<MethodDeclarationSyntax>();
// Register a code action that will invoke the fix.
context.RegisterCodeFix(
new RenameAsyncCodeAction("Add Async to the end of the method name",
c => RenameMethodAsync(context.Document, methodDeclaration, c)),
diagnostic);
}
private async Task<Solution> RenameMethodAsync(Document document, MethodDeclarationSyntax methodDeclaration, CancellationToken cancellationToken)
{
var model = await document.GetSemanticModelAsync().ConfigureAwait(false);
var oldSolution = document.Project.Solution;
var symbol = model.GetDeclaredSymbol(methodDeclaration);
var oldName = methodDeclaration.Identifier.ToString();
var newName = string.Empty;
// Check to see if name already contains Async at the end
if (HasAsyncSuffix(oldName))
{
newName = oldName.Substring(0, oldName.Length - 5) + "Async";
}
else
{
newName = oldName + "Async";
}
var newSolution = await Renamer.RenameSymbolAsync(document.Project.Solution, symbol, newName, document.Project.Solution.Workspace.Options).ConfigureAwait(false);
// Gets all identifiers to check for renaming conflicts
var syntaxTree = await document.GetSyntaxTreeAsync().ConfigureAwait(false);
var descendentTokens = syntaxTree.GetRoot().DescendantTokens();
var usedNames = descendentTokens.Where(token => token.IsKind(SyntaxKind.IdentifierToken)).Select(token => token.Value);
while (usedNames.Contains(newName))
{
// No codefix should be offered if the name conflicts with another method.
return oldSolution;
}
return newSolution;
}
/// <summary>
/// This spellchecker obviously has limitations, but it may be helpful to some.
/// </summary>
/// <param name="oldName"></param>
/// <returns>Returns a boolean of whether or not "Async" may have been in the Method name already but was mispelled.</returns>
public bool HasAsyncSuffix(string oldName)
{
if (oldName.Length >= 5)
{
var last5letters = oldName.Substring(oldName.Length - 5);
// Check case. The A in Async must be capitalized
if (last5letters.Contains("async") || last5letters.Contains("asinc"))
{
return true;
}
else if (((last5letters.Contains("A") || last5letters.Contains("a")) && last5letters.Contains("s") && last5letters.Contains("y")
&& last5letters.Contains("n") && last5letters.Contains("c")) && !last5letters.ToLower().Equals("scany"))
{
return true; // Basic spellchecker. This is obviously not conclusive, but it may catch a small error if the letters are simply switched around.
}
}
return false;
}
public sealed override FixAllProvider GetFixAllProvider()
{
return null;
}
private class RenameAsyncCodeAction : CodeAction
{
private Func<CancellationToken, Task<Solution>> _generateSolution;
private string _title;
public RenameAsyncCodeAction(string title, Func<CancellationToken, Task<Solution>> generateSolution)
{
_title = title;
_generateSolution = generateSolution;
}
public override string Title { get { return _title; } }
protected override Task<Solution> GetChangedSolutionAsync(CancellationToken cancellationToken)
{
return base.GetChangedSolutionAsync(cancellationToken);
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="Settings">
<Import Project="$(SolutionDir)..\..\build\Targets\VSL.Settings.targets" />
</ImportGroup>
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{0D9287FD-F17F-4CB8-B622-904E69994AC6}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Tests</RootNamespace>
<AssemblyName>Tests</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
<SccProjectName>SAK</SccProjectName>
<SccLocalPath>SAK</SccLocalPath>
<SccAuxPath>SAK</SccAuxPath>
<SccProvider>SAK</SccProvider>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\..\</SolutionDir>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CodeAnalysis">
<HintPath>$(VSLOutDir)\Microsoft.CodeAnalysis.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Microsoft.CodeAnalysis.CSharp">
<SpecificVersion>False</SpecificVersion>
<HintPath>(VSLOutDir)\Microsoft.CodeAnalysis.CSharp.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Microsoft.CodeAnalysis.CSharp.Workspaces">
<SpecificVersion>False</SpecificVersion>
<HintPath>(VSLOutDir)\Microsoft.CodeAnalysis.CSharp.Workspaces.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Microsoft.CodeAnalysis.VisualBasic">
<HintPath>(VSLOutDir)\Microsoft.CodeAnalysis.VisualBasic.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces">
<HintPath>(VSLOutDir)\Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Microsoft.CodeAnalysis.Workspaces">
<SpecificVersion>False</SpecificVersion>
<HintPath>(VSLOutDir)\Microsoft.CodeAnalysis.Workspaces.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Microsoft.CodeAnalysis.Workspaces.Desktop">
<SpecificVersion>False</SpecificVersion>
<HintPath>(VSLOutDir)\Microsoft.CodeAnalysis.Workspaces.Desktop.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Collections.Immutable">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
</ItemGroup>
<Choose>
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"><Private>false</Private></Reference>
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework"><Private>false</Private></Reference>
</ItemGroup>
</Otherwise>
</Choose>
<ItemGroup>
<Compile Include="Async_Tests\AsyncLambdaTests.cs" />
<Compile Include="Async_Tests\AsyncVoidTests.cs" />
<Compile Include="Async_Tests\BlockingAsyncTests.cs" />
<Compile Include="Async_Tests\CancellationTests.cs" />
<Compile Include="Backend\CodeFixVerifier.Helper.cs" />
<Compile Include="Backend\DiagnosticVerifier.Helper.cs" />
<Compile Include="CodeFixVerifier.cs" />
<Compile Include="Backend\DiagnosticResult.cs" />
<Compile Include="Async_Tests\RenameAsyncTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="DiagnosticVerifier.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AsyncPackage.csproj">
<Project>{68d3fdd2-da02-453b-9df9-022f65f9265e}</Project>
<Name>AsyncPackage</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
</ItemGroup>
</When>
</Choose>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<ImportGroup Label="Targets">
<Import Project="$(SolutionDir)..\..\build\Targets\VSL.Imports.targets" />
</ImportGroup>
</Project>
// 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;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TestTemplate;
namespace AsyncPackage.Tests
{
/// <summary>
/// Unit Tests for the AsyncLambdaDiagnosticAnalzer and AsyncLambdaVariableCodeFix
/// </summary>
[TestClass]
public class AsyncLambdaTests : CodeFixVerifier
{
private const string DefaultHeader = @"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{ ";
private const string DefaultFooter = @"
}
}";
private DiagnosticResult expected003 = new DiagnosticResult
{
Id = "Async003",
Message = "This async lambda is passed as a void-returning delegate type",
Severity = DiagnosticSeverity.Warning,
// Location should be changed within test methods
Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 10) }
};
private DiagnosticResult expected004 = new DiagnosticResult
{
Id = "Async004",
Message = "This async lambda is stored as a void-returning delegate type",
Severity = DiagnosticSeverity.Warning,
// Location should be changed within test methods
Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 10) }
};
protected override CodeFixProvider GetCSharpCodeFixProvider()
{
return new AsyncLambdaVariableCodeFix();
}
protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer()
{
return new AsyncLambdaAnalyzer();
}
[TestMethod]
public void AL001_None_NoMethodNoDiagnostics()
{
var test = @"";
VerifyCSharpDiagnostic(test);
}
[TestMethod]
public void AL002_DACF_AssignVoidableVariable()
{
var body = @"
public void method()
{
//assign to voidable variable
Action thing = async () =>
{
await Task.Delay(500);
};
}";
var test = DefaultHeader + body + DefaultFooter;
expected004.Locations = new[] { new DiagnosticResultLocation("Test0.cs", 16, 17) };
VerifyCSharpDiagnostic(test, expected004);
var fix = @"
public void method()
{
//assign to voidable variable
Func<Task> thing = async () =>
{
await Task.Delay(500);
};
}";
var testfix = DefaultHeader + fix + DefaultFooter;
// Causes new unused using directory error because the code is not using System.Action anymore
VerifyCSharpFix(test, testfix, null, true);
}
// Task function assigned to lambda - no diagnostic should show
[TestMethod]
public void AL003_None_TaskReturningDelegateType()
{
var body = @"
static void Main(string[] args)
{
//assign as correct variable
Func<Task> thing2 = async () =>
{
await Task.Delay(666);
};
}";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Method with void-returning delegate type - diagnostic should show on the lambda
[TestMethod]
public void AL004_DA_PassAsVoidReturningDelagateType()
{
var body = @"
//bad implementation
public static double BadMethod(Action action)
{
return 0;
}
//pass as void-returning delegate type
double num = BadMethod(async () =>
{
await Task.Delay(1000);
});
";
var test = DefaultHeader + body + DefaultFooter;
expected003.Locations = new[] { new DiagnosticResultLocation("Test0.cs", 20, 32) };
VerifyCSharpDiagnostic(test, expected003);
}
// Method with correct delegate type - no diagnostic should show
[TestMethod]
public void AL005_None_PassAsTaskReturningDelagateType()
{
var body = @"
//good implementation
public static double GoodMethod(Func<Task> func)
{
return 0;
}
//pass as void-returning delegate type
double num = GoodMethod(async () =>
{
await Task.Delay(1000);
});
";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Lambda overrides a Task function - no diagnostic should show
[TestMethod]
public void AL006_None_TaskOverrideDelegateType()
{
var body = @"
static void Main(string[] args)
{
//use correct override
Task.Factory.StartNew(async () =>
{
await Task.Delay(12345);
});
}";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Test delegate vs => correct - no diagnostic should show
[TestMethod]
public void AL007_None_DelegateLambdaTaskReturn()
{
var body = @"
//good implementation
public static double GoodMethod(Func<Task> func)
{
return 0;
}
//pass as void-returning delegate type
double num = GoodMethod(async delegate ()
{
await Task.Delay(222);
});
";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Test delegate vs => incorrect - 1 diagnostic should show
[TestMethod]
public void AL008_DA_DelegateLambdaVoidReturn()
{
var body = @"
//good implementation
public static double BadMethod(Action a)
{
return 0;
}
//pass as void-returning delegate type
double num = BadMethod(async delegate ()
{
await Task.Delay(100);
});
";
var test = DefaultHeader + body + DefaultFooter;
expected003.Locations = new[] { new DiagnosticResultLocation("Test0.cs", 20, 32) };
VerifyCSharpDiagnostic(test, expected003);
}
// Test simple lambda correct - no diagnostic should show
[TestMethod]
public void AL009_None_SimpleLambdaTaskReturn()
{
var body = @"
//good implementation
public static double GoodMethod(Func<Task> func)
{
return 0;
}
//pass as void-returning delegate type
double num = GoodMethod(async () => await Task.Delay(10));
";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Test simple lambda incorrect - 1 diagnostic should show
[TestMethod]
public void AL010_DA_SimpleLambdaVoidReturn()
{
var body = @"
//good implementation
public static double BadMethod(Action a)
{
return 0;
}
//pass as void-returning delegate type
double num = BadMethod(async () => await Task.Delay(10));
";
var test = DefaultHeader + body + DefaultFooter;
expected003.Locations = new[] { new DiagnosticResultLocation("Test0.cs", 20, 32) };
VerifyCSharpDiagnostic(test, expected003);
}
// Missing necessary using directives - 1 diagnostic
[TestMethod]
public void AL011_DA_MissingUsings()
{
var body = @"
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{
//bad implementation
public static double BadMethod(System.Action action)
{
return 0;
}
//pass as void-returning delegate type
double num = BadMethod(async () =>
{
await System.Threading.Tasks.Task.Delay(1000);
});
}
}";
var test = body;
expected003.Locations = new[] { new DiagnosticResultLocation("Test0.cs", 18, 32) };
VerifyCSharpDiagnostic(test, expected003);
}
}
}
// 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;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TestTemplate;
namespace AsyncPackage.Tests
{
/// <summary>
/// Unit Tests for the AsyncVoidAnalyzer and AsyncVoidCodeFix
/// </summary>
[TestClass]
public class AsyncVoidTests : CodeFixVerifier
{
private const string DefaultHeader = @"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{ ";
private const string DefaultFooter = @"
}
}";
private DiagnosticResult expected001 = new DiagnosticResult
{
Id = "Async001",
Message = "This method has the async keyword but it returns void",
Severity = DiagnosticSeverity.Warning,
// Location should be changed within test methods
Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 10) }
};
protected override CodeFixProvider GetCSharpCodeFixProvider()
{
return new AsyncVoidCodeFix();
}
protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer()
{
return new AsyncVoidAnalyzer();
}
protected override DiagnosticAnalyzer GetBasicDiagnosticAnalyzer()
{
return new AsyncVoidAnalyzer();
}
// No methods - no diagnostic should show
[TestMethod]
public void AV001_None_NoMethodNoDiagnostics()
{
var body = @"";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Task Return Async Method - single request - should show no diagnostic
[TestMethod]
public void AV002_None_TaskReturnAsyncSingleRequest()
{
var body = @"
public static async Task DelayAsync()
{
await Task.Delay(1000);
}";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Task Return Async Method - serial requests - should show no diagnostic
[TestMethod]
public void AV003_None_TaskReturnAsyncSerialRequests()
{
var body = @"
public static async Task DelayMultipleTimesAsync()
{
await Task.Delay(1000);
await Task.Delay(1000);
await Task.Delay(1000);
await Task.Delay(1000);
}";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Task Return Async Method - parallel requests - should show no diagnostic
[TestMethod]
public void AV004_None_TaskReturnAsyncParallelRequests()
{
var body = @"
public async Task SomeAsyncTask()
{ int value = 708;
await ValuePlusOne(value);
await ValuePlusTwo(value);
await ValuePlusThree(value);
}
public async Task<int> ValuePlusOne(int num)
{
await Task.Delay(90);
return num;
}
public async Task<int> ValuePlusTwo(int num)
{
await Task.Delay(990);
return num;
}
public async Task<int> ValuePlusThree(int num)
{
await Task.Delay(9990);
return num;
}";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Task<int> Return Async Method - Single request - should show no diagnostic
[TestMethod]
public void AV005_None_TaskIntReturnAsyncSingleRequest()
{
var body = @"
public static async Task<int> MultiplyfactorsAsync(int factor1, int factor2)
{
await Task.Delay(5000);
//delay once
return (factor1 * factor2);
}";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Task<int> Return Async Method - serial requests - should show no diagnostic
[TestMethod]
public void AV006_None_TaskIntReturnWithAsync()
{
var body = @"
private async Task<int> MathAsync(int num1)
{
//delays
await Task.Delay(3000);
await Task.Delay(1000);
await Task.Delay(num1 * 15);
return (num1);
} ";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Task<string> Return Async Method - single request - should show no diagnostic
[TestMethod]
public void AV007_None_TaskStringReturnAsyncSingleRequest()
{
var body = @"
public static Task<String> ReturnAAAAsync()
{
return Task.Run(() =>
{ return (""AAA""); });
}";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Task<string> Return Async Method - serial requests - should show no diagnostic
[TestMethod]
public void AV008_None_TaskStringReturnAsyncSerialRequests()
{
var body = @"
public async static Task<String> LongTaskAAsync()
{
await Task.Delay(2000);
await Task.Delay(2000);
await Task.Delay(2000);
return await Task.Run(() =>
{
return (""AAA"");
});
}";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Task<int> Return Async Method - serial requests - should show no diagnostic
[TestMethod]
public void AV009_None_TaskIntReturnAsyncSerialRequests()
{
var body = @"
public static async Task<int> MultiplyAsync(int factor1, int factor2)
{
//delay three times
await Task.Delay(100);
await Task.Delay(100);
await Task.Delay(100);
return (factor1 * factor2);
}";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Task Return Async Method - single request - should show no diagnostic
[TestMethod]
public void AV010_None_TaskReturnNoAsyncSingleRequest()
{
var body = @"
public static async Task Delay()
{
await Task.Delay(1000);
}";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Task<int> Return Async Method - serial requests - should show no diagnostic
[TestMethod]
public void AV011_None_TaskIntReturnNoAsyncSerialRequests()
{
var body = @"
public static async Task<int> Multiply(int factor1, int factor2)
{
//delay three times
await Task.Delay(100);
await Task.Delay(100);
await Task.Delay(100);
return (factor1 * factor2);
}";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Task<bool> async method - no diagnostic
[TestMethod]
public void AV012_None_TaskBoolReturnAsync()
{
var body = @"
private async Task<bool> TrueorFalseAsync(bool trueorfalse)
{
await Task.Delay(700);
return !(trueorfalse);
} ";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Void Return Async Method with Event handling - should show no diagnostic
[TestMethod]
public void AV013_None_AsyncVoidWithEventHandling()
{
var body = @"
private async void button1_Click(object sender, EventArgs e)
{
await Button1ClickAsync();
}
public async Task Button1ClickAsync()
{
// Do asynchronous work.
await Task.Delay(1000);
}";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Void Return Async Method - parallel requests - should show 1 diagnostic
[TestMethod]
public void AV014_DACF_VoidReturnAsyncParallelRequests()
{
var body = @"
public async void SomeAsyncTask()
{
int value = 708;
await ValuePlusOne(value);
await ValuePlusTwo(value);
await ValuePlusThree(value);
}
public async Task<int> ValuePlusOne(int num)
{
await Task.Delay(90);
return num;
}
public async Task<int> ValuePlusTwo(int num)
{
await Task.Delay(990);
return num;
}
public async Task<int> ValuePlusThree(int num)
{
await Task.Delay(9990);
return num;
}";
var test = DefaultHeader + body + DefaultFooter;
expected001.Locations = new[] { new DiagnosticResultLocation("Test0.cs", 13, 27) };
VerifyCSharpDiagnostic(test, expected001);
var fixbody = @"
public async Task SomeAsyncTask()
{
int value = 708;
await ValuePlusOne(value);
await ValuePlusTwo(value);
await ValuePlusThree(value);
}
public async Task<int> ValuePlusOne(int num)
{
await Task.Delay(90);
return num;
}
public async Task<int> ValuePlusTwo(int num)
{
await Task.Delay(990);
return num;
}
public async Task<int> ValuePlusThree(int num)
{
await Task.Delay(9990);
return num;
}";
var fixtest = DefaultHeader + fixbody + DefaultFooter;
VerifyCSharpFix(test, fixtest);
}
// No diagnostic shown during async void return when asynchronous event handler is used - parallel requests
[TestMethod]
public void AV015_None_VoidReturnaSyncWithEventParallel()
{
var body = @"
private async void button1_Click(object sender, EventArgs e)
{
await Button1ClickAsync();
await Button2ClickAsync();
}
public async Task Button1ClickAsync()
{
// Do asynchronous work.
await Task.Delay(1000);
}
public async Task Button2ClickAsync()
{
//Do asynchronous work.
await Task.Delay(3000);
}";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// No diagnostic shown during async void return when asynchronous event handler is used - serial requests
[TestMethod]
public void AV016_None_VoidReturnaSyncWithEventSerial()
{
var body = @"
private async void button1_Click(object sender, EventArgs e)
{
await Button1ClickAsync();
await Button1ClickAsync();
await Button1ClickAsync();
}
public async Task Button1ClickAsync()
{
// Do asynchronous work.
await Task.Delay(1000);
}";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Void Return Async Method with no event handlers - 1 diagnostic should show
[TestMethod]
public void AV017_DACF_AsyncVoidWithOutEvent1()
{
var body = @"
public async void AsyncVoidReturnTaskT()
{
Console.WriteLine(""Begin Program"");
Console.WriteLine(await AsyncTaskReturnT());
Console.WriteLine(""End Program"");
}
private async Task<string> AsyncTaskReturnT()
{
await Task.Delay(65656565);
return ""Program is processing...."";
}";
var test = DefaultHeader + body + DefaultFooter;
expected001.Locations = new[] { new DiagnosticResultLocation("Test0.cs", 13, 27) };
VerifyCSharpDiagnostic(test, expected001);
var fixbody = @"
public async Task AsyncVoidReturnTaskT()
{
Console.WriteLine(""Begin Program"");
Console.WriteLine(await AsyncTaskReturnT());
Console.WriteLine(""End Program"");
}
private async Task<string> AsyncTaskReturnT()
{
await Task.Delay(65656565);
return ""Program is processing...."";
}";
var fixtest = DefaultHeader + fixbody + DefaultFooter;
VerifyCSharpFix(test, fixtest);
}
// Void Return Async Method with no event handlers - 1 diagnostic should show
[TestMethod]
public void AV018_DACF_AsyncVoidWithOutEvent2()
{
var body = @"
private async void WaitForIt(int value)
{
await Task.Delay(value);
}
private void DoSomethingSilent(int value)
{
WaitForIt(value);
}";
var test = DefaultHeader + body + DefaultFooter;
expected001.Locations = new[] { new DiagnosticResultLocation("Test0.cs", 13, 28) };
VerifyCSharpDiagnostic(test, expected001);
var fixbody = @"
private async Task WaitForIt(int value)
{
await Task.Delay(value);
}
private void DoSomethingSilent(int value)
{
WaitForIt(value);
}";
var fixtest = DefaultHeader + fixbody + DefaultFooter;
VerifyCSharpFix(test, fixtest, null, true);
}
// Check to make sure the diagnostic still shows for methods with two parameters that are not Event Handlers
[TestMethod]
public void AV019_DACF_AsyncVoidTwoParams()
{
var body = @"
private async void WaitForIt(int value, int value2)
{
await Task.Delay(value+value2);
}";
var test = DefaultHeader + body + DefaultFooter;
expected001.Locations = new[] { new DiagnosticResultLocation("Test0.cs", 13, 28) };
VerifyCSharpDiagnostic(test, expected001);
var fixbody = @"
private async Task WaitForIt(int value, int value2)
{
await Task.Delay(value+value2);
}";
var fixtest = DefaultHeader + fixbody + DefaultFooter;
VerifyCSharpFix(test, fixtest);
}
// Check to make sure the diagnostic still shows for methods with a parameter that implements Event Handler
[TestMethod]
public void AV020_DA_AsyncVoidImplementsEvent()
{
var body = @"
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Threading;
using System.Threading.Tasks;
namespace TestingTemplate
{
[TestClass]
public class UnitTest1
{
//Show no diagnostic for a param that implements an EventArgs
public async void EventHandlerImplementAsync(object sender, ImplementsEvents e)
{
await Task.Delay(1000);
}
}
public class ImplementsEvents : EventArgs
{
public ImplementsEvents() { }
}
}";
var test = body;
VerifyCSharpDiagnostic(test);
}
// Check to make sure the diagnostic still shows for methods with a parameter that implements Event Handler
[TestMethod]
public void AV021_DA_AsyncVoidParentImplementsEvent()
{
var body = @"
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Threading;
using System.Threading.Tasks;
namespace TestingTemplate
{
[TestClass]
public class UnitTest1
{
//Show no diagnostic for a param that implements an EventArgs
public async void EventHandlerImplementAsync(object sender, ParentImplementsEvents e)
{
await Task.Delay(1000);
}
}
public class ImplementsEvents : EventArgs
{
public ImplementsEvents() { }
}
public class ParentImplementsEvents : ImplementsEvents
{
public ParentImplementsEvents() { }
}
}
";
var test = body;
VerifyCSharpDiagnostic(test);
}
// Check to make sure the diagnostic still shows for methods with a parameter that implements Event Handler
[TestMethod]
public void AV022_DA_AsyncVoidGrandfatherImplementsEvent()
{
var body = @"
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Threading;
using System.Threading.Tasks;
namespace TestingTemplate
{
[TestClass]
public class UnitTest1
{
//Show no diagnostic for a param that implements an EventArgs
public async void EventHandlerImplementAsync(object sender, ParentParentImplementsEvents e)
{
await Task.Delay(1000);
}
}
public class ImplementsEvents : EventArgs
{
public ImplementsEvents() { }
}
public class ParentImplementsEvents : ImplementsEvents
{
public ParentImplementsEvents() { }
}
public class ParentParentImplementsEvents : ParentImplementsEvents
{
public ParentParentImplementsEvents() { }
}
}";
var test = body;
VerifyCSharpDiagnostic(test);
}
#region VB Tests
// Check to make sure the diagnostic appears for VB
[TestMethod]
public void AV023_DA_VBDiagnosticSimple()
{
var body = @"
Module Module1
Async Sub example()
Await Task.Delay(100)
End Sub
End Module
";
var test = body;
DiagnosticResult expected001vb = new DiagnosticResult
{
Id = "Async001",
Message = "This method has the async keyword but it returns void",
Severity = DiagnosticSeverity.Warning,
Locations = new[] { new DiagnosticResultLocation("Test0.vb", 4, 15) }
};
VerifyBasicDiagnostic(test, expected001vb);
}
// Check to make sure the diagnostic does not appear for the case of VB event handlers
[TestMethod]
public void AV024_None_VBEventHandler()
{
var body = @"
imports System
Module Module1
Async Sub event_method(sender As Object, e As EventArgs)
Await Task.Delay(100)
End Sub
End Module
";
var test = body;
VerifyBasicDiagnostic(test);
}
#endregion
}
}
// 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;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TestTemplate;
namespace AsyncPackage.Tests
{
/// <summary>
/// Unit Tests for the BlockingAsyncAnalyzer and BlockingAsyncCodeFix
/// </summary>
[TestClass]
public class BlockingAsyncTests : CodeFixVerifier
{
private const string DefaultHeader = @"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{ ";
private const string DefaultFooter = @"
}
}";
private DiagnosticResult expected = new DiagnosticResult
{
Id = "Async006",
Message = "This method is blocking on async code",
Severity = DiagnosticSeverity.Warning,
// Location should be changed within test methods
Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 10) }
};
protected override CodeFixProvider GetCSharpCodeFixProvider()
{
return new BlockingAsyncCodeFix();
}
protected override CodeFixProvider GetBasicCodeFixProvider()
{
return new BlockingAsyncCodeFix();
}
protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer()
{
return new BlockingAsyncAnalyzer();
}
protected override DiagnosticAnalyzer GetBasicDiagnosticAnalyzer()
{
return new BlockingAsyncAnalyzer();
}
// No methods - no diagnostic should show
[TestMethod]
public void BA001_None_NoMethodNoDiagnostics()
{
var body = @"";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Wait block on async code - 1 diagnostic - code fix
[TestMethod]
public void BA002_DACF_WaitBlockAsyncCode()
{
var body = @"
async Task<int> fooAsync(int somenumber)
{
foo1Async(somenumber).Wait();
return somenumber;
}
async Task<int> foo1Async(int value)
{
await Task.Yield();
return value;
}";
var test = DefaultHeader + body + DefaultFooter;
expected.Id = "Async006";
expected.Locations = new[] { new DiagnosticResultLocation("Test0.cs", 16, 13) };
VerifyCSharpDiagnostic(test, expected);
var fixbody = @"
async Task<int> fooAsync(int somenumber)
{
await foo1Async(somenumber);
return somenumber;
}
async Task<int> foo1Async(int value)
{
await Task.Yield();
return value;
}";
var fixtest = DefaultHeader + fixbody + DefaultFooter;
VerifyCSharpFix(test, fixtest);
}
// Result block on async code - 1 diagnostic - code fix
[TestMethod]
public void BA003_DACF_ResultBlockAsyncCode()
{
var body = @"
async Task foo2Async(int somenumber)
{
var temp = foo3Async(somenumber).Result;
}
async Task<int> foo3Async(int value)
{
await Task.Yield();
return value;
}";
var test = DefaultHeader + body + DefaultFooter;
expected.Id = "Async006";
expected.Locations = new[] { new DiagnosticResultLocation("Test0.cs", 16, 24) };
VerifyCSharpDiagnostic(test, expected);
var fixbody = @"
async Task foo2Async(int somenumber)
{
var temp = await foo3Async(somenumber);
}
async Task<int> foo3Async(int value)
{
await Task.Yield();
return value;
}";
var fixtest = DefaultHeader + fixbody + DefaultFooter;
VerifyCSharpFix(test, fixtest);
}
// Invocation expression assigned to variable - 1 diagnostic
[TestMethod]
public void BA004_DA_InvocationExpressionVariable()
{
var body = @"
async Task<Task<int>> SomeMethodAsync()
{
var t = addAsync(25, 50);
t.Wait();
return t;
}
async Task<int> addAsync(int num1, int num2)
{
await Task.Delay(29292);
return (num1 + num2);
}";
var test = DefaultHeader + body + DefaultFooter;
expected.Id = "Async006";
expected.Locations = new[] { new DiagnosticResultLocation("Test0.cs", 17, 13) };
var fixbody = @"
async Task<Task<int>> SomeMethodAsync()
{
var t = addAsync(25, 50);
await t;
return t;
}
async Task<int> addAsync(int num1, int num2)
{
await Task.Delay(29292);
return (num1 + num2);
}";
var fixtest = DefaultHeader + fixbody + DefaultFooter;
VerifyCSharpDiagnostic(test, expected);
VerifyCSharpFix(test, fixtest);
}
// Async method using waitall on task - 1 diagnostic - code fix
[TestMethod]
public void BA005_DACF_WaitAllBlockAsyncCode()
{
var body = @"
async Task WaitAllAsync()
//Source: http://msdn.microsoft.com/en-us/library/dd270695(v=vs.110).aspx
{
Func<object, int> action = (object obj) =>
{
int i = (int)obj;
// The tasks that receive an argument between 2 and 5 throw exceptions
if (2 <= i && i <= 5)
{
throw new InvalidOperationException();
}
int tickCount = Environment.TickCount;
return tickCount;
};
const int n = 10;
// Construct started tasks
Task<int>[] tasks = new Task<int>[n];
for (int i = 0; i<n; i++)
{
tasks[i] = Task<int>.Factory.StartNew(action, i);
}
// Exceptions thrown by tasks will be propagated to the main thread
// while it waits for the tasks. The actual exceptions will be wrapped in AggregateException.
try
{
// Wait for all the tasks to finish.
Task.WaitAll(tasks);
// We should never get to this point
}
catch (AggregateException e)
{
for (int j = 0; j<e.InnerExceptions.Count; j++)
{
Console.WriteLine(e.InnerExceptions[j].ToString());
}
}
}";
var test = DefaultHeader + body + DefaultFooter;
expected.Id = "Async006";
expected.Locations = new[] { new DiagnosticResultLocation("Test0.cs", 46, 17) };
VerifyCSharpDiagnostic(test, expected);
var fixbody = @"
async Task WaitAllAsync()
//Source: http://msdn.microsoft.com/en-us/library/dd270695(v=vs.110).aspx
{
Func<object, int> action = (object obj) =>
{
int i = (int)obj;
// The tasks that receive an argument between 2 and 5 throw exceptions
if (2 <= i && i <= 5)
{
throw new InvalidOperationException();
}
int tickCount = Environment.TickCount;
return tickCount;
};
const int n = 10;
// Construct started tasks
Task<int>[] tasks = new Task<int>[n];
for (int i = 0; i<n; i++)
{
tasks[i] = Task<int>.Factory.StartNew(action, i);
}
// Exceptions thrown by tasks will be propagated to the main thread
// while it waits for the tasks. The actual exceptions will be wrapped in AggregateException.
try
{
// Wait for all the tasks to finish.
await Task.WhenAll(tasks);
// We should never get to this point
}
catch (AggregateException e)
{
for (int j = 0; j<e.InnerExceptions.Count; j++)
{
Console.WriteLine(e.InnerExceptions[j].ToString());
}
}
}";
var fixtest = DefaultHeader + fixbody + DefaultFooter;
VerifyCSharpFix(test, fixtest, null, true);
}
// Async with thread.sleep - 1 diagnostic - code fix
[TestMethod]
public void BA006_DACF_AsyncWithThreadSleep()
{
var body = @"
async Task<string> SleepHeadAsync(string phrase)
{
Thread.Sleep(9999);
return phrase;
}";
var test = DefaultHeader + body + DefaultFooter;
expected.Id = "Async006";
expected.Locations = new[] { new DiagnosticResultLocation("Test0.cs", 16, 13) };
VerifyCSharpDiagnostic(test, expected);
var fixbody = @"
async Task<string> SleepHeadAsync(string phrase)
{
await Task.Delay(9999);
return phrase;
}";
var fixtest = DefaultHeader + fixbody + DefaultFooter;
VerifyCSharpFix(test, fixtest, null, true);
}
// Thread.sleep within loop - 1 diagnostic - code fix
[TestMethod]
public void BA007_DACF_ThreadSleepInLoop()
{
var body = @"
async Task SleepAsync()
{
for (int i = 0; i < 5; i++)
{
Thread.Sleep(3000);
}
}";
var test = DefaultHeader + body + DefaultFooter;
expected.Id = "Async006";
expected.Locations = new[] { new DiagnosticResultLocation("Test0.cs", 18, 17) };
VerifyCSharpDiagnostic(test, expected);
var fixbody = @"
async Task SleepAsync()
{
for (int i = 0; i < 5; i++)
{
await Task.Delay(3000);
}
}";
var fixtest = DefaultHeader + fixbody + DefaultFooter;
VerifyCSharpFix(test, fixtest, null, true);
}
// Thread.sleep(timespan) - 1 diagnostic - code fix
[TestMethod]
public void BA008_DACF_AsyncWithThreadSleepTimeSpan()
{
var body = @"
async Task TimeSpanAsync()
{
TimeSpan time = new TimeSpan(1000);
Thread.Sleep(time);
}";
var test = DefaultHeader + body + DefaultFooter;
expected.Id = "Async006";
expected.Locations = new[] { new DiagnosticResultLocation("Test0.cs", 17, 13) };
VerifyCSharpDiagnostic(test, expected);
var fixbody = @"
async Task TimeSpanAsync()
{
TimeSpan time = new TimeSpan(1000);
await Task.Delay(time);
}";
var fixtest = DefaultHeader + fixbody + DefaultFooter;
VerifyCSharpFix(test, fixtest, null, true);
}
// Thread.sleep(TimeSpan) within loop - 1 diagnostic - code fix
[TestMethod]
public void BA009_DACF_ThreadSleepTimeSpanInForLoop()
{
var body = @"
async Task TimespaninForloopAsync()
{
TimeSpan interval = new TimeSpan(2, 20, 55, 33, 0);
for (int i = 0; i < 5; i++)
{
Thread.Sleep(interval);
}
}";
var test = DefaultHeader + body + DefaultFooter;
expected.Id = "Async006";
expected.Locations = new[] { new DiagnosticResultLocation("Test0.cs", 20, 17) };
VerifyCSharpDiagnostic(test, expected);
var fixbody = @"
async Task TimespaninForloopAsync()
{
TimeSpan interval = new TimeSpan(2, 20, 55, 33, 0);
for (int i = 0; i < 5; i++)
{
await Task.Delay(interval);
}
}";
var fixtest = DefaultHeader + fixbody + DefaultFooter;
VerifyCSharpFix(test, fixtest, null, true);
}
// Thread.sleep(timespan) within while loop - 1 diagnostic - code fix
[TestMethod]
public void BA010_DACF_ThreadSleepTimeSpanInWhileLoop()
{
var body = @"
async Task TimeSpanWhileLoop()
{
bool trueorfalse = true;
TimeSpan interval = new TimeSpan(0, 0, 2);
while (trueorfalse)
{
for (int i = 0; i < 5; i++)
{
Thread.Sleep(interval);
}
trueorfalse = false;
}
}";
var test = DefaultHeader + body + DefaultFooter;
expected.Id = "Async006";
expected.Locations = new[] { new DiagnosticResultLocation("Test0.cs", 22, 21) };
VerifyCSharpDiagnostic(test, expected);
var fixbody = @"
async Task TimeSpanWhileLoop()
{
bool trueorfalse = true;
TimeSpan interval = new TimeSpan(0, 0, 2);
while (trueorfalse)
{
for (int i = 0; i < 5; i++)
{
await Task.Delay(interval);
}
trueorfalse = false;
}
}";
var fixtest = DefaultHeader + fixbody + DefaultFooter;
VerifyCSharpFix(test, fixtest, null, true);
}
// Async with task.delay - no diagnostic
[TestMethod]
public void BA011_None_AsyncWithAsync()
{
var body = @"
async Task SleepNowAsync()
{
await Task.Delay(1000);
}";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Async method calls a function with thread.sleep in it - out of scope, no diagnostic
[TestMethod]
public void BA012_None_HiddenSyncCode()
{
var body = @"
async Task CallAnotherMethodAsync()
{
SleepAlittle(5888);
}
public void SleepAlittle(int value)
{
Thread.Sleep(value);
}";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Non async method calls thread.wait - no diagnostic
[TestMethod]
public void BA013_None_NonAsyncWait()
{
var body = @"
Task Example()
{
Task.Wait();
}";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Async method calls a different Task method - no diagnostic
[TestMethod]
public void BA014_None_AsyncWithOtherMethod()
{
var body = @"
async Task Example()
{
await Task.Delay(100);
}";
var test = DefaultHeader + body + DefaultFooter;
VerifyCSharpDiagnostic(test);
}
// Async method calls a Wait method on a Task, but not the same Wait - no diagnostic
[TestMethod]
public void BA015_None_AsyncCallsOtherWait()
{
var test = @"
using System;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
async Task Example(Action a, string s)
{
await Task.Delay(100);
var t = new Task(a);
t.Wait(s);
}
}
public static class MyTaskExtensions
{
public static void Wait(this Task t, string s)
{
s = s + 1;
}
}
}";
VerifyCSharpDiagnostic(test);
}
// Async method calls a WaitAll method on a Task, but not the same WaitAll - no diagnostic
[TestMethod]
public void BA016_None_AsyncCallsOtherWaitAll()
{
var test = @"
using System;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
async Task Example(Action a, string s)
{
await Task.Delay(100);
var t = new Task(a);
t.WaitAll(s);
}
}
public static class MyTaskExtensions
{
public static void WaitAll(this Task t, string s)
{
s = s + 1;
}
}
}";
VerifyCSharpDiagnostic(test);
}
// Async method calls a WaitAny method on a Task, but not the same WaitAny - no diagnostic
[TestMethod]
public void BA017_None_AsyncCallsOtherWaitAny()
{
var test = @"
using System;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
async Task Example(Action a, string s)
{
await Task.Delay(100);
var t = new Task(a);
t.WaitAny(s);
}
}
public static class MyTaskExtensions
{
public static void WaitAny(this Task t, string s)
{
s = s + 1;
}
}
}";
VerifyCSharpDiagnostic(test);
}
// Async method calls a Sleep method on a Task, but not the same Sleep - no diagnostic
[TestMethod]
public void BA018_None_AsyncCallsOtherSleep()
{
var test = @"
using System;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
async Task Example(Action a, string s)
{
await Task.Delay(100);
var t = new Task(a);
t.Sleep(s);
}
}
public static class MyTaskExtensions
{
public static void Sleep(this Task t, string s)
{
s = s + 1;
}
}
}";
VerifyCSharpDiagnostic(test);
}
// Async method calls a GetResult method on a Task, but not the same GetResult - no diagnostic
[TestMethod]
public void BA019_None_AsyncCallsOtherGetResult()
{
var test = @"
using System;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
async Task Example(Action a, string s)
{
await Task.Delay(100);
var t = new Task(a);
t.GetResult(s);
}
}
public static class MyTaskExtensions
{
public static void GetResult(this Task t, string s)
{
s = s + 1;
}
}
}";
VerifyCSharpDiagnostic(test);
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Simplification;
namespace TestTemplate
{
/// <summary>
/// Diagnostic Producer class with extra methods dealing with applying codefixes
/// All methods are static
/// </summary>
public abstract partial class CodeFixVerifier : DiagnosticVerifier
{
/// <summary>
/// Apply the inputted CodeAction to the inputted document.
/// Meant to be used to apply codefixes.
/// </summary>
/// <param name="document">The Document to apply the fix on</param>
/// <param name="codeAction">A CodeAction that will be applied to the Document.</param>
/// <returns>A Document with the changes from the CodeAction</returns>
private static Document ApplyFix(Document document, CodeAction codeAction)
{
var operations = codeAction.GetOperationsAsync(CancellationToken.None).GetAwaiter().GetResult();
var solution = operations.OfType<ApplyChangesOperation>().Single().ChangedSolution;
return solution.GetDocument(document.Id);
}
/// <summary>
/// Compare two collections of Diagnostics,and return a list of any new diagnostics that appear only in the second collection.
/// Note: Considers Diagnostics to be the same if they have the same Ids. In the case of multiple diagnostics with the same Id in a row,
/// this method may not necessarily return the new one.
/// </summary>
/// <param name="diagnostics">The Diagnostics that existed in the code before the CodeFix was applied</param>
/// <param name="newDiagnostics">The Diagnostics that exist in the code after the CodeFix was applied</param>
/// <returns>A list of Diagnostics that only surfaced in the code after the CodeFix was applied</returns>
private static IEnumerable<Diagnostic> GetNewDiagnostics(IEnumerable<Diagnostic> diagnostics, IEnumerable<Diagnostic> newDiagnostics)
{
var oldArray = diagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray();
var newArray = newDiagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray();
int oldIndex = 0;
int newIndex = 0;
while (newIndex < newArray.Length)
{
if (oldIndex < oldArray.Length && oldArray[oldIndex].Id == newArray[newIndex].Id)
{
++oldIndex;
++newIndex;
}
else
{
yield return newArray[newIndex++];
}
}
}
/// <summary>
/// Get the existing compiler diagnostics on the inputted document.
/// </summary>
/// <param name="document">The Document to run the compiler diagnostic analyzers on</param>
/// <returns>The compiler diagnostics that were found in the code</returns>
private static IEnumerable<Diagnostic> GetCompilerDiagnostics(Document document)
{
return document.GetSemanticModelAsync().Result.GetDiagnostics();
}
/// <summary>
/// Given a Document, turn it into a string based on the syntax root
/// </summary>
/// <param name="document">The Document to be converted to a string</param>
/// <returns>A string containing the syntax of the Document after formatting</returns>
private static string GetStringFromDocument(Document document)
{
var simplifiedDoc = Simplifier.ReduceAsync(document, Simplifier.Annotation).Result;
var root = simplifiedDoc.GetSyntaxRootAsync().Result;
root = Formatter.Format(root, Formatter.Annotation, simplifiedDoc.Project.Solution.Workspace);
return root.GetText().ToString();
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis;
namespace TestTemplate
{
/// <summary>
/// Location where the diagnostic appears, as determined by path, line number, and column number.
/// </summary>
public struct DiagnosticResultLocation
{
public DiagnosticResultLocation(string path, int line, int column)
{
if (line < 0 && column < 0)
{
throw new ArgumentOutOfRangeException("At least one of line and column must be > 0");
}
if (line < -1 || column < -1)
{
throw new ArgumentOutOfRangeException("Both line and column must be >= -1");
}
this.Path = path;
this.Line = line;
this.Column = column;
}
public string Path;
public int Line;
public int Column;
}
/// <summary>
/// Struct that stores information about a Diagnostic appearing in a source
/// </summary>
public struct DiagnosticResult
{
private DiagnosticResultLocation[] locations;
public DiagnosticResultLocation[] Locations
{
get
{
if (this.locations == null)
{
this.locations = Array.Empty<DiagnosticResultLocation>();
}
return this.locations;
}
set
{
this.locations = value;
}
}
public DiagnosticSeverity Severity { get; set; }
public string Id { get; set; }
public string Message { get; set; }
public string Path
{
get
{
return this.Locations.Length > 0 ? this.Locations[0].Path : "";
}
}
public int Line
{
get
{
return this.Locations.Length > 0 ? this.Locations[0].Line : -1;
}
}
public int Column
{
get
{
return this.Locations.Length > 0 ? this.Locations[0].Column : -1;
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
using CSharp = Microsoft.CodeAnalysis.CSharp;
using VisualBasic = Microsoft.CodeAnalysis.VisualBasic;
namespace TestTemplate
{
/// <summary>
/// Class for turning strings into documents and getting the diagnostics on them
/// All methods are static
/// </summary>
public abstract partial class DiagnosticVerifier
{
private static readonly MetadataReference CorlibReference = MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
private static readonly MetadataReference SystemCoreReference = MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location);
private static readonly MetadataReference CSharpSymbolsReference = MetadataReference.CreateFromFile(typeof(CSharpCompilation).Assembly.Location);
private static readonly MetadataReference CodeAnalysisReference = MetadataReference.CreateFromFile(typeof(Compilation).Assembly.Location);
internal static string DefaultFilePathPrefix = "Test";
internal static string CSharpDefaultFileExt = "cs";
internal static string VisualBasicDefaultExt = "vb";
internal static string CSharpDefaultFilePath = DefaultFilePathPrefix + 0 + "." + CSharpDefaultFileExt;
internal static string VisualBasicDefaultFilePath = DefaultFilePathPrefix + 0 + "." + VisualBasicDefaultExt;
internal static string TestProjectName = "TestProject";
#region Get Diagnostics
/// <summary>
/// Given classes in the form of strings, their language, and an IDiagnosticAnlayzer to apply to it, return the diagnostics found in the string after converting it to a document.
/// </summary>
/// <param name="sources">Classes in the form of strings</param>
/// <param name="language">The language the source classes are in</param>
/// <param name="analyzer">The analyzer to be run on the sources</param>
/// <returns>An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location</returns>
private static Diagnostic[] GetSortedDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer)
{
return GetSortedDiagnosticsFromDocuments(analyzer, GetDocuments(sources, language));
}
/// <summary>
/// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it.
/// The returned diagnostics are then ordered by location in the source document.
/// </summary>
/// <param name="analyzer">The analyzer to run on the documents</param>
/// <param name="documents">The Documents that the analyzer will be run on</param>
/// <returns>An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location</returns>
protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(DiagnosticAnalyzer analyzer, Document[] documents)
{
var projects = new HashSet<Project>();
foreach (var document in documents)
{
projects.Add(document.Project);
}
var diagnostics = new List<Diagnostic>();
foreach (var project in projects)
{
var compilationWithAnalyzers = project.GetCompilationAsync().GetAwaiter().GetResult().WithAnalyzers(ImmutableArray.Create(analyzer));
var diags = compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().GetAwaiter().GetResult();
foreach (var diag in diags)
{
if (diag.Location == Location.None || diag.Location.IsInMetadata)
{
diagnostics.Add(diag);
}
else
{
for (int i = 0; i < documents.Length; i++)
{
var document = documents[i];
var tree = document.GetSyntaxTreeAsync().GetAwaiter().GetResult();
if (tree == diag.Location.SourceTree)
{
diagnostics.Add(diag);
}
}
}
}
}
var results = SortDiagnostics(diagnostics);
diagnostics.Clear();
return results;
}
/// <summary>
/// Sort diagnostics by location in source document
/// </summary>
/// <param name="diagnostics">The list of Diagnostics to be sorted</param>
/// <returns>An IEnumerable containing the Diagnostics in order of Location</returns>
private static Diagnostic[] SortDiagnostics(IEnumerable<Diagnostic> diagnostics)
{
return diagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray();
}
#endregion
#region Set up compilation and documents
/// <summary>
/// Given an array of strings as sources and a language, turn them into a project and return the documents and spans of it.
/// </summary>
/// <param name="sources">Classes in the form of strings</param>
/// <param name="language">The language the source code is in</param>
/// <returns>An array of Documents produced from the source strings</returns>
private static Document[] GetDocuments(string[] sources, string language)
{
if (language != LanguageNames.CSharp && language != LanguageNames.VisualBasic)
{
throw new ArgumentException("Unsupported Language");
}
for (int i = 0; i < sources.Length; i++)
{
string fileName = language == LanguageNames.CSharp ? "Test" + i + ".cs" : "Test" + i + ".vb";
}
var project = CreateProject(sources, language);
var documents = project.Documents.ToArray();
if (sources.Length != documents.Length)
{
throw new SystemException("Amount of sources did not match amount of Documents created");
}
return documents;
}
/// <summary>
/// Create a Document from a string through creating a project that contains it.
/// </summary>
/// <param name="source">Classes in the form of a string</param>
/// <param name="language">The language the source code is in</param>
/// <returns>A Document created from the source string</returns>
protected static Document CreateDocument(string source, string language = LanguageNames.CSharp)
{
return CreateProject(new[] { source }, language).Documents.First();
}
/// <summary>
/// Create a project using the inputted strings as sources.
/// </summary>
/// <param name="sources">Classes in the form of strings</param>
/// <param name="language">The language the source code is in</param>
/// <returns>A Project created out of the Documents created from the source strings</returns>
private static Project CreateProject(string[] sources, string language = LanguageNames.CSharp)
{
string fileNamePrefix = DefaultFilePathPrefix;
string fileExt = language == LanguageNames.CSharp ? CSharpDefaultFileExt : VisualBasicDefaultExt;
var projectId = ProjectId.CreateNewId(debugName: TestProjectName);
var solution = new AdhocWorkspace()
.CurrentSolution
.AddProject(projectId, TestProjectName, TestProjectName, language)
.AddMetadataReference(projectId, CorlibReference)
.AddMetadataReference(projectId, SystemCoreReference)
.AddMetadataReference(projectId, CSharpSymbolsReference)
.AddMetadataReference(projectId, CodeAnalysisReference);
int count = 0;
foreach (var source in sources)
{
var newFileName = fileNamePrefix + count + "." + fileExt;
var documentId = DocumentId.CreateNewId(projectId, debugName: newFileName);
solution = solution.AddDocument(documentId, newFileName, SourceText.From(source));
count++;
}
return solution.GetProject(projectId);
}
#endregion
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace TestTemplate
{
/// <summary>
/// Superclass of all Unit tests made for diagnostics with codefixes.
/// Contains methods used to verify correctness of codefixes
/// </summary>
public abstract partial class CodeFixVerifier : DiagnosticVerifier
{
/// <summary>
/// Returns the codefix being tested (C#) - to be implemented in non-abstract class
/// </summary>
/// <returns>The CodeFixProvider to be used for CSharp code</returns>
protected virtual CodeFixProvider GetCSharpCodeFixProvider()
{
return null;
}
/// <summary>
/// Returns the codefix being tested (VB) - to be implemented in non-abstract class
/// </summary>
/// <returns>The CodeFixProvider to be used for VisualBasic code</returns>
protected virtual CodeFixProvider GetBasicCodeFixProvider()
{
return null;
}
/// <summary>
/// Called to test a C# codefix when applied on the inputted string as a source
/// </summary>
/// <param name="oldSource">A class in the form of a string before the CodeFix was applied to it</param>
/// <param name="newSource">A class in the form of a string after the CodeFix was applied to it</param>
/// <param name="codeFixIndex">Index determining which codefix to apply if there are multiple</param>
/// <param name="allowNewCompilerDiagnostics">A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied</param>
protected void VerifyCSharpFix(string oldSource, string newSource, int? codeFixIndex = null, bool allowNewCompilerDiagnostics = false)
{
VerifyFix(LanguageNames.CSharp, GetCSharpDiagnosticAnalyzer(), GetCSharpCodeFixProvider(), oldSource, newSource, codeFixIndex, allowNewCompilerDiagnostics);
}
/// <summary>
/// Called to test a VB codefix when applied on the inputted string as a source
/// </summary>
/// <param name="oldSource">A class in the form of a string before the CodeFix was applied to it</param>
/// <param name="newSource">A class in the form of a string after the CodeFix was applied to it</param>
/// <param name="codeFixIndex">Index determining which codefix to apply if there are multiple in the same location</param>
/// <param name="allowNewCompilerDiagnostics">A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied</param>
protected void VerifyBasicFix(string oldSource, string newSource, int? codeFixIndex = null, bool allowNewCompilerDiagnostics = false)
{
VerifyFix(LanguageNames.VisualBasic, GetBasicDiagnosticAnalyzer(), GetBasicCodeFixProvider(), oldSource, newSource, codeFixIndex, allowNewCompilerDiagnostics);
}
/// <summary>
/// General verifier for codefixes.
/// Creates a Document from the source string, then gets diagnostics on it and applies the relevant codefixes.
/// Then gets the string after the codefix is applied and compares it with the expected result.
/// Note: If any codefix causes new diagnostics to show up, the test fails unless allowNewCompilerDiagnostics is set to true.
/// </summary>
/// <param name="language">The language the source code is in</param>
/// <param name="analyzer">The analyzer to be applied to the source code</param>
/// <param name="codeFixProvider">The codefix to be applied to the code wherever the relevant Diagnostic is found</param>
/// <param name="oldSource">A class in the form of a string before the CodeFix was applied to it</param>
/// <param name="newSource">A class in the form of a string after the CodeFix was applied to it</param>
/// <param name="codeFixIndex">Index determining which codefix to apply if there are multiple in the same location</param>
/// <param name="allowNewCompilerDiagnostics">A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied</param>
private void VerifyFix(string language, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string oldSource, string newSource, int? codeFixIndex, bool allowNewCompilerDiagnostics)
{
var document = CreateDocument(oldSource, language);
var analyzerDiagnostics = GetSortedDiagnosticsFromDocuments(analyzer, new[] { document });
var compilerDiagnostics = GetCompilerDiagnostics(document);
var attempts = analyzerDiagnostics.Length;
for (int i = 0; i < attempts; ++i)
{
var actions = new List<CodeAction>();
var context = new CodeFixContext(document, analyzerDiagnostics[0], (a, d) => actions.Add(a), CancellationToken.None);
codeFixProvider.RegisterCodeFixesAsync(context).Wait();
if (!actions.Any())
{
break;
}
if (codeFixIndex != null)
{
document = ApplyFix(document, actions.ElementAt((int)codeFixIndex));
break;
}
document = ApplyFix(document, actions.ElementAt(0));
analyzerDiagnostics = GetSortedDiagnosticsFromDocuments(analyzer, new[] { document });
var newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, GetCompilerDiagnostics(document));
// Check if applying the code fix introduced any new compiler diagnostics
if (!allowNewCompilerDiagnostics && newCompilerDiagnostics.Any())
{
// Format and get the compiler diagnostics again so that the locations make sense in the output
document = document.WithSyntaxRoot(Formatter.Format(document.GetSyntaxRootAsync().Result, Formatter.Annotation, document.Project.Solution.Workspace));
newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, GetCompilerDiagnostics(document));
Assert.IsTrue(false,
string.Format("Fix introduced new compiler diagnostics:\r\n{0}\r\n\r\nNew document:\r\n{1}\r\n",
string.Join("\r\n", newCompilerDiagnostics.Select(d => d.ToString())),
document.GetSyntaxRootAsync().Result.ToFullString()));
}
// Check if there are analyzer diagnostics left after the code fix
if (!analyzerDiagnostics.Any())
{
break;
}
}
// After applying all of the code fixes, compare the resulting string to the inputted one
var actual = GetStringFromDocument(document);
Assert.AreEqual(newSource, actual);
}
}
}
// 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.Runtime.InteropServices;
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("d945baa9-7483-4aae-9553-6d6efabeacb0")]
<?xml version="1.0" encoding="utf-8"?>
<packages>
</packages>
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Composition" version="1.0.27" targetFramework="net45" />
<package id="NuGet.CommandLine" version="2.8.5" targetFramework="net45" />
</packages>
param($installPath, $toolsPath, $package, $project)
$p = Get-Project
$analyzerPath = join-path $toolsPath "analyzers"
$analyzerFilePath = join-path $analyzerPath "AsyncPackage.dll"
$p.Object.AnalyzerReferences.Add("$analyzerFilePath")
\ No newline at end of file
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册