diff --git a/PolySharp.slnx b/PolySharp.slnx index 3b5474c..f3e0503 100644 --- a/PolySharp.slnx +++ b/PolySharp.slnx @@ -9,6 +9,7 @@ + diff --git a/src/PolySharp.SourceGenerators/Extensions/CompilationExtensions.cs b/src/PolySharp.SourceGenerators/Extensions/CompilationExtensions.cs index 9d934e7..ce421cf 100644 --- a/src/PolySharp.SourceGenerators/Extensions/CompilationExtensions.cs +++ b/src/PolySharp.SourceGenerators/Extensions/CompilationExtensions.cs @@ -50,18 +50,51 @@ public static bool HasAccessibleTypeWithMetadataName(this Compilation compilatio // If there is only a single matching symbol, check its accessibility if (compilation.GetTypeByMetadataName(fullyQualifiedMetadataName) is INamedTypeSymbol typeSymbol) { - return compilation.IsSymbolAccessibleWithin(typeSymbol, compilation.Assembly); + return isSymbolAccessible(typeSymbol); } // Otherwise, check all available types foreach (INamedTypeSymbol currentTypeSymbol in compilation.GetTypesByMetadataName(fullyQualifiedMetadataName)) { - if (compilation.IsSymbolAccessibleWithin(currentTypeSymbol, compilation.Assembly)) + if (isSymbolAccessible(currentTypeSymbol)) { return true; } } return false; + + bool isSymbolAccessible(INamedTypeSymbol symbol) + { + if (!compilation.IsSymbolAccessibleWithin(symbol, compilation.Assembly)) + { + return false; + } + else if (!SymbolEqualityComparer.Default.Equals(compilation.Assembly, symbol.ContainingAssembly)) + { + foreach (AttributeData attribute in symbol.GetAttributes()) + { + if (attribute.AttributeClass is + { + ContainingNamespace: + { + ContainingNamespace: + { + ContainingNamespace.IsGlobalNamespace: true, + Name: "Microsoft", + }, + Name: "CodeAnalysis", + + }, + Name: "EmbeddedAttribute", + }) + { + return false; + } + } + } + + return true; + } } } \ No newline at end of file diff --git a/tests/PolySharp.InternalsVisibleTo.Tests/LanguageFeatures.cs b/tests/PolySharp.InternalsVisibleTo.Tests/LanguageFeatures.cs new file mode 100644 index 0000000..012a4c9 --- /dev/null +++ b/tests/PolySharp.InternalsVisibleTo.Tests/LanguageFeatures.cs @@ -0,0 +1,299 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.Versioning; +#if !NETSTANDARD2_1 +using System.Threading.Tasks; +#endif + +#pragma warning disable CA2255 + +namespace PolySharp.InternalsVisibleTo.Tests; + +internal class TestClass +{ + private string? name; + + // AllowNullAttribute + public void TakeValue1([AllowNull] string name) + { + } + + // DisallowNullAttribute + public void TakeValue2([DisallowNull] string? name) + { + } + + // DoesNotReturnAttribute + [DoesNotReturn] + public void Throws() + { + throw null!; + } + + // DoesNotReturnIfAttribute + public void Throws([DoesNotReturnIf(true)] bool value) + { + } + + // MaybeNullAttribute + [return: MaybeNull] + public string ModifyValue() + { + return null; + } + + // MaybeNullWhenAttribute + public bool ModifyValue([MaybeNullWhen(true)] out string result) + { + result = null; + + return true; + } + + // MemberNotNullAttribute + [MemberNotNull(nameof(name))] + public void AssignsField() + { + this.name = ""; + } + + // MemberNotNullWhenAttribute + [MemberNotNullWhen(true, nameof(name))] + public bool ConditionallyAssignsField() + { + this.name = ""; + + return true; + } + + // NotNullAttribute + public void TakeValue3([NotNull] string? value) + { + throw null!; + } + + // NotNullIfNotNullAttribute + [return: NotNullIfNotNull(nameof(value))] + public string? TakeValue4(string? value) + { + return value; + } + + // NotNullWhenAttribute + public bool TakeValue([NotNullWhen(true)] out string? value) + { + value = this.name ?? ""; + + return true; + } + + [RequiresPreviewFeatures] + public void PreviewApi() + { + } + + public void TakeRegex([StringSyntax(StringSyntaxAttribute.Regex)] string pattern) + { + } + + [ModuleInitializer] + public static void InitializeModule() + { + } + + public void RefReadonlyMethod(ref readonly int x) + { + } + + [Experimental("PS0001")] + public void ExperimentalMethod() + { + } +} + +internal class TestClassWithRequiredMembers +{ + // SetsRequiredMembersAttribute + [SetsRequiredMembers] +#pragma warning disable IDE0290 + public TestClassWithRequiredMembers() +#pragma warning restore IDE0290 + { + Name = ""; + } + + // CompilerFeatureRequiredAttribute, RequiredMemberAttribute + public required string Name { get; init; } +} + +// IsExternalInit +internal record Person(string Name); + +internal readonly struct TestStruct +{ + private readonly int number; + + // UnscopedRefAttribute + [UnscopedRef] + public readonly ref readonly int GetRef() + { + return ref this.number; + } +} + +internal static class IndexAndRangeTests +{ + // Index + public static int TestIndex(ReadOnlySpan numbers) + { + return numbers[^1]; + } + + // Range + public static ReadOnlySpan TestRange(ReadOnlySpan numbers) + { + return numbers[1..^4]; + } +} + +[CollectionBuilder(typeof(CollectionClass), nameof(Create))] +internal class CollectionClass : IEnumerable +{ + public static CollectionClass Test() + { + Test2(1, 2, 3); + + return [1, 2, 3]; + } + + public static void Test2(params CollectionClass collection) + { + + } + + public static CollectionClass Create(ReadOnlySpan values) + { + return new(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return null!; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return null!; + } +} + +internal class AnotherTestClass +{ + // CallerArgumentExpressionAttribute + public string AutomaticName(int number, [CallerArgumentExpression(nameof(number))] string name = "") + { + return name; + } + + [SkipLocalsInit] + public void Stackalloc() + { + _ = stackalloc int[8]; + } + + public void Handler(string name, [InterpolatedStringHandlerArgument(nameof(name))] ref TestHandler handler) + { + } +} + +[InterpolatedStringHandler] +internal struct TestHandler +{ +} + +#if !NETSTANDARD2_1 + +internal struct TaskLikeType +{ + [AsyncMethodBuilder(typeof(CustomAsyncMethodBuilder))] + public static async TaskLikeType TestAsync() + { + await Task.Delay(1); + } + + private sealed class CustomAsyncMethodBuilder + { + public static CustomAsyncMethodBuilder Create() + { + return null!; + } + + public TaskLikeType Task => default; + + public void SetException(Exception e) + { + } + + public void SetResult() + { + } + + public void SetStateMachine(IAsyncStateMachine _) + { + } + + public void AwaitOnCompleted( + ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : INotifyCompletion + where TStateMachine : IAsyncStateMachine + { + } + + public void AwaitUnsafeOnCompleted( + ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : ICriticalNotifyCompletion + where TStateMachine : IAsyncStateMachine + { + } + + public void Start(ref TStateMachine stateMachine) + where TStateMachine : IAsyncStateMachine + { + + } + } +} + +#endif + +internal static class OverloadResolutionPriorityTests +{ + public static void Test() + { + TestOverload(1); + } + + [Obsolete("Do not use", error: true)] + [OverloadResolutionPriority(-1)] + public static void TestOverload(int x) + { + } + + public static void TestOverload(int x, int y = 0) + { + } +} + +internal static class ConstantExpectedTests +{ + public static void CpuIntrinsic([ConstantExpected] int value) + { + } + + public static void AnotherCpuIntrinsic([ConstantExpected(Min = 0, Max = 8)] int value) + { + } +} diff --git a/tests/PolySharp.InternalsVisibleTo.Tests/PolySharp.InternalsVisibleTo.Tests.csproj b/tests/PolySharp.InternalsVisibleTo.Tests/PolySharp.InternalsVisibleTo.Tests.csproj new file mode 100644 index 0000000..8c37d27 --- /dev/null +++ b/tests/PolySharp.InternalsVisibleTo.Tests/PolySharp.InternalsVisibleTo.Tests.csproj @@ -0,0 +1,21 @@ + + + + net472;net48;net481;netstandard2.0;netstandard2.1;net8.0;net9.0 + true + + + + + + + + + + + + + + + + diff --git a/tests/PolySharp.InternalsVisibleTo.Tests/RuntimeSupport.cs b/tests/PolySharp.InternalsVisibleTo.Tests/RuntimeSupport.cs new file mode 100644 index 0000000..6d6ca97 --- /dev/null +++ b/tests/PolySharp.InternalsVisibleTo.Tests/RuntimeSupport.cs @@ -0,0 +1,110 @@ +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; + +[assembly: TargetPlatform("windows6.1")] + +[assembly: DisableRuntimeMarshalling] + +namespace PolySharp.InternalsVisbleTo.Tests; + +internal class RandomApis +{ + [StackTraceHidden] + public void HideMe() + { + } +} + +internal class PlatformSpecificApis +{ + [UnmanagedCallersOnly] + [SuppressGCTransition] + public static void NativeFunction() + { + } + + [ObsoletedOSPlatform("windows6.1")] + public void Obsoleted() + { + } + + [SupportedOSPlatform("windows6.1")] + public void Supported() + { + } + + [SupportedOSPlatformGuard("windows6.1")] + public void SupportedGuard() + { + } + + [UnsupportedOSPlatform("windows6.1")] + public void Unsupported() + { + } + + [UnsupportedOSPlatformGuard("windows6.1")] + public void UnsupportedGuard() + { + } +} + +internal class ReflectionApis +{ + [RequiresUnreferencedCode("No idea what I'll reflect on")] + public void ReflectOnSomethingCrazy() + { + } + + public void ReflectOnInputType([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type) + { + } + + [DynamicDependency("PolySharp.Tests.ReflectionApis.ReflectOnSomethingCrazy()")] + public void ReflectDependingOnStuff() + { + } + + [UnconditionalSuppressMessage("Don't worry about it", "0000")] + public void SuppressEverything(Type type) + { + _ = type.GetProperties(); + } + + [RequiresDynamicCode("This method creates some type at runtime")] + public void MakeUpSomeNewType() + { + } + + [RequiresAssemblyFiles("This method needs access to the assembly files")] + public void ReferenceSomeAssemblyFile() + { + } +} + +internal class AccessorApis +{ +#pragma warning disable CS0169, IDE0044 + private int field; +#pragma warning restore CS0169, IDE0044 + + [StackTraceHidden] + public void HideMe() + { + } + + [UnsafeAccessor(UnsafeAccessorKind.Field, Name = nameof(field))] + public static extern ref int GetField(RandomApis obj); +} + +[InlineArray(16)] +internal struct Int8 +{ +#pragma warning disable CS0169, IDE0044, IDE0051 + private int value0; +#pragma warning restore CS0169, IDE0044, IDE0051 +} \ No newline at end of file diff --git a/tests/PolySharp.Tests/LanguageFeatures.cs b/tests/PolySharp.Tests/LanguageFeatures.cs index d5df709..a35bfaa 100644 --- a/tests/PolySharp.Tests/LanguageFeatures.cs +++ b/tests/PolySharp.Tests/LanguageFeatures.cs @@ -10,6 +10,8 @@ #pragma warning disable CA2255 +[assembly: InternalsVisibleTo("PolySharp.InternalsVisibleTo.Tests")] + namespace PolySharp.Tests; internal class TestClass