Skip to content

Commit 5219fc8

Browse files
committed
update fix relations
1 parent 7726621 commit 5219fc8

1 file changed

Lines changed: 154 additions & 91 deletions

File tree

tools/CodeAnalysisTool/CodeGraphWalker.cs

Lines changed: 154 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,18 @@ public class CodeGraphWalker : CSharpSyntaxWalker
2727
private readonly HashSet<string> _classNames = new HashSet<string>();
2828
private readonly HashSet<string> _methodFullNames = new HashSet<string>();
2929
private readonly HashSet<string> _propertyFullNames = new HashSet<string>();
30+
private readonly HashSet<string> _variableFullNames = new HashSet<string>();
3031

3132
// Track used/unused elements
3233
private readonly HashSet<string> _usedClasses = new HashSet<string>();
3334
private readonly HashSet<string> _usedMethods = new HashSet<string>();
3435
private readonly HashSet<string> _usedProperties = new HashSet<string>();
36+
private readonly HashSet<string> _usedVariables = new HashSet<string>();
3537

3638
// Track method calls and property access
3739
private readonly Dictionary<string, List<string>> _methodCallMap = new Dictionary<string, List<string>>();
3840
private readonly Dictionary<string, List<string>> _methodPropertyMap = new Dictionary<string, List<string>>();
41+
private readonly Dictionary<string, string> _variableTypeMap = new Dictionary<string, string>();
3942

4043
// Override to use custom parameters
4144
public CodeGraphWalker() : base(SyntaxWalkerDepth.Node)
@@ -214,10 +217,10 @@ public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node)
214217
}
215218

216219
// Record property->type
217-
//if (!_propertyTypeMap.ContainsKey(fullPropertyName))
218-
//{
219-
// _propertyTypeMap[fullPropertyName] = typeFullName;
220-
//}
220+
if (!_variableTypeMap.ContainsKey(fullPropertyName))
221+
{
222+
_variableTypeMap[fullPropertyName] = typeFullName;
223+
}
221224
}
222225

223226
base.VisitPropertyDeclaration(node);
@@ -236,7 +239,7 @@ public override void VisitLocalDeclarationStatement(LocalDeclarationStatementSyn
236239
{
237240
string variableName = variable.Identifier.Text;
238241
string fullVariableName = $"{_currentMethod}.{variableName}";
239-
//_variableFullNames.Add(fullVariableName);
242+
_variableFullNames.Add(fullVariableName);
240243

241244
// Get type information
242245
var typeSymbol = SemanticModel.GetTypeInfo(node.Declaration.Type).Type;
@@ -250,7 +253,7 @@ public override void VisitLocalDeclarationStatement(LocalDeclarationStatementSyn
250253
_usedClasses.Add(typeFullName);
251254
}
252255

253-
//_variableTypeMap[fullVariableName] = typeFullName;
256+
_variableTypeMap[fullVariableName] = typeFullName;
254257
}
255258
}
256259

@@ -282,8 +285,8 @@ public override void VisitFieldDeclaration(FieldDeclarationSyntax node)
282285
{
283286
string variableName = variable.Identifier.Text;
284287
string fullVariableName = $"{_currentClass}.{variableName}";
285-
//_variableFullNames.Add(fullVariableName);
286-
//_variableTypeMap[fullVariableName] = typeFullName;
288+
_variableFullNames.Add(fullVariableName);
289+
_variableTypeMap[fullVariableName] = typeFullName;
287290
}
288291
}
289292

@@ -406,6 +409,37 @@ public override void VisitMemberAccessExpression(MemberAccessExpressionSyntax no
406409
base.VisitMemberAccessExpression(node);
407410
}
408411

412+
/// <summary>
413+
/// Visit identifier name expressions (e.g. variable references)
414+
/// </summary>
415+
public override void VisitIdentifierName(IdentifierNameSyntax node)
416+
{
417+
// Only track identifiers within a method context
418+
if (SemanticModel != null && !string.IsNullOrEmpty(_currentMethod))
419+
{
420+
string identifierName = node.Identifier.Text;
421+
string fullVariableName = $"{_currentMethod}.{identifierName}";
422+
423+
// If this is a variable we're tracking, mark it as used
424+
if (_variableFullNames.Contains(fullVariableName))
425+
{
426+
_usedVariables.Add(fullVariableName);
427+
}
428+
429+
// Also check if it might be a class field
430+
if (!string.IsNullOrEmpty(_currentClass))
431+
{
432+
string fieldName = $"{_currentClass}.{identifierName}";
433+
if (_variableFullNames.Contains(fieldName))
434+
{
435+
_usedVariables.Add(fieldName);
436+
}
437+
}
438+
}
439+
440+
base.VisitIdentifierName(node);
441+
}
442+
409443
/// <summary>
410444
/// Improves property access tracking by processing object initializers
411445
/// </summary>
@@ -474,48 +508,6 @@ public override void VisitObjectCreationExpression(ObjectCreationExpressionSynta
474508
base.VisitObjectCreationExpression(node);
475509
}
476510

