Skip to content

Commit 6e35a9a

Browse files
committed
Handle global statements
1 parent e88ba97 commit 6e35a9a

File tree

3 files changed

+62
-3
lines changed

3 files changed

+62
-3
lines changed

CodeParser/Parser/Parser.Phase1.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ public partial class Parser
99
{
1010
private readonly List<INamedTypeSymbol> _allNamedTypesInSolution = new();
1111

12+
private readonly Dictionary<IAssemblySymbol, List<GlobalStatementSyntax>> _globalStatementsByAssembly = new(SymbolEqualityComparer.Default);
13+
14+
1215
private async Task BuildHierarchy(Solution solution)
1316
{
1417
foreach (var project in solution.Projects)
@@ -40,6 +43,7 @@ private void BuildHierarchy(Compilation compilation)
4043
// Assembly has no source location.
4144
var assemblySymbol = compilation.Assembly;
4245
var assemblyElement = GetOrCreateCodeElement(assemblySymbol, CodeElementType.Assembly, null!, null!);
46+
_globalStatementsByAssembly[assemblySymbol] = new List<GlobalStatementSyntax>();
4347

4448
foreach (var syntaxTree in compilation.SyntaxTrees)
4549
{
@@ -146,6 +150,12 @@ private void ProcessNodeForHierarchy(SyntaxNode node, SemanticModel semanticMode
146150
symbol = semanticModel.GetDeclaredSymbol(node) as IEventSymbol;
147151
elementType = CodeElementType.Event;
148152
break;
153+
154+
case GlobalStatementSyntax globalStatementSyntax:
155+
var assemblySymbol = semanticModel.Compilation.Assembly;
156+
_globalStatementsByAssembly[assemblySymbol].Add(globalStatementSyntax);
157+
return; // We'll handle these collectively later
158+
149159
// Add more cases as needed (e.g., for events, delegates, etc.)
150160
}
151161

CodeParser/Parser/Parser.Phase2.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,57 @@ private void AnalyzeDependencies(Solution solution)
5757

5858
++loop;
5959
}
60+
61+
// Analyze global statements for each assembly
62+
AnalyzeGlobalStatementsForAssembly(solution);
6063
}
6164

65+
66+
private void AnalyzeGlobalStatementsForAssembly(Solution solution)
67+
{
68+
foreach (var statement in _globalStatementsByAssembly)
69+
{
70+
var assemblySymbol = statement.Key;
71+
var globalStatements = statement.Value;
72+
if (globalStatements.Count == 0)
73+
{
74+
continue;
75+
}
76+
77+
// Find the existing assembly element
78+
var symbolKey = GetSymbolKey(assemblySymbol);
79+
var assemblyElement = _symbolKeyToElementMap[symbolKey];
80+
81+
// Create a dummy class for this assembly's global statements
82+
var dummyClassId = Guid.NewGuid().ToString();
83+
var dummyClassName = "GlobalStatements";
84+
var dummyClassFullName = BuildSymbolName(assemblySymbol) + "." + dummyClassName;
85+
var dummyClass = new CodeElement(dummyClassId, CodeElementType.Class, dummyClassName, dummyClassFullName,
86+
assemblyElement);
87+
_codeGraph.Nodes[dummyClassId] = dummyClass;
88+
assemblyElement.Children.Add(dummyClass);
89+
90+
// Create a dummy method to contain global statements
91+
var dummyMethodId = Guid.NewGuid().ToString();
92+
var dummyMethodName = "Execute";
93+
var dummyMethodFullName = $"{dummyClassName}.{dummyMethodName}";
94+
var dummyMethod = new CodeElement(dummyMethodId, CodeElementType.Method, dummyMethodName,
95+
dummyMethodFullName, dummyClass);
96+
_codeGraph.Nodes[dummyMethodId] = dummyMethod;
97+
dummyClass.Children.Add(dummyMethod);
98+
99+
// Analyze global statements within the context of the dummy method
100+
foreach (var globalStatement in globalStatements)
101+
{
102+
var document = solution.GetDocument(globalStatement.SyntaxTree);
103+
var semanticModel = document?.GetSemanticModelAsync().Result;
104+
if (semanticModel != null)
105+
{
106+
AnalyzeMethodBody(dummyMethod, globalStatement, semanticModel);
107+
}
108+
}
109+
}
110+
}
62111
private void AnalyzeAttributeDependencies(CodeElement element, ISymbol symbol)
63112
{
64113
foreach (var attributeData in symbol.GetAttributes())

CodeParser/Parser/Parser.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public async Task<CodeGraph> ParseSolution(string solutionPath)
4242

4343
// Makes the cycle detection easier because I never get to the assembly as shared ancestor
4444
// for a nested dependency.
45-
InsertGlobalNamesapceIfUsed();
45+
InsertGlobalNamespaceIfUsed();
4646
return _codeGraph;
4747
}
4848

@@ -57,10 +57,10 @@ private void Clear()
5757
/// If any assembly uses the global namespace we add the global namespace to all assemblies.
5858
/// For example a unit test assembly may have the autogenerated Main.
5959
/// </summary>
60-
private void InsertGlobalNamesapceIfUsed()
60+
private void InsertGlobalNamespaceIfUsed()
6161
{
6262
var global = "global";
63-
var assemblies = _codeGraph.Nodes.Values.Where(n => n.Parent is null);
63+
var assemblies = _codeGraph.Nodes.Values.Where(n => n.Parent is null).ToList();
6464
Debug.Assert(assemblies.All(a => a.ElementType == CodeElementType.Assembly));
6565
var isGlobalNsUsed = assemblies.Any(a => a.Children.Any(c => c.ElementType != CodeElementType.Namespace));
6666

0 commit comments

Comments
 (0)