Skip to content

Call type refactoring #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6,146 changes: 6,146 additions & 0 deletions ApprovalTestTool/References/446736ffcda573c08f80d95b8ecf13675bd6a486.txt

Large diffs are not rendered by default.

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions CSharpCodeAnalyst.sln
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Contracts", "Contracts\Cont
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApprovalTestTool", "ApprovalTestTool\ApprovalTestTool.csproj", "{767539BE-FBE3-4B46-9A5E-21D60E1B278B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestApps", "TestApps", "{4553EF99-1D3C-14C7-0D22-5364D18C373B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FollowHeuristic", "TestApps\FollowHeuristic\FollowHeuristic.csproj", "{30665FC1-D5F2-4F4C-BBFA-277184C15E45}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -54,11 +58,18 @@ Global
{767539BE-FBE3-4B46-9A5E-21D60E1B278B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{767539BE-FBE3-4B46-9A5E-21D60E1B278B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{767539BE-FBE3-4B46-9A5E-21D60E1B278B}.Release|Any CPU.Build.0 = Release|Any CPU
{30665FC1-D5F2-4F4C-BBFA-277184C15E45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{30665FC1-D5F2-4F4C-BBFA-277184C15E45}.Debug|Any CPU.Build.0 = Debug|Any CPU
{30665FC1-D5F2-4F4C-BBFA-277184C15E45}.Release|Any CPU.ActiveCfg = Release|Any CPU
{30665FC1-D5F2-4F4C-BBFA-277184C15E45}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2BBCF792-C019-4195-AF08-45CC642B8A18}
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{30665FC1-D5F2-4F4C-BBFA-277184C15E45} = {4553EF99-1D3C-14C7-0D22-5364D18C373B}
EndGlobalSection
EndGlobal
67 changes: 34 additions & 33 deletions CSharpCodeAnalyst/Exploration/CodeGraphExplorer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@

namespace CSharpCodeAnalyst.Exploration;

internal class Context
{
public HashSet<string> Remember { get; } = [];

public HashSet<string> BlockedAbstraction { get; } = [];

public Context Clone()
{
var clone = new Context();
return clone;
}
}

public class CodeGraphExplorer : ICodeGraphExplorer
{
private List<Relationship> _allRelationships = [];
Expand Down Expand Up @@ -194,9 +207,8 @@ public SearchResult FollowIncomingCallsHeuristically(string id)

var method = _codeGraph.Nodes[id];

var restriction = new FollowIncomingCallsRestriction();
var processingQueue = new PriorityQueue<CodeElement, int>();
processingQueue.Enqueue(method, 0); // Start with the initial method, priority 0
var processingQueue = new PriorityQueue<(CodeElement, Context), int>();
processingQueue.Enqueue((method, new Context()), 0); // Start with the initial method, priority 0

var foundRelationships = new HashSet<Relationship>();
var foundElements = new HashSet<CodeElement>();
Expand All @@ -210,12 +222,13 @@ public SearchResult FollowIncomingCallsHeuristically(string id)
{
// 0 = highest priority

var element = processingQueue.Dequeue();
var (element, context) = processingQueue.Dequeue();
if (!processed.Add(element.Id))
{
continue;
}

var currentContext = context.Clone();

if (element.ElementType == CodeElementType.Event)
{
Expand All @@ -224,14 +237,14 @@ public SearchResult FollowIncomingCallsHeuristically(string id)
foundRelationships.UnionWith(specializations);
var specializedSources = specializations.Select(d => _codeGraph.Nodes[d.SourceId]).ToHashSet();
foundElements.UnionWith(specializedSources);
AddToProcessingQueue(specializedSources, 0);
AddToProcessingQueue(specializedSources, currentContext, 0);

// Add all methods that invoke the event
var invokes = allInvokes.Where(call => call.TargetId == element.Id).ToArray();
foundRelationships.UnionWith(invokes);
var invokeSources = invokes.Select(d => _codeGraph.Nodes[d.SourceId]).ToHashSet();
foundElements.UnionWith(invokeSources);
AddToProcessingQueue(invokeSources, 2);
AddToProcessingQueue(invokeSources, currentContext, 2);
}

if (element.ElementType == CodeElementType.Method)
Expand All @@ -243,53 +256,43 @@ public SearchResult FollowIncomingCallsHeuristically(string id)
foundRelationships.UnionWith(abstractions);
var abstractionTargets = abstractions.Select(d => _codeGraph.Nodes[d.TargetId]).ToHashSet();
foundElements.UnionWith(abstractionTargets);
restriction.BlockeBaseCalls.UnionWith(abstractionTargets.Select(t => t.Id));
AddToProcessingQueue(abstractionTargets, 0);
AddToProcessingQueue(abstractionTargets, currentContext, 0);


// Add Events that are handled by this method (priority 1).
var handles = allHandles.Where(h => h.SourceId == element.Id).ToArray();
foundRelationships.UnionWith(handles);
var events = handles.Select(h => _codeGraph.Nodes[h.TargetId]).ToHashSet();
foundElements.UnionWith(events);
AddToProcessingQueue(events, 1);
AddToProcessingQueue(events, currentContext, 1);


// 3. Calls (priority 2)
var calls = allCalls.Where(call => call.TargetId == element.Id && IsAllowedCall(call)).ToArray();
var calls = allCalls.Where(call => call.TargetId == element.Id && IsAllowedCall(call, currentContext)).ToArray();
foundRelationships.UnionWith(calls);
var callSources = calls
.Select(d => _codeGraph.Nodes[d.SourceId])
.ToHashSet();
foundElements.UnionWith(callSources);
AddToProcessingQueue(callSources, 2);
AddToProcessingQueue(callSources, currentContext, 2);
}
}

return new SearchResult(foundElements, foundRelationships);

void AddToProcessingQueue(IEnumerable<CodeElement> elementsToExplore, int priority)
void AddToProcessingQueue(IEnumerable<CodeElement> elementsToExplore, Context context, int priority)
{
foreach (var elementToExplore in elementsToExplore)
{
processingQueue.Enqueue(_codeGraph.Nodes[elementToExplore.Id], priority);
processingQueue.Enqueue((_codeGraph.Nodes[elementToExplore.Id], context), priority);
}
}

bool IsAllowedCall(Relationship call)
{
if (restriction.BlockeBaseCalls.Contains(call.TargetId))
{
var allow = !IsCallToOwnBase(call);
if (!allow)
{
var sourceName = _codeGraph.Nodes[call.SourceId].FullName;
var targetName = _codeGraph.Nodes[call.TargetId].FullName;
Trace.WriteLine($"Removed: {sourceName} -> {targetName}");
}

return allow;
}
bool IsAllowedCall(Relationship call, Context context)
{
var sourceName = _codeGraph.Nodes[call.SourceId].FullName;
var targetName = _codeGraph.Nodes[call.TargetId].FullName;
Trace.WriteLine($"Removed: {sourceName} -> {targetName}");

return true;
}
Expand Down Expand Up @@ -341,7 +344,7 @@ public SearchResult FindFullInheritanceTree(string id)
}
}

// Find sub-classes recursive
// Find subclasses recursively
processingQueue.Enqueue(type);
processed.Clear();
while (processingQueue.Any())
Expand Down Expand Up @@ -532,13 +535,12 @@ private class FollowIncomingCallsRestriction
/// This is because the method may be indirectly called by the interface.
/// If we proceed we may also find calls the base. But this is the wrong direction for the path we follow.
/// So if we followed an abstraction we block the base call to this abstraction
///
/// <code>
/// class Base
/// {
/// protected virtual void Foo() {}
/// }
///
///
/// class Derived : Base
/// {
/// // We start following here!
Expand All @@ -548,11 +550,10 @@ private class FollowIncomingCallsRestriction
/// }
/// }
/// </code>
///
/// Hashset of target ids of base methods.
/// </summary>
public HashSet<string> BlockeBaseCalls { get; } = [];

public HashSet<string> BlockedAbstraction { get; } = [];
}
}
Expand Down
8 changes: 6 additions & 2 deletions CSharpCodeAnalyst/Project/ProjectData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public void SetCodeGraph(CodeGraph codeGraph)
.SelectMany(element => element.Relationships)
.Select(relationship => new SerializableRelationship(relationship.SourceId, relationship.TargetId,
relationship.Type,
(uint)relationship.Attributes,
relationship.SourceLocations))
.ToList();
}
Expand Down Expand Up @@ -78,8 +79,11 @@ public CodeGraph GetCodeGraph()
foreach (var sd in Relationships)
{
var source = codeStructure.Nodes[sd.SourceId];
var relationship = new Relationship(sd.SourceId, sd.TargetId, sd.Type);
relationship.SourceLocations = sd.SourceLocations;
var relationship = new Relationship(sd.SourceId, sd.TargetId, sd.Type)
{
Attributes = (RelationshipAttribute)sd.Attributes,
SourceLocations = sd.SourceLocations
};
source.Relationships.Add(relationship);
}

Expand Down
2 changes: 2 additions & 0 deletions CSharpCodeAnalyst/Project/SerializableRelationship.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ public class SerializableRelationship(
string sourceId,
string targetId,
RelationshipType type,
uint attributes,
List<SourceLocation> sourceLocations)
{
public uint Attributes { get; set; } = attributes;
public string SourceId { get; set; } = sourceId;
public string TargetId { get; set; } = targetId;
public RelationshipType Type { get; set; } = type;
Expand Down
Loading