Skip to content

Commit

Permalink
Introduce new InternalsVisibleToAnalyzer analyzer (ACZ0112) with `Fri…
Browse files Browse the repository at this point in the history
…endAttribute` concept (#7086)
  • Loading branch information
christothes authored Jan 23, 2024
1 parent adc439e commit 7787c1b
Show file tree
Hide file tree
Showing 12 changed files with 826 additions and 289 deletions.
3 changes: 2 additions & 1 deletion eng/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
<IsTestProject Condition="'$(IsTestHelperLibrary)' == 'true'">false</IsTestProject>
</PropertyGroup>

<PropertyGroup Condition="'$(SignAssembly)' != 'false'">
<!-- Exclude TestReferenceWithInternalsVisibleTo from strong name signing, as it is required for a test scenario -->
<PropertyGroup Condition="'$(SignAssembly)' != 'false' and !$(MSBuildProjectName.EndsWith('TestReferenceWithInternalsVisibleTo'))">
<SignAssembly>true</SignAssembly>
<DelaySign>false</DelaySign>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)AzureSDKToolsKey.snk</AssemblyOriginatorKeyFile>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Collections.Generic;
using System.Threading.Tasks;
using Xunit;
using Verifier = Azure.ClientSdk.Analyzers.Tests.AzureAnalyzerVerifier<Azure.ClientSdk.Analyzers.InternalsVisibleToAnalyzer>;

