using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace RobloxCS { internal sealed class SymbolAnalyzerResults { public List TypesWithMembersUsedAsValues { get; set; } = new List(); 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(); 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(); 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() .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; } } }