477-
// Helpers for building full names from symbols
478-
private string BuildFullTypeName(ITypeSymbol typeSymbol)
479-
{
480-
if (typeSymbol == null)
481-
return "Unknown";
482-
483-
if (typeSymbol.ContainingNamespace != null && !string.IsNullOrEmpty(typeSymbol.ContainingNamespace.Name))
484-
{
485-
return $"{typeSymbol.ContainingNamespace}.{typeSymbol.Name}";
486-
}
487-
488-
return typeSymbol.Name;
489-
}
490-
491-
private string BuildFullMethodName(IMethodSymbol methodSymbol)
492-
{
493-
if (methodSymbol == null)
494-
return "Unknown";
495-
496-
if (methodSymbol.ContainingType != null)
497-
{
498-
string typeName = BuildFullTypeName(methodSymbol.ContainingType);
499-
return $"{typeName}.{methodSymbol.Name}";
500-
}
501-
502-
return methodSymbol.Name;
503-
}
504-
505-
private string BuildFullPropertyName(IPropertySymbol propertySymbol)
506-
{
507-
if (propertySymbol == null)
508-
return "Unknown";
509-
510-
if (propertySymbol.ContainingType != null)
511-
{
512-
string typeName = BuildFullTypeName(propertySymbol.ContainingType);
513-
return $"{typeName}.{propertySymbol.Name}";
514-
}
515-
516-
return propertySymbol.Name;
517-
}
518-
519511
/// <summary>
520512
/// Generates the final D3 graph with all nodes and links
521513
/// </summary>
@@ -710,6 +702,18 @@ public D3Graph GetGraph()
710702
});
711703
}
712704