namespace Azure.ClientSdk.Analyzers.Tests
{
public class AZC0112Tests
{
[Fact]
public async Task AZC0020WhenInheritingFromInternalInterface()
{
string code = @"
using System;
using TestReferenceWithInternalsVisibleTo;
namespace LibraryNamespace
{
public class {|AZC0112:MyClass|} : IInternalInterface
{
}
}";
await Verifier.VerifyAnalyzerAsync(code, additionalReferences: new[] { typeof(TestReferenceWithInternalsVisibleTo.PublicClass) });
}

[Fact]
public async Task NoAZC0020WhenInheritingFromInternalInterfaceWithFriendAttribute()
{
string code = @"
using System;
using TestReferenceWithInternalsVisibleTo;
namespace LibraryNamespace
{
public class MyClass : IInternalInterfaceWithFriendAttribute
{
}
}";
await Verifier.VerifyAnalyzerAsync(code, additionalReferences: new[] { typeof(TestReferenceWithInternalsVisibleTo.PublicClass) });
}

[Fact]
public async Task AZC0020WhenDerivingFromInternalClass()
{
string code = @"
using System;
using TestReferenceWithInternalsVisibleTo;
namespace LibraryNamespace
{
internal class {|AZC0112:MyClass|} : InternalClass
{
}
}";
await Verifier.VerifyAnalyzerAsync(code, additionalReferences: new[] { typeof(TestReferenceWithInternalsVisibleTo.PublicClass) });
}

[Fact]
public async Task NoAZC0020WhenInheritingFromInternalClassWithFriendAttribute()
{
string code = @"
using System;
using TestReferenceWithInternalsVisibleTo;
namespace LibraryNamespace
{
internal class MyClass : InternalClassWithFriendAttribute
{
}
}";
await Verifier.VerifyAnalyzerAsync(code, additionalReferences: new[] { typeof(TestReferenceWithInternalsVisibleTo.PublicClass) });
}

[Fact]
public async Task AZC0020WhenDeclaringInternalProperty()
{
string code = @"
using System;
using TestReferenceWithInternalsVisibleTo;
namespace LibraryNamespace
{
public class MyClass
{
internal InternalClass {|AZC0112:PropReferencesInternalType|} { {|AZC0112:get|}; set;}
}
}";
await Verifier.VerifyAnalyzerAsync(code, additionalReferences: new[] { typeof(TestReferenceWithInternalsVisibleTo.PublicClass) });
}

[Fact]
public async Task NoAZC0020WhenDeclaringInternalPropertyWithFriendAttribute()
{
string code = @"
using System;
using TestReferenceWithInternalsVisibleTo;
namespace LibraryNamespace
{
public class MyClass
{
internal InternalClassWithFriendAttribute PropReferencesInternalType { get; set;}
}
}";
await Verifier.VerifyAnalyzerAsync(code, additionalReferences: new[] { typeof(TestReferenceWithInternalsVisibleTo.PublicClass) });
}

[Fact]
public async Task NoAZC0020WhenDeclaringInternalFieldWithFriendAttribute()
{
string code = @"
using System;
using TestReferenceWithInternalsVisibleTo;
namespace LibraryNamespace
{
public class MyClass
{
internal InternalClassWithFriendAttribute fieldReferencesInternalType;
}
}";
await Verifier.VerifyAnalyzerAsync(code, additionalReferences: new[] { typeof(TestReferenceWithInternalsVisibleTo.PublicClass) });
}

[Fact]
public async Task AZC0020WhenDeclaringInternalField()
{
string code = @"
using System;
using TestReferenceWithInternalsVisibleTo;
namespace LibraryNamespace
{
public class MyClass
{
internal InternalClass {|AZC0112:fieldReferencesInternalType|};
}
}";
await Verifier.VerifyAnalyzerAsync(code, additionalReferences: new[] { typeof(TestReferenceWithInternalsVisibleTo.PublicClass) });
}

[Fact]
public async Task AZC0020WhenReferencingInternalProperty()
{
string code = @"
using System;
using TestReferenceWithInternalsVisibleTo;
using System.Reflection;
namespace LibraryNamespace
{
public class MyClass
{
public void MyMethod()
{
var myClass = new PublicClass();
var value = {|AZC0112:myClass.InternalProperty|};
}
}
}";
await Verifier.VerifyAnalyzerAsync(code, additionalReferences: new[] { typeof(TestReferenceWithInternalsVisibleTo.PublicClass) });
}

[Fact]
public async Task NoAZC0020WhenReferencingInternalPropertyWithFriendAttribute()
{
string code = @"
using System;
using TestReferenceWithInternalsVisibleTo;
using System.Reflection;
namespace LibraryNamespace
{
public class MyClass
{
public void MyMethod()
{
var myClass = new PublicClass();
var value = myClass.InternalPropertyWithFriendAttribute;
}
}
}";
await Verifier.VerifyAnalyzerAsync(code, additionalReferences: new[] { typeof(TestReferenceWithInternalsVisibleTo.PublicClass) });
}

[Fact]
public async Task AZC0020WhenReferencingInternalMethod()
{
string code = @"
using System;
using TestReferenceWithInternalsVisibleTo;
using System.Reflection;
namespace LibraryNamespace
{
public class MyClass
{
public void MyMethod()
{
var myClass = new PublicClass();
{|AZC0112:myClass.InternalMethod|}();
}
}
}";
await Verifier.VerifyAnalyzerAsync(code, additionalReferences: new[] { typeof(TestReferenceWithInternalsVisibleTo.PublicClass) });
}

[Fact]
public async Task NoAZC0020WhenReferencingInternalMethodWithFriendAttribute()
{
string code = @"
using System;
using TestReferenceWithInternalsVisibleTo;
using System.Reflection;
namespace LibraryNamespace
{
public class MyClass
{
public void MyMethod()
{
var myClass = new PublicClass();
myClass.InternalMethodWithFriendAttribute();
}
}
}";
await Verifier.VerifyAnalyzerAsync(code, additionalReferences: new[] { typeof(TestReferenceWithInternalsVisibleTo.PublicClass) });
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

<ItemGroup>
<ProjectReference Include="..\Azure.ClientSdk.Analyzers\Azure.ClientSdk.Analyzers.csproj" />
<ProjectReference Include="..\TestReferenceWithInternalsVisibleTo\TestReferenceWithInternalsVisibleTo.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
Expand All @@ -18,14 +19,15 @@ namespace Azure.ClientSdk.Analyzers.Tests
{
private static readonly ReferenceAssemblies DefaultReferenceAssemblies =
ReferenceAssemblies.Default.AddPackages(ImmutableArray.Create(
new PackageIdentity("Azure.Core", "1.26.0"),
new PackageIdentity("Microsoft.Bcl.AsyncInterfaces", "1.1.0"),
new PackageIdentity("Azure.Core", "1.35.0"),
new PackageIdentity("Microsoft.Bcl.AsyncInterfaces", "1.1.1"),
new PackageIdentity("Newtonsoft.Json", "12.0.3"),
new PackageIdentity("System.Text.Json", "4.6.0"),
new PackageIdentity("System.Threading.Tasks.Extensions", "4.5.3")));
new PackageIdentity("System.Text.Json", "4.7.2"),
new PackageIdentity("System.Threading.Tasks.Extensions", "4.5.4")));

public static CSharpAnalyzerTest<TAnalyzer, XUnitVerifier> CreateAnalyzer(string source, LanguageVersion languageVersion = LanguageVersion.Latest)
=> new CSharpAnalyzerTest<TAnalyzer, XUnitVerifier>
public static CSharpAnalyzerTest<TAnalyzer, XUnitVerifier> CreateAnalyzer(string source, LanguageVersion languageVersion = LanguageVersion.Latest, Type[] additionalReferences = null)
{
var test = new CSharpAnalyzerTest<TAnalyzer, XUnitVerifier>
{
ReferenceAssemblies = DefaultReferenceAssemblies,
SolutionTransforms = {(solution, projectId) =>
Expand All @@ -37,9 +39,18 @@ public static CSharpAnalyzerTest<TAnalyzer, XUnitVerifier> CreateAnalyzer(string
TestCode = source,
TestBehaviors = TestBehaviors.SkipGeneratedCodeCheck
};
if (additionalReferences != null)
{
foreach (var reference in additionalReferences)
{
test.TestState.AdditionalReferences.Add(reference.Assembly);
}
}
return test;
}

public static Task VerifyAnalyzerAsync(string source, LanguageVersion languageVersion = LanguageVersion.Latest)
=> CreateAnalyzer(source, languageVersion).RunAsync(CancellationToken.None);
public static Task VerifyAnalyzerAsync(string source, LanguageVersion languageVersion = LanguageVersion.Latest, Type[] additionalReferences = null)
=> CreateAnalyzer(source, languageVersion, additionalReferences).RunAsync(CancellationToken.None);

public static Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] diagnostics)
{
Expand Down
Loading

0 comments on commit 7787c1b

Please sign in to comment.