diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/ImplementInterface/ImplementInterfaceTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/ImplementInterface/ImplementInterfaceTests.cs index bd2acd4d2fb5762c0e947803eb5c1469540b5cc2..b101db65d439e7714826635ad2501adecd37e2d8 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/ImplementInterface/ImplementInterfaceTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/ImplementInterface/ImplementInterfaceTests.cs @@ -2641,5 +2641,50 @@ private static string DisposePattern(string disposeVisibility, string className, }} #endregion"; } + + [WorkItem(1132014)] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + public void TestInaccesibleAttributes() + { + Test( +@"using System; + +public class Foo : [|Holder.SomeInterface|] +{ +} + +public class Holder +{ + public interface SomeInterface + { + void Something([SomeAttribute] string helloWorld); + } + + private class SomeAttribute : Attribute + { + } +}", +@"using System; + +public class Foo : Holder.SomeInterface +{ + public void Something(string helloWorld) + { + throw new NotImplementedException(); + } +} + +public class Holder +{ + public interface SomeInterface + { + void Something([SomeAttribute] string helloWorld); + } + + private class SomeAttribute : Attribute + { + } +}"); + } } } diff --git a/src/EditorFeatures/VisualBasicTest/Diagnostics/ImplementInterface/ImplementInterfaceTests.vb b/src/EditorFeatures/VisualBasicTest/Diagnostics/ImplementInterface/ImplementInterfaceTests.vb index a068855d2d18a30c6c585e5d8aed3e021f7b2b96..6be40c32f99d02f5e96835f2f14ab30192a51239 100644 --- a/src/EditorFeatures/VisualBasicTest/Diagnostics/ImplementInterface/ImplementInterfaceTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Diagnostics/ImplementInterface/ImplementInterfaceTests.vb @@ -2127,5 +2127,45 @@ End Interface", index:=1, compareTokens:=False) Return code End Function + + + + Public Sub TestInaccesibleAttributes() + Test( +"Imports System + +Public Class Foo + Implements [|Holder.SomeInterface|] +End Class + +Public Class Holder + Public Interface SomeInterface + Sub Something( helloWorld As String) + End Interface + + Private Class SomeAttribute + Inherits Attribute + End Class +End Class", +"Imports System + +Public Class Foo + Implements Holder.SomeInterface + + Public Sub Something(helloWorld As String) Implements Holder.SomeInterface.Something + Throw New NotImplementedException() + End Sub +End Class + +Public Class Holder + Public Interface SomeInterface + Sub Something( helloWorld As String) + End Interface + + Private Class SomeAttribute + Inherits Attribute + End Class +End Class", compareTokens:=False) + End Sub End Class End Namespace diff --git a/src/Features/Core/ImplementInterface/AbstractImplementInterfaceService.CodeAction_Method.cs b/src/Features/Core/ImplementInterface/AbstractImplementInterfaceService.CodeAction_Method.cs index b773e7245a5960f0df62f0d6ad5ec08bd072d129..69e080ee738d2cbcd8545b15180aedbff055b679 100644 --- a/src/Features/Core/ImplementInterface/AbstractImplementInterfaceService.CodeAction_Method.cs +++ b/src/Features/Core/ImplementInterface/AbstractImplementInterfaceService.CodeAction_Method.cs @@ -28,7 +28,9 @@ internal partial class ImplementInterfaceCodeAction var updatedMethod = method.EnsureNonConflictingNames( this.State.ClassOrStructType, syntaxFacts, cancellationToken); - updatedMethod = updatedMethod.RemoveAttributeFromParametersAndReturnType(compilation.ComAliasNameAttributeType()); + updatedMethod = updatedMethod.RemoveInaccessibleAttributesAndAttributesOfType( + accessibleWithin: this.State.ClassOrStructType, + removeAttributeType: compilation.ComAliasNameAttributeType()); return CodeGenerationSymbolFactory.CreateMethodSymbol( updatedMethod, diff --git a/src/Features/Core/ImplementInterface/AbstractImplementInterfaceService.CodeAction_Property.cs b/src/Features/Core/ImplementInterface/AbstractImplementInterfaceService.CodeAction_Property.cs index 43713042f5a18066a493217b2dafc06fbe370a09..dbb55bac9c1410873663b332c1df64875448dccc 100644 --- a/src/Features/Core/ImplementInterface/AbstractImplementInterfaceService.CodeAction_Property.cs +++ b/src/Features/Core/ImplementInterface/AbstractImplementInterfaceService.CodeAction_Property.cs @@ -32,7 +32,9 @@ internal partial class ImplementInterfaceCodeAction var getAccessor = property.GetMethod == null ? null : CodeGenerationSymbolFactory.CreateAccessorSymbol( - property.GetMethod.RemoveAttributeFromParametersAndReturnType(comAliasNameAttribute), + property.GetMethod.RemoveInaccessibleAttributesAndAttributesOfType( + accessibleWithin: this.State.ClassOrStructType, + removeAttributeType: comAliasNameAttribute), attributes: null, accessibility: accessibility, explicitInterfaceSymbol: useExplicitInterfaceSymbol ? property.GetMethod : null, @@ -41,7 +43,9 @@ internal partial class ImplementInterfaceCodeAction var setAccessor = property.SetMethod == null ? null : CodeGenerationSymbolFactory.CreateAccessorSymbol( - property.SetMethod.RemoveAttributeFromParametersAndReturnType(comAliasNameAttribute), + property.SetMethod.RemoveInaccessibleAttributesAndAttributesOfType( + accessibleWithin: this.State.ClassOrStructType, + removeAttributeType: comAliasNameAttribute), attributes: null, accessibility: accessibility, explicitInterfaceSymbol: useExplicitInterfaceSymbol ? property.SetMethod : null, diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs index 14e08ce5a0ab511447db407f80fd6582c3de6938..a1b8955ed0c43869f5108a036daa90179d12a049 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs @@ -168,29 +168,34 @@ public static IMethodSymbol RenameParameters(this IMethodSymbol method, IList statements = null, IList handlesExpressions = null) { - if (attributeType == null) - { - return method; - } + Func shouldRemoveAttribute = a => + a.AttributeClass.Equals(removeAttributeType) || !a.AttributeClass.IsAccessibleWithin(accessibleWithin); + return method.RemoveAttributesCore(shouldRemoveAttribute, statements, handlesExpressions); + } + + private static IMethodSymbol RemoveAttributesCore( + this IMethodSymbol method, Func shouldRemoveAttribute, + IList statements, IList handlesExpressions) + { + var methodHasAttribute = method.GetAttributes().Any(shouldRemoveAttribute); var someParameterHasAttribute = method.Parameters - .Any(m => m.GetAttributes().Any(a => a.AttributeClass.Equals(attributeType))); + .Any(m => m.GetAttributes().Any(shouldRemoveAttribute)); - var returnTypeHasAttribute = method.GetReturnTypeAttributes() - .Any(a => a.AttributeClass.Equals(attributeType)); + var returnTypeHasAttribute = method.GetReturnTypeAttributes().Any(shouldRemoveAttribute); - if (!someParameterHasAttribute && !returnTypeHasAttribute) + if (!methodHasAttribute && !someParameterHasAttribute && !returnTypeHasAttribute) { return method; } return CodeGenerationSymbolFactory.CreateMethodSymbol( method.ContainingType, - method.GetAttributes(), + method.GetAttributes().Where(a => !shouldRemoveAttribute(a)).ToList(), method.DeclaredAccessibility, method.GetSymbolModifiers(), method.ReturnType, @@ -199,12 +204,12 @@ public static IMethodSymbol RenameParameters(this IMethodSymbol method, IList CodeGenerationSymbolFactory.CreateParameterSymbol( - p.GetAttributes().Where(a => !a.AttributeClass.Equals(attributeType)).ToList(), + p.GetAttributes().Where(a => !shouldRemoveAttribute(a)).ToList(), p.RefKind, p.IsParams, p.Type, p.Name, p.IsOptional, p.HasExplicitDefaultValue, p.HasExplicitDefaultValue ? p.ExplicitDefaultValue : null)).ToList(), statements, handlesExpressions, - method.GetReturnTypeAttributes().Where(a => !a.AttributeClass.Equals(attributeType)).ToList()); + method.GetReturnTypeAttributes().Where(a => !shouldRemoveAttribute(a)).ToList()); } public static bool? IsMoreSpecificThan(this IMethodSymbol method1, IMethodSymbol method2)