File size: 4,107 Bytes
1ae2e8e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace RobloxCS
{
    internal sealed class SymbolAnalyzerResults
    {
        public List<INamespaceOrTypeSymbol> TypesWithMembersUsedAsValues { get; set; } = new List<INamespaceOrTypeSymbol>();

        public bool TypeHasMemberUsedAsValue(INamespaceOrTypeSymbol namespaceOrType)
        {
            return TypesWithMembersUsedAsValues.Any(symbol => SymbolEqualityComparer.Default.Equals(symbol, namespaceOrType));
        }
    }

    internal sealed class SymbolAnalyzer
    {
        private readonly SyntaxTree _tree;
        private readonly SemanticModel _semanticModel;
        private readonly SymbolAnalyzerResults _results = new SymbolAnalyzerResults();

        public SymbolAnalyzer(SyntaxTree tree, SemanticModel semanticModel)
        {
            _tree = tree;
            _semanticModel = semanticModel;
        }

        public SymbolAnalyzerResults Analyze()
        {
            AnalyzeUsings();
            AnalyzeNamespaces();
            return _results;
        }

        private void AnalyzeNamespaces()
        {
            var root = _tree.GetRoot();
            var namespaceDeclarations = root.DescendantNodes().OfType<NamespaceDeclarationSyntax>();

            foreach (var namespaceDeclaration in namespaceDeclarations)
            {
                var symbolInfo = _semanticModel.GetSymbolInfo(namespaceDeclaration.Name);
                if (symbolInfo.Symbol is INamespaceOrTypeSymbol namespaceOrTypeSymbol && HasMembersUsedAsValues(namespaceOrTypeSymbol, root))
                {
                    _results.TypesWithMembersUsedAsValues.Add(namespaceOrTypeSymbol);
                }
            }
        }

        private void AnalyzeUsings()
        {
            var root = _tree.GetRoot();
            var usingDirectives = root.DescendantNodes().OfType<UsingDirectiveSyntax>();

            foreach (var usingDirective in usingDirectives)
            {
                if (usingDirective.Name == null) continue;

                var symbolInfo = _semanticModel.GetSymbolInfo(usingDirective.Name);
                if (symbolInfo.Symbol is INamespaceOrTypeSymbol namespaceOrTypeSymbol && HasMembersUsedAsValues(namespaceOrTypeSymbol, root))
                {
                    _results.TypesWithMembersUsedAsValues.Add(namespaceOrTypeSymbol);
                }
            }
        }
        
        private bool HasMembersUsedAsValues(INamespaceOrTypeSymbol namespaceOrTypeSymbol, SyntaxNode root)
        {
            var typeUsages = root.DescendantNodes()
                .OfType<IdentifierNameSyntax>()
                .Where(identifier => 
                    _semanticModel.GetSymbolInfo(identifier).Symbol is INamedTypeSymbol symbol
                        && SymbolEqualityComparer.Default.Equals(symbol.ContainingNamespace, namespaceOrTypeSymbol)
                );

            foreach (var usage in typeUsages)
            {
                if (IsUsedAsValue(usage))
                {
                    return true;
                }
            }
            return false;
        }

        private bool IsUsedAsValue(SyntaxNode node)
        {
            // Check for object instantiation, member access, or variable declarator
            if (node.Parent is ObjectCreationExpressionSyntax ||
                node.Parent is MemberAccessExpressionSyntax ||
                node.Parent is VariableDeclaratorSyntax ||
                node.Parent is AssignmentExpressionSyntax)
            {
                return true;
            }

            // Check if used in a method invocation
            if (node.Parent is InvocationExpressionSyntax invocation)
            {
                var symbolInfo = _semanticModel.GetSymbolInfo(invocation);
                if (symbolInfo.Symbol is IMethodSymbol methodSymbol)
                {
                    return methodSymbol.Parameters.Any(p => SymbolEqualityComparer.Default.Equals(p.Type, _semanticModel.GetTypeInfo(node).Type));
                }
            }

            return false;
        }
    }
}