705+
// Add variable nodes
706+
foreach (var variable in _variableFullNames)
707+
{
708+
graph.Nodes.Add(new D3Node
709+
{
710+
Id = variable,
711+
Group = "variable",
712+
Label = variable.Split('.').Last(),
713+
Used = _usedVariables.Contains(variable)
714+
});
715+
}
716+
713717
// Add external nodes for references that would be dangling otherwise
714718
foreach (var externalNode in externalNodes)
715719
{
@@ -739,64 +743,88 @@ public D3Graph GetGraph()
739743

740744
// 4) Links:
741745
// (a) namespace -> class
742-
foreach (var cls in _classNames)
746+
foreach (var className in _classNames)
743747
{
744-
int idx = cls.LastIndexOf('.');
745-
if (idx > 0)
748+
var namespaceName = className.Split('.')[0];
749+
graph.Links.Add(new D3Link
746750
{
747-
var ns = cls.Substring(0, idx);
748-
if (_namespaceNames.Contains(ns))
751+
Source = namespaceName,
752+
Target = className,
753+
Type = "containment"
754+
});
755+
}
756+
757+
// (b) class -> method
758+
foreach (var method in _methodFullNames)
759+
{
760+
int lastDot = method.LastIndexOf('.');
761+
if (lastDot > 0)
762+
{
763+
string className = method.Substring(0, lastDot);
764+
if (_classNames.Contains(className))
749765
{
750766
graph.Links.Add(new D3Link
751767
{
752-
Source = ns,
753-
Target = cls,
768+
Source = className,
769+
Target = method,
754770
Type = "containment"
755771
});
756772
}
757773
}
758774
}
759-
760-
// (b) class -> method
761-
foreach (var method in _methodFullNames)
775+
776+
// (c) class -> property
777+
foreach (var property in _propertyFullNames)
762778
{
763-
int idx = method.LastIndexOf('.');
764-
if (idx > 0)
779+
int lastDot = property.LastIndexOf('.');
780+
if (lastDot > 0)
765781
{
766-
var cls = method.Substring(0, idx);
767-
if (_classNames.Contains(cls))
782+
string className = property.Substring(0, lastDot);
783+
if (_classNames.Contains(className))
768784
{
769785
graph.Links.Add(new D3Link
770786
{
771-
Source = cls,
772-
Target = method,
787+
Source = className,
788+
Target = property,
773789
Type = "containment"
774790
});
775791
}
776792
}
777793
}
778794

779-
// (c) class->property
780-
foreach (var prop in _propertyFullNames)
795+
// (d) method -> variable (variables belong to methods)
796+
foreach (var variable in _variableFullNames)
781797
{
782-
int idx = prop.LastIndexOf('.');
783-
if (idx > 0)
798+
int lastDot = variable.LastIndexOf('.');
799+
if (lastDot > 0)
784800
{
785-
var cls = prop.Substring(0, idx);
786-
// If that class is in _classNames, link them
787-
if (_classNames.Contains(cls))
801+
string container = variable.Substring(0, lastDot);
802+
803+
// Check if this is a method variable or class field
804+
if (_methodFullNames.Contains(container))
788805
{
806+
// Method variable
789807
graph.Links.Add(new D3Link
790808
{
791-
Source = cls,
792-
Target = prop,
809+
Source = container,
810+
Target = variable,
811+
Type = "containment"
812+
});
813+
}
814+
else if (_classNames.Contains(container))
815+
{
816+
// Class field
817+
graph.Links.Add(new D3Link
818+
{
819+
Source = container,
820+
Target = variable,
793821
Type = "containment"
794822
});
795823
}
796824
}
797825
}
798826

799-
// (d) method->property usage
827+
// (e) method -> property usage
800828
foreach (var kvp in _methodPropertyMap)
801829
{
802830
var callerMethod = kvp.Key; // e.g. "MyApp.Core.Foo.Bar"
@@ -817,26 +845,19 @@ public D3Graph GetGraph()
817845
}
818846
}
819847
}
820-
821-
// (e) method -> method (method calls)
848+
849+
// (f) method calls
822850
foreach (var kvp in _methodCallMap)
823851
{
824-
var caller = kvp.Key;
852+
string caller = kvp.Key;
825853
foreach (var callee in kvp.Value)
826854
{
827-
// Make sure both ends of the link exist
828-
if (NodeExists(graph, caller) && NodeExists(graph, callee))
855+
// Skip self-calls (they clutter the graph)
856+
if (caller != callee)
829857
{
830-
// default to internal call
831-
var linkType = "call";
832-
833-
// Check if this is an external call (a method outside our codebase)
834-
bool isExternal = !_methodFullNames.Contains(callee);
835-
if (isExternal)
836-
{
837-
linkType = "external";
838-
}
839-
858+
// External calls get a different edge type
859+
string linkType = _methodFullNames.Contains(callee) ? "call" : "external";
860+
840861
graph.Links.Add(new D3Link
841862
{
842863
Source = caller,
@@ -857,6 +878,48 @@ private bool NodeExists(D3Graph graph, string nodeId)
857878
{
858879
return graph.Nodes.Any(n => n.Id == nodeId);
859880
}
881+
882+
// Helpers for building full names from symbols
883+
private string BuildFullTypeName(ITypeSymbol typeSymbol)
884+
{
885+
if (typeSymbol == null)
886+
return "Unknown";
887+
888+
if (typeSymbol.ContainingNamespace != null && !string.IsNullOrEmpty(typeSymbol.ContainingNamespace.Name))
889+
{
890+
return $"{typeSymbol.ContainingNamespace}.{typeSymbol.Name}";
891+
}
892+
893+
return typeSymbol.Name;
894+
}
895+
896+
private string BuildFullMethodName(IMethodSymbol methodSymbol)
897+
{
898+
if (methodSymbol == null)
899+
return "Unknown";
900+
901+
if (methodSymbol.ContainingType != null)
902+
{
903+
string typeName = BuildFullTypeName(methodSymbol.ContainingType);
904+
return $"{typeName}.{methodSymbol.Name}";
905+
}
906+
907+
return methodSymbol.Name;
908+
}
909+
910+
private string BuildFullPropertyName(IPropertySymbol propertySymbol)
911+
{
912+
if (propertySymbol == null)
913+
return "Unknown";
914+
915+
if (propertySymbol.ContainingType != null)
916+
{
917+
string typeName = BuildFullTypeName(propertySymbol.ContainingType);
918+
return $"{typeName}.{propertySymbol.Name}";
919+
}
920+
921+
return propertySymbol.Name;
922+
}
860923
}
861924

862925
/// <summary>

0 commit comments

Comments
 (0)