File: Semantics\SuppressAccessibilityChecksTests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Semantic\Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#nullable disable
 
using System.IO;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics
{
    public class SuppressAccessibilityChecksTests : CSharpTestBase
    {
        private static SemanticModel GetSemanticModelWithIgnoreAccessibility()
        {
            var compilationA = CreateCompilation(@"
namespace N
{
    class A
    {
        A M() { return new A(); }
        int _num;
    }
}"
                );
 
            var referenceA = MetadataReference.CreateFromStream(compilationA.EmitToStream());
 
            var compilationB = CreateCompilation(@"
using A = N.A;
 
class B 
{
    void Main() 
    {
        new A().M();
    }
}
 
", new MetadataReference[] { referenceA }, TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All));
 
            var syntaxTree = compilationB.SyntaxTrees[0];
            return compilationB.GetSemanticModel(syntaxTree, ignoreAccessibility: true);
        }
 
        [Fact]
        public void TestAccessPrivateMemberOfInternalType()
        {
            var semanticModel = GetSemanticModelWithIgnoreAccessibility();
            var invocation = semanticModel.SyntaxTree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single();
            var position = invocation.FullSpan.Start;
 
            Assert.Equal("A", semanticModel.GetTypeInfo(invocation).Type.Name);
            Assert.Equal("M", semanticModel.GetSymbolInfo(invocation).Symbol.Name);
            Assert.NotEmpty(semanticModel.LookupSymbols(position, name: "A"));
 
            semanticModel = semanticModel.Compilation.GetSemanticModel(semanticModel.SyntaxTree);
            Assert.Equal("A", semanticModel.GetTypeInfo(invocation).Type.Name);
            Assert.Null(semanticModel.GetSymbolInfo(invocation).Symbol);
            Assert.Equal("M", semanticModel.GetSymbolInfo(invocation).CandidateSymbols.Single().Name);
            Assert.Equal(CandidateReason.Inaccessible, semanticModel.GetSymbolInfo(invocation).CandidateReason);
        }
 
        [Fact]
        public void TestAccessChecksInSpeculativeExpression()
        {
            var semanticModel = GetSemanticModelWithIgnoreAccessibility();
            var invocation = semanticModel.SyntaxTree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single();
            var position = invocation.FullSpan.Start;
 
            var exp = SyntaxFactory.ParseExpression("new A().M()._num");
            Assert.Equal("Int32",
                semanticModel.GetSpeculativeTypeInfo(position, exp, SpeculativeBindingOption.BindAsExpression).Type.Name);
 
            Assert.Equal("_num",
                semanticModel.GetSpeculativeSymbolInfo(position, exp, SpeculativeBindingOption.BindAsExpression).Symbol.Name);
        }
 
        [Fact]
        public void TestAccessChecksInSpeculativeSemanticModel()
        {
            var semanticModel = GetSemanticModelWithIgnoreAccessibility();
            var invocation = semanticModel.SyntaxTree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single();
            var position = invocation.FullSpan.Start;
 
            SemanticModel speculativeSemanticModel;
            var statement = SyntaxFactory.ParseStatement("var goo = new A().M();");
 
            semanticModel.TryGetSpeculativeSemanticModel(position, statement, out speculativeSemanticModel);
            var creationExpression =
                speculativeSemanticModel.GetTypeInfo(
                    statement.DescendantNodes().OfType<ObjectCreationExpressionSyntax>().Single());
 
            Assert.Equal("A", creationExpression.Type.Name);
        }
 
        [Fact]
        public void TestAccessChecksInsideLambdaExpression()
        {
            var source = @"
using System.Collections.Generic;
 
class P { bool _p; }
 
class C
{
    static void M()
    {
        var tmp = new List<P>();
        tmp.Find(a => true);
    }
}
";
 
            var tree = SyntaxFactory.ParseSyntaxTree(source);
            var comp = CreateCompilation(tree);
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: true);
 
            var expr = (ExpressionSyntax)tree.GetCompilationUnitRoot().DescendantNodes().OfType<SimpleLambdaExpressionSyntax>().Single().Body;
 
            var symbolInfo = model.GetSpeculativeSymbolInfo(expr.FullSpan.Start,
                                                           SyntaxFactory.ParseExpression("a._p"),
                                                           SpeculativeBindingOption.BindAsExpression);
 
            Assert.Equal("_p", symbolInfo.Symbol.Name);
        }
 
        [Fact]
        public void TestExtensionMethodInInternalClass()
        {
            var compilationA = CreateCompilationWithMscorlib40AndSystemCore(@"
public class A
{
    A M() { return new A(); }
    internal int _num;
}
 
internal static class E
{
    internal static int InternalExtension(this A theClass, int newNum)
    {
        theClass._num = newNum;
        
        return newNum;
    }
}
");
 
            var referenceA = MetadataReference.CreateFromStream(compilationA.EmitToStream());
 
            var compilationB = CreateCompilation(@"
class B 
{
    void Main() 
    {
        new A().M();
    }
}
 
", new MetadataReference[] { referenceA }, TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All));
 
            var syntaxTree = compilationB.SyntaxTrees[0];
            var semanticModel = compilationB.GetSemanticModel(syntaxTree, ignoreAccessibility: true);
 
            var invocation = syntaxTree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single();
 
            Assert.Equal("A", semanticModel.GetTypeInfo(invocation).Type.Name);
            Assert.Equal("M", semanticModel.GetSymbolInfo(invocation).Symbol.Name);
 
            var speculativeInvocation = SyntaxFactory.ParseExpression("new A().InternalExtension(67)");
            var position = invocation.FullSpan.Start;
 
            Assert.Equal("Int32", semanticModel.GetSpeculativeTypeInfo(position, speculativeInvocation, SpeculativeBindingOption.BindAsExpression).Type.Name);
            Assert.Equal("InternalExtension", semanticModel.GetSpeculativeSymbolInfo(position, speculativeInvocation, SpeculativeBindingOption.BindAsExpression).Symbol.Name);
        }
 
        [Fact]
        public void TestGetSpeculativeSemanticModelForPropertyAccessorBody()
        {
            var compilation = CreateCompilation(@"
class R
{
    private int _p;
}
 
class C : R 
{
    
    private int M
    {
        set
        {
            int y = 1000;
        }
    }
}
");
 
            var blockStatement = (BlockSyntax)SyntaxFactory.ParseStatement(@"
{ 
   int z = 0; 
 
   _p = 123L;
}
");
 
            var tree = compilation.SyntaxTrees[0];
            var root = tree.GetCompilationUnitRoot();
            var model = compilation.GetSemanticModel(tree, ignoreAccessibility: true);
 
            AccessorDeclarationSyntax accessorDecl = root.DescendantNodes().OfType<AccessorDeclarationSyntax>().Single();
 
            var speculatedMethod = accessorDecl.ReplaceNode(accessorDecl.Body, blockStatement);
 
            SemanticModel speculativeModel;
            var success =
                model.TryGetSpeculativeSemanticModelForMethodBody(
                    accessorDecl.Body.Statements[0].SpanStart, speculatedMethod, out speculativeModel);
 
            Assert.True(success);
            Assert.NotNull(speculativeModel);
 
            var p =
                speculativeModel.SyntaxTree.GetRoot()
                    .DescendantNodes()
                    .OfType<IdentifierNameSyntax>()
                    .Single(s => s.Identifier.ValueText == "_p");
 
            var symbolSpeculation =
                speculativeModel.GetSpeculativeSymbolInfo(p.FullSpan.Start, p, SpeculativeBindingOption.BindAsExpression);
 
            Assert.Equal("_p", symbolSpeculation.Symbol.Name);
 
            var typeSpeculation =
                speculativeModel.GetSpeculativeTypeInfo(p.FullSpan.Start, p, SpeculativeBindingOption.BindAsExpression);
 
            Assert.Equal("Int32", typeSpeculation.Type.Name);
        }
    }
}