Spaces:
Running
Running
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;
}
}
} |