File: SyntaxNodeExtensionsTests.cs
Web Access
Project: src\test\Analyzers\Microsoft.Analyzers.Extra.Tests\Microsoft.Analyzers.Extra.Tests.csproj (Microsoft.Analyzers.Extra.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.Extensions.ExtraAnalyzers.Utilities;
using Moq;
using Xunit;
 
namespace Microsoft.Extensions.ExtraAnalyzers.Test;
 
public class SyntaxNodeExtensionsTests
{
    [Fact]
    public void CheckFindNodeInTreeUpToSpecifiedParentByMethodNameReturnsNullWhenNodeIsNotfound()
    {
        var node = SyntaxFactory.VariableDeclarator("v");
        var emptyList = new List<string>();
 
        Assert.Null(node.FindNodeInTreeUpToSpecifiedParentByMethodName(new Mock<SemanticModel>().Object, emptyList, new List<Type>()));
    }
 
    [Fact]
    public void FindNodeInTreeUpToSpecifiedParentByMethodName_WhenNodeFounded()
    {
        string codeStr = @"
	         public static class Extensions {
                public static string AddA(this string a)
                {
                    return a + ""a"";
                }
             }
 
	         public class MyClass {
			    int Method1() { return 0; }
			    void Method2()
			    {
				    string a = ""ab"";
                    a.AddA();
			    }
		     }";
 
        SyntaxTree tree = SyntaxFactory.ParseSyntaxTree(codeStr);
 
        var compilation = CSharpCompilation.Create(
                        "MyCompilation",
                        syntaxTrees: new[] { tree },
                        references: new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) });
        var model = compilation.GetSemanticModel(tree);
        var methodInvocSyntax = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().FirstOrDefault();
        var parentToFind = "Extensions.AddA(string)";
        Assert.Equal("a.AddA()", methodInvocSyntax?.FindNodeInTreeUpToSpecifiedParentByMethodName(model, new[] { parentToFind }, Array.Empty<Type>())?.ToString());
    }
 
    [Fact]
    public void FindNodeInTreeUpToSpecifiedParentByMethodName_WhenStopped()
    {
        string codeStr = @"
	         public static class Extensions {
                public static string AddA(this string a)
                {
                    return a + ""a"";
                }
             }
 
	         public class MyClass {
			    int Method1() { return 0; }
			    void Method2()
			    {
				    string a = ""ab"";
                    a.AddA().AddA();
			    }
		     }";
 
        SyntaxTree tree = SyntaxFactory.ParseSyntaxTree(codeStr);
 
        var compilation = CSharpCompilation.Create(
                        "MyCompilation",
                        syntaxTrees: new[] { tree },
                        references: new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) });
        var model = compilation.GetSemanticModel(tree);
        var methodInvocSyntax = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().FirstOrDefault();
 
        var typesToStopTraversing = new HashSet<Type>
        {
            typeof(ExpressionStatementSyntax),
        };
 
        Assert.Null(methodInvocSyntax?.FindNodeInTreeUpToSpecifiedParentByMethodName(model, Array.Empty<string>(), typesToStopTraversing));
    }
 
    [Fact]
    public void CheckGetFirstAncestorOfSyntaxKindReturnsNullWhenNodeIsNotfound()
    {
        var node = SyntaxFactory.VariableDeclarator("v");
 
        Assert.Null(node.GetFirstAncestorOfSyntaxKind(SyntaxKind.EqualsValueClause));
    }
 
    [Fact]
    public void GetExpressionNameReturnsNullWhenExpressionIsNotMemberAccessOrMemeberBinding()
    {
        var node = SyntaxFactory.InvocationExpression(SyntaxFactory.IdentifierName("CheckGetFirstAncestorOfSyntaxKindReturnsNullWhenNodeIsNotfound"));
 
        Assert.Null(node.GetExpressionName());
    }
 
    [Theory]
    [InlineData("expectedName", true)]
    [InlineData("anotherNameExpected", false)]
    public void IdentifierNameEqualsReturnsResultWhenNodeTypeIsIdentifierNameSyntax(string expectedName, bool result)
    {
        var node = SyntaxFactory.IdentifierName("expectedName");
 
        Assert.Equal(result, node.IdentifierNameEquals(expectedName));
    }
 
    [Fact]
    public void IdentifierNameEqualsReturnsFalseWhenNodeTypeIsNotIdentifierNameSyntax()
    {
        Assert.False(((LiteralExpressionSyntax)null!).IdentifierNameEquals("a"));
    }
 
    [Fact]
    public void NodeHasSpecifiedMethodReturnsFalseWhenMethodSymbolIsNull()
    {
        string codeStr = @"
                using System;
 
                public class MyClassClass
                {
                    virtual public void MyMehtod()
                    {
                        Console.WriteLine(""Hello from MyClass"");
                    }
                }
            ";
        SyntaxTree tree = SyntaxFactory.ParseSyntaxTree(codeStr);
 
        var compilation = CSharpCompilation.Create(
                            "MyCompilation",
                            syntaxTrees: new[] { tree },
                            references: new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) });
        var model = compilation.GetSemanticModel(tree);
        var methodInvocSyntax = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().FirstOrDefault();
        Assert.False(methodInvocSyntax!.NodeHasSpecifiedMethod(model, new HashSet<string>()));
    }
 
    [Fact]
    public void NodeHasSpecifiedMethodContainsReducedForm()
    {
        string codeStr = @"
             public static class Extensions {
                public static string AddA(this string a)
                {
                    return a + ""a"";
                }
             }
 
	         public class MyClass {
			    int Method1() { return 0; }
			    void Method2()
			    {
				    string a = ""ab"";
                    a.AddA();
			    }
		     }";
 
        SyntaxTree tree = SyntaxFactory.ParseSyntaxTree(codeStr);
        var compilation = CSharpCompilation.Create(
                        "MyCompilation",
                        syntaxTrees: new[] { tree },
                        references: new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) });
        var model = compilation.GetSemanticModel(tree);
        var methodInvocSyntax = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().FirstOrDefault();
        Assert.True(methodInvocSyntax!.NodeHasSpecifiedMethod(model, new HashSet<string> { "Extensions.AddA(string)" }));
    }
 
    [Fact]
    public void GetExpressionName_WithMemberAccessExpression()
    {
        var console = SyntaxFactory.IdentifierName("Console");
        var writeline = SyntaxFactory.IdentifierName("WriteLine");
        var memberaccess = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, console, writeline);
        var expression = SyntaxFactory.InvocationExpression(memberaccess, SyntaxFactory.ArgumentList());
 
        Assert.Equal(writeline.ToString(), expression.GetExpressionName()?.ToString());
    }
 
    [Fact]
    public void GetExpressionName_WithMemberBindingExpression()
    {
        var b = SyntaxFactory.IdentifierName("b");
        var memberbind = SyntaxFactory.MemberBindingExpression(SyntaxFactory.ParseToken("."), b);
        var expression = SyntaxFactory.InvocationExpression(memberbind);
 
        Assert.Equal(b.ToString(), expression.GetExpressionName()?.ToString());
    }
}