diff --git a/Compilers.sln b/Compilers.sln index 07d8da2518545..e14ec5a431f96 100644 --- a/Compilers.sln +++ b/Compilers.sln @@ -69,8 +69,6 @@ Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "VisualBasicErrorFactsGenera EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "AnalyzerDriver", "src\Compilers\Core\AnalyzerDriver\AnalyzerDriver.shproj", "{D0BC9BE7-24F6-40CA-8DC6-FCB93BD44B34}" EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SharedCollections", "src\Compilers\Core\SharedCollections\SharedCollections.shproj", "{C1930979-C824-496B-A630-70F5369A636F}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpWinRTTest", "src\Compilers\CSharp\Test\WinRT\CSharpWinRTTest.csproj", "{FCFA8808-A1B6-48CC-A1EA-0B8CA8AEDA8E}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "vbc", "src\Compilers\VisualBasic\vbc\vbc.csproj", "{E58EE9D7-1239-4961-A0C1-F9EC3952C4C1}" @@ -142,7 +140,6 @@ Global src\Dependencies\CodeAnalysis.Metadata\Microsoft.CodeAnalysis.Metadata.projitems*{afde6bea-5038-4a4a-a88e-dbd2e4088eed}*SharedItemsImports = 4 src\Dependencies\PooledObjects\Microsoft.CodeAnalysis.PooledObjects.projitems*{afde6bea-5038-4a4a-a88e-dbd2e4088eed}*SharedItemsImports = 4 src\Compilers\CSharp\CSharpAnalyzerDriver\CSharpAnalyzerDriver.projitems*{b501a547-c911-4a05-ac6e-274a50dff30e}*SharedItemsImports = 4 - src\Compilers\Core\SharedCollections\SharedCollections.projitems*{c1930979-c824-496b-a630-70f5369a636f}*SharedItemsImports = 13 src\Test\Utilities\Shared\TestUtilities.projitems*{ccbd3438-3e84-40a9-83ad-533f23bcfca5}*SharedItemsImports = 4 src\Dependencies\PooledObjects\Microsoft.CodeAnalysis.PooledObjects.projitems*{cd77a8cc-2885-47a7-b99c-fbf13353400b}*SharedItemsImports = 13 src\Compilers\Core\AnalyzerDriver\AnalyzerDriver.projitems*{d0bc9be7-24f6-40ca-8dc6-fcb93bd44b34}*SharedItemsImports = 13 @@ -1052,7 +1049,6 @@ Global {6AA96934-D6B7-4CC8-990D-DB6B9DD56E34} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC} {909B656F-6095-4AC2-A5AB-C3F032315C45} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC} {D0BC9BE7-24F6-40CA-8DC6-FCB93BD44B34} = {A41D1B99-F489-4C43-BBDF-96D61B19A6B9} - {C1930979-C824-496B-A630-70F5369A636F} = {A41D1B99-F489-4C43-BBDF-96D61B19A6B9} {FCFA8808-A1B6-48CC-A1EA-0B8CA8AEDA8E} = {32A48625-F0AD-419D-828B-A50BDABA38EA} {E58EE9D7-1239-4961-A0C1-F9EC3952C4C1} = {C65C6143-BED3-46E6-869E-9F0BE6E84C37} {E3CD2895-76A8-4D11-A316-EA67CB5EA42C} = {32A48625-F0AD-419D-828B-A50BDABA38EA} diff --git a/build/Targets/Dependencies.props b/build/Targets/Dependencies.props index d77e580f8e396..2687bdedb8af5 100644 --- a/build/Targets/Dependencies.props +++ b/build/Targets/Dependencies.props @@ -35,7 +35,7 @@ 4.1.0 4.1.0 4.0.1 - 1.4.1-beta-24322-03 + 1.4.1-beta-24410-02 4.0.1 4.1.0 4.0.1 diff --git a/build/Targets/VSL.Imports.targets b/build/Targets/VSL.Imports.targets index 0610b862e08f9..941dbc951ea93 100644 --- a/build/Targets/VSL.Imports.targets +++ b/build/Targets/VSL.Imports.targets @@ -58,35 +58,18 @@ - - - true - - + - + - - - - - true - - - - - true - - - - $(VSLToolsPath)\Strong Name Keys\35MSSharedLib1024.snk $(RoslynPublicKey) 31BF3856AD364E35 + true @@ -207,7 +190,7 @@ $(RoslynAssemblyVersionBase) - - - true - Cannot sign an unofficial build. - - $(BUILD_BUILDNUMBER) - A build number must be specified for a signed build. + A build number must be specified for a signed build. @@ -48,7 +42,7 @@ - + $(RoslynAssemblyVersionBase).0 $(RoslynFileVersionBase).$(BuildNumberFiveDigitDateStamp) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs index 3077e20b340b3..8875b1bf3239e 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs @@ -648,7 +648,7 @@ private UnboundLambda MakeQueryUnboundLambda(RangeVariableMap qvm, ImmutableArra { return MakeQueryUnboundLambda(expression, new QueryUnboundLambdaState(this, qvm, parameters, (LambdaSymbol lambdaSymbol, Binder lambdaBodyBinder, DiagnosticBag diagnostics) => { - return lambdaBodyBinder.BindLambdaExpressionAsBlock(RefKind.None, expression, diagnostics); + return lambdaBodyBinder.BindLambdaExpressionAsBlock(expression, diagnostics); })); } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index 28775e3dbefc9..84bd721321623 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -3661,13 +3661,15 @@ internal BoundBlock BindExpressionBodyAsBlock(ArrowExpressionClauseSyntax expres /// /// Binds a lambda with expression e as either { return e;} or { e; }. /// - public BoundBlock BindLambdaExpressionAsBlock(RefKind refKind, ExpressionSyntax body, DiagnosticBag diagnostics) + public BoundBlock BindLambdaExpressionAsBlock(ExpressionSyntax body, DiagnosticBag diagnostics) { - Binder bodyBinder = this.GetBinder(refKind != RefKind.None ? body.Parent : body); + Binder bodyBinder = this.GetBinder(body); Debug.Assert(bodyBinder != null); - BoundExpression expression = bodyBinder.BindValue(body, diagnostics, refKind != RefKind.None ? BindValueKind.RefReturn : BindValueKind.RValue); - return bodyBinder.CreateBlockFromExpression(body, bodyBinder.GetDeclaredLocalsForScope(body), refKind, expression, body, diagnostics); + RefKind refKind; + var expressionSyntax = ((ExpressionSyntax)body).SkipRef(out refKind); + BoundExpression expression = bodyBinder.BindValue(expressionSyntax, diagnostics, refKind != RefKind.None ? BindValueKind.RefReturn : BindValueKind.RValue); + return bodyBinder.CreateBlockFromExpression(body, bodyBinder.GetDeclaredLocalsForScope(body), refKind, expression, expressionSyntax, diagnostics); } internal virtual ImmutableArray Locals diff --git a/src/Compilers/CSharp/Portable/Binder/ExpressionVariableBinder.cs b/src/Compilers/CSharp/Portable/Binder/ExpressionVariableBinder.cs index 2b5e08a5bf77c..d2761466c6608 100644 --- a/src/Compilers/CSharp/Portable/Binder/ExpressionVariableBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/ExpressionVariableBinder.cs @@ -27,8 +27,7 @@ protected override ImmutableArray BuildLocals() internal override ImmutableArray GetDeclaredLocalsForScope(CSharpSyntaxNode scopeDesignator) { - if (ScopeDesignator == scopeDesignator || - ScopeDesignator.Kind() == SyntaxKind.RefExpression && ScopeDesignator == scopeDesignator.Parent) + if (ScopeDesignator == scopeDesignator) { return this.Locals; } diff --git a/src/Compilers/CSharp/Portable/Binder/SwitchBinder_BindPatternSwitch.cs b/src/Compilers/CSharp/Portable/Binder/SwitchBinder_BindPatternSwitch.cs index c3b758769fac1..0d595ed65b37f 100644 --- a/src/Compilers/CSharp/Portable/Binder/SwitchBinder_BindPatternSwitch.cs +++ b/src/Compilers/CSharp/Portable/Binder/SwitchBinder_BindPatternSwitch.cs @@ -127,7 +127,10 @@ private BoundPatternSwitchLabel BindPatternSwitchSectionLabel( node, boundSwitchExpression, boundSwitchExpression.Type, caseLabelSyntax.Value, node.HasErrors, diagnostics, out wasExpression, wasSwitchCase: true); bool hasErrors = pattern.HasErrors; var constantValue = pattern.ConstantValue; - if (!hasErrors && (object)constantValue != null && this.FindMatchingSwitchCaseLabel(constantValue, caseLabelSyntax) != label) + if (!hasErrors && + (object)constantValue != null && + pattern.Value.Type == SwitchGoverningType && + this.FindMatchingSwitchCaseLabel(constantValue, caseLabelSyntax) != label) { diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, pattern.ConstantValue.GetValueToDisplay() ?? label.Name); hasErrors = true; @@ -142,7 +145,7 @@ private BoundPatternSwitchLabel BindPatternSwitchSectionLabel( bool hasErrors = pattern.HasErrors; if (defaultLabel != null) { - diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, "default"); + diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, label.Name); hasErrors = true; } diff --git a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs index 7191c404d3412..e2e50b13b418e 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs @@ -890,9 +890,7 @@ protected override BoundBlock BindLambdaBody(LambdaSymbol lambdaSymbol, Binder l { if (this.IsExpressionLambda) { - var refKind = CodeAnalysis.RefKind.None; - var body = ((ExpressionSyntax)this.Body).SkipRef(out refKind); - return lambdaBodyBinder.BindLambdaExpressionAsBlock(refKind, body, diagnostics); + return lambdaBodyBinder.BindLambdaExpressionAsBlock((ExpressionSyntax)this.Body, diagnostics); } else { diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index 82778fb86b0cf..2f3222e9dc310 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -6127,24 +6127,6 @@ internal static string ERR_MultiTypeInDeclaration { } } - /// - /// Looks up a localized string similar to '{0}' cannot be assigned a reference because it is not a by-reference local. - /// - internal static string ERR_MustBeRefAssignable { - get { - return ResourceManager.GetString("ERR_MustBeRefAssignable", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Expected a by-reference local. - /// - internal static string ERR_MustBeRefAssignableLocal { - get { - return ResourceManager.GetString("ERR_MustBeRefAssignableLocal", resourceCulture); - } - } - /// /// Looks up a localized string similar to In order for '{0}' to be applicable as a short circuit operator, its declaring type '{1}' must define operator true and operator false. /// diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index c888bca760b96..c1938bd9be965 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -4806,12 +4806,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Struct members cannot return 'this' or other instance members by reference - - '{0}' cannot be assigned a reference because it is not a by-reference local - - - Expected a by-reference local - Cannot initialize a by-value variable with a reference diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index e060e17920eb8..00ed27157ec75 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1391,44 +1391,35 @@ internal enum ErrorCode ERR_MustHaveRefReturn = 8150, ERR_RefReturnMustHaveIdentityConversion = 8151, ERR_CloseUnimplementedInterfaceMemberWrongRefReturn = 8152, - ERR_VoidReturningMethodCannotReturnByRef = 8153, + ERR_RefReturningCallInExpressionTree = 8153, ERR_BadIteratorReturnRef = 8154, ERR_BadRefReturnExpressionTree = 8155, - ERR_RefReturningCallInExpressionTree = 8156, - - ERR_RefReturnLvalueExpected = 8157, - ERR_RefReturnNonreturnableLocal = 8158, - ERR_RefReturnNonreturnableLocal2 = 8159, - ERR_RefReturnRangeVariable = 8160, - ERR_RefReturnRangeVariable2 = 8170, - ERR_RefReturnReadonly = 8171, - ERR_RefReturnReadonlyStatic = 8172, - ERR_RefReturnReadonly2 = 8173, - ERR_RefReturnReadonlyStatic2 = 8174, - ERR_RefReturnCall = 8175, - ERR_RefReturnCall2 = 8176, - ERR_RefReturnParameter = 8177, - ERR_RefReturnParameter2 = 8178, - ERR_RefReturnLocal = 8179, - ERR_RefReturnLocal2 = 8180, - ERR_RefReturnStructThis = 8181, - - // Available = 8182, 8183 - - ERR_MustBeRefAssignable = 8184, - ERR_MustBeRefAssignableLocal = 8185, - ERR_InitializeByValueVariableWithReference = 8186, - ERR_InitializeByReferenceVariableWithValue = 8187, - ERR_RefAssignmentMustHaveIdentityConversion = 8188, - ERR_ByReferenceVariableMustBeInitialized = 8189, - - ERR_AnonDelegateCantUseLocal = 8190, - ERR_BadIteratorLocalType = 8191, - ERR_BadAsyncLocalType = 8192, - ERR_RefReturningCallAndAwait = 8193, + ERR_RefReturnLvalueExpected = 8156, + ERR_RefReturnNonreturnableLocal = 8157, + ERR_RefReturnNonreturnableLocal2 = 8158, + ERR_RefReturnRangeVariable = 8159, + ERR_RefReturnReadonly = 8160, + ERR_RefReturnReadonlyStatic = 8161, + ERR_RefReturnReadonly2 = 8162, + ERR_RefReturnReadonlyStatic2 = 8163, + ERR_RefReturnCall = 8164, + ERR_RefReturnCall2 = 8165, + ERR_RefReturnParameter = 8166, + ERR_RefReturnParameter2 = 8167, + ERR_RefReturnLocal = 8168, + ERR_RefReturnLocal2 = 8169, + ERR_RefReturnStructThis = 8170, + ERR_InitializeByValueVariableWithReference = 8171, + ERR_InitializeByReferenceVariableWithValue = 8172, + ERR_RefAssignmentMustHaveIdentityConversion = 8173, + ERR_ByReferenceVariableMustBeInitialized = 8174, + ERR_AnonDelegateCantUseLocal = 8175, + ERR_BadIteratorLocalType = 8176, + ERR_BadAsyncLocalType = 8177, + ERR_RefReturningCallAndAwait = 8178, #endregion diagnostics for ref locals and ref returns introduced in C# 7 - // Available = 8194, 8195 + // Available = 8179-8195 #region diagnostics for out var ERR_ImplicitlyTypedOutVariableUsedInTheSameArgumentList = 8196, diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs index 9ffba0b17a3dd..f9a6e656e1180 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs @@ -121,6 +121,17 @@ public static SourceLocalSymbol MakeLocal( return new LocalWithInitializer(containingSymbol, binder, typeSyntax, identifierToken, initializer, declarationKind); } + /// + /// + /// Binder that owns the scope for the local, the one that returns it in its array. + /// + /// + /// Enclosing binder for the location where the local is declared, if different from the . + /// It should be used to bind something at that location. + /// + /// + /// + /// public static SourceLocalSymbol MakeOutVariable( Symbol containingSymbol, Binder scopeBinder, @@ -129,7 +140,12 @@ public static SourceLocalSymbol MakeOutVariable( SyntaxToken identifierToken, CSharpSyntaxNode context) { - return new OutLocalSymbol(containingSymbol, scopeBinder, enclosingBinderOpt, typeSyntax, identifierToken, context); + if (typeSyntax.IsVar) + { + return new PossiblyImplicitlyTypedOutVarLocalSymbol(containingSymbol, scopeBinder, enclosingBinderOpt, typeSyntax, identifierToken, context); + } + + return new SourceLocalSymbol(containingSymbol, scopeBinder, false, typeSyntax, identifierToken, LocalDeclarationKind.RegularVariable); } internal override bool IsImportedFromMetadata @@ -581,14 +597,15 @@ protected override TypeSymbol InferTypeOfVarVariable(DiagnosticBag diagnostics) } /// - /// Symbol for an out variable local. + /// Symbol for an out variable local that might require type inference during overload resolution, i.e. + /// its type is syntactically 'var'. /// - private class OutLocalSymbol : SourceLocalSymbol + private class PossiblyImplicitlyTypedOutVarLocalSymbol : SourceLocalSymbol { private readonly CSharpSyntaxNode _containingInvocation; private readonly Binder _enclosingBinderOpt; - public OutLocalSymbol( + public PossiblyImplicitlyTypedOutVarLocalSymbol( Symbol containingSymbol, Binder scopeBinder, Binder enclosingBinderOpt, diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index bce6baa227300..55b636f7448ed 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -1354,6 +1354,7 @@ private static bool NormalizeTaskTypesInType(CSharpCompilation compilation, ref switch (type.Kind) { case SymbolKind.NamedType: + case SymbolKind.ErrorType: { var namedType = (NamedTypeSymbol)type; var changed = type.IsTupleType ? @@ -1369,6 +1370,13 @@ private static bool NormalizeTaskTypesInType(CSharpCompilation compilation, ref type = arrayType; return changed; } + case SymbolKind.PointerType: + { + var pointerType = (PointerTypeSymbol)type; + var changed = NormalizeTaskTypesInPointer(compilation, ref pointerType); + type = pointerType; + return changed; + } } return false; } @@ -1456,6 +1464,18 @@ private static bool NormalizeTaskTypesInArray(CSharpCompilation compilation, ref return true; } + private static bool NormalizeTaskTypesInPointer(CSharpCompilation compilation, ref PointerTypeSymbol pointerType) + { + var pointedAtType = pointerType.PointedAtType; + if (!NormalizeTaskTypesInType(compilation, ref pointedAtType)) + { + return false; + } + // Preserve custom modifiers but without normalizing those types. + pointerType = new PointerTypeSymbol(pointedAtType, pointerType.CustomModifiers); + return true; + } + internal static Cci.TypeReferenceWithAttributes GetTypeRefWithAttributes( this TypeSymbol type, CSharpCompilation declaringCompilation, diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs index bee22b376341d..8c01cc9c6ef9f 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs @@ -1272,13 +1272,12 @@ class Derived : Base "; CreateCompilationWithMscorlib45(text).VerifyDiagnostics( - // (13,29): error CS8893: 'Derived.Method1()' must not return by reference to match overridden member 'Base.Method1()' - // public override ref int Method1() { return ref field; } - Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Method1").WithArguments("Derived.Method1()", "Base.Method1()", "not ").WithLocation(13, 29), - // (14,25): error CS8893: 'Derived.Method2(ref int)' must return by reference to match overridden member 'Base.Method2(ref int)' - // public override int Method2(ref int i) { return i; } - Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Method2").WithArguments("Derived.Method2(ref int)", "Base.Method2(ref int)", "").WithLocation(14, 25) - ); + // (13,29): error CS8148: 'Derived.Method1()' must not return by reference to match overridden member 'Base.Method1()' + // public override ref int Method1() { return ref field; } + Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Method1").WithArguments("Derived.Method1()", "Base.Method1()", "not ").WithLocation(13, 29), + // (14,25): error CS8148: 'Derived.Method2(ref int)' must return by reference to match overridden member 'Base.Method2(ref int)' + // public override int Method2(ref int i) { return i; } + Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Method2").WithArguments("Derived.Method2(ref int)", "Base.Method2(ref int)", "").WithLocation(14, 25)); } [Fact] @@ -1418,13 +1417,12 @@ class Derived : Base } "; CreateCompilationWithMscorlib45(text).VerifyDiagnostics( - // (15,29): error CS8893: 'Derived.Proprty1' must not return by reference to match overridden member 'Base.Proprty1' - // public override ref int Proprty1 { get { return ref field; } } - Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Proprty1").WithArguments("Derived.Proprty1", "Base.Proprty1", "not ").WithLocation(15, 29), - // (16,25): error CS8893: 'Derived.Property2' must return by reference to match overridden member 'Base.Property2' - // public override int Property2 { get { return 0; } } - Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Property2").WithArguments("Derived.Property2", "Base.Property2", "").WithLocation(16, 25) - ); + // (15,29): error CS8148: 'Derived.Proprty1' must not return by reference to match overridden member 'Base.Proprty1' + // public override ref int Proprty1 { get { return ref field; } } + Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Proprty1").WithArguments("Derived.Proprty1", "Base.Proprty1", "not ").WithLocation(15, 29), + // (16,25): error CS8148: 'Derived.Property2' must return by reference to match overridden member 'Base.Property2' + // public override int Property2 { get { return 0; } } + Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Property2").WithArguments("Derived.Property2", "Base.Property2", "").WithLocation(16, 25)); } [Fact] @@ -1478,13 +1476,12 @@ class Derived : Base } "; CreateCompilationWithMscorlib45(text).VerifyDiagnostics( - // (15,29): error CS8893: 'Derived.this[int, int]' must not return by reference to match overridden member 'Base.this[int, int]' - // public override ref int this[int x, int y] { get { return ref field; } } - Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "this").WithArguments("Derived.this[int, int]", "Base.this[int, int]", "not ").WithLocation(15, 29), - // (16,25): error CS8893: 'Derived.this[int, string]' must return by reference to match overridden member 'Base.this[int, string]' - // public override int this[int x, string y] { get { return field; } } - Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "this").WithArguments("Derived.this[int, string]", "Base.this[int, string]", "").WithLocation(16, 25) - ); + // (15,29): error CS8148: 'Derived.this[int, int]' must not return by reference to match overridden member 'Base.this[int, int]' + // public override ref int this[int x, int y] { get { return ref field; } } + Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "this").WithArguments("Derived.this[int, int]", "Base.this[int, int]", "not ").WithLocation(15, 29), + // (16,25): error CS8148: 'Derived.this[int, string]' must return by reference to match overridden member 'Base.this[int, string]' + // public override int this[int x, string y] { get { return field; } } + Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "this").WithArguments("Derived.this[int, string]", "Base.this[int, string]", "").WithLocation(16, 25)); } /// @@ -2052,31 +2049,30 @@ class Derived : Base } "; CreateCompilationWithMscorlib45(text).VerifyDiagnostics( - // (16,16): warning CS0114: 'Derived.Method3()' hides inherited member 'Base.Method3()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. - // public int Method3() { return 0; } //wrong return type - Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "Method3").WithArguments("Derived.Method3()", "Base.Method3()").WithLocation(16, 16), - // (18,28): error CS8893: 'Derived.Method5(ref object)' must return by reference to match overridden member 'Base.Method5(ref object)' - // public override object Method5(ref object o) { return null; } //wrong by-value return - Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Method5").WithArguments("Derived.Method5(ref object)", "Base.Method5(ref object)", "").WithLocation(18, 28), - // (19,32): error CS8893: 'Derived.Method6(ref object)' must not return by reference to match overridden member 'Base.Method6(ref object)' - // public override ref object Method6(ref object o) { return ref o; } //wrong by-ref return - Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Method6").WithArguments("Derived.Method6(ref object)", "Base.Method6(ref object)", "not ").WithLocation(19, 32), - // (15,19): warning CS0114: 'Derived.Method2()' hides inherited member 'Base.Method2()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. - // public object Method2() { return null; } //missed override keyword - Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "Method2").WithArguments("Derived.Method2()", "Base.Method2()").WithLocation(15, 19), - // (12,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Method2()' - // class Derived : Base - Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Method2()").WithLocation(12, 7), - // (12,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Method4(int)' - // class Derived : Base - Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Method4(int)").WithLocation(12, 7), - // (12,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Method3()' - // class Derived : Base - Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Method3()").WithLocation(12, 7), - // (12,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Method1()' - // class Derived : Base - Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Method1()").WithLocation(12, 7) - ); + // (16,16): warning CS0114: 'Derived.Method3()' hides inherited member 'Base.Method3()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. + // public int Method3() { return 0; } //wrong return type + Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "Method3").WithArguments("Derived.Method3()", "Base.Method3()").WithLocation(16, 16), + // (18,28): error CS8148: 'Derived.Method5(ref object)' must return by reference to match overridden member 'Base.Method5(ref object)' + // public override object Method5(ref object o) { return null; } //wrong by-value return + Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Method5").WithArguments("Derived.Method5(ref object)", "Base.Method5(ref object)", "").WithLocation(18, 28), + // (19,32): error CS8148: 'Derived.Method6(ref object)' must not return by reference to match overridden member 'Base.Method6(ref object)' + // public override ref object Method6(ref object o) { return ref o; } //wrong by-ref return + Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Method6").WithArguments("Derived.Method6(ref object)", "Base.Method6(ref object)", "not ").WithLocation(19, 32), + // (15,19): warning CS0114: 'Derived.Method2()' hides inherited member 'Base.Method2()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. + // public object Method2() { return null; } //missed override keyword + Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "Method2").WithArguments("Derived.Method2()", "Base.Method2()").WithLocation(15, 19), + // (12,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Method3()' + // class Derived : Base + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Method3()").WithLocation(12, 7), + // (12,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Method2()' + // class Derived : Base + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Method2()").WithLocation(12, 7), + // (12,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Method1()' + // class Derived : Base + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Method1()").WithLocation(12, 7), + // (12,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Method4(int)' + // class Derived : Base + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Method4(int)").WithLocation(12, 7)); } [Fact] @@ -2121,67 +2117,66 @@ public override object Property7 { set { } } } "; CreateCompilationWithMscorlib45(text).VerifyDiagnostics( - // (23,25): error CS1715: 'Derived.Property3': type must be 'object' to match overridden member 'Base.Property3' - // public override int Property3 { get; set; } //wrong type - Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "Property3").WithArguments("Derived.Property3", "Base.Property3", "object").WithLocation(23, 25), - // (28,45): error CS0546: 'Derived.Property6.set': cannot override because 'Base.Property6' does not have an overridable set accessor - // public override object Property6 { get; set; } - Diagnostic(ErrorCode.ERR_NoSetToOverride, "set").WithArguments("Derived.Property6.set", "Base.Property6").WithLocation(28, 45), - // (29,40): error CS0546: 'Derived.Property7.set': cannot override because 'Base.Property7' does not have an overridable set accessor - // public override object Property7 { set { } } - Diagnostic(ErrorCode.ERR_NoSetToOverride, "set").WithArguments("Derived.Property7.set", "Base.Property7").WithLocation(29, 40), - // (30,40): error CS0545: 'Derived.Property8.get': cannot override because 'Base.Property8' does not have an overridable get accessor - // public override object Property8 { get; set; } - Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("Derived.Property8.get", "Base.Property8").WithLocation(30, 40), - // (31,40): error CS0545: 'Derived.Property9.get': cannot override because 'Base.Property9' does not have an overridable get accessor - // public override object Property9 { get { return null; } } - Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("Derived.Property9.get", "Base.Property9").WithLocation(31, 40), - // (35,32): error CS8893: 'Derived.Property10' must not return by reference to match overridden member 'Base.Property10' - // public override ref object Property10 { get { return ref o; } } - Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Property10").WithArguments("Derived.Property10", "Base.Property10", "not ").WithLocation(35, 32), - // (36,28): error CS8893: 'Derived.Property11' must return by reference to match overridden member 'Base.Property11' - // public override object Property11 { get { return null; } } - Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Property11").WithArguments("Derived.Property11", "Base.Property11", "").WithLocation(36, 28), - // (22,19): warning CS0114: 'Derived.Property2' hides inherited member 'Base.Property2'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. - // public object Property2 { get; set; } //missed override keyword - Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "Property2").WithArguments("Derived.Property2", "Base.Property2").WithLocation(22, 19), - // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property5.get' - // class Derived : Base - Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property5.get").WithLocation(19, 7), - // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property11.get' - // class Derived : Base - Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property11.get").WithLocation(19, 7), - // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property3.get' - // class Derived : Base - Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property3.get").WithLocation(19, 7), - // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property2.set' - // class Derived : Base - Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property2.set").WithLocation(19, 7), - // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property9.set' - // class Derived : Base - Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property9.set").WithLocation(19, 7), - // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property10.get' - // class Derived : Base - Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property10.get").WithLocation(19, 7), - // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property3.set' - // class Derived : Base - Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property3.set").WithLocation(19, 7), - // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property7.get' - // class Derived : Base - Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property7.get").WithLocation(19, 7), - // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property1.set' - // class Derived : Base - Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property1.set").WithLocation(19, 7), - // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property1.get' - // class Derived : Base - Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property1.get").WithLocation(19, 7), - // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property2.get' - // class Derived : Base - Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property2.get").WithLocation(19, 7), - // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property4.set' - // class Derived : Base - Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property4.set").WithLocation(19, 7) - ); + // (23,25): error CS1715: 'Derived.Property3': type must be 'object' to match overridden member 'Base.Property3' + // public override int Property3 { get; set; } //wrong type + Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "Property3").WithArguments("Derived.Property3", "Base.Property3", "object").WithLocation(23, 25), + // (28,45): error CS0546: 'Derived.Property6.set': cannot override because 'Base.Property6' does not have an overridable set accessor + // public override object Property6 { get; set; } + Diagnostic(ErrorCode.ERR_NoSetToOverride, "set").WithArguments("Derived.Property6.set", "Base.Property6").WithLocation(28, 45), + // (29,40): error CS0546: 'Derived.Property7.set': cannot override because 'Base.Property7' does not have an overridable set accessor + // public override object Property7 { set { } } + Diagnostic(ErrorCode.ERR_NoSetToOverride, "set").WithArguments("Derived.Property7.set", "Base.Property7").WithLocation(29, 40), + // (30,40): error CS0545: 'Derived.Property8.get': cannot override because 'Base.Property8' does not have an overridable get accessor + // public override object Property8 { get; set; } + Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("Derived.Property8.get", "Base.Property8").WithLocation(30, 40), + // (31,40): error CS0545: 'Derived.Property9.get': cannot override because 'Base.Property9' does not have an overridable get accessor + // public override object Property9 { get { return null; } } + Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("Derived.Property9.get", "Base.Property9").WithLocation(31, 40), + // (35,32): error CS8148: 'Derived.Property10' must not return by reference to match overridden member 'Base.Property10' + // public override ref object Property10 { get { return ref o; } } + Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Property10").WithArguments("Derived.Property10", "Base.Property10", "not ").WithLocation(35, 32), + // (36,28): error CS8148: 'Derived.Property11' must return by reference to match overridden member 'Base.Property11' + // public override object Property11 { get { return null; } } + Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Property11").WithArguments("Derived.Property11", "Base.Property11", "").WithLocation(36, 28), + // (22,19): warning CS0114: 'Derived.Property2' hides inherited member 'Base.Property2'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. + // public object Property2 { get; set; } //missed override keyword + Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "Property2").WithArguments("Derived.Property2", "Base.Property2").WithLocation(22, 19), + // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property1.get' + // class Derived : Base + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property1.get").WithLocation(19, 7), + // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property3.set' + // class Derived : Base + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property3.set").WithLocation(19, 7), + // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property2.get' + // class Derived : Base + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property2.get").WithLocation(19, 7), + // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property2.set' + // class Derived : Base + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property2.set").WithLocation(19, 7), + // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property3.get' + // class Derived : Base + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property3.get").WithLocation(19, 7), + // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property1.set' + // class Derived : Base + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property1.set").WithLocation(19, 7), + // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property11.get' + // class Derived : Base + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property11.get").WithLocation(19, 7), + // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property4.set' + // class Derived : Base + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property4.set").WithLocation(19, 7), + // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property9.set' + // class Derived : Base + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property9.set").WithLocation(19, 7), + // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property7.get' + // class Derived : Base + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property7.get").WithLocation(19, 7), + // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property5.get' + // class Derived : Base + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property5.get").WithLocation(19, 7), + // (19,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base.Property10.get' + // class Derived : Base + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.Property10.get").WithLocation(19, 7)); } [Fact] @@ -2490,19 +2485,18 @@ class Class : Interface } "; CreateCompilationWithMscorlib45(text).VerifyDiagnostics( - // (10,15): error CS8897: 'Class' does not implement interface member 'Interface.Method4(ref object)'. 'Class.Method4(ref object)' cannot implement 'Interface.Method4(ref object)' because it does not return by value - // class Class : Interface - Diagnostic(ErrorCode.ERR_CloseUnimplementedInterfaceMemberWrongRefReturn, "Interface").WithArguments("Class", "Interface.Method4(ref object)", "Class.Method4(ref object)", "value").WithLocation(10, 15), - // (10,15): error CS0535: 'Class' does not implement interface member 'Interface.Method2(int)' - // class Class : Interface - Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Class", "Interface.Method2(int)").WithLocation(10, 15), - // (10,15): error CS8897: 'Class' does not implement interface member 'Interface.Method3(ref object)'. 'Class.Method3(ref object)' cannot implement 'Interface.Method3(ref object)' because it does not return by reference - // class Class : Interface - Diagnostic(ErrorCode.ERR_CloseUnimplementedInterfaceMemberWrongRefReturn, "Interface").WithArguments("Class", "Interface.Method3(ref object)", "Class.Method3(ref object)", "reference").WithLocation(10, 15), - // (10,15): error CS0535: 'Class' does not implement interface member 'Interface.Method1()' - // class Class : Interface - Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Class", "Interface.Method1()").WithLocation(10, 15) - ); + // (10,15): error CS8152: 'Class' does not implement interface member 'Interface.Method4(ref object)'. 'Class.Method4(ref object)' cannot implement 'Interface.Method4(ref object)' because it does not return by value + // class Class : Interface + Diagnostic(ErrorCode.ERR_CloseUnimplementedInterfaceMemberWrongRefReturn, "Interface").WithArguments("Class", "Interface.Method4(ref object)", "Class.Method4(ref object)", "value").WithLocation(10, 15), + // (10,15): error CS0535: 'Class' does not implement interface member 'Interface.Method2(int)' + // class Class : Interface + Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Class", "Interface.Method2(int)").WithLocation(10, 15), + // (10,15): error CS8152: 'Class' does not implement interface member 'Interface.Method3(ref object)'. 'Class.Method3(ref object)' cannot implement 'Interface.Method3(ref object)' because it does not return by reference + // class Class : Interface + Diagnostic(ErrorCode.ERR_CloseUnimplementedInterfaceMemberWrongRefReturn, "Interface").WithArguments("Class", "Interface.Method3(ref object)", "Class.Method3(ref object)", "reference").WithLocation(10, 15), + // (10,15): error CS0535: 'Class' does not implement interface member 'Interface.Method1()' + // class Class : Interface + Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Class", "Interface.Method1()").WithLocation(10, 15)); } [Fact] @@ -2543,28 +2537,27 @@ public object Property5 { set { } } } "; CreateCompilationWithMscorlib45(text).VerifyDiagnostics( - // (17,15): error CS0535: 'Class' does not implement interface member 'Interface.Property2.set' - // class Class : Interface - Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Class", "Interface.Property2.set").WithLocation(17, 15), - // (17,15): error CS0535: 'Class' does not implement interface member 'Interface.Property3.get' - // class Class : Interface - Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Class", "Interface.Property3.get").WithLocation(17, 15), - // (17,15): error CS0535: 'Class' does not implement interface member 'Interface.Property5.get' - // class Class : Interface - Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Class", "Interface.Property5.get").WithLocation(17, 15), - // (17,15): error CS0535: 'Class' does not implement interface member 'Interface.Property7.set' - // class Class : Interface - Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Class", "Interface.Property7.set").WithLocation(17, 15), - // (17,15): error CS8897: 'Class' does not implement interface member 'Interface.Property8'. 'Class.Property8' cannot implement 'Interface.Property8' because it does not return by reference - // class Class : Interface - Diagnostic(ErrorCode.ERR_CloseUnimplementedInterfaceMemberWrongRefReturn, "Interface").WithArguments("Class", "Interface.Property8", "Class.Property8", "reference").WithLocation(17, 15), - // (17,15): error CS8897: 'Class' does not implement interface member 'Interface.Property9'. 'Class.Property9' cannot implement 'Interface.Property9' because it does not return by value - // class Class : Interface - Diagnostic(ErrorCode.ERR_CloseUnimplementedInterfaceMemberWrongRefReturn, "Interface").WithArguments("Class", "Interface.Property9", "Class.Property9", "value").WithLocation(17, 15), - // (17,15): error CS0535: 'Class' does not implement interface member 'Interface.Property1' - // class Class : Interface - Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Class", "Interface.Property1").WithLocation(17, 15) - ); + // (17,15): error CS0535: 'Class' does not implement interface member 'Interface.Property2.set' + // class Class : Interface + Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Class", "Interface.Property2.set").WithLocation(17, 15), + // (17,15): error CS0535: 'Class' does not implement interface member 'Interface.Property3.get' + // class Class : Interface + Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Class", "Interface.Property3.get").WithLocation(17, 15), + // (17,15): error CS0535: 'Class' does not implement interface member 'Interface.Property5.get' + // class Class : Interface + Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Class", "Interface.Property5.get").WithLocation(17, 15), + // (17,15): error CS0535: 'Class' does not implement interface member 'Interface.Property7.set' + // class Class : Interface + Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Class", "Interface.Property7.set").WithLocation(17, 15), + // (17,15): error CS8152: 'Class' does not implement interface member 'Interface.Property8'. 'Class.Property8' cannot implement 'Interface.Property8' because it does not return by reference + // class Class : Interface + Diagnostic(ErrorCode.ERR_CloseUnimplementedInterfaceMemberWrongRefReturn, "Interface").WithArguments("Class", "Interface.Property8", "Class.Property8", "reference").WithLocation(17, 15), + // (17,15): error CS8152: 'Class' does not implement interface member 'Interface.Property9'. 'Class.Property9' cannot implement 'Interface.Property9' because it does not return by value + // class Class : Interface + Diagnostic(ErrorCode.ERR_CloseUnimplementedInterfaceMemberWrongRefReturn, "Interface").WithArguments("Class", "Interface.Property9", "Class.Property9", "value").WithLocation(17, 15), + // (17,15): error CS0535: 'Class' does not implement interface member 'Interface.Property1' + // class Class : Interface + Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Class", "Interface.Property1").WithLocation(17, 15)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index 7b4888107633d..42ae4b004c174 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -1193,13 +1193,13 @@ static void M() "; CreateCompilationWithMscorlib45(text).VerifyDiagnostics( - // (11,22): error CS8083: By-reference returns may only be used in by-reference returning methods. + // (11,22): error CS8149: By-reference returns may only be used in by-reference returning methods. // ME(() => ref i); Diagnostic(ErrorCode.ERR_MustNotHaveRefReturn, "i").WithLocation(11, 22), - // (12,20): error CS8083: By-reference returns may only be used in by-reference returning methods. + // (12,20): error CS8149: By-reference returns may only be used in by-reference returning methods. // ME(() => { return ref i; }); Diagnostic(ErrorCode.ERR_MustNotHaveRefReturn, "return").WithLocation(12, 20), - // (13,23): error CS8083: By-reference returns may only be used in by-reference returning methods. + // (13,23): error CS8149: By-reference returns may only be used in by-reference returning methods. // ME(delegate { return ref i; }); Diagnostic(ErrorCode.ERR_MustNotHaveRefReturn, "return").WithLocation(13, 23)); } @@ -1223,13 +1223,13 @@ static void M() "; CreateCompilationWithMscorlib45(text).VerifyDiagnostics( - // (9,33): error CS8083: By-reference returns may only be used in by-reference returning methods. + // (9,33): error CS8149: By-reference returns may only be used in by-reference returning methods. // var e = new E(() => ref i); Diagnostic(ErrorCode.ERR_MustNotHaveRefReturn, "i").WithLocation(9, 33), - // (10,27): error CS8083: By-reference returns may only be used in by-reference returning methods. + // (10,27): error CS8149: By-reference returns may only be used in by-reference returning methods. // e = new E(() => { return ref i; }); Diagnostic(ErrorCode.ERR_MustNotHaveRefReturn, "return").WithLocation(10, 27), - // (11,30): error CS8083: By-reference returns may only be used in by-reference returning methods. + // (11,30): error CS8149: By-reference returns may only be used in by-reference returning methods. // e = new E(delegate { return ref i; }); Diagnostic(ErrorCode.ERR_MustNotHaveRefReturn, "return").WithLocation(11, 30)); } @@ -1268,10 +1268,10 @@ static void M() "; CreateCompilationWithMscorlib45(text).VerifyDiagnostics( - // (18,13): error CS8084: By-value returns may only be used in by-value returning methods. + // (18,13): error CS8150: By-value returns may only be used in by-value returning methods. // return i; Diagnostic(ErrorCode.ERR_MustHaveRefReturn, "return").WithLocation(18, 13), - // (23,17): error CS8083: By-reference returns may only be used in by-reference returning methods. + // (23,17): error CS8149: By-reference returns may only be used in by-reference returning methods. // return ref i; Diagnostic(ErrorCode.ERR_MustNotHaveRefReturn, "return").WithLocation(23, 17)); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs index 8b943824e6e20..f5deb19a620bd 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs @@ -293,7 +293,7 @@ class Test // (28,20): error CS0103: The name 'List2' does not exist in the current context // s = nameof(List2<>.Add); Diagnostic(ErrorCode.ERR_NameNotInContext, "List2<>").WithArguments("List2").WithLocation(28, 20), - // (31,20): error CS8083: An alias-qualified name is not an expression. + // (31,20): error CS8149: An alias-qualified name is not an expression. // s = nameof(global::Program); // not an expression Diagnostic(ErrorCode.ERR_AliasQualifiedNameNotAnExpression, "global::Program").WithLocation(31, 20), // (32,20): error CS0305: Using the generic type 'Test' requires 1 type arguments @@ -305,7 +305,7 @@ class Test // (33,20): error CS0841: Cannot use local variable 'b' before it is declared // s = nameof(b); // cannot use before declaration Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "b").WithArguments("b").WithLocation(33, 20), - // (35,20): error CS8084: Type parameters are not allowed on a method group as an argument to 'nameof'. + // (35,20): error CS8150: Type parameters are not allowed on a method group as an argument to 'nameof'. // s = nameof(System.Linq.Enumerable.Select); // type parameters not allowed on method group in nameof Diagnostic(ErrorCode.ERR_NameofMethodGroupWithTypeParameters, "System.Linq.Enumerable.Select").WithLocation(35, 20), // (43,13): error CS0103: The name 'nameof' does not exist in the current context diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs index 76882060ed28d..b7e2808a80390 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs @@ -11822,7 +11822,7 @@ static object Test1(out int x, out int x2) parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( - // (7,23): error CS8927: Reference to an implicitly-typed out variable 'x1' is not permitted in the same argument list. + // (7,23): error CS8181: Reference to an implicitly-typed out variable 'x1' is not permitted in the same argument list. // out x1); Diagnostic(ErrorCode.ERR_ImplicitlyTypedOutVariableUsedInTheSameArgumentList, "x1").WithArguments("x1").WithLocation(7, 23) ); @@ -11863,7 +11863,7 @@ static object Test1(out int x, int x2) parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( - // (7,25): error CS8927: Reference to an implicitly-typed out variable 'x1' is not permitted in the same argument list. + // (7,25): error CS8181: Reference to an implicitly-typed out variable 'x1' is not permitted in the same argument list. // Test1(out x1, Diagnostic(ErrorCode.ERR_ImplicitlyTypedOutVariableUsedInTheSameArgumentList, "x1").WithArguments("x1").WithLocation(7, 25) ); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs index 7321fbd1fba66..d0b7eef02ac4d 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs @@ -744,6 +744,113 @@ .method public hidebysig specialname rtspecialname instance void .ctor() cil man Assert.Equal("System.Threading.Tasks.Task)>", normalized.ToTestDisplayString()); } + [Fact] + public void NormalizeTaskTypes_Pointers() + { + string source = +@"unsafe class C +{ +#pragma warning disable CS0169 + static C>* F0; +#pragma warning restore CS0169 +} +struct MyTask +{ + public static MyTaskMethodBuilder CreateAsyncMethodBuilder() => new MyTaskMethodBuilder(); +} +struct MyTaskMethodBuilder +{ +}"; + var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.UnsafeDebugDll); + compilation.VerifyDiagnostics( + // (4,12): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('C>') + // static C>* F0; + Diagnostic(ErrorCode.ERR_ManagedAddr, "C>*").WithArguments("C>").WithLocation(4, 12)); + + var type = compilation.GetMember("C.F0").Type; + var normalized = type.NormalizeTaskTypes(compilation); + Assert.Equal("C>*", type.ToTestDisplayString()); + Assert.Equal("C>*", normalized.ToTestDisplayString()); + } + + [Fact] + public void NormalizeTaskTypes_PointersCustomModifiers() + { + var ilSource = +@".class public C +{ + .field public static class MyTask modopt(class MyTask) *[] F0 + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret } +} +.class public MyTask +{ + .method public hidebysig static class MyTaskMethodBuilder CreateAsyncMethodBuilder() cil managed { ldnull ret } + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret } +} +.class public MyTaskMethodBuilder +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret } +} +"; + var source = +@""; + var reference = CompileIL(ilSource); + var compilation = CreateCompilationWithMscorlib45(source, references: new[] { reference }); + compilation.VerifyDiagnostics(); + + var type = compilation.GetMember("C.F0").Type; + var normalized = type.NormalizeTaskTypes(compilation); + Assert.Equal("MyTask modopt(MyTask) *[]", type.ToTestDisplayString()); + Assert.Equal("System.Threading.Tasks.Task modopt(MyTask) *[]", normalized.ToTestDisplayString()); + } + + [Fact] + public void NormalizeTaskTypes_Errors() + { + string source = +@"class C +{ +#pragma warning disable CS0169 + static A F0; + static MyTask F1; +#pragma warning restore CS0169 +} +struct MyTask +{ + public static MyTaskMethodBuilder CreateAsyncMethodBuilder() => new MyTaskMethodBuilder(); +} +struct MyTask +{ + public static MyTaskMethodBuilder CreateAsyncMethodBuilder() => new MyTaskMethodBuilder(); +} +struct MyTaskMethodBuilder +{ +} +struct MyTaskMethodBuilder +{ +}"; + var compilation = CreateCompilationWithMscorlib45(source); + compilation.VerifyDiagnostics( + // (5,19): error CS0246: The type or namespace name 'B' could not be found (are you missing a using directive or an assembly reference?) + // static MyTask F1; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "B").WithArguments("B").WithLocation(5, 19), + // (4,12): error CS0246: The type or namespace name 'A<,>' could not be found (are you missing a using directive or an assembly reference?) + // static A F0; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "A").WithArguments("A<,>").WithLocation(4, 12)); + + var type = compilation.GetMember("C.F0").Type; + Assert.Equal(TypeKind.Error, type.TypeKind); + var normalized = type.NormalizeTaskTypes(compilation); + Assert.Equal("A", type.ToTestDisplayString()); + Assert.Equal("A", normalized.ToTestDisplayString()); + + type = compilation.GetMember("C.F1").Type; + Assert.Equal(TypeKind.Error, ((NamedTypeSymbol)type).TypeArguments[0].TypeKind); + normalized = type.NormalizeTaskTypes(compilation); + Assert.Equal("MyTask", type.ToTestDisplayString()); + Assert.Equal("System.Threading.Tasks.Task", normalized.ToTestDisplayString()); + } + [Fact] public void NormalizeTaskTypes_Inner() { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternSwitchTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternSwitchTests.cs index 05deb4071af05..236c86ac81f66 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternSwitchTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternSwitchTests.cs @@ -1163,5 +1163,62 @@ public static double MakeNaN(int x) var comp = CompileAndVerify(compilation, expectedOutput: expectedOutput); } + [Fact, WorkItem(12573, "https://github.com/dotnet/roslyn/issues/12573")] + public void EnumAndUnderlyingType() + { + var source = +@"using System; + +class Program +{ + public static void Main(string[] args) + { + M(0); + M(0L); + M((byte)0); + M(EnumA.ValueA); + M(2); + } + + public static void M(object value) + { + switch (value) + { + case 0: + Console.WriteLine(""0""); + break; + case 0L: + Console.WriteLine(""0L""); + break; + case (byte)0: + Console.WriteLine(""(byte)0""); + break; + case EnumA.ValueA: + Console.WriteLine(""EnumA.ValueA""); + break; + default: + Console.WriteLine(""Default""); + break; + } + } +} + +public enum EnumA +{ + ValueA, + ValueB, + ValueC +} +"; + var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe); + compilation.VerifyDiagnostics(); + var expectedOutput = +@"0 +0L +(byte)0 +EnumA.ValueA +Default"; + var comp = CompileAndVerify(compilation, expectedOutput: expectedOutput); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturns.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturns.cs index 63c0006e46bb2..d59e151e98cfb 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturns.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturns.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics { public class RefLocalsAndReturnsTests : CompilingTestBase { - internal static CSharpCompilation CreateCompilationRef( + private static CSharpCompilation CreateCompilationRef( string text, IEnumerable references = null, CSharpCompilationOptions options = null, @@ -31,7 +31,7 @@ void A() }"; var comp = CreateCompilationRef(text); comp.VerifyDiagnostics( - // (6,17): error CS8935: A declaration of a by-reference variable must have an initializer + // (6,17): error CS8174: A declaration of a by-reference variable must have an initializer // ref int x; Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "x").WithLocation(6, 17), // (6,17): warning CS0168: The variable 'x' is declared but never used @@ -55,7 +55,7 @@ void A() }"; var comp = CreateCompilationRef(text); comp.VerifyDiagnostics( - // (7,17): error CS8933: Cannot initialize a by-reference variable with a value + // (7,17): error CS8172: Cannot initialize a by-reference variable with a value // ref int x = a; Diagnostic(ErrorCode.ERR_InitializeByReferenceVariableWithValue, "x = a").WithLocation(7, 17) ); @@ -76,7 +76,7 @@ void A() }"; var comp = CreateCompilationRef(text); comp.VerifyDiagnostics( - // (8,13): error CS8932: Cannot initialize a by-value variable with a reference + // (8,13): error CS8171: Cannot initialize a by-value variable with a reference // var y = ref x; Diagnostic(ErrorCode.ERR_InitializeByValueVariableWithReference, "y = ref x").WithLocation(8, 13) ); @@ -120,19 +120,19 @@ ref int E() }"; var comp = CreateCompilationRef(text); comp.VerifyDiagnostics( - // (6,20): error CS8910: An expression cannot be used in this context because it may not be returned by reference + // (6,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference // return ref 2 + 2; Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "2 + 2").WithLocation(6, 20), - // (11,20): error CS8910: An expression cannot be used in this context because it may not be returned by reference + // (11,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference // return ref 2; Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "2").WithLocation(11, 20), - // (16,20): error CS8910: An expression cannot be used in this context because it may not be returned by reference + // (16,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference // return ref null; Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "null").WithLocation(16, 20), - // (23,20): error CS8910: An expression cannot be used in this context because it may not be returned by reference + // (23,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference // return ref VoidMethod(); Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "VoidMethod()").WithLocation(23, 20), - // (30,20): error CS8910: An expression cannot be used in this context because it may not be returned by reference + // (30,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference // return ref P1; Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "P1").WithArguments("Test.P1").WithLocation(30, 20) ); @@ -161,19 +161,19 @@ void VoidMethod(){} }"; var comp = CreateCompilationRef(text); comp.VerifyDiagnostics( - // (9,27): error CS8910: An expression cannot be used in this context because it may not be returned by reference + // (9,27): error CS8156: An expression cannot be used in this context because it may not be returned by reference // D1 d1 = () => ref 2 + 2; Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "2 + 2").WithLocation(9, 27), - // (10,27): error CS8910: An expression cannot be used in this context because it may not be returned by reference + // (10,27): error CS8156: An expression cannot be used in this context because it may not be returned by reference // D1 d2 = () => ref 2; Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "2").WithLocation(10, 27), - // (11,27): error CS8910: An expression cannot be used in this context because it may not be returned by reference + // (11,27): error CS8156: An expression cannot be used in this context because it may not be returned by reference // D2 d3 = () => ref null; Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "null").WithLocation(11, 27), - // (12,27): error CS8910: An expression cannot be used in this context because it may not be returned by reference + // (12,27): error CS8156: An expression cannot be used in this context because it may not be returned by reference // D2 d4 = () => ref VoidMethod(); Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "VoidMethod()").WithLocation(12, 27), - // (13,27): error CS8910: An expression cannot be used in this context because it may not be returned by reference + // (13,27): error CS8156: An expression cannot be used in this context because it may not be returned by reference // D1 d5 = () => ref P1; Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "P1").WithArguments("Test.P1").WithLocation(13, 27)); } @@ -234,16 +234,16 @@ ref char Test1(char arg1, S1 arg2) }"; var comp = CreateCompilationRef(text); comp.VerifyDiagnostics( - // (18,24): error CS8924: Cannot return local 'l' by reference because it is not a ref local + // (18,24): error CS8168: Cannot return local 'l' by reference because it is not a ref local // return ref l; Diagnostic(ErrorCode.ERR_RefReturnLocal, "l").WithArguments("l").WithLocation(18, 24), - // (28,24): error CS8925: Cannot return a member of local 'l' by reference because it is not a ref local + // (28,24): error CS8169: Cannot return a member of local 'l' by reference because it is not a ref local // return ref l.x; Diagnostic(ErrorCode.ERR_RefReturnLocal2, "l").WithArguments("l").WithLocation(28, 24), - // (37,24): error CS8922: Cannot return a parameter by reference 'arg1' because it is not a ref or out parameter + // (37,24): error CS8166: Cannot return a parameter by reference 'arg1' because it is not a ref or out parameter // return ref arg1; Diagnostic(ErrorCode.ERR_RefReturnParameter, "arg1").WithArguments("arg1").WithLocation(37, 24), - // (46,24): error CS8923: Cannot return or a member of parameter 'arg2' by reference because it is not a ref or out parameter + // (46,24): error CS8167: Cannot return or a member of parameter 'arg2' by reference because it is not a ref or out parameter // return ref arg2.x; Diagnostic(ErrorCode.ERR_RefReturnParameter2, "arg2").WithArguments("arg2").WithLocation(46, 24) ); @@ -292,13 +292,13 @@ ref char Test1() // (13,30): error CS1657: Cannot use 'ro' as a ref or out value because it is a 'foreach iteration variable' // ref char r = ref ro; Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "ro").WithArguments("ro", "foreach iteration variable").WithLocation(13, 30), - // (18,24): error CS8924: Cannot return local 'ro' by reference because it is not a ref local + // (18,24): error CS8168: Cannot return local 'ro' by reference because it is not a ref local // return ref ro; Diagnostic(ErrorCode.ERR_RefReturnLocal, "ro").WithArguments("ro").WithLocation(18, 24), // (23,30): error CS1655: Cannot use fields of 'ro' as a ref or out value because it is a 'foreach iteration variable' // ref char r = ref ro.x; Diagnostic(ErrorCode.ERR_RefReadonlyLocal2Cause, "ro.x").WithArguments("ro", "foreach iteration variable").WithLocation(23, 30), - // (28,24): error CS8925: Cannot return a member of local 'ro' by reference because it is not a ref local + // (28,24): error CS8169: Cannot return a member of local 'ro' by reference because it is not a ref local // return ref ro.x; Diagnostic(ErrorCode.ERR_RefReturnLocal2, "ro").WithArguments("ro").WithLocation(28, 24) ); @@ -514,25 +514,25 @@ ref char Test2() // (65,33): error CS0192: A readonly field cannot be used as a ref or out value (except in a constructor) // ref char temp = ref i1; Diagnostic(ErrorCode.ERR_RefReadonly, "i1").WithLocation(65, 33), - // (68,24): error CS8916: A readonly field cannot be returned by reference + // (68,24): error CS8160: A readonly field cannot be returned by reference // return ref i1; Diagnostic(ErrorCode.ERR_RefReturnReadonly, "i1").WithLocation(68, 24), // (72,33): error CS1649: Members of readonly field 'Test.i2' cannot be used as a ref or out value (except in a constructor) // ref char temp = ref i2.x; Diagnostic(ErrorCode.ERR_RefReadonly2, "i2.x").WithArguments("Test.i2").WithLocation(72, 33), - // (75,24): error CS8918: Members of readonly field 'Test.i2' cannot be returned by reference + // (75,24): error CS8162: Members of readonly field 'Test.i2' cannot be returned by reference // return ref i2.x; Diagnostic(ErrorCode.ERR_RefReturnReadonly2, "i2.x").WithArguments("Test.i2").WithLocation(75, 24), // (83,33): error CS0199: A static readonly field cannot be used as a ref or out value (except in a static constructor) // ref char temp = ref s1; Diagnostic(ErrorCode.ERR_RefReadonlyStatic, "s1").WithLocation(83, 33), - // (86,24): error CS8917: A static readonly field cannot be returned by reference + // (86,24): error CS8161: A static readonly field cannot be returned by reference // return ref s1; Diagnostic(ErrorCode.ERR_RefReturnReadonlyStatic, "s1").WithLocation(86, 24), // (90,33): error CS1651: Fields of static readonly field 'Test.s2' cannot be used as a ref or out value (except in a static constructor) // ref char temp = ref s2.x; Diagnostic(ErrorCode.ERR_RefReadonlyStatic2, "s2.x").WithArguments("Test.s2").WithLocation(90, 33), - // (93,24): error CS8919: Fields of static readonly field 'Test.s2' cannot be returned by reference + // (93,24): error CS8163: Fields of static readonly field 'Test.s2' cannot be returned by reference // return ref s2.x; Diagnostic(ErrorCode.ERR_RefReturnReadonlyStatic2, "s2.x").WithArguments("Test.s2").WithLocation(93, 24) ); @@ -598,31 +598,31 @@ static ref char Test1() }"; var comp = CreateCompilationRef(text); comp.VerifyDiagnostics( - // (10,24): error CS8927: Struct members cannot return 'this' or other instance members by reference + // (10,24): error CS8170: Struct members cannot return 'this' or other instance members by reference // return ref this; Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithArguments("this").WithLocation(10, 24), - // (15,24): error CS8927: Struct members cannot return 'this' or other instance members by reference + // (15,24): error CS8170: Struct members cannot return 'this' or other instance members by reference // return ref x; Diagnostic(ErrorCode.ERR_RefReturnStructThis, "x").WithArguments("this").WithLocation(15, 24), - // (20,24): error CS8927: Struct members cannot return 'this' or other instance members by reference + // (20,24): error CS8170: Struct members cannot return 'this' or other instance members by reference // return ref this.x; Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this.x").WithArguments("this").WithLocation(20, 24), - // (36,32): error CS8924: Cannot return local 'M1' by reference because it is not a ref local + // (36,32): error CS8168: Cannot return local 'M1' by reference because it is not a ref local // return ref Foo(ref M1); Diagnostic(ErrorCode.ERR_RefReturnLocal, "M1").WithArguments("M1").WithLocation(36, 32), - // (36,24): error CS8920: Cannot return by reference a result of 'Test.Foo(ref char)' because the argument passed to parameter 'arg' cannot be returned by reference + // (36,24): error CS8164: Cannot return by reference a result of 'Test.Foo(ref char)' because the argument passed to parameter 'arg' cannot be returned by reference // return ref Foo(ref M1); Diagnostic(ErrorCode.ERR_RefReturnCall, "Foo(ref M1)").WithArguments("Test.Foo(ref char)", "arg").WithLocation(36, 24), - // (41,32): error CS8925: Cannot return a member of local 'M2' by reference because it is not a ref local + // (41,32): error CS8169: Cannot return a member of local 'M2' by reference because it is not a ref local // return ref Foo(ref M2.x); Diagnostic(ErrorCode.ERR_RefReturnLocal2, "M2").WithArguments("M2").WithLocation(41, 32), - // (41,24): error CS8920: Cannot return by reference a result of 'Test.Foo(ref char)' because the argument passed to parameter 'arg' cannot be returned by reference + // (41,24): error CS8164: Cannot return by reference a result of 'Test.Foo(ref char)' because the argument passed to parameter 'arg' cannot be returned by reference // return ref Foo(ref M2.x); Diagnostic(ErrorCode.ERR_RefReturnCall, "Foo(ref M2.x)").WithArguments("Test.Foo(ref char)", "arg").WithLocation(41, 24), - // (46,32): error CS8924: Cannot return local 'M2' by reference because it is not a ref local + // (46,32): error CS8168: Cannot return local 'M2' by reference because it is not a ref local // return ref Foo(ref M2).x; Diagnostic(ErrorCode.ERR_RefReturnLocal, "M2").WithArguments("M2").WithLocation(46, 32), - // (46,24): error CS8921: Cannot return by reference a member of result of 'Test.Foo(ref Test.S1)' because the argument passed to parameter 'arg' cannot be returned by reference + // (46,24): error CS8165: Cannot return by reference a member of result of 'Test.Foo(ref Test.S1)' because the argument passed to parameter 'arg' cannot be returned by reference // return ref Foo(ref M2).x; Diagnostic(ErrorCode.ERR_RefReturnCall2, "Foo(ref M2)").WithArguments("Test.Foo(ref Test.S1)", "arg").WithLocation(46, 24)); } @@ -702,22 +702,22 @@ ref char Test1(char arg1, S1 arg2) }"; var comp = CreateCompilationRef(text); comp.VerifyDiagnostics( - // (18,24): error CS8911: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference + // (18,24): error CS8157: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference // return ref r; Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "r").WithArguments("r").WithLocation(18, 24), - // (28,24): error CS8911: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference + // (28,24): error CS8157: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference // return ref r; Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "r").WithArguments("r").WithLocation(28, 24), - // (38,24): error CS8912: Cannot return by reference a member of 'r' because it was initialized to a value that cannot be returned by reference + // (38,24): error CS8158: Cannot return by reference a member of 'r' because it was initialized to a value that cannot be returned by reference // return ref r.x; Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal2, "r").WithArguments("r").WithLocation(38, 24), - // (47,24): error CS8911: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference + // (47,24): error CS8157: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference // return ref r; Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "r").WithArguments("r").WithLocation(47, 24), - // (56,24): error CS8911: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference + // (56,24): error CS8157: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference // return ref r; Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "r").WithArguments("r").WithLocation(56, 24), - // (65,24): error CS8912: Cannot return by reference a member of 'r' because it was initialized to a value that cannot be returned by reference + // (65,24): error CS8158: Cannot return by reference a member of 'r' because it was initialized to a value that cannot be returned by reference // return ref r.x; Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal2, "r").WithArguments("r").WithLocation(65, 24) @@ -786,19 +786,19 @@ ref char Test1(char arg1, S1 arg2) }"; var comp = CreateCompilationRef(text); comp.VerifyDiagnostics( - // (19,24): error CS8911: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference + // (19,24): error CS8157: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference // return ref r; //1 Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "r").WithArguments("r").WithLocation(19, 24), - // (25,24): error CS8912: Cannot return by reference a member of 'r' because it was initialized to a value that cannot be returned by reference + // (25,24): error CS8158: Cannot return by reference a member of 'r' because it was initialized to a value that cannot be returned by reference // return ref r.x; //2 Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal2, "r").WithArguments("r").WithLocation(25, 24), // (34,24): error CS0103: The name 'r' does not exist in the current context // return ref r; Diagnostic(ErrorCode.ERR_NameNotInContext, "r").WithArguments("r").WithLocation(34, 24), - // (43,24): error CS8911: Cannot return 'valid' by reference because it was initialized to a value that cannot be returned by reference + // (43,24): error CS8157: Cannot return 'valid' by reference because it was initialized to a value that cannot be returned by reference // return ref valid; //4 Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "valid").WithArguments("valid").WithLocation(43, 24), - // (52,24): error CS8911: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference + // (52,24): error CS8157: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference // return ref r; //5 Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "r").WithArguments("r").WithLocation(52, 24), // (18,30): error CS0165: Use of unassigned local variable 'r' @@ -842,23 +842,21 @@ ref char Foo2(ref char c, ref char b) var options = TestOptions.Regular; var comp = CreateCompilationWithMscorlib45(text, parseOptions: options); comp.VerifyDiagnostics( - // (14,13): error CS8894: By-reference returns may only be used in methods that return by reference - // return ref b; - Diagnostic(ErrorCode.ERR_MustNotHaveRefReturn, "return").WithLocation(14, 13), - // (19,13): error CS8895: By-value returns may only be used in methods that return by value - // return c; - Diagnostic(ErrorCode.ERR_MustHaveRefReturn, "return").WithLocation(19, 13), - // (6,18): warning CS0168: The variable 'Foo' is declared but never used - // ref char Foo(ref char a, ref char b) - Diagnostic(ErrorCode.WRN_UnreferencedVar, "Foo").WithArguments("Foo").WithLocation(6, 18), - // (12,14): warning CS0168: The variable 'Foo1' is declared but never used - // char Foo1(ref char a, ref char b) - Diagnostic(ErrorCode.WRN_UnreferencedVar, "Foo1").WithArguments("Foo1").WithLocation(12, 14), - // (17,18): warning CS0168: The variable 'Foo2' is declared but never used - // ref char Foo2(ref char c, ref char b) - Diagnostic(ErrorCode.WRN_UnreferencedVar, "Foo2").WithArguments("Foo2").WithLocation(17, 18) - - ); + // (14,13): error CS8149: By-reference returns may only be used in methods that return by reference + // return ref b; + Diagnostic(ErrorCode.ERR_MustNotHaveRefReturn, "return").WithLocation(14, 13), + // (19,13): error CS8150: By-value returns may only be used in methods that return by value + // return c; + Diagnostic(ErrorCode.ERR_MustHaveRefReturn, "return").WithLocation(19, 13), + // (6,18): warning CS0168: The variable 'Foo' is declared but never used + // ref char Foo(ref char a, ref char b) + Diagnostic(ErrorCode.WRN_UnreferencedVar, "Foo").WithArguments("Foo").WithLocation(6, 18), + // (12,14): warning CS0168: The variable 'Foo1' is declared but never used + // char Foo1(ref char a, ref char b) + Diagnostic(ErrorCode.WRN_UnreferencedVar, "Foo1").WithArguments("Foo1").WithLocation(12, 14), + // (17,18): warning CS0168: The variable 'Foo2' is declared but never used + // ref char Foo2(ref char c, ref char b) + Diagnostic(ErrorCode.WRN_UnreferencedVar, "Foo2").WithArguments("Foo2").WithLocation(17, 18)); } [Fact] @@ -886,41 +884,39 @@ public static void Main() var options = TestOptions.Regular; var comp = CreateCompilationWithMscorlib45(text, parseOptions: options); comp.VerifyDiagnostics( - // (9,50): error CS8894: By-reference returns may only be used in methods that return by reference - // char Foo1(ref char a, ref char b) => ref b; - Diagnostic(ErrorCode.ERR_MustNotHaveRefReturn, "b").WithLocation(9, 50), - // (11,50): error CS8895: By-value returns may only be used in methods that return by value - // ref char Foo2(ref char c, ref char b) => c; - Diagnostic(ErrorCode.ERR_MustHaveRefReturn, "c").WithLocation(11, 50), - // (16,54): error CS8940: Cannot use ref local 'r' inside an anonymous method, lambda expression, or query expression - // ref char Moo1(ref char a, ref char b) => ref r; - Diagnostic(ErrorCode.ERR_AnonDelegateCantUseLocal, "r").WithArguments("r").WithLocation(16, 54), - // (16,54): error CS8896: The return expression must be of type 'char' because this method returns by reference - // ref char Moo1(ref char a, ref char b) => ref r; - Diagnostic(ErrorCode.ERR_RefReturnMustHaveIdentityConversion, "r").WithArguments("char").WithLocation(16, 54), - // (17,46): error CS8940: Cannot use ref local 'r' inside an anonymous method, lambda expression, or query expression - // char Moo3(ref char a, ref char b) => r; - Diagnostic(ErrorCode.ERR_AnonDelegateCantUseLocal, "r").WithArguments("r").WithLocation(17, 46), - // (17,46): error CS0266: Cannot implicitly convert type 'int' to 'char'. An explicit conversion exists (are you missing a cast?) - // char Moo3(ref char a, ref char b) => r; - Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "r").WithArguments("int", "char").WithLocation(17, 46), - // (7,18): warning CS0168: The variable 'Foo' is declared but never used - // ref char Foo(ref char a, ref char b) => ref a; - Diagnostic(ErrorCode.WRN_UnreferencedVar, "Foo").WithArguments("Foo").WithLocation(7, 18), - // (9,14): warning CS0168: The variable 'Foo1' is declared but never used - // char Foo1(ref char a, ref char b) => ref b; - Diagnostic(ErrorCode.WRN_UnreferencedVar, "Foo1").WithArguments("Foo1").WithLocation(9, 14), - // (11,18): warning CS0168: The variable 'Foo2' is declared but never used - // ref char Foo2(ref char c, ref char b) => c; - Diagnostic(ErrorCode.WRN_UnreferencedVar, "Foo2").WithArguments("Foo2").WithLocation(11, 18), - // (16,18): warning CS0168: The variable 'Moo1' is declared but never used - // ref char Moo1(ref char a, ref char b) => ref r; - Diagnostic(ErrorCode.WRN_UnreferencedVar, "Moo1").WithArguments("Moo1").WithLocation(16, 18), - // (17,14): warning CS0168: The variable 'Moo3' is declared but never used - // char Moo3(ref char a, ref char b) => r; - Diagnostic(ErrorCode.WRN_UnreferencedVar, "Moo3").WithArguments("Moo3").WithLocation(17, 14) - ); + // (9,50): error CS8149: By-reference returns may only be used in methods that return by reference + // char Foo1(ref char a, ref char b) => ref b; + Diagnostic(ErrorCode.ERR_MustNotHaveRefReturn, "b").WithLocation(9, 50), + // (11,50): error CS8150: By-value returns may only be used in methods that return by value + // ref char Foo2(ref char c, ref char b) => c; + Diagnostic(ErrorCode.ERR_MustHaveRefReturn, "c").WithLocation(11, 50), + // (16,54): error CS8175: Cannot use ref local 'r' inside an anonymous method, lambda expression, or query expression + // ref char Moo1(ref char a, ref char b) => ref r; + Diagnostic(ErrorCode.ERR_AnonDelegateCantUseLocal, "r").WithArguments("r").WithLocation(16, 54), + // (16,54): error CS8151: The return expression must be of type 'char' because this method returns by reference + // ref char Moo1(ref char a, ref char b) => ref r; + Diagnostic(ErrorCode.ERR_RefReturnMustHaveIdentityConversion, "r").WithArguments("char").WithLocation(16, 54), + // (17,46): error CS8175: Cannot use ref local 'r' inside an anonymous method, lambda expression, or query expression + // char Moo3(ref char a, ref char b) => r; + Diagnostic(ErrorCode.ERR_AnonDelegateCantUseLocal, "r").WithArguments("r").WithLocation(17, 46), + // (17,46): error CS0266: Cannot implicitly convert type 'int' to 'char'. An explicit conversion exists (are you missing a cast?) + // char Moo3(ref char a, ref char b) => r; + Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "r").WithArguments("int", "char").WithLocation(17, 46), + // (7,18): warning CS0168: The variable 'Foo' is declared but never used + // ref char Foo(ref char a, ref char b) => ref a; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "Foo").WithArguments("Foo").WithLocation(7, 18), + // (9,14): warning CS0168: The variable 'Foo1' is declared but never used + // char Foo1(ref char a, ref char b) => ref b; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "Foo1").WithArguments("Foo1").WithLocation(9, 14), + // (11,18): warning CS0168: The variable 'Foo2' is declared but never used + // ref char Foo2(ref char c, ref char b) => c; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "Foo2").WithArguments("Foo2").WithLocation(11, 18), + // (16,18): warning CS0168: The variable 'Moo1' is declared but never used + // ref char Moo1(ref char a, ref char b) => ref r; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "Moo1").WithArguments("Moo1").WithLocation(16, 18), + // (17,14): warning CS0168: The variable 'Moo3' is declared but never used + // char Moo3(ref char a, ref char b) => r; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "Moo3").WithArguments("Moo3").WithLocation(17, 14)); } - } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SwitchTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SwitchTests.cs index af77df4633cce..438c80a240ec6 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SwitchTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SwitchTests.cs @@ -359,14 +359,14 @@ public static void Main() } }"; CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular6).VerifyDiagnostics( - // (15,13): error CS0152: The switch statement contains multiple cases with the label value 'default' + // (15,13): error CS0152: The switch statement contains multiple cases with the label value 'default:' // default: //CS0152 Diagnostic(ErrorCode.ERR_DuplicateCaseLabel, "default:").WithArguments("default:").WithLocation(15, 13) ); CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular6WithV7SwitchBinder).VerifyDiagnostics( - // (15,13): error CS0152: The switch statement contains multiple cases with the label value 'default' + // (15,13): error CS0152: The switch statement contains multiple cases with the label value 'default:' // default: //CS0152 - Diagnostic(ErrorCode.ERR_DuplicateCaseLabel, "default:").WithArguments("default").WithLocation(15, 13) + Diagnostic(ErrorCode.ERR_DuplicateCaseLabel, "default:").WithArguments("default:").WithLocation(15, 13) ); CreateCompilationWithMscorlib(text).VerifyDiagnostics( // (15,13): error CS0152: The switch statement contains multiple cases with the label value 'default:' @@ -1135,9 +1135,9 @@ static void Main() { } // (9,17): error CS7036: There is no argument given that corresponds to the required formal parameter 'o' of 'C.M(object)' // M(); Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M").WithArguments("o", "C.M(object)").WithLocation(9, 17), - // (12,13): error CS0152: The switch statement contains multiple cases with the label value '0' + // (12,13): error CS8120: The switch case has already been handled by a previous case. // case 0: - Diagnostic(ErrorCode.ERR_DuplicateCaseLabel, "case 0:").WithArguments("0").WithLocation(12, 13) + Diagnostic(ErrorCode.ERR_PatternIsSubsumed, "case 0:").WithLocation(12, 13) ); } diff --git a/src/Compilers/Core/CodeAnalysisTest/Text/StringTextDecodingTests.cs b/src/Compilers/Core/CodeAnalysisTest/Text/StringTextDecodingTests.cs index c4a56bd49b927..91b90dbb69cfe 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Text/StringTextDecodingTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Text/StringTextDecodingTests.cs @@ -44,7 +44,7 @@ private static SourceText CreateMemoryStreamBasedEncodedText(byte[] bytes, using (var stream = new MemoryStream(buffer, 0, bytes.Length, writable: true, publiclyVisible: true)) { - return EncodedStringText.Create(stream, getEncoding, readEncodingOpt, algorithm); + return EncodedStringText.Create(stream, new Lazy(getEncoding), readEncodingOpt, algorithm); } } diff --git a/src/Compilers/Core/Portable/EncodedStringText.cs b/src/Compilers/Core/Portable/EncodedStringText.cs index 01402eaaa05dc..1847452e0aa4e 100644 --- a/src/Compilers/Core/Portable/EncodedStringText.cs +++ b/src/Compilers/Core/Portable/EncodedStringText.cs @@ -24,7 +24,7 @@ internal static class EncodedStringText /// 2. CodePage 1252. /// 3. Latin1. /// - private static readonly Encoding s_fallbackEncoding = GetFallbackEncoding(); + private static readonly Lazy s_fallbackEncoding = new Lazy(GetFallbackEncoding); private static Encoding GetFallbackEncoding() { @@ -74,14 +74,14 @@ internal static SourceText Create(Stream stream, bool canBeEmbedded = false) { return Create(stream, - () => s_fallbackEncoding, + s_fallbackEncoding, defaultEncoding: defaultEncoding, checksumAlgorithm: checksumAlgorithm, canBeEmbedded: canBeEmbedded); } // internal for testing - internal static SourceText Create(Stream stream, Func getEncoding, + internal static SourceText Create(Stream stream, Lazy getEncoding, Encoding defaultEncoding = null, SourceHashAlgorithm checksumAlgorithm = SourceHashAlgorithm.Sha1, bool canBeEmbedded = false) @@ -104,7 +104,7 @@ internal static SourceText Create(Stream stream, Func getEncoding, try { - return Decode(stream, defaultEncoding ?? getEncoding(), checksumAlgorithm, throwIfBinaryDetected: detectEncoding); + return Decode(stream, defaultEncoding ?? getEncoding.Value, checksumAlgorithm, throwIfBinaryDetected: detectEncoding); } catch (DecoderFallbackException e) { diff --git a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs index 53cf943d116ce..c889e9c4580d8 100644 --- a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs +++ b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs @@ -1739,7 +1739,11 @@ public void WriteMetadataAndIL(PdbWriter pdbWriterOpt, Stream metadataStream, St Debug.Assert(mvidFixup.IsDefault); Debug.Assert(mvidStringFixup.IsDefault); - var rootBuilder = new MetadataRootBuilder(metadata, module.Properties.TargetRuntimeVersion); + // TODO (https://github.com/dotnet/roslyn/issues/3905): + // InterfaceImpl table emitted by Roslyn is not compliant with ECMA spec. + // Once fixed enable validation in DEBUG builds. + var rootBuilder = new MetadataRootBuilder(metadata, module.Properties.TargetRuntimeVersion, suppressValidation: true); + rootBuilder.Serialize(metadataBuilder, methodBodyStreamRva: 0, mappedFieldDataStreamRva: 0); metadataSizes = rootBuilder.Sizes; @@ -1789,7 +1793,10 @@ public void BuildMetadataAndIL( public MetadataRootBuilder GetRootBuilder() { - return new MetadataRootBuilder(metadata, module.Properties.TargetRuntimeVersion); + // TODO (https://github.com/dotnet/roslyn/issues/3905): + // InterfaceImpl table emitted by Roslyn is not compliant with ECMA spec. + // Once fixed enable validation in DEBUG builds. + return new MetadataRootBuilder(metadata, module.Properties.TargetRuntimeVersion, suppressValidation: true); } public PortablePdbBuilder GetPortablePdbBuilder(MetadataSizes typeSystemMetadataSizes, MethodDefinitionHandle debugEntryPoint, Func, BlobContentId> deterministicIdProviderOpt) @@ -2612,8 +2619,10 @@ private void PopulateModuleTableRow(out Blob mvidFixup) else { // The guid will be filled in later: - mvidHandle = metadata.ReserveGuid(out mvidFixup); - new BlobWriter(mvidFixup).WriteBytes(0, mvidFixup.Length); + var reservedGuid = metadata.ReserveGuid(); + mvidFixup = reservedGuid.Content; + mvidHandle = reservedGuid.Handle; + reservedGuid.CreateWriter().WriteBytes(0, mvidFixup.Length); } metadata.AddModule( @@ -2787,7 +2796,7 @@ private int[] SerializeMethodBodies(BlobBuilder ilBuilder, PdbWriter pdbWriterOp var lastLocalVariableHandle = default(LocalVariableHandle); var lastLocalConstantHandle = default(LocalConstantHandle); - var encoder = new MethodBodiesEncoder(ilBuilder); + var encoder = new MethodBodyStreamEncoder(ilBuilder); var mvidStringHandle = default(UserStringHandle); mvidStringFixup = default(Blob); @@ -2843,7 +2852,7 @@ private int[] SerializeMethodBodies(BlobBuilder ilBuilder, PdbWriter pdbWriterOp return bodyOffsets; } - private int SerializeMethodBody(MethodBodiesEncoder encoder, IMethodBody methodBody, StandaloneSignatureHandle localSignatureHandleOpt, ref UserStringHandle mvidStringHandle, ref Blob mvidStringFixup) + private int SerializeMethodBody(MethodBodyStreamEncoder encoder, IMethodBody methodBody, StandaloneSignatureHandle localSignatureHandleOpt, ref UserStringHandle mvidStringHandle, ref Blob mvidStringFixup) { int ilLength = methodBody.IL.Length; var exceptionRegions = methodBody.ExceptionRegions; @@ -2852,35 +2861,34 @@ private int SerializeMethodBody(MethodBodiesEncoder encoder, IMethodBody methodB // Check if an identical method body has already been serialized. // If so, use the RVA of the already serialized one. // Note that we don't need to rewrite the fake tokens in the body before looking it up. - int bodyOffset; // Don't do small body method caching during deterministic builds until this issue is fixed // https://github.com/dotnet/roslyn/issues/7595 + int bodyOffset; if (!_deterministic && isSmallBody && _smallMethodBodies.TryGetValue(methodBody.IL, out bodyOffset)) { return bodyOffset; } - MethodBodyAttributes attributes = - (methodBody.LocalsAreZeroed ? MethodBodyAttributes.InitLocals : 0) | - (MayUseSmallExceptionHeaders(exceptionRegions) ? 0 : MethodBodyAttributes.LargeExceptionRegions); - - var bodyEncoder = encoder.AddMethodBody(methodBody.MaxStack, exceptionRegions.Length, localSignatureHandleOpt, attributes); - - Blob ilBlob; - var ehEncoder = bodyEncoder.WriteInstructions(methodBody.IL, out bodyOffset, out ilBlob); + var encodedBody = encoder.AddMethodBody( + codeSize: methodBody.IL.Length, + maxStack: methodBody.MaxStack, + exceptionRegionCount: exceptionRegions.Length, + hasSmallExceptionRegions: MayUseSmallExceptionHeaders(exceptionRegions), + localVariablesSignature: localSignatureHandleOpt, + attributes: (methodBody.LocalsAreZeroed ? MethodBodyAttributes.InitLocals : 0)); // Don't do small body method caching during deterministic builds until this issue is fixed // https://github.com/dotnet/roslyn/issues/7595 if (isSmallBody && !_deterministic) { - _smallMethodBodies.Add(methodBody.IL, bodyOffset); + _smallMethodBodies.Add(methodBody.IL, encodedBody.Offset); } - SubstituteFakeTokens(ilBlob, methodBody.IL, ref mvidStringHandle, ref mvidStringFixup); - SerializeMethodBodyExceptionHandlerTable(ehEncoder, exceptionRegions); + WriteInstructions(encodedBody.Instructions, methodBody.IL, ref mvidStringHandle, ref mvidStringFixup); + SerializeMethodBodyExceptionHandlerTable(encodedBody.ExceptionRegions, exceptionRegions); - return bodyOffset; + return encodedBody.Offset; } /// @@ -3033,13 +3041,13 @@ private UserStringHandle GetOrAddUserString(string str) return default(UserStringHandle); } - private UserStringHandle ReserveUserString(int length, out Blob fixup) + private ReservedBlob ReserveUserString(int length) { if (!_userStringTokenOverflow) { try { - return metadata.ReserveUserString(length, out fixup); + return metadata.ReserveUserString(length); } catch (ImageFormatLimitationException) { @@ -3048,8 +3056,7 @@ private UserStringHandle ReserveUserString(int length, out Blob fixup) } } - fixup = default(Blob); - return default(UserStringHandle); + return default(ReservedBlob); } internal const uint LiteralMethodDefinitionToken = 0x80000000; @@ -3057,15 +3064,18 @@ private UserStringHandle ReserveUserString(int length, out Blob fixup) internal const uint SourceDocumentIndex = 0x20000000; internal const uint ModuleVersionIdStringToken = 0x80000000; - private void SubstituteFakeTokens(Blob blob, ImmutableArray methodBodyIL, ref UserStringHandle mvidStringHandle, ref Blob mvidStringFixup) + private void WriteInstructions(Blob finalIL, ImmutableArray generatedIL, ref UserStringHandle mvidStringHandle, ref Blob mvidStringFixup) { // write the raw body first and then patch tokens: - var writer = new BlobWriter(blob); + var writer = new BlobWriter(finalIL); + + writer.WriteBytes(generatedIL); + writer.Offset = 0; int offset = 0; - while (offset < methodBodyIL.Length) + while (offset < generatedIL.Length) { - var operandType = InstructionOperandTypes.ReadOperandType(methodBodyIL, ref offset); + var operandType = InstructionOperandTypes.ReadOperandType(generatedIL, ref offset); switch (operandType) { case OperandType.InlineField: @@ -3073,7 +3083,7 @@ private void SubstituteFakeTokens(Blob blob, ImmutableArray methodBodyIL, case OperandType.InlineTok: case OperandType.InlineType: { - int pseudoToken = ReadInt32(methodBodyIL, offset); + int pseudoToken = ReadInt32(generatedIL, offset); int token = 0; // If any bits in the high-order byte of the pseudotoken are nonzero, replace the opcode with Ldc_i4 // and either clear the high-order byte in the pseudotoken or ignore the pseudotoken. @@ -3083,7 +3093,7 @@ private void SubstituteFakeTokens(Blob blob, ImmutableArray methodBodyIL, int tokenMask = pseudoToken & unchecked((int)0xff000000); if (tokenMask != 0 && (uint)pseudoToken != 0xffffffff) { - Debug.Assert(ReadByte(methodBodyIL, offset - 1) == (byte)ILOpCode.Ldtoken); + Debug.Assert(ReadByte(generatedIL, offset - 1) == (byte)ILOpCode.Ldtoken); writer.Offset = offset - 1; writer.WriteByte((byte)ILOpCode.Ldc_i4); switch ((uint)tokenMask) @@ -3112,7 +3122,7 @@ private void SubstituteFakeTokens(Blob blob, ImmutableArray methodBodyIL, { writer.Offset = offset; - int pseudoToken = ReadInt32(methodBodyIL, offset); + int pseudoToken = ReadInt32(generatedIL, offset); UserStringHandle handle; if ((uint)pseudoToken == ModuleVersionIdStringToken) @@ -3124,7 +3134,9 @@ private void SubstituteFakeTokens(Blob blob, ImmutableArray methodBodyIL, { const int guidStringLength = 36; Debug.Assert(guidStringLength == default(Guid).ToString().Length); - mvidStringHandle = ReserveUserString(guidStringLength, out mvidStringFixup); + var reserved = ReserveUserString(guidStringLength); + mvidStringHandle = reserved.Handle; + mvidStringFixup = reserved.Content; } handle = mvidStringHandle; @@ -3148,7 +3160,7 @@ private void SubstituteFakeTokens(Blob blob, ImmutableArray methodBodyIL, break; case OperandType.InlineSwitch: - int argCount = ReadInt32(methodBodyIL, offset); + int argCount = ReadInt32(generatedIL, offset); // skip switch arguments count and arguments offset += (argCount + 1) * 4; break; @@ -3179,13 +3191,11 @@ private void SubstituteFakeTokens(Blob blob, ImmutableArray methodBodyIL, private void SerializeMethodBodyExceptionHandlerTable(ExceptionRegionEncoder encoder, ImmutableArray regions) { - encoder.StartRegions(); - foreach (var region in regions) { var exceptionType = region.ExceptionType; - encoder.AddRegion( + encoder.Add( region.HandlerKind, region.TryStartOffset, region.TryLength, @@ -3194,8 +3204,6 @@ private void SerializeMethodBodyExceptionHandlerTable(ExceptionRegionEncoder enc (exceptionType != null) ? GetTypeHandle(exceptionType) : default(EntityHandle), region.FilterDecisionStartOffset); } - - encoder.EndRegions(); } private static bool MayUseSmallExceptionHeaders(ImmutableArray exceptionRegions) diff --git a/src/Compilers/Core/Portable/PEWriter/PeWriter.cs b/src/Compilers/Core/Portable/PEWriter/PeWriter.cs index 867da2a243b39..c2bc248d44d95 100644 --- a/src/Compilers/Core/Portable/PEWriter/PeWriter.cs +++ b/src/Compilers/Core/Portable/PEWriter/PeWriter.cs @@ -198,8 +198,7 @@ public static bool WritePeToStream( deterministicIdProvider); var peBlob = new BlobBuilder(); - BlobContentId peContentId; - peBuilder.Serialize(peBlob, out peContentId); + var peContentId = peBuilder.Serialize(peBlob); PatchModuleVersionIds(mvidFixup, mvidStringFixup, peContentId.Guid); diff --git a/src/Compilers/Core/Portable/project.json b/src/Compilers/Core/Portable/project.json index 49d61edd5ceda..e4ac18df55618 100644 --- a/src/Compilers/Core/Portable/project.json +++ b/src/Compilers/Core/Portable/project.json @@ -1,8 +1,8 @@ { "supports": {}, "dependencies": { - "System.Collections.Immutable": "1.2.0", - "System.Reflection.Metadata": "1.4.1-beta-24322-03" + "System.Collections.Immutable": "1.2.0", + "System.Reflection.Metadata": "1.4.1-beta-24410-02" }, "frameworks": { ".NETPortable,Version=v4.5,Profile=Profile7": {} diff --git a/src/Dependencies/Metadata/project.json b/src/Dependencies/Metadata/project.json index f79e9c8f5114d..32e4a1a3951e1 100644 --- a/src/Dependencies/Metadata/project.json +++ b/src/Dependencies/Metadata/project.json @@ -1,7 +1,7 @@ { "supports": {}, "dependencies": { - "System.Reflection.Metadata": "1.4.1-beta-24322-03" + "System.Reflection.Metadata": "1.4.1-beta-24410-02" }, "frameworks": { ".NETPortable,Version=v4.5,Profile=Profile7": {} diff --git a/src/Dependencies/PooledObjects/Microsoft.CodeAnalysis.PooledObjects.shproj b/src/Dependencies/PooledObjects/Microsoft.CodeAnalysis.PooledObjects.shproj index 6274cf7f1762a..d00c5194a1adb 100644 --- a/src/Dependencies/PooledObjects/Microsoft.CodeAnalysis.PooledObjects.shproj +++ b/src/Dependencies/PooledObjects/Microsoft.CodeAnalysis.PooledObjects.shproj @@ -1,7 +1,7 @@  - c1930979-c824-496b-a630-70f5369a636f + cd77a8cc-2885-47a7-b99c-fbf13353400b 14.0 diff --git a/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj b/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj index a5cff4cd926e4..ffea03529173a 100644 --- a/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj +++ b/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj @@ -211,7 +211,7 @@ - + diff --git a/src/EditorFeatures/CSharpTest/CodeActions/ReplacePropertyWithMethods/ReplacePropertyWithMethodsTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/ReplacePropertyWithMethods/ReplacePropertyWithMethodsTests.cs index b86307ae8d736..08327c4efcf47 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/ReplacePropertyWithMethods/ReplacePropertyWithMethodsTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/ReplacePropertyWithMethods/ReplacePropertyWithMethodsTests.cs @@ -293,6 +293,23 @@ private int GetProp() }", compareTokens: false); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsReplacePropertyWithMethods)] + public async Task TestComputedPropWithTrailingTriviaAfterArrow() + { + await TestAsync( +@"class C +{ + public int [||]Prop => /* return 42 */ 42; +}", +@"class C +{ + public int GetProp() + { + return /* return 42 */ 42; + } +}", compareTokens: false); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsReplacePropertyWithMethods)] public async Task TestAbstractProperty() { diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/Async/AddAwaitTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/Async/AddAwaitTests.cs index f91133d9ad385..12dee49297f84 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/Async/AddAwaitTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/Async/AddAwaitTests.cs @@ -497,7 +497,16 @@ await TestAsync( public async Task TestAssignmentExpressionWithConversionInNonAsyncFunction() { await TestMissingAsync( -@"using System . Threading . Tasks ; class TestClass { private Task MyTestMethod1Async ( ) { long myInt = [|MyIntMethodAsync ( )|] ; } private Task < int > MyIntMethodAsync ( ) { return Task . FromResult ( result : 1 ) ; } } "); +@"using System . Threading . Tasks ; +class TestClass { + private Task MyTestMethod1Async ( ) { + long myInt = [|MyIntMethodAsync ( )|] ; + } + + private Task < int > MyIntMethodAsync ( ) { + return Task . FromResult ( result : 1 ) ; + } +} "); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddAwait)] diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/Async/AddAsyncTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/MakeMethodAsynchronous/MakeMethodAsynchronousTests.cs similarity index 88% rename from src/EditorFeatures/CSharpTest/Diagnostics/Async/AddAsyncTests.cs rename to src/EditorFeatures/CSharpTest/Diagnostics/MakeMethodAsynchronous/MakeMethodAsynchronousTests.cs index 14e6b4a6ea5f6..a710f25b17c2d 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/Async/AddAsyncTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/MakeMethodAsynchronous/MakeMethodAsynchronousTests.cs @@ -1,17 +1,23 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CSharp.CodeFixes.Async; +using Microsoft.CodeAnalysis.CSharp.MakeMethodAsynchronous; using Microsoft.CodeAnalysis.Diagnostics; using Roslyn.Test.Utilities; +using System; +using System.Threading.Tasks; using Xunit; -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.Async +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.MakeMethodAsynchronous { - public partial class AddAsyncTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest + public partial class MakeMethodAsynchronousTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest { + internal override Tuple CreateDiagnosticProviderAndFixer(Workspace workspace) + { + return new Tuple( + null, new CSharpMakeMethodAsynchronousCodeFixProvider()); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddAsync)] public async Task AwaitInVoidMethodWithModifiers() { @@ -33,13 +39,41 @@ public static void Test() class Program { - public static async void Test() + public static async void TestAsync() { await Task.Delay(1); } }"; await TestAsync(initial, expected); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddAsync)] + public async Task AwaitInVoidMethodWithModifiers2() + { + var initial = +@"using System; +using System.Threading.Tasks; + +class Program +{ + public static void Test() + { + [|await Task.Delay(1);|] + } +}"; + + var expected = +@"using System; +using System.Threading.Tasks; + +class Program +{ + public static async Task TestAsync() + { + await Task.Delay(1); + } +}"; + await TestAsync(initial, expected, index: 1); + } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddAsync)] public async Task AwaitInTaskMethodNoModifiers() @@ -62,7 +96,7 @@ Task Test() class Program { - async Task Test() + async Task TestAsync() { await Task.Delay(1); } @@ -91,7 +125,7 @@ class Program class Program { - public/*Comment*/static/*Comment*/async Task/*Comment*/Test() + public/*Comment*/static/*Comment*/async Task/*Comment*/TestAsync() { await Task.Delay(1); } @@ -176,7 +210,7 @@ void Test() @"using System.Threading.Tasks; class Program { - async void Test() + async void TestAsync() { await Task.Delay(1); } @@ -201,7 +235,7 @@ Task Test() @"using System.Threading.Tasks; class Program { - async Task Test() + async Task TestAsync() { await Task.Delay(1); } @@ -226,7 +260,7 @@ Task Test() @"using System.Threading.Tasks; class Program { - async Task Test() + async Task TestAsync() { await Task.Delay(1); } @@ -251,7 +285,7 @@ int Test() @"using System.Threading.Tasks; class Program { - async Task Test() + async Task TestAsync() { await Task.Delay(1); } @@ -274,7 +308,7 @@ void Test() var expected = @"class Program { - async void Test() + async void TestAsync() { await Task.Delay(1); } @@ -297,7 +331,7 @@ Task Test() var expected = @"class Program { - async Task Test() + async Task TestAsync() { await Task.Delay(1); } @@ -320,7 +354,7 @@ Task Test() var expected = @"class Program { - async Task Test() + async Task TestAsync() { await Task.Delay(1); } @@ -343,7 +377,7 @@ int Test() var expected = @"class Program { - async System.Threading.Tasks.Task Test() + async System.Threading.Tasks.Task TestAsync() { await Task.Delay(1); } @@ -366,7 +400,7 @@ Program Test() var expected = @"class Program { - async System.Threading.Tasks.Task Test() + async System.Threading.Tasks.Task TestAsync() { await Task.Delay(1); } @@ -389,7 +423,7 @@ asdf Test() var expected = @"class Program { - async System.Threading.Tasks.Task Test() + async System.Threading.Tasks.Task TestAsync() { await Task.Delay(1); } @@ -456,10 +490,5 @@ static async void Main() } }"); } - - internal override Tuple CreateDiagnosticProviderAndFixer(Workspace workspace) - { - return new Tuple(null, new CSharpAddAsyncCodeFixProvider()); - } } } diff --git a/src/EditorFeatures/CSharpTest/TypeInferrer/TypeInferrerTests.cs b/src/EditorFeatures/CSharpTest/TypeInferrer/TypeInferrerTests.cs index 40f4949536aad..0e25c4fe26412 100644 --- a/src/EditorFeatures/CSharpTest/TypeInferrer/TypeInferrerTests.cs +++ b/src/EditorFeatures/CSharpTest/TypeInferrer/TypeInferrerTests.cs @@ -1850,5 +1850,24 @@ void Foo() }"; await TestAsync(text, "global::System.Collections.Generic.IEnumerable", testPosition: false); } + + [WorkItem(12755, "https://github.com/dotnet/roslyn/issues/12755")] + [Fact, Trait(Traits.Feature, Traits.Features.TypeInferenceService)] + public async Task TestObjectCreationBeforeArrayIndexing() + { + var text = +@"using System; +class C +{ + void M() + { + int[] array; + C p = new [||] + array[4] = 4; + } +}"; + + await TestAsync(text, "global::C", testNode: false); + } } } \ No newline at end of file diff --git a/src/EditorFeatures/Core/Implementation/EditorLayerExtensionManager.cs b/src/EditorFeatures/Core/Implementation/EditorLayerExtensionManager.cs index 2af1bd32981ef..8cb52768eebc9 100644 --- a/src/EditorFeatures/Core/Implementation/EditorLayerExtensionManager.cs +++ b/src/EditorFeatures/Core/Implementation/EditorLayerExtensionManager.cs @@ -69,11 +69,11 @@ public override void HandleException(object provider, Exception exception) { base.HandleException(provider, exception); - _errorReportingService?.ShowErrorInfoForCodeFix( - codefixName: provider.GetType().Name, - OnEnable: () => { EnableProvider(provider); LogEnableProvider(provider); }, - OnEnableAndIgnore: () => { EnableProvider(provider); IgnoreProvider(provider); LogEnableAndIgnoreProvider(provider); }, - OnClose: () => LogLeaveDisabled(provider)); + _errorReportingService?.ShowErrorInfo(String.Format(WorkspacesResources._0_encountered_an_error_and_has_been_disabled, provider.GetType().Name), + new ErrorReportingUI(WorkspacesResources.Show_Stack_Trace, ErrorReportingUI.UIKind.HyperLink, () => ShowDetailedErrorInfo(exception), closeAfterAction: false), + new ErrorReportingUI(WorkspacesResources.Enable, ErrorReportingUI.UIKind.Button, () => { EnableProvider(provider); LogEnableProvider(provider); }), + new ErrorReportingUI(WorkspacesResources.Enable_and_ignore_future_errors, ErrorReportingUI.UIKind.Button, () => { EnableProvider(provider); LogEnableProvider(provider); }), + new ErrorReportingUI(String.Empty, ErrorReportingUI.UIKind.Close, () => LogLeaveDisabled(provider))); } else { @@ -93,6 +93,11 @@ public override void HandleException(object provider, Exception exception) _errorLoggerService?.LogException(provider, exception); } + private void ShowDetailedErrorInfo(Exception exception) + { + _errorReportingService.ShowDetailedErrorInfo(exception); + } + private static void LogLeaveDisabled(object provider) { LogAction(CodefixInfobar_LeaveDisabled, provider); diff --git a/src/EditorFeatures/Core/Implementation/Workspaces/EditorErrorReportingService.cs b/src/EditorFeatures/Core/Implementation/Workspaces/EditorErrorReportingService.cs index 47ab1704e5ecc..7a9fb43684a47 100644 --- a/src/EditorFeatures/Core/Implementation/Workspaces/EditorErrorReportingService.cs +++ b/src/EditorFeatures/Core/Implementation/Workspaces/EditorErrorReportingService.cs @@ -8,9 +8,9 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.Workspaces { internal class EditorErrorReportingService : IErrorReportingService { - public void ShowErrorInfoForCodeFix(string codefixName, Action OnEnable, Action OnEnableAndIgnore, Action OnClose) + public void ShowDetailedErrorInfo(Exception exception) { - ShowErrorInfo($"{codefixName} crashed"); + Logger.Log(FunctionId.Extension_Exception, exception.StackTrace); } public void ShowErrorInfo(string message, params ErrorReportingUI[] items) diff --git a/src/EditorFeatures/VisualBasicTest/BasicEditorServicesTest.vbproj b/src/EditorFeatures/VisualBasicTest/BasicEditorServicesTest.vbproj index ad2f2dc3bef80..1e180a5bfc497 100644 --- a/src/EditorFeatures/VisualBasicTest/BasicEditorServicesTest.vbproj +++ b/src/EditorFeatures/VisualBasicTest/BasicEditorServicesTest.vbproj @@ -167,7 +167,7 @@ - + @@ -618,4 +618,4 @@ - + \ No newline at end of file diff --git a/src/EditorFeatures/VisualBasicTest/Diagnostics/Async/AddAsyncTests.vb b/src/EditorFeatures/VisualBasicTest/Diagnostics/MakeMethodAsynchronous/MakeMethodAsynchronousTests.vb similarity index 84% rename from src/EditorFeatures/VisualBasicTest/Diagnostics/Async/AddAsyncTests.vb rename to src/EditorFeatures/VisualBasicTest/Diagnostics/MakeMethodAsynchronous/MakeMethodAsynchronousTests.vb index 1bd958cfee680..033a32035b39a 100644 --- a/src/EditorFeatures/VisualBasicTest/Diagnostics/Async/AddAsyncTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Diagnostics/MakeMethodAsynchronous/MakeMethodAsynchronousTests.vb @@ -2,17 +2,23 @@ Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.Diagnostics -Imports Microsoft.CodeAnalysis.VisualBasic.CodeFixes.Async +Imports Microsoft.CodeAnalysis.VisualBasic.MakeMethodAsynchronous -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.Async - Public Class AddAsyncTests +Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.MakeMethodAsynchronous + Public Class MakeMethodAsynchronousTests Inherits AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest + Friend Overrides Function CreateDiagnosticProviderAndFixer(workspace As Workspace) As Tuple(Of DiagnosticAnalyzer, CodeFixProvider) + Return Tuple.Create(Of DiagnosticAnalyzer, CodeFixProvider)( + Nothing, + New VisualBasicMakeMethodAsynchronousCodeFixProvider()) + End Function + Public Async Function TestAwaitInSubNoModifiers() As Task Await TestAsync( NewLines("Imports System \n Imports System.Threading.Tasks \n Module Program \n Sub Test() \n [|Await Task.Delay(1)|] \n End Sub \n End Module"), - NewLines("Imports System \n Imports System.Threading.Tasks \n Module Program \n Async Sub Test() \n Await Task.Delay(1) \n End Sub \n End Module") + NewLines("Imports System \n Imports System.Threading.Tasks \n Module Program \n Async Sub TestAsync() \n Await Task.Delay(1) \n End Sub \n End Module") ) End Function @@ -20,7 +26,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.Async Public Async Function TestAwaitInSubWithModifiers() As Task Await TestAsync( NewLines("Imports System \n Imports System.Threading.Tasks \n Module Program \n Public Shared Sub Test() \n [|Await Task.Delay(1)|] \n End Sub \n End Module"), - NewLines("Imports System \n Imports System.Threading.Tasks \n Module Program \n Public Shared Async Sub Test() \n Await Task.Delay(1) \n End Sub \n End Module") + NewLines("Imports System \n Imports System.Threading.Tasks \n Module Program \n Public Shared Async Sub TestAsync() \n Await Task.Delay(1) \n End Sub \n End Module") ) End Function @@ -28,7 +34,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.Async Public Async Function TestAwaitInFunctionNoModifiers() As Task Await TestAsync( NewLines("Imports System \n Imports System.Threading.Tasks \n Module Program \n Function Test() As Integer \n [|Await Task.Delay(1)|] \n Function Sub \n End Module"), - NewLines("Imports System \n Imports System.Threading.Tasks \n Module Program \n Async Function Test() As Task(Of Integer) \n Await Task.Delay(1) \n Function Sub \n End Module") + NewLines("Imports System \n Imports System.Threading.Tasks \n Module Program \n Async Function TestAsync() As Task(Of Integer) \n Await Task.Delay(1) \n Function Sub \n End Module") ) End Function @@ -36,7 +42,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.Async Public Async Function TestAwaitInFunctionWithModifiers() As Task Await TestAsync( NewLines("Imports System \n Imports System.Threading.Tasks \n Module Program \n Public Shared Function Test() As Integer \n [|Await Task.Delay(1)|] \n Function Sub \n End Module"), - NewLines("Imports System \n Imports System.Threading.Tasks \n Module Program \n Public Shared Async Function Test() As Task(Of Integer) \n Await Task.Delay(1) \n Function Sub \n End Module") + NewLines("Imports System \n Imports System.Threading.Tasks \n Module Program \n Public Shared Async Function TestAsync() As Task(Of Integer) \n Await Task.Delay(1) \n Function Sub \n End Module") ) End Function @@ -91,7 +97,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.Async Dim expected = - Async Function rtrt() As Task + Async Function rtrtAsync() As Task Await Nothing End Function @@ -108,13 +114,30 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.Async Dim expected = - Async Sub rtrt() + Async Sub rtrtAsync() Await Nothing End Sub Await TestAsync(initial, expected) End Function + + Public Async Function TestBadAwaitInNonAsyncVoidMethod1() As Task + Dim initial = + + Sub rtrt() + [|Await Nothing|] + End Sub + + Dim expected = + + Async Function rtrtAsync() As Threading.Tasks.Task + Await Nothing + End Function + + Await TestAsync(initial, expected, index:=1) + End Function + Public Async Function TestBadAwaitInNonAsyncFunction() As Task Dim initial = @@ -125,7 +148,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.Async Dim expected = - Async Function rtrt() As Task + Async Function rtrtAsync() As Task Await Nothing End Function @@ -142,7 +165,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.Async Dim expected = - Async Function rtrt() As Task(Of Integer) + Async Function rtrtAsync() As Task(Of Integer) Await Nothing End Function @@ -159,7 +182,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.Async Dim expected = - Async Function rtrt() As Threading.Tasks.Task(Of Integer) + Async Function rtrtAsync() As Threading.Tasks.Task(Of Integer) Await Nothing End Function @@ -179,7 +202,7 @@ End Class Dim expected = Class Program - Async Function rtrt() As Task + Async Function rtrtAsync() As Task Await Nothing End Function End Class @@ -200,7 +223,7 @@ End Class Dim expected = Class Program - Async Function rtrt() As Task(Of Integer) + Async Function rtrtAsync() As Task(Of Integer) Await Nothing End Function End Class @@ -221,7 +244,7 @@ End Class Dim expected = Class Program - Async Function rtrt() As System.Threading.Tasks.Task(Of Integer) + Async Function rtrtAsync() As System.Threading.Tasks.Task(Of Integer) Await Nothing End Function End Class @@ -242,7 +265,7 @@ End Class Dim expected = Class Program - Async Function rtrt() As System.Threading.Tasks.Task(Of Program) + Async Function rtrtAsync() As System.Threading.Tasks.Task(Of Program) Await Nothing End Function End Class @@ -263,7 +286,7 @@ End Class Dim expected = Class Program - Async Function rtrt() As System.Threading.Tasks.Task(Of asdf) + Async Function rtrtAsync() As System.Threading.Tasks.Task(Of asdf) Await Nothing End Function End Class @@ -288,11 +311,5 @@ End Module Await TestMissingAsync(initial) End Function - - Friend Overrides Function CreateDiagnosticProviderAndFixer(workspace As Workspace) As Tuple(Of DiagnosticAnalyzer, CodeFixProvider) - Return Tuple.Create(Of DiagnosticAnalyzer, CodeFixProvider)( - Nothing, - New VisualBasicAddAsyncCodeFixProvider()) - End Function End Class End Namespace diff --git a/src/Features/CSharp/Portable/CSharpFeatures.csproj b/src/Features/CSharp/Portable/CSharpFeatures.csproj index df90dcedee2e0..c2fe6118634f4 100644 --- a/src/Features/CSharp/Portable/CSharpFeatures.csproj +++ b/src/Features/CSharp/Portable/CSharpFeatures.csproj @@ -66,7 +66,6 @@ - @@ -329,6 +328,7 @@ + diff --git a/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs b/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs index a189d87ffca87..d39049e97648f 100644 --- a/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs +++ b/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs @@ -548,15 +548,6 @@ internal static string Make_0_return_Task_instead_of_void { } } - /// - /// Looks up a localized string similar to Make the containing scope 'async'.. - /// - internal static string Make_the_containing_scope_async { - get { - return ResourceManager.GetString("Make_the_containing_scope_async", resourceCulture); - } - } - /// /// Looks up a localized string similar to <member name> = . /// diff --git a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx index ee60746116c07..a6ead4e6be7e9 100644 --- a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx +++ b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx @@ -255,9 +255,6 @@ Insert 'await'. - - Make the containing scope 'async'. - Make {0} return Task instead of void. diff --git a/src/Features/CSharp/Portable/CodeFixes/Async/CSharpAddAsyncCodeFixProvider.cs b/src/Features/CSharp/Portable/CodeFixes/Async/CSharpAddAsyncCodeFixProvider.cs deleted file mode 100644 index 905fa1d2525c9..0000000000000 --- a/src/Features/CSharp/Portable/CodeFixes/Async/CSharpAddAsyncCodeFixProvider.cs +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Immutable; -using System.Composition; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CodeFixes.Async; -using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Shared.Extensions; - -namespace Microsoft.CodeAnalysis.CSharp.CodeFixes.Async -{ - [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.AddAsync), Shared] - internal class CSharpAddAsyncCodeFixProvider : AbstractAddAsyncCodeFixProvider - { - /// - /// The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'. - /// - private const string CS4032 = nameof(CS4032); - - /// - /// The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'. - /// - private const string CS4033 = nameof(CS4033); - - /// - /// The 'await' operator can only be used within an async lambda expression. Consider marking this method with the 'async' modifier. - /// - private const string CS4034 = nameof(CS4034); - - public override ImmutableArray FixableDiagnosticIds - { - get { return ImmutableArray.Create(CS4032, CS4033, CS4034); } - } - - protected override string GetDescription(Diagnostic diagnostic, SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken) - { - return CSharpFeaturesResources.Make_the_containing_scope_async; - } - - protected override async Task GetNewRoot(SyntaxNode root, SyntaxNode oldNode, SemanticModel semanticModel, Diagnostic diagnostic, Document document, CancellationToken cancellationToken) - { - var nodeToModify = GetContainingMember(oldNode); - if (nodeToModify == null) - { - return null; - } - - var modifiedNode = await ConvertToAsync(nodeToModify, semanticModel, document, cancellationToken).ConfigureAwait(false); - if (modifiedNode != null) - { - return root.ReplaceNode(nodeToModify, modifiedNode); - } - - return null; - } - - private static SyntaxNode GetContainingMember(SyntaxNode oldNode) - { - foreach (var node in oldNode.Ancestors()) - { - switch (node.Kind()) - { - case SyntaxKind.ParenthesizedLambdaExpression: - case SyntaxKind.SimpleLambdaExpression: - case SyntaxKind.AnonymousMethodExpression: - if ((node as AnonymousFunctionExpressionSyntax)?.AsyncKeyword.Kind() != SyntaxKind.AsyncKeyword) - { - return node; - } - break; - case SyntaxKind.MethodDeclaration: - if ((node as MethodDeclarationSyntax)?.Modifiers.Any(SyntaxKind.AsyncKeyword) == false) - { - return node; - } - break; - default: - continue; - } - } - - return null; - } - - private Task ConvertToAsync(SyntaxNode node, SemanticModel semanticModel, Document document, CancellationToken cancellationToken) - { - return node.TypeSwitch( - (MethodDeclarationSyntax methodNode) => ConvertMethodToAsync(document, semanticModel, methodNode, cancellationToken), - (ParenthesizedLambdaExpressionSyntax parenthesizedLambda) => Task.FromResult(ConvertParenthesizedLambdaToAsync(parenthesizedLambda)), - (SimpleLambdaExpressionSyntax simpleLambda) => Task.FromResult(ConvertSimpleLambdaToAsync(simpleLambda)), - (AnonymousMethodExpressionSyntax anonymousMethod) => Task.FromResult(ConvertAnonymousMethodToAsync(anonymousMethod)), - @default => Task.FromResult(null)); - } - - private static SyntaxNode ConvertParenthesizedLambdaToAsync(ParenthesizedLambdaExpressionSyntax parenthesizedLambda) - { - return SyntaxFactory.ParenthesizedLambdaExpression( - SyntaxFactory.Token(SyntaxKind.AsyncKeyword), - parenthesizedLambda.ParameterList, - parenthesizedLambda.ArrowToken, - parenthesizedLambda.Body) - .WithTriviaFrom(parenthesizedLambda) - .WithAdditionalAnnotations(Formatter.Annotation); - } - - private static SyntaxNode ConvertSimpleLambdaToAsync(SimpleLambdaExpressionSyntax simpleLambda) - { - return SyntaxFactory.SimpleLambdaExpression( - SyntaxFactory.Token(SyntaxKind.AsyncKeyword), - simpleLambda.Parameter, - simpleLambda.ArrowToken, - simpleLambda.Body) - .WithTriviaFrom(simpleLambda) - .WithAdditionalAnnotations(Formatter.Annotation); - } - - private static SyntaxNode ConvertAnonymousMethodToAsync(AnonymousMethodExpressionSyntax anonymousMethod) - { - return SyntaxFactory.AnonymousMethodExpression( - SyntaxFactory.Token(SyntaxKind.AsyncKeyword), - anonymousMethod.DelegateKeyword, - anonymousMethod.ParameterList, - anonymousMethod.Block) - .WithTriviaFrom(anonymousMethod) - .WithAdditionalAnnotations(Formatter.Annotation); - } - - protected override SyntaxNode AddAsyncKeyword(SyntaxNode node) - { - var methodNode = node as MethodDeclarationSyntax; - if (methodNode == null) - { - return null; - } - - return methodNode - .AddModifiers(SyntaxFactory.Token(SyntaxKind.AsyncKeyword)) - .WithAdditionalAnnotations(Formatter.Annotation); - } - - protected override SyntaxNode AddAsyncKeywordAndTaskReturnType(SyntaxNode node, ITypeSymbol existingReturnType, INamedTypeSymbol taskTypeSymbol) - { - var methodNode = node as MethodDeclarationSyntax; - if (methodNode == null) - { - return null; - } - - if (taskTypeSymbol == null) - { - return null; - } - - var returnType = taskTypeSymbol.Construct(existingReturnType).GenerateTypeSyntax(); - return AddAsyncKeyword(methodNode.WithReturnType(returnType)); - } - - protected override bool DoesConversionExist(Compilation compilation, ITypeSymbol source, ITypeSymbol destination) - { - return compilation.ClassifyConversion(source, destination).Exists; - } - } -} diff --git a/src/Features/CSharp/Portable/CodeFixes/Async/CSharpAddAwaitCodeFixProvider.cs b/src/Features/CSharp/Portable/CodeFixes/Async/CSharpAddAwaitCodeFixProvider.cs index 49f5431d1af8e..82e2076a1c31d 100644 --- a/src/Features/CSharp/Portable/CodeFixes/Async/CSharpAddAwaitCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/CodeFixes/Async/CSharpAddAwaitCodeFixProvider.cs @@ -1,5 +1,7 @@ // 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.Composition; using System.Linq; @@ -17,7 +19,7 @@ namespace Microsoft.CodeAnalysis.CSharp.CodeFixes.Async { [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.AddAwait), Shared] - internal class CSharpAddAwaitCodeFixProvider : AbstractAddAsyncAwaitCodeFixProvider + internal class CSharpAddAwaitCodeFixProvider : AbstractAddAwaitCodeFixProvider { /// /// Because this call is not awaited, execution of the current method continues before the call is completed. @@ -36,10 +38,20 @@ internal class CSharpAddAwaitCodeFixProvider : AbstractAddAsyncAwaitCodeFixProvi public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(CS0029, CS4014, CS4016); - protected override string GetDescription(Diagnostic diagnostic, SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken) => - CSharpFeaturesResources.Insert_await; + protected override async Task GetDescriptionAndNodeAsync( + SyntaxNode root, SyntaxNode oldNode, SemanticModel semanticModel, Diagnostic diagnostic, Document document, CancellationToken cancellationToken) + { + var newRoot = await GetNewRootAsync( + root, oldNode, semanticModel, diagnostic, document, cancellationToken).ConfigureAwait(false); + if (newRoot == null) + { + return default(DescriptionAndNode); + } + + return new DescriptionAndNode(CSharpFeaturesResources.Insert_await, newRoot); + } - protected override Task GetNewRoot( + private Task GetNewRootAsync( SyntaxNode root, SyntaxNode oldNode, SemanticModel semanticModel, diff --git a/src/Features/CSharp/Portable/MakeMethodAsynchronous/CSharpMakeMethodAsynchronousCodeFixProvider.cs b/src/Features/CSharp/Portable/MakeMethodAsynchronous/CSharpMakeMethodAsynchronousCodeFixProvider.cs new file mode 100644 index 0000000000000..dabb0290fefc7 --- /dev/null +++ b/src/Features/CSharp/Portable/MakeMethodAsynchronous/CSharpMakeMethodAsynchronousCodeFixProvider.cs @@ -0,0 +1,87 @@ +// 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.Immutable; +using System.Composition; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.MakeMethodAsynchronous; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.CSharp.MakeMethodAsynchronous +{ + [ExportCodeFixProvider(LanguageNames.CSharp), Shared] + internal class CSharpMakeMethodAsynchronousCodeFixProvider : AbstractMakeMethodAsynchronousCodeFixProvider + { + private const string CS4032 = nameof(CS4032); // The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'. + private const string CS4033 = nameof(CS4033); // The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'. + private const string CS4034 = nameof(CS4034); // The 'await' operator can only be used within an async lambda expression. Consider marking this method with the 'async' modifier. + + private static readonly SyntaxToken s_asyncToken = SyntaxFactory.Token(SyntaxKind.AsyncKeyword); + + public override ImmutableArray FixableDiagnosticIds { get; } = + ImmutableArray.Create(CS4032, CS4033, CS4034); + + protected override bool IsMethodOrAnonymousFunction(SyntaxNode node) + { + return node.IsKind(SyntaxKind.MethodDeclaration) || node.IsAnyLambdaOrAnonymousMethod(); + } + + protected override SyntaxNode AddAsyncTokenAndFixReturnType( + bool keepVoid, IMethodSymbol methodSymbolOpt, SyntaxNode node, + INamedTypeSymbol taskType, INamedTypeSymbol taskOfTType) + { + return node.TypeSwitch( + (MethodDeclarationSyntax method) => FixMethod(keepVoid, methodSymbolOpt, method, taskType, taskOfTType), + (AnonymousMethodExpressionSyntax method) => FixAnonymousMethod(method), + (ParenthesizedLambdaExpressionSyntax lambda) => FixParenthesizedLambda(lambda), + (SimpleLambdaExpressionSyntax lambda) => FixSimpleLambda(lambda), + _ => node); + } + + private SyntaxNode FixMethod( + bool keepVoid, IMethodSymbol methodSymbol, MethodDeclarationSyntax method, + ITypeSymbol taskType, INamedTypeSymbol taskOfTType) + { + var newReturnType = method.ReturnType; + + if (methodSymbol.ReturnsVoid) + { + if (!keepVoid) + { + newReturnType = taskType.GenerateTypeSyntax(); + } + } + else + { + if (!IsTaskLike(methodSymbol.ReturnType, taskType, taskOfTType)) + { + // If it's not already Task-like, then wrap the existing return type + // in Task<>. + newReturnType = taskOfTType.Construct(methodSymbol.ReturnType).GenerateTypeSyntax(); + } + } + + var newModifiers = method.Modifiers.Add(s_asyncToken); + return method.WithReturnType(newReturnType).WithModifiers(newModifiers); + } + + private SyntaxNode FixParenthesizedLambda(ParenthesizedLambdaExpressionSyntax lambda) + { + return lambda.WithoutLeadingTrivia() + .WithAsyncKeyword(s_asyncToken.WithPrependedLeadingTrivia(lambda.GetLeadingTrivia())); + } + + private SyntaxNode FixSimpleLambda(SimpleLambdaExpressionSyntax lambda) + { + return lambda.WithoutLeadingTrivia() + .WithAsyncKeyword(s_asyncToken.WithPrependedLeadingTrivia(lambda.GetLeadingTrivia())); + } + + private SyntaxNode FixAnonymousMethod(AnonymousMethodExpressionSyntax method) + { + return method.WithoutLeadingTrivia() + .WithAsyncKeyword(s_asyncToken.WithPrependedLeadingTrivia(method.GetLeadingTrivia())); + } + } +} \ No newline at end of file diff --git a/src/Features/CSharp/Portable/ReplacePropertyWithMethods/CSharpReplacePropertyWithMethodsService.cs b/src/Features/CSharp/Portable/ReplacePropertyWithMethods/CSharpReplacePropertyWithMethodsService.cs index 357cb1f696722..1088def4cedc7 100644 --- a/src/Features/CSharp/Portable/ReplacePropertyWithMethods/CSharpReplacePropertyWithMethodsService.cs +++ b/src/Features/CSharp/Portable/ReplacePropertyWithMethods/CSharpReplacePropertyWithMethodsService.cs @@ -132,8 +132,13 @@ private static SyntaxNode GetGetMethod( if (propertyDeclaration.ExpressionBody != null) { - var returnStatement = SyntaxFactory.ReturnStatement(propertyDeclaration.ExpressionBody.Expression) - .WithSemicolonToken(propertyDeclaration.SemicolonToken); + var returnKeyword = SyntaxFactory.Token(SyntaxKind.ReturnKeyword) + .WithTrailingTrivia(propertyDeclaration.ExpressionBody.ArrowToken.TrailingTrivia); + + var returnStatement = SyntaxFactory.ReturnStatement( + returnKeyword, + propertyDeclaration.ExpressionBody.Expression, + propertyDeclaration.SemicolonToken); statements.Add(returnStatement); } else diff --git a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.ProjectSymbolReference.cs b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.ProjectSymbolReference.cs index 20d90a98cb559..3c02f29ed2c26 100644 --- a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.ProjectSymbolReference.cs +++ b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.ProjectSymbolReference.cs @@ -47,21 +47,11 @@ protected override CodeActionPriority GetPriority(Document document) if (document.Project.Id == _project.Id) { - if (!SearchResult.DesiredNameDiffersFromSourceName()) + if (SearchResult.DesiredNameMatchesSourceName(document)) { // The name doesn't change. This is a normal priority action. return CodeActionPriority.Medium; } - - // We need to update the source name. If all we're doing is changing the - // casing, and this is a case insensitive language, then this is just a - // normal priority action. Otherwise, this wil be low priority. - var syntaxFacts = document.GetLanguageService(); - if (!syntaxFacts.IsCaseSensitive && - SearchResult.DesiredNameDiffersFromSourceNameOnlyByCase()) - { - return CodeActionPriority.Medium; - } } // This is a weaker match. This should be lower than all other fixes. diff --git a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.Reference.cs b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.Reference.cs index e1099ef9ced7b..dbfdcd787a0fb 100644 --- a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.Reference.cs +++ b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.Reference.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CodeFixes.AddImport { internal abstract partial class AbstractAddImportCodeFixProvider { - private abstract class Reference : IComparable, IEquatable + private abstract class Reference : IEquatable { protected readonly AbstractAddImportCodeFixProvider provider; public readonly SearchResult SearchResult; @@ -24,7 +24,7 @@ protected Reference(AbstractAddImportCodeFixProvider provider this.SearchResult = searchResult; } - public virtual int CompareTo(Reference other) + public int CompareTo(Document document, Reference other) { // If references have different weights, order by the ones with lower weight (i.e. // they are better matches). @@ -38,7 +38,36 @@ public virtual int CompareTo(Reference other) return 1; } - // If the weight are the same, just order them based on their names. + if (this.SearchResult.DesiredNameMatchesSourceName(document)) + { + if (!other.SearchResult.DesiredNameMatchesSourceName(document)) + { + // Prefer us as our name doesn't need to change. + return -1; + } + } + else + { + if (other.SearchResult.DesiredNameMatchesSourceName(document)) + { + // Prefer them as their name doesn't need to change. + return 1; + } + else + { + // Both our names need to change. Sort by the name we're + // changing to. + var diff = StringComparer.OrdinalIgnoreCase.Compare( + this.SearchResult.DesiredName, other.SearchResult.DesiredName); + if (diff != 0) + { + return diff; + } + } + } + + // If the weights are the same and no names changed, just order + // them based on the namespace we're adding an import for. return INamespaceOrTypeSymbolExtensions.CompareNameParts( this.SearchResult.NameParts, other.SearchResult.NameParts); } diff --git a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SymbolReference.cs b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SymbolReference.cs index 1db72b539b73c..daa4ecf13b6aa 100644 --- a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SymbolReference.cs +++ b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SymbolReference.cs @@ -26,19 +26,6 @@ public SymbolReference(AbstractAddImportCodeFixProvider provi protected abstract Glyph? GetGlyph(Document document); protected abstract bool CheckForExistingImport(Project project); - public override int CompareTo(Reference other) - { - var diff = base.CompareTo(other); - if (diff != 0) - { - return diff; - } - - var name1 = this.SymbolResult.DesiredName; - var name2 = (other as SymbolReference)?.SymbolResult.DesiredName; - return StringComparer.Ordinal.Compare(name1, name2); - } - public override bool Equals(object obj) { var equals = base.Equals(obj); @@ -88,6 +75,13 @@ public override async Task CreateCodeActionAsync( return null; } + if (!this.SearchResult.DesiredNameMatchesSourceName(document)) + { + // The name is going to change. Make it clear in the description that + // this is going to happen. + description = $"{this.SearchResult.DesiredName} - {description}"; + } + return new OperationBasedCodeAction(description, GetGlyph(document), GetPriority(document), c => this.GetOperationsAsync(document, node, placeSystemNamespaceFirst, c), this.GetIsApplicableCheck(document.Project)); diff --git a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SymbolReferenceFinder.cs b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SymbolReferenceFinder.cs index 7b36d278a005c..e19030d5575ca 100644 --- a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SymbolReferenceFinder.cs +++ b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SymbolReferenceFinder.cs @@ -74,10 +74,10 @@ private INamespaceSymbol MapToCompilationNamespaceIfPossible(INamespaceSymbol co return _semanticModel.Compilation.GetCompilationNamespace(containingNamespace) ?? containingNamespace; } - internal Task> FindInAllSymbolsInProjectAsync( - Project project, bool exact, CancellationToken cancellationToken) + internal Task> FindInAllSymbolsInStartingProjectAsync( + bool exact, CancellationToken cancellationToken) { - var searchScope = new AllSymbolsProjectSearchScope(_owner, project, exact, cancellationToken); + var searchScope = new AllSymbolsProjectSearchScope(_owner, _document.Project, exact, cancellationToken); return DoAsync(searchScope); } @@ -91,11 +91,11 @@ internal Task> FindInSourceSymbolsInProjectAsync( } internal Task> FindInMetadataSymbolsAsync( - Solution solution, IAssemblySymbol assembly, PortableExecutableReference metadataReference, + IAssemblySymbol assembly, PortableExecutableReference metadataReference, bool exact, CancellationToken cancellationToken) { var searchScope = new MetadataSymbolsSearchScope( - _owner, solution, assembly, metadataReference, exact, cancellationToken); + _owner, _document.Project.Solution, assembly, metadataReference, exact, cancellationToken); return DoAsync(searchScope); } @@ -153,7 +153,7 @@ private List DeDupeAndSortReferences(List allR .Distinct() .Where(NotNull) .Where(NotGlobalNamespace) - .Order() + .OrderBy((r1, r2) => r1.CompareTo(_document, r2)) .ToList(); } diff --git a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SymbolResult.cs b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SymbolResult.cs index 11e5aeaf2fdeb..5b6c869d31ab2 100644 --- a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SymbolResult.cs +++ b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SymbolResult.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CodeFixes.AddImport @@ -49,6 +50,27 @@ public bool DesiredNameDiffersFromSourceNameOnlyByCase() return StringComparer.OrdinalIgnoreCase.Equals( this.NameNode.GetFirstToken().ValueText, this.DesiredName); } + + public bool DesiredNameMatchesSourceName(Document document) + { + if (!this.DesiredNameDiffersFromSourceName()) + { + // Names match in any language. + return true; + } + + var syntaxFacts = document.GetLanguageService(); + + // Names differ. But in a case insensitive language they may match. + if (!syntaxFacts.IsCaseSensitive && + this.DesiredNameDiffersFromSourceNameOnlyByCase()) + { + return true; + } + + // Name are totally different in any language. + return false; + } } private struct SymbolResult where T : ISymbol diff --git a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.cs b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.cs index 09ac9f304b4fc..bc36903e9a2d1 100644 --- a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.cs +++ b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.cs @@ -160,8 +160,8 @@ private async Task> FindResultsAsync( // First search the current project to see if any symbols (source or metadata) match the // search string. - await FindResultsInAllProjectSymbolsAsync( - project, allReferences, finder, exact, cancellationToken).ConfigureAwait(false); + await FindResultsInAllSymbolsInStartingProjectAsync( + allReferences, finder, exact, cancellationToken).ConfigureAwait(false); // Only bother doing this for host workspaces. We don't want this for // things like the Interactive workspace as we can't even add project @@ -186,11 +186,11 @@ await FindResultsInAllProjectSymbolsAsync( return allReferences; } - private async Task FindResultsInAllProjectSymbolsAsync( - Project project, List allSymbolReferences, - SymbolReferenceFinder finder, bool exact, CancellationToken cancellationToken) + private async Task FindResultsInAllSymbolsInStartingProjectAsync( + List allSymbolReferences, SymbolReferenceFinder finder, + bool exact, CancellationToken cancellationToken) { - var references = await finder.FindInAllSymbolsInProjectAsync(project, exact, cancellationToken).ConfigureAwait(false); + var references = await finder.FindInAllSymbolsInStartingProjectAsync(exact, cancellationToken).ConfigureAwait(false); AddRange(allSymbolReferences, references); } @@ -272,7 +272,7 @@ private async Task FindResultsInUnreferencedMetadataSymbolsAsync( if (assembly != null) { findTasks.Add(finder.FindInMetadataSymbolsAsync( - project.Solution, assembly, reference, exact, linkedTokenSource.Token)); + assembly, reference, exact, linkedTokenSource.Token)); } } diff --git a/src/Features/Core/Portable/CodeFixes/Async/AbstractAddAsyncCodeFixProvider.cs b/src/Features/Core/Portable/CodeFixes/Async/AbstractAddAsyncCodeFixProvider.cs deleted file mode 100644 index 2ae03a8e0c2f8..0000000000000 --- a/src/Features/Core/Portable/CodeFixes/Async/AbstractAddAsyncCodeFixProvider.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; - -namespace Microsoft.CodeAnalysis.CodeFixes.Async -{ - internal abstract partial class AbstractAddAsyncCodeFixProvider : AbstractAddAsyncAwaitCodeFixProvider - { - protected const string SystemThreadingTasksTask = "System.Threading.Tasks.Task"; - protected const string SystemThreadingTasksTaskT = "System.Threading.Tasks.Task`1"; - protected abstract SyntaxNode AddAsyncKeyword(SyntaxNode methodNode); - protected abstract SyntaxNode AddAsyncKeywordAndTaskReturnType(SyntaxNode methodNode, ITypeSymbol existingReturnType, INamedTypeSymbol taskTypeSymbol); - protected abstract bool DoesConversionExist(Compilation compilation, ITypeSymbol source, ITypeSymbol destination); - - protected async Task ConvertMethodToAsync(Document document, SemanticModel semanticModel, SyntaxNode methodNode, CancellationToken cancellationToken) - { - var methodSymbol = semanticModel.GetDeclaredSymbol(methodNode, cancellationToken) as IMethodSymbol; - - if (methodSymbol.ReturnsVoid) - { - return AddAsyncKeyword(methodNode); - } - - var returnType = methodSymbol.ReturnType; - var compilation = semanticModel.Compilation; - - var taskSymbol = compilation.GetTypeByMetadataName(SystemThreadingTasksTask); - var genericTaskSymbol = compilation.GetTypeByMetadataName(SystemThreadingTasksTaskT); - if (taskSymbol == null) - { - return null; - } - - if (returnType is IErrorTypeSymbol) - { - // The return type of the method will not bind. This could happen for a lot of reasons. - // The type may not actually exist or the user could just be missing a using/import statement. - // We're going to try and see if there are any known types that have the same name as - // our return type, and then check if those are convertible to Task. If they are then - // we assume the user just has a missing using. If they are not, we wrap the return - // type in a generic Task. - var typeName = returnType.Name; - var syntaxFacts = document.Project.LanguageServices.GetService(); - var results = await SymbolFinder.FindDeclarationsAsync( - document.Project, typeName, ignoreCase: syntaxFacts.IsCaseSensitive, filter: SymbolFilter.Type, cancellationToken: cancellationToken).ConfigureAwait(false); - - if (results.OfType().Any(s => DoesConversionExist(compilation, s, taskSymbol))) - { - return AddAsyncKeyword(methodNode); - } - - return AddAsyncKeywordAndTaskReturnType(methodNode, returnType, genericTaskSymbol); - } - - if (DoesConversionExist(compilation, returnType, taskSymbol)) - { - return AddAsyncKeyword(methodNode); - } - - return AddAsyncKeywordAndTaskReturnType(methodNode, returnType, genericTaskSymbol); - } - } -} diff --git a/src/Features/Core/Portable/CodeFixes/Async/AbstractAddAsyncAwaitCodeFixProvider.cs b/src/Features/Core/Portable/CodeFixes/Async/AbstractAddAwaitCodeFixProvider.cs similarity index 53% rename from src/Features/Core/Portable/CodeFixes/Async/AbstractAddAsyncAwaitCodeFixProvider.cs rename to src/Features/Core/Portable/CodeFixes/Async/AbstractAddAwaitCodeFixProvider.cs index 7649b1c64f0b4..5d84473cd3935 100644 --- a/src/Features/Core/Portable/CodeFixes/Async/AbstractAddAsyncAwaitCodeFixProvider.cs +++ b/src/Features/Core/Portable/CodeFixes/Async/AbstractAddAwaitCodeFixProvider.cs @@ -1,30 +1,32 @@ // 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.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; namespace Microsoft.CodeAnalysis.CodeFixes.Async { - internal abstract partial class AbstractAddAsyncAwaitCodeFixProvider : AbstractAsyncCodeFix + internal abstract partial class AbstractAddAwaitCodeFixProvider : AbstractAsyncCodeFix { - protected abstract string GetDescription(Diagnostic diagnostic, SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken); - protected abstract Task GetNewRoot(SyntaxNode root, SyntaxNode oldNode, SemanticModel semanticModel, Diagnostic diagnostic, Document document, CancellationToken cancellationToken); + protected abstract Task GetDescriptionAndNodeAsync( + SyntaxNode root, SyntaxNode oldNode, SemanticModel semanticModel, Diagnostic diagnostic, Document document, CancellationToken cancellationToken); - protected override async Task GetCodeFix(SyntaxNode root, SyntaxNode node, Document document, Diagnostic diagnostic, CancellationToken cancellationToken) + protected override async Task GetCodeActionAsync( + SyntaxNode root, SyntaxNode node, Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var newRoot = await this.GetNewRoot(root, node, semanticModel, diagnostic, document, cancellationToken).ConfigureAwait(false); - if (newRoot != null) + var data = await this.GetDescriptionAndNodeAsync(root, node, semanticModel, diagnostic, document, cancellationToken).ConfigureAwait(false); + if (data.Node == null) { - return new MyCodeAction( - this.GetDescription(diagnostic, node, semanticModel, cancellationToken), - token => Task.FromResult(document.WithSyntaxRoot(newRoot))); + return null; } - return null; + return new MyCodeAction( + data.Description, + c => Task.FromResult(document.WithSyntaxRoot(data.Node))); } protected static bool TryGetExpressionType( @@ -51,5 +53,17 @@ public MyCodeAction(string title, Func> create { } } + + protected struct DescriptionAndNode + { + public readonly string Description; + public readonly SyntaxNode Node; + + public DescriptionAndNode(string description, SyntaxNode node) + { + Description = description; + Node = node; + } + } } -} +} \ No newline at end of file diff --git a/src/Features/Core/Portable/CodeFixes/Async/AbstractAsyncCodeFix.cs b/src/Features/Core/Portable/CodeFixes/Async/AbstractAsyncCodeFix.cs index e682ff9f47aaf..1e3abdbe5021c 100644 --- a/src/Features/Core/Portable/CodeFixes/Async/AbstractAsyncCodeFix.cs +++ b/src/Features/Core/Portable/CodeFixes/Async/AbstractAsyncCodeFix.cs @@ -1,5 +1,6 @@ // 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 System.Threading.Tasks; @@ -11,7 +12,8 @@ namespace Microsoft.CodeAnalysis.CodeFixes.Async { internal abstract partial class AbstractAsyncCodeFix : CodeFixProvider { - protected abstract Task GetCodeFix(SyntaxNode root, SyntaxNode node, Document document, Diagnostic diagnostic, CancellationToken cancellationToken); + protected abstract Task GetCodeActionAsync( + SyntaxNode root, SyntaxNode node, Document document, Diagnostic diagnostic, CancellationToken cancellationToken); public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { @@ -25,11 +27,11 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var diagnostic = context.Diagnostics.FirstOrDefault(); - var codeAction = await GetCodeFix(root, node, context.Document, diagnostic, context.CancellationToken).ConfigureAwait(false); - + var codeAction = await GetCodeActionAsync( + root, node, context.Document, diagnostic, context.CancellationToken).ConfigureAwait(false); if (codeAction != null) { - context.RegisterCodeFix(codeAction, diagnostic); + context.RegisterCodeFix(codeAction, context.Diagnostics); } } @@ -46,4 +48,4 @@ private bool TryGetNode(SyntaxNode root, TextSpan span, out SyntaxNode node) return node != null; } } -} +} \ No newline at end of file diff --git a/src/Features/Core/Portable/CodeFixes/Async/AbstractChangeToAsyncCodeFixProvider.cs b/src/Features/Core/Portable/CodeFixes/Async/AbstractChangeToAsyncCodeFixProvider.cs index 75efc23bc06fb..ccc879f3d625a 100644 --- a/src/Features/Core/Portable/CodeFixes/Async/AbstractChangeToAsyncCodeFixProvider.cs +++ b/src/Features/Core/Portable/CodeFixes/Async/AbstractChangeToAsyncCodeFixProvider.cs @@ -12,22 +12,23 @@ internal abstract partial class AbstractChangeToAsyncCodeFixProvider : AbstractA protected abstract Task GetDescription(Diagnostic diagnostic, SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken); protected abstract Task> GetRootInOtherSyntaxTree(SyntaxNode node, SemanticModel semanticModel, Diagnostic diagnostic, CancellationToken cancellationToken); - protected override async Task GetCodeFix(SyntaxNode root, SyntaxNode node, Document document, Diagnostic diagnostic, CancellationToken cancellationToken) + protected override async Task GetCodeActionAsync( + SyntaxNode root, SyntaxNode node, Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var result = await GetRootInOtherSyntaxTree(node, semanticModel, diagnostic, cancellationToken).ConfigureAwait(false); - if (result != null) + if (result == null) { - var syntaxTree = result.Item1; - var newRoot = result.Item2; - var otherDocument = document.Project.Solution.GetDocument(syntaxTree); - return new MyCodeAction( - await this.GetDescription(diagnostic, node, semanticModel, cancellationToken).ConfigureAwait(false), - token => Task.FromResult(otherDocument.WithSyntaxRoot(newRoot))); + return null; } - return null; + var syntaxTree = result.Item1; + var newRoot = result.Item2; + var otherDocument = document.Project.Solution.GetDocument(syntaxTree); + return new MyCodeAction( + await this.GetDescription(diagnostic, node, semanticModel, cancellationToken).ConfigureAwait(false), + token => Task.FromResult(otherDocument.WithSyntaxRoot(newRoot))); } private class MyCodeAction : CodeAction.DocumentChangeAction diff --git a/src/Features/Core/Portable/CodeFixes/CodeFixContextExtensions.cs b/src/Features/Core/Portable/CodeFixes/CodeFixContextExtensions.cs index b9d045b97c0ed..8a1226e45a66a 100644 --- a/src/Features/Core/Portable/CodeFixes/CodeFixContextExtensions.cs +++ b/src/Features/Core/Portable/CodeFixes/CodeFixContextExtensions.cs @@ -24,10 +24,13 @@ internal static void RegisterFixes(this CodeFixContext context, IEnumerable internal static void RegisterFixes(this CodeFixContext context, IEnumerable actions, ImmutableArray diagnostics) { - foreach (var action in actions) + if (actions != null) { - context.RegisterCodeFix(action, diagnostics); + foreach (var action in actions) + { + context.RegisterCodeFix(action, diagnostics); + } } } } -} +} \ No newline at end of file diff --git a/src/Features/Core/Portable/Features.csproj b/src/Features/Core/Portable/Features.csproj index fc6f5f5189de1..056a089bed8a6 100644 --- a/src/Features/Core/Portable/Features.csproj +++ b/src/Features/Core/Portable/Features.csproj @@ -110,8 +110,7 @@ - - + @@ -242,6 +241,7 @@ + diff --git a/src/Features/Core/Portable/FeaturesResources.Designer.cs b/src/Features/Core/Portable/FeaturesResources.Designer.cs index 900dd818cccb8..8ee89a72d4a6a 100644 --- a/src/Features/Core/Portable/FeaturesResources.Designer.cs +++ b/src/Features/Core/Portable/FeaturesResources.Designer.cs @@ -1620,6 +1620,42 @@ internal static string location_unknown { } } + /// + /// Looks up a localized string similar to Make containing scope async. + /// + internal static string Make_containing_scope_async { + get { + return ResourceManager.GetString("Make_containing_scope_async", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Make containing scope async (return Task). + /// + internal static string Make_containing_scope_async_return_Task { + get { + return ResourceManager.GetString("Make_containing_scope_async_return_Task", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Make method async. + /// + internal static string Make_method_async { + get { + return ResourceManager.GetString("Make_method_async", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Make method async (return Task). + /// + internal static string Make_method_async_return_Task { + get { + return ResourceManager.GetString("Make_method_async_return_Task", resourceCulture); + } + } + /// /// Looks up a localized string similar to Make method synchronous.. /// diff --git a/src/Features/Core/Portable/FeaturesResources.resx b/src/Features/Core/Portable/FeaturesResources.resx index bcbe9ba029b16..e81918e95442e 100644 --- a/src/Features/Core/Portable/FeaturesResources.resx +++ b/src/Features/Core/Portable/FeaturesResources.resx @@ -1046,6 +1046,18 @@ This version used in: {2} Remove tag + + Make containing scope async + + + Make containing scope async (return Task) + + + Make method async + + + Make method async (return Task) + (Unknown) diff --git a/src/Features/Core/Portable/MakeMethodAsyncOrSync/AbstractMakeMethodAsyncOrSyncCodeFixProvider.cs b/src/Features/Core/Portable/MakeMethodAsyncOrSync/AbstractMakeMethodAsyncOrSyncCodeFixProvider.cs new file mode 100644 index 0000000000000..0a4895e721451 --- /dev/null +++ b/src/Features/Core/Portable/MakeMethodAsyncOrSync/AbstractMakeMethodAsyncOrSyncCodeFixProvider.cs @@ -0,0 +1,150 @@ +// 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.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Rename; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.MakeMethodAsyncOrSync +{ + internal abstract class AbstractMakeMethodAsyncOrAsyncCodeFixProvider : CodeFixProvider + { + protected abstract bool IsMethodOrAnonymousFunction(SyntaxNode node); + protected abstract SyntaxNode AddAsyncTokenAndFixReturnType( + bool keepVoid, IMethodSymbol methodSymbolOpt, SyntaxNode node, + INamedTypeSymbol taskType, INamedTypeSymbol taskOfTType); + + public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + + public override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + var diagnostic = context.Diagnostics.First(); + var cancellationToken = context.CancellationToken; + + var node = GetContainingFunction(diagnostic, cancellationToken); + if (node == null) + { + return; + } + + var semanticModel = await context.Document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var symbol = semanticModel.GetDeclaredSymbol(node, cancellationToken) as IMethodSymbol; + + // If it's a void returning method, offer to keep the void return type, or convert to + // a Task return type. + if (symbol?.MethodKind == MethodKind.Ordinary && + symbol.ReturnsVoid) + { + context.RegisterCodeFix( + new MyCodeAction(FeaturesResources.Make_method_async, c => FixNodeAsync( + context.Document, diagnostic, keepVoid: true, cancellationToken: c)), + context.Diagnostics); + + context.RegisterCodeFix( + new MyCodeAction(FeaturesResources.Make_method_async_return_Task, c => FixNodeAsync( + context.Document, diagnostic, keepVoid: false, cancellationToken: c)), + context.Diagnostics); + } + else + { + context.RegisterCodeFix( + new MyCodeAction(FeaturesResources.Make_method_async, c => FixNodeAsync( + context.Document, diagnostic, keepVoid: false, cancellationToken: c)), + context.Diagnostics); + } + } + + private const string AsyncSuffix = "Async"; + + private async Task FixNodeAsync( + Document document, Diagnostic diagnostic, + bool keepVoid, CancellationToken cancellationToken) + { + var node = GetContainingFunction(diagnostic, cancellationToken); + + // See if we're on an actual method declaration (otherwise we're on a lambda declaration). + // If we're on a method declaration, we'll get an IMethodSymbol back. In that case, check + // if it has the 'Async' suffix, and remove that suffix if so. + var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var methodSymbolOpt = semanticModel.GetDeclaredSymbol(node) as IMethodSymbol; + + if (methodSymbolOpt?.MethodKind == MethodKind.Ordinary && + !methodSymbolOpt.Name.EndsWith(AsyncSuffix)) + { + return await RenameThenAddAsyncTokenAsync( + keepVoid, document, node, methodSymbolOpt, cancellationToken).ConfigureAwait(false); + } + else + { + return await AddAsyncTokenAsync( + keepVoid, document, methodSymbolOpt, node, cancellationToken).ConfigureAwait(false); + } + } + + private SyntaxNode GetContainingFunction(Diagnostic diagnostic, CancellationToken cancellationToken) + { + var token = diagnostic.Location.FindToken(cancellationToken); + var node = token.GetAncestor(IsMethodOrAnonymousFunction); + return node; + } + + private async Task RenameThenAddAsyncTokenAsync( + bool keepVoid, Document document, SyntaxNode node, + IMethodSymbol methodSymbol, CancellationToken cancellationToken) + { + var name = methodSymbol.Name; + var newName = name + AsyncSuffix; + var solution = document.Project.Solution; + + // Store the path to this node. That way we can find it post rename. + var syntaxPath = new SyntaxPath(node); + + // Rename the method to add the 'Async' suffix, then add the 'async' keyword. + var newSolution = await Renamer.RenameSymbolAsync(solution, methodSymbol, newName, solution.Options, cancellationToken).ConfigureAwait(false); + var newDocument = newSolution.GetDocument(document.Id); + var newRoot = await newDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + + SyntaxNode newNode; + if (syntaxPath.TryResolve(newRoot, out newNode)) + { + var semanticModel = await newDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var newMethod = (IMethodSymbol)semanticModel.GetDeclaredSymbol(newNode, cancellationToken); + return await AddAsyncTokenAsync(keepVoid, newDocument, newMethod, newNode, cancellationToken).ConfigureAwait(false); + } + + return newSolution; + } + + private async Task AddAsyncTokenAsync( + bool keepVoid, Document document, IMethodSymbol methodSymbolOpt, + SyntaxNode node, CancellationToken cancellationToken) + { + var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); + var taskType = compilation.GetTypeByMetadataName("System.Threading.Tasks.Task"); + var taskOfTType = compilation.GetTypeByMetadataName("System.Threading.Tasks.Task`1"); + + var newNode = AddAsyncTokenAndFixReturnType(keepVoid, methodSymbolOpt, node, taskType, taskOfTType) + .WithAdditionalAnnotations(Formatter.Annotation); + + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var newRoot = root.ReplaceNode(node, newNode); + + var newDocument = document.WithSyntaxRoot(newRoot); + return newDocument.Project.Solution; + } + + private class MyCodeAction : CodeAction.SolutionChangeAction + { + public MyCodeAction(string title, Func> createChangedSolution) + : base(title, createChangedSolution, equivalenceKey: title) + { + } + } + } +} \ No newline at end of file diff --git a/src/Features/Core/Portable/MakeMethodAsyncOrSync/AbstractMakeMethodAsynchronousCodeFixProvider.cs b/src/Features/Core/Portable/MakeMethodAsyncOrSync/AbstractMakeMethodAsynchronousCodeFixProvider.cs new file mode 100644 index 0000000000000..7d596e1ea25d1 --- /dev/null +++ b/src/Features/Core/Portable/MakeMethodAsyncOrSync/AbstractMakeMethodAsynchronousCodeFixProvider.cs @@ -0,0 +1,150 @@ +// 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.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Rename; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.MakeMethodAsynchronous +{ + internal abstract class AbstractMakeMethodAsynchronousCodeFixProvider : CodeFixProvider + { + protected abstract bool IsMethodOrAnonymousFunction(SyntaxNode node); + protected abstract SyntaxNode AddAsyncTokenAndFixReturnType( + bool keepVoid, IMethodSymbol methodSymbolOpt, SyntaxNode node, + INamedTypeSymbol taskType, INamedTypeSymbol taskOfTType); + + public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + + public override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + var diagnostic = context.Diagnostics.First(); + var cancellationToken = context.CancellationToken; + + var node = GetContainingFunction(diagnostic, cancellationToken); + if (node == null) + { + return; + } + + var semanticModel = await context.Document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var symbol = semanticModel.GetDeclaredSymbol(node, cancellationToken) as IMethodSymbol; + + // If it's a void returning method, offer to keep the void return type, or convert to + // a Task return type. + if (symbol?.MethodKind == MethodKind.Ordinary && + symbol.ReturnsVoid) + { + context.RegisterCodeFix( + new MyCodeAction(FeaturesResources.Make_method_async, c => FixNodeAsync( + context.Document, diagnostic, keepVoid: true, cancellationToken: c)), + context.Diagnostics); + + context.RegisterCodeFix( + new MyCodeAction(FeaturesResources.Make_method_async_return_Task, c => FixNodeAsync( + context.Document, diagnostic, keepVoid: false, cancellationToken: c)), + context.Diagnostics); + } + else + { + context.RegisterCodeFix( + new MyCodeAction(FeaturesResources.Make_method_async, c => FixNodeAsync( + context.Document, diagnostic, keepVoid: false, cancellationToken: c)), + context.Diagnostics); + } + } + + private const string AsyncSuffix = "Async"; + + private async Task FixNodeAsync( + Document document, Diagnostic diagnostic, + bool keepVoid, CancellationToken cancellationToken) + { + var node = GetContainingFunction(diagnostic, cancellationToken); + + // See if we're on an actual method declaration (otherwise we're on a lambda declaration). + // If we're on a method declaration, we'll get an IMethodSymbol back. In that case, check + // if it has the 'Async' suffix, and remove that suffix if so. + var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var methodSymbolOpt = semanticModel.GetDeclaredSymbol(node) as IMethodSymbol; + + if (methodSymbolOpt?.MethodKind == MethodKind.Ordinary && + !methodSymbolOpt.Name.EndsWith(AsyncSuffix)) + { + return await RenameThenAddAsyncTokenAsync( + keepVoid, document, node, methodSymbolOpt, cancellationToken).ConfigureAwait(false); + } + else + { + return await AddAsyncTokenAsync( + keepVoid, document, methodSymbolOpt, node, cancellationToken).ConfigureAwait(false); + } + } + + private SyntaxNode GetContainingFunction(Diagnostic diagnostic, CancellationToken cancellationToken) + { + var token = diagnostic.Location.FindToken(cancellationToken); + var node = token.GetAncestor(IsMethodOrAnonymousFunction); + return node; + } + + private async Task RenameThenAddAsyncTokenAsync( + bool keepVoid, Document document, SyntaxNode node, + IMethodSymbol methodSymbol, CancellationToken cancellationToken) + { + var name = methodSymbol.Name; + var newName = name + AsyncSuffix; + var solution = document.Project.Solution; + + // Store the path to this node. That way we can find it post rename. + var syntaxPath = new SyntaxPath(node); + + // Rename the method to add the 'Async' suffix, then add the 'async' keyword. + var newSolution = await Renamer.RenameSymbolAsync(solution, methodSymbol, newName, solution.Options, cancellationToken).ConfigureAwait(false); + var newDocument = newSolution.GetDocument(document.Id); + var newRoot = await newDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + + SyntaxNode newNode; + if (syntaxPath.TryResolve(newRoot, out newNode)) + { + var semanticModel = await newDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var newMethod = (IMethodSymbol)semanticModel.GetDeclaredSymbol(newNode, cancellationToken); + return await AddAsyncTokenAsync(keepVoid, newDocument, newMethod, newNode, cancellationToken).ConfigureAwait(false); + } + + return newSolution; + } + + private async Task AddAsyncTokenAsync( + bool keepVoid, Document document, IMethodSymbol methodSymbolOpt, + SyntaxNode node, CancellationToken cancellationToken) + { + var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); + var taskType = compilation.GetTypeByMetadataName("System.Threading.Tasks.Task"); + var taskOfTType = compilation.GetTypeByMetadataName("System.Threading.Tasks.Task`1"); + + var newNode = AddAsyncTokenAndFixReturnType(keepVoid, methodSymbolOpt, node, taskType, taskOfTType) + .WithAdditionalAnnotations(Formatter.Annotation); + + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var newRoot = root.ReplaceNode(node, newNode); + + var newDocument = document.WithSyntaxRoot(newRoot); + return newDocument.Project.Solution; + } + + private class MyCodeAction : CodeAction.SolutionChangeAction + { + public MyCodeAction(string title, Func> createChangedSolution) + : base(title, createChangedSolution, equivalenceKey: title) + { + } + } + } +} \ No newline at end of file diff --git a/src/Features/Core/Portable/MakeMethodAsyncOrSync/AbstractMakeMethodSynchronousCodeFixProvider.cs b/src/Features/Core/Portable/MakeMethodAsyncOrSync/AbstractMakeMethodSynchronousCodeFixProvider.cs new file mode 100644 index 0000000000000..b608ef6fdf182 --- /dev/null +++ b/src/Features/Core/Portable/MakeMethodAsyncOrSync/AbstractMakeMethodSynchronousCodeFixProvider.cs @@ -0,0 +1,108 @@ +// 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.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Rename; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.MakeMethodSynchronous +{ + internal abstract class AbstractMakeMethodSynchronousCodeFixProvider : CodeFixProvider + { + public static readonly string EquivalenceKey = FeaturesResources.Make_method_synchronous; + + protected abstract bool IsMethodOrAnonymousFunction(SyntaxNode node); + protected abstract SyntaxNode RemoveAsyncTokenAndFixReturnType(IMethodSymbol methodSymbolOpt, SyntaxNode node, ITypeSymbol taskType, ITypeSymbol taskOfTType); + + public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + + public override Task RegisterCodeFixesAsync(CodeFixContext context) + { + context.RegisterCodeFix( + new MyCodeAction(c => FixNodeAsync(context.Document, context.Diagnostics.First(), c)), + context.Diagnostics); + return SpecializedTasks.EmptyTask; + } + + private const string AsyncSuffix = "Async"; + + private async Task FixNodeAsync( + Document document, Diagnostic diagnostic, CancellationToken cancellationToken) + { + var token = diagnostic.Location.FindToken(cancellationToken); + var node = token.GetAncestor(IsMethodOrAnonymousFunction); + + // See if we're on an actual method declaration (otherwise we're on a lambda declaration). + // If we're on a method declaration, we'll get an IMethodSymbol back. In that case, check + // if it has the 'Async' suffix, and remove that suffix if so. + var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var methodSymbolOpt = semanticModel.GetDeclaredSymbol(node) as IMethodSymbol; + + if (methodSymbolOpt?.MethodKind == MethodKind.Ordinary && + methodSymbolOpt.Name.Length > AsyncSuffix.Length && + methodSymbolOpt.Name.EndsWith(AsyncSuffix)) + { + return await RenameThenRemoveAsyncTokenAsync(document, node, methodSymbolOpt, cancellationToken).ConfigureAwait(false); + } + else + { + return await RemoveAsyncTokenAsync(document, methodSymbolOpt, node, cancellationToken).ConfigureAwait(false); + } + } + + private async Task RenameThenRemoveAsyncTokenAsync(Document document, SyntaxNode node, IMethodSymbol methodSymbol, CancellationToken cancellationToken) + { + var name = methodSymbol.Name; + var newName = name.Substring(0, name.Length - AsyncSuffix.Length); + var solution = document.Project.Solution; + + // Store the path to this node. That way we can find it post rename. + var syntaxPath = new SyntaxPath(node); + + // Rename the method to remove the 'Async' suffix, then remove the 'async' keyword. + var newSolution = await Renamer.RenameSymbolAsync(solution, methodSymbol, newName, solution.Options, cancellationToken).ConfigureAwait(false); + var newDocument = newSolution.GetDocument(document.Id); + var newRoot = await newDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + + SyntaxNode newNode; + if (syntaxPath.TryResolve(newRoot, out newNode)) + { + var semanticModel = await newDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var newMethod = (IMethodSymbol)semanticModel.GetDeclaredSymbol(newNode, cancellationToken); + return await RemoveAsyncTokenAsync(newDocument, newMethod, newNode, cancellationToken).ConfigureAwait(false); + } + + return newSolution; + } + + private async Task RemoveAsyncTokenAsync(Document document, IMethodSymbol methodSymbolOpt, SyntaxNode node, CancellationToken cancellationToken) + { + var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); + var taskType = compilation.GetTypeByMetadataName("System.Threading.Tasks.Task"); + var taskOfTType = compilation.GetTypeByMetadataName("System.Threading.Tasks.Task`1"); + + var newNode = RemoveAsyncTokenAndFixReturnType(methodSymbolOpt, node, taskType, taskOfTType) + .WithAdditionalAnnotations(Formatter.Annotation); + + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var newRoot = root.ReplaceNode(node, newNode); + + var newDocument = document.WithSyntaxRoot(newRoot); + return newDocument.Project.Solution; + } + + private class MyCodeAction : CodeAction.SolutionChangeAction + { + public MyCodeAction(Func> createChangedSolution) + : base(FeaturesResources.Make_method_synchronous, createChangedSolution, AbstractMakeMethodSynchronousCodeFixProvider.EquivalenceKey) + { + } + } + } +} diff --git a/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.cs b/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.cs new file mode 100644 index 0000000000000..4303aacc15ae4 --- /dev/null +++ b/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.cs @@ -0,0 +1,172 @@ +// 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.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Rename; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.MakeMethodAsynchronous +{ + internal abstract class AbstractMakeMethodAsynchronousCodeFixProvider : CodeFixProvider + { + protected abstract bool IsMethodOrAnonymousFunction(SyntaxNode node); + protected abstract SyntaxNode AddAsyncTokenAndFixReturnType( + bool keepVoid, IMethodSymbol methodSymbolOpt, SyntaxNode node, + INamedTypeSymbol taskType, INamedTypeSymbol taskOfTType); + + public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + + public override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + var diagnostic = context.Diagnostics.First(); + var cancellationToken = context.CancellationToken; + + var node = GetContainingFunction(diagnostic, cancellationToken); + if (node == null) + { + return; + } + + var semanticModel = await context.Document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var symbol = semanticModel.GetDeclaredSymbol(node, cancellationToken) as IMethodSymbol; + + // If it's a void returning method, offer to keep the void return type, or convert to + // a Task return type. + if (symbol?.MethodKind == MethodKind.Ordinary && + symbol.ReturnsVoid) + { + context.RegisterCodeFix( + new MyCodeAction(FeaturesResources.Make_method_async, c => FixNodeAsync( + context.Document, diagnostic, keepVoid: true, cancellationToken: c)), + context.Diagnostics); + + context.RegisterCodeFix( + new MyCodeAction(FeaturesResources.Make_method_async_return_Task, c => FixNodeAsync( + context.Document, diagnostic, keepVoid: false, cancellationToken: c)), + context.Diagnostics); + } + else + { + context.RegisterCodeFix( + new MyCodeAction(FeaturesResources.Make_method_async, c => FixNodeAsync( + context.Document, diagnostic, keepVoid: false, cancellationToken: c)), + context.Diagnostics); + } + } + + private const string AsyncSuffix = "Async"; + + private async Task FixNodeAsync( + Document document, Diagnostic diagnostic, + bool keepVoid, CancellationToken cancellationToken) + { + var node = GetContainingFunction(diagnostic, cancellationToken); + + // See if we're on an actual method declaration (otherwise we're on a lambda declaration). + // If we're on a method declaration, we'll get an IMethodSymbol back. In that case, check + // if it has the 'Async' suffix, and remove that suffix if so. + var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var methodSymbolOpt = semanticModel.GetDeclaredSymbol(node) as IMethodSymbol; + + if (methodSymbolOpt?.MethodKind == MethodKind.Ordinary && + !methodSymbolOpt.Name.EndsWith(AsyncSuffix)) + { + return await RenameThenAddAsyncTokenAsync( + keepVoid, document, node, methodSymbolOpt, cancellationToken).ConfigureAwait(false); + } + else + { + return await AddAsyncTokenAsync( + keepVoid, document, methodSymbolOpt, node, cancellationToken).ConfigureAwait(false); + } + } + + private SyntaxNode GetContainingFunction(Diagnostic diagnostic, CancellationToken cancellationToken) + { + var token = diagnostic.Location.FindToken(cancellationToken); + var node = token.GetAncestor(IsMethodOrAnonymousFunction); + return node; + } + + private async Task RenameThenAddAsyncTokenAsync( + bool keepVoid, Document document, SyntaxNode node, + IMethodSymbol methodSymbol, CancellationToken cancellationToken) + { + var name = methodSymbol.Name; + var newName = name + AsyncSuffix; + var solution = document.Project.Solution; + + // Store the path to this node. That way we can find it post rename. + var syntaxPath = new SyntaxPath(node); + + // Rename the method to add the 'Async' suffix, then add the 'async' keyword. + var newSolution = await Renamer.RenameSymbolAsync(solution, methodSymbol, newName, solution.Options, cancellationToken).ConfigureAwait(false); + var newDocument = newSolution.GetDocument(document.Id); + var newRoot = await newDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + + SyntaxNode newNode; + if (syntaxPath.TryResolve(newRoot, out newNode)) + { + var semanticModel = await newDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var newMethod = (IMethodSymbol)semanticModel.GetDeclaredSymbol(newNode, cancellationToken); + return await AddAsyncTokenAsync(keepVoid, newDocument, newMethod, newNode, cancellationToken).ConfigureAwait(false); + } + + return newSolution; + } + + private async Task AddAsyncTokenAsync( + bool keepVoid, Document document, IMethodSymbol methodSymbolOpt, + SyntaxNode node, CancellationToken cancellationToken) + { + var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); + var taskType = compilation.GetTypeByMetadataName("System.Threading.Tasks.Task"); + var taskOfTType = compilation.GetTypeByMetadataName("System.Threading.Tasks.Task`1"); + + var newNode = AddAsyncTokenAndFixReturnType(keepVoid, methodSymbolOpt, node, taskType, taskOfTType) + .WithAdditionalAnnotations(Formatter.Annotation); + + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var newRoot = root.ReplaceNode(node, newNode); + + var newDocument = document.WithSyntaxRoot(newRoot); + return newDocument.Project.Solution; + } + + protected static bool IsTaskLike( + ITypeSymbol returnType, ITypeSymbol taskType, INamedTypeSymbol taskOfTType) + { + if (returnType.Equals(taskType)) + { + return true; + } + + if (returnType.OriginalDefinition.Equals(taskOfTType)) + { + return true; + } + + if (returnType.IsErrorType() && + returnType.Name.Equals("Task")) + { + return true; + } + + return false; + } + + private class MyCodeAction : CodeAction.SolutionChangeAction + { + public MyCodeAction(string title, Func> createChangedSolution) + : base(title, createChangedSolution, equivalenceKey: title) + { + } + } + } +} \ No newline at end of file diff --git a/src/Features/VisualBasic/Portable/BasicFeatures.vbproj b/src/Features/VisualBasic/Portable/BasicFeatures.vbproj index 709b2fac11d23..69896b253a52d 100644 --- a/src/Features/VisualBasic/Portable/BasicFeatures.vbproj +++ b/src/Features/VisualBasic/Portable/BasicFeatures.vbproj @@ -91,7 +91,6 @@ - @@ -352,6 +351,7 @@ + diff --git a/src/Features/VisualBasic/Portable/CodeFixes/Async/VisualBasicAddAsyncCodeFixProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/Async/VisualBasicAddAsyncCodeFixProvider.vb deleted file mode 100644 index ea13f481ca3f2..0000000000000 --- a/src/Features/VisualBasic/Portable/CodeFixes/Async/VisualBasicAddAsyncCodeFixProvider.vb +++ /dev/null @@ -1,111 +0,0 @@ -' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -Imports System.Collections.Immutable -Imports System.Composition -Imports System.Threading -Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.CodeFixes -Imports Microsoft.CodeAnalysis.CodeFixes.Async -Imports Microsoft.CodeAnalysis.Formatting -Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - -Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.Async - - Friend Class VisualBasicAddAsyncCodeFixProvider - Inherits AbstractAddAsyncCodeFixProvider - - Friend Const BC36937 As String = "BC36937" ' error BC36937: 'Await' can only be used when contained within a method or lambda expression marked with the 'Async' modifier. - Friend Const BC37057 As String = "BC37057" ' error BC37057: 'Await' can only be used within an Async method. Consider marking this method with the 'Async' modifier and changing its return type to 'Task'. - Friend Const BC37058 As String = "BC37058" ' error BC37058: 'Await' can only be used within an Async method. Consider marking this method with the 'Async' modifier and changing its return type to 'Task'. - Friend Const BC37059 As String = "BC37059" ' error BC37059: 'Await' can only be used within an Async lambda expression. Consider marking this expression with the 'Async' modifier and changing its return type to 'Task'. - - Friend Shared ReadOnly Ids As ImmutableArray(Of String) = ImmutableArray.Create(BC36937, BC37057, BC37058, BC37059) - - Public Overrides ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String) - Get - Return Ids - End Get - End Property - - Protected Overrides Function GetDescription(diagnostic As Diagnostic, node As SyntaxNode, semanticModel As SemanticModel, cancellationToken As CancellationToken) As String - Return VBFeaturesResources.Make_the_containing_scope_Async - End Function - - Protected Overrides Async Function GetNewRoot(root As SyntaxNode, oldNode As SyntaxNode, semanticModel As SemanticModel, diagnostic As Diagnostic, document As Document, cancellationToken As CancellationToken) As Task(Of SyntaxNode) - Dim methodNode = GetContainingMember(oldNode) - If methodNode Is Nothing Then - Return Nothing - End If - Return root.ReplaceNode(methodNode, Await ConvertToAsync(methodNode, semanticModel, document, cancellationToken).ConfigureAwait(False)) - End Function - - Private Shared Function GetContainingMember(oldNode As SyntaxNode) As StatementSyntax - - Dim lambda = oldNode.GetAncestor(Of LambdaExpressionSyntax) - If lambda IsNot Nothing Then - Return TryCast(lambda.ChildNodes().FirstOrDefault(Function(a) _ - a.IsKind(SyntaxKind.FunctionLambdaHeader) Or - a.IsKind(SyntaxKind.SubLambdaHeader)), - StatementSyntax) - End If - - Dim ancestor As MethodBlockBaseSyntax = oldNode.GetAncestor(Of MethodBlockBaseSyntax) - If ancestor IsNot Nothing Then - Return TryCast(ancestor.ChildNodes().FirstOrDefault(Function(a) _ - a.IsKind(SyntaxKind.SubStatement) Or - a.IsKind(SyntaxKind.FunctionStatement)), - StatementSyntax) - End If - - Return Nothing - End Function - - Private Async Function ConvertToAsync(node As StatementSyntax, semanticModel As SemanticModel, document As Document, cancellationToken As CancellationToken) As Task(Of SyntaxNode) - Dim methodNode = TryCast(node, MethodStatementSyntax) - If methodNode IsNot Nothing Then - Return Await ConvertMethodToAsync(document, semanticModel, methodNode, cancellationToken).ConfigureAwait(False) - End If - - Dim lambdaNode = TryCast(node, LambdaHeaderSyntax) - If lambdaNode IsNot Nothing Then - Return lambdaNode.AddModifiers(SyntaxFactory.Token(SyntaxKind.AsyncKeyword)).WithAdditionalAnnotations(Formatter.Annotation) - End If - - Return Nothing - End Function - - Protected Overrides Function AddAsyncKeyword(node As SyntaxNode) As SyntaxNode - Dim methodNode = TryCast(node, MethodStatementSyntax) - If methodNode Is Nothing Then - Return Nothing - End If - ' Visual Basic includes newlines in the trivia for MethodStatementSyntax nodes. If we are - ' inserting into the beginning of method statement, we will need to move the trivia. - Dim token = methodNode.ChildTokens().FirstOrDefault() - Dim keyword = methodNode.DeclarationKeyword - If keyword = token Then - Dim trivia = token.LeadingTrivia - methodNode = methodNode.ReplaceToken(token, token.WithLeadingTrivia()) - Return methodNode.AddModifiers(SyntaxFactory.Token(SyntaxKind.AsyncKeyword).WithLeadingTrivia(trivia)).WithAdditionalAnnotations(Formatter.Annotation) - End If - Return methodNode.AddModifiers(SyntaxFactory.Token(SyntaxKind.AsyncKeyword)).WithAdditionalAnnotations(Formatter.Annotation) - End Function - - Protected Overrides Function AddAsyncKeywordAndTaskReturnType(node As SyntaxNode, existingReturnType As ITypeSymbol, taskTypeSymbol As INamedTypeSymbol) As SyntaxNode - Dim methodNode = TryCast(node, MethodStatementSyntax) - If methodNode Is Nothing Then - Return Nothing - End If - If taskTypeSymbol Is Nothing Then - Return Nothing - End If - - Dim returnType = taskTypeSymbol.Construct(existingReturnType).GenerateTypeSyntax() - Return AddAsyncKeyword(methodNode.WithAsClause(methodNode.AsClause.WithType(returnType))) - End Function - - Protected Overrides Function DoesConversionExist(compilation As Compilation, source As ITypeSymbol, destination As ITypeSymbol) As Boolean - Return compilation.ClassifyConversion(source, destination).Exists - End Function - End Class -End Namespace diff --git a/src/Features/VisualBasic/Portable/CodeFixes/Async/VisualBasicAddAwaitCodeFixProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/Async/VisualBasicAddAwaitCodeFixProvider.vb index 92fa5c237e9e2..d302b40c25f18 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/Async/VisualBasicAddAwaitCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/Async/VisualBasicAddAwaitCodeFixProvider.vb @@ -15,7 +15,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.Async Friend Class VisualBasicAddAwaitCodeFixProvider - Inherits AbstractAddAsyncAwaitCodeFixProvider + Inherits AbstractAddAwaitCodeFixProvider Friend Const BC30311 As String = "BC30311" ' error BC30311: Value of type 'X' cannot be converted to 'Y'. Friend Const BC37055 As String = "BC37055" ' error BC37055: Since this is an async method, the return expression must be of type 'blah' rather than 'baz' @@ -29,11 +29,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.Async End Get End Property - Protected Overrides Function GetDescription(diagnostic As Diagnostic, node As SyntaxNode, semanticModel As SemanticModel, cancellationToken As CancellationToken) As String - Return VBFeaturesResources.Insert_Await + Protected Overrides Async Function GetDescriptionAndNodeAsync(root As SyntaxNode, oldNode As SyntaxNode, semanticModel As SemanticModel, diagnostic As Diagnostic, document As Document, cancellationToken As CancellationToken) As Task(Of DescriptionAndNode) + Dim newRoot = Await GetNewRootAsync( + root, oldNode, semanticModel, diagnostic, document, cancellationToken).ConfigureAwait(False) + If newRoot Is Nothing Then + Return Nothing + End If + + Return New DescriptionAndNode(VBFeaturesResources.Insert_Await, newRoot) End Function - Protected Overrides Function GetNewRoot(root As SyntaxNode, oldNode As SyntaxNode, semanticModel As SemanticModel, diagnostic As Diagnostic, document As Document, cancellationToken As CancellationToken) As Task(Of SyntaxNode) + Private Function GetNewRootAsync(root As SyntaxNode, oldNode As SyntaxNode, semanticModel As SemanticModel, diagnostic As Diagnostic, document As Document, cancellationToken As CancellationToken) As Task(Of SyntaxNode) Dim expression = TryCast(oldNode, ExpressionSyntax) If expression Is Nothing Then Return SpecializedTasks.Default(Of SyntaxNode)() diff --git a/src/Features/VisualBasic/Portable/MakeMethodAsynchronous/VisualBasicMakeMethodAsynchronousCodeFixProvider.vb b/src/Features/VisualBasic/Portable/MakeMethodAsynchronous/VisualBasicMakeMethodAsynchronousCodeFixProvider.vb new file mode 100644 index 0000000000000..544cd0330c0d8 --- /dev/null +++ b/src/Features/VisualBasic/Portable/MakeMethodAsynchronous/VisualBasicMakeMethodAsynchronousCodeFixProvider.vb @@ -0,0 +1,133 @@ +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +Imports System.Collections.Immutable +Imports System.Composition +Imports Microsoft.CodeAnalysis.CodeFixes +Imports Microsoft.CodeAnalysis.MakeMethodAsynchronous +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax + +Namespace Microsoft.CodeAnalysis.VisualBasic.MakeMethodAsynchronous + + Friend Class VisualBasicMakeMethodAsynchronousCodeFixProvider + Inherits AbstractMakeMethodAsynchronousCodeFixProvider + + Friend Const BC36937 As String = "BC36937" ' error BC36937: 'Await' can only be used when contained within a method or lambda expression marked with the 'Async' modifier. + Friend Const BC37057 As String = "BC37057" ' error BC37057: 'Await' can only be used within an Async method. Consider marking this method with the 'Async' modifier and changing its return type to 'Task'. + Friend Const BC37058 As String = "BC37058" ' error BC37058: 'Await' can only be used within an Async method. Consider marking this method with the 'Async' modifier and changing its return type to 'Task'. + Friend Const BC37059 As String = "BC37059" ' error BC37059: 'Await' can only be used within an Async lambda expression. Consider marking this expression with the 'Async' modifier and changing its return type to 'Task'. + + Private Shared ReadOnly s_diagnosticIds As ImmutableArray(Of String) = ImmutableArray.Create( + BC36937, BC37057, BC37058, BC37059) + + Private Shared ReadOnly s_asyncToken As SyntaxToken = SyntaxFactory.Token(SyntaxKind.AsyncKeyword) + + Public Overrides ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String) + Get + Return s_diagnosticIds + End Get + End Property + + Protected Overrides Function IsMethodOrAnonymousFunction(node As SyntaxNode) As Boolean + Return node.IsKind(SyntaxKind.FunctionBlock) OrElse + node.IsKind(SyntaxKind.SubBlock) OrElse + node.IsKind(SyntaxKind.MultiLineFunctionLambdaExpression) OrElse + node.IsKind(SyntaxKind.MultiLineSubLambdaExpression) OrElse + node.IsKind(SyntaxKind.SingleLineFunctionLambdaExpression) OrElse + node.IsKind(SyntaxKind.SingleLineSubLambdaExpression) + End Function + + Protected Overrides Function AddAsyncTokenAndFixReturnType( + keepVoid As Boolean, methodSymbolOpt As IMethodSymbol, node As SyntaxNode, + taskType As INamedTypeSymbol, taskOfTType As INamedTypeSymbol) As SyntaxNode + + If node.IsKind(SyntaxKind.SingleLineSubLambdaExpression) OrElse + node.IsKind(SyntaxKind.SingleLineFunctionLambdaExpression) Then + + Return FixSingleLineLambdaExpression(DirectCast(node, SingleLineLambdaExpressionSyntax)) + ElseIf node.IsKind(SyntaxKind.MultiLineSubLambdaExpression) OrElse + node.IsKind(SyntaxKind.MultiLineFunctionLambdaExpression) Then + + Return FixMultiLineLambdaExpression(DirectCast(node, MultiLineLambdaExpressionSyntax)) + ElseIf node.IsKind(SyntaxKind.SubBlock) Then + Return FixSubBlock(keepVoid, DirectCast(node, MethodBlockSyntax), taskType) + Else + Return FixFunctionBlock(methodSymbolOpt, DirectCast(node, MethodBlockSyntax), taskType, taskOfTType) + End If + End Function + + Private Function FixFunctionBlock(methodSymbol As IMethodSymbol, node As MethodBlockSyntax, + taskType As INamedTypeSymbol, taskOfTType As INamedTypeSymbol) As SyntaxNode + + Dim functionStatement = node.SubOrFunctionStatement + Dim newFunctionStatement = AddAsyncKeyword(functionStatement) + + If Not IsTaskLike(methodSymbol.ReturnType, taskType, taskOfTType) Then + ' if the current return type is not already task-list, then wrap it in Task(of ...) + Dim returnType = taskOfTType.Construct(methodSymbol.ReturnType).GenerateTypeSyntax() + newFunctionStatement = newFunctionStatement.WithAsClause( + newFunctionStatement.AsClause.WithType(returnType)) + End If + + Return node.WithSubOrFunctionStatement(newFunctionStatement) + End Function + + Private Function FixSubBlock( + keepVoid As Boolean, node As MethodBlockSyntax, taskType As INamedTypeSymbol) As SyntaxNode + + If keepVoid Then + ' User wants to keep this a void method, so keep this as a sub. + Dim newSubStatement = AddAsyncKeyword(node.SubOrFunctionStatement) + Return node.WithSubOrFunctionStatement(newSubStatement) + End If + + ' Have to convert this sub into a func. + Dim asClause = SyntaxFactory.SimpleAsClause(taskType.GenerateTypeSyntax()) + + Dim subStatement = node.SubOrFunctionStatement + Dim functionStatement = SyntaxFactory.FunctionStatement( + subStatement.AttributeLists, + subStatement.Modifiers.Add(s_asyncToken), + SyntaxFactory.Token(SyntaxKind.FunctionKeyword).WithTriviaFrom(subStatement.SubOrFunctionKeyword), + subStatement.Identifier, + subStatement.TypeParameterList, + subStatement.ParameterList, + asClause, + subStatement.HandlesClause, + subStatement.ImplementsClause) + + Dim endFunctionStatement = SyntaxFactory.EndFunctionStatement( + node.EndSubOrFunctionStatement.EndKeyword, + SyntaxFactory.Token(SyntaxKind.FunctionKeyword).WithTriviaFrom(node.EndSubOrFunctionStatement.BlockKeyword)) + + Dim block = SyntaxFactory.FunctionBlock( + functionStatement, + node.Statements, + endFunctionStatement) + + Return block + End Function + + Private Shared Function AddAsyncKeyword(subOrFunctionStatement As MethodStatementSyntax) As MethodStatementSyntax + Dim modifiers = subOrFunctionStatement.Modifiers + Dim newModifiers = modifiers.Add(s_asyncToken) + Return subOrFunctionStatement.WithModifiers(newModifiers) + End Function + + Private Function FixMultiLineLambdaExpression(node As MultiLineLambdaExpressionSyntax) As SyntaxNode + Dim header As LambdaHeaderSyntax = GetNewHeader(node) + Return node.WithSubOrFunctionHeader(header).WithLeadingTrivia(node.GetLeadingTrivia()) + End Function + + Private Function FixSingleLineLambdaExpression(node As SingleLineLambdaExpressionSyntax) As SingleLineLambdaExpressionSyntax + Dim header As LambdaHeaderSyntax = GetNewHeader(node) + Return node.WithSubOrFunctionHeader(header).WithLeadingTrivia(node.GetLeadingTrivia()) + End Function + + Private Shared Function GetNewHeader(node As LambdaExpressionSyntax) As LambdaHeaderSyntax + Dim header = DirectCast(node.SubOrFunctionHeader, LambdaHeaderSyntax) + Dim newModifiers = header.Modifiers.Add(s_asyncToken) + Dim newHeader = header.WithModifiers(newModifiers) + Return newHeader + End Function + End Class +End Namespace \ No newline at end of file diff --git a/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb b/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb index 83bf5f5e22699..e13c9fc4cc479 100644 --- a/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb +++ b/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb @@ -1520,15 +1520,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.VBFeaturesResources End Get End Property - ''' - ''' Looks up a localized string similar to Make the containing scope 'Async'.. - ''' - Friend ReadOnly Property Make_the_containing_scope_Async() As String - Get - Return ResourceManager.GetString("Make_the_containing_scope_Async", resourceCulture) - End Get - End Property - ''' ''' Looks up a localized string similar to Mid statement. ''' diff --git a/src/Features/VisualBasic/Portable/VBFeaturesResources.resx b/src/Features/VisualBasic/Portable/VBFeaturesResources.resx index 8c80d3c2ce046..91ad0beaaaf19 100644 --- a/src/Features/VisualBasic/Portable/VBFeaturesResources.resx +++ b/src/Features/VisualBasic/Portable/VBFeaturesResources.resx @@ -979,9 +979,6 @@ Sub(<parameterList>) <statement> Insert 'Await'. - - Make the containing scope 'Async'. - Make {0} an Async Function. diff --git a/src/Test/PdbUtilities/project.json b/src/Test/PdbUtilities/project.json index db4e30afca948..ba4775787d279 100644 --- a/src/Test/PdbUtilities/project.json +++ b/src/Test/PdbUtilities/project.json @@ -2,7 +2,7 @@ "supports": {}, "dependencies": { "System.Collections.Immutable": "1.2.0", - "System.Reflection.Metadata": "1.4.1-beta-24322-03", + "System.Reflection.Metadata": "1.4.1-beta-24410-02", "Microsoft.DiaSymReader.Native": "1.5.0-beta1", "Microsoft.DiaSymReader": "1.1.0-beta1-60625-03", "Microsoft.DiaSymReader.PortablePdb": "1.2.0-beta1-60723-01" diff --git a/src/Tools/ProcessWatchdog/project.json b/src/Tools/ProcessWatchdog/project.json index 34b08d994e8de..236fc4a5db5c4 100644 --- a/src/Tools/ProcessWatchdog/project.json +++ b/src/Tools/ProcessWatchdog/project.json @@ -2,7 +2,7 @@ "dependencies": { "CommandLineParser": "2.0.273-beta", "System.Collections.Immutable": "1.2.0", - "System.Reflection.Metadata": "1.4.1-beta-24322-03", + "System.Reflection.Metadata": "1.4.1-beta-24410-02", }, "frameworks": { "net46": {} diff --git a/src/Tools/SignRoslyn/project.json b/src/Tools/SignRoslyn/project.json index af9e3987f9d42..79b4d3eb50c8f 100644 --- a/src/Tools/SignRoslyn/project.json +++ b/src/Tools/SignRoslyn/project.json @@ -2,7 +2,7 @@ "supports": {}, "dependencies": { "System.Collections.Immutable": "1.2.0", - "System.Reflection.Metadata": "1.4.1-beta-24322-03", + "System.Reflection.Metadata": "1.4.1-beta-24410-02", "Newtonsoft.Json": "8.0.3" }, "frameworks": { diff --git a/src/Tools/Source/RunTests/project.json b/src/Tools/Source/RunTests/project.json index 5b28dfcfeff4c..f477a4ce4d62e 100644 --- a/src/Tools/Source/RunTests/project.json +++ b/src/Tools/Source/RunTests/project.json @@ -3,7 +3,7 @@ "Newtonsoft.Json": "8.0.3", "RestSharp": "105.2.3", "System.Collections.Immutable": "1.2.0", - "System.Reflection.Metadata": "1.4.1-beta-24322-03", + "System.Reflection.Metadata": "1.4.1-beta-24410-02", }, "frameworks": { "net46": {} diff --git a/src/VisualStudio/Core/Def/Implementation/Workspace/DetailedErrorInfoDialog.xaml b/src/VisualStudio/Core/Def/Implementation/Workspace/DetailedErrorInfoDialog.xaml new file mode 100644 index 0000000000000..0381e8f461f0f --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/Workspace/DetailedErrorInfoDialog.xaml @@ -0,0 +1,49 @@ + + + + + + + + + + + +