Skip to content

Commit 2faa4c3

Browse files
author
Kapil Borle
committed
Remove derived digraph class
1 parent 8d3d2b3 commit 2faa4c3

File tree

3 files changed

+194
-52
lines changed

3 files changed

+194
-52
lines changed

Engine/Helper.cs

Lines changed: 79 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3557,75 +3557,104 @@ public object VisitUsingExpression(UsingExpressionAst usingExpressionAst)
35573557
}
35583558

35593559
/// Class to represent a directed graph
3560-
public class Digraph
3560+
/// Class to represent a directed graph
3561+
public class Digraph<T>
35613562
{
3563+
public int NumVertices
3564+
{
3565+
get { return graph.Count; }
3566+
}
3567+
35623568
private List<List<int>> graph;
3569+
private Dictionary<T, int> vertexIndexMap;
35633570

3564-
public Digraph()
3571+
3572+
private int GetIndex(T vertex)
35653573
{
3566-
graph = new List<List<int>> ();
3574+
int idx;
3575+
return vertexIndexMap.TryGetValue(vertex, out idx) ? idx : -1;
35673576
}
35683577

3569-
public Digraph(int numVertices, List<Tuple<int, int>> edges) : this()
3578+
public IEnumerable<T> GetNeighbors(T vertex)
35703579
{
3571-
for (int v = 0; v < numVertices; v++)
3580+
ValidateVertexArgument(vertex);
3581+
var idx = GetIndex(vertex);
3582+
var idxVertexMap = vertexIndexMap.ToDictionary(x => x.Value, x => x.Key);
3583+
foreach (var neighbor in graph[idx])
35723584
{
3573-
AddVertex();
3585+
yield return idxVertexMap[neighbor];
35743586
}
3587+
}
35753588

3576-
foreach (Tuple<int, int> tuple in edges)
3577-
{
3578-
var fromV = tuple.Item1;
3579-
var toV = tuple.Item2;
3580-
ValidateVertex(fromV);
3581-
ValidateVertex(toV);
3582-
AddEdge(fromV, toV);
3583-
}
3589+
public IEnumerable<T> GetVertices()
3590+
{
3591+
return vertexIndexMap.Keys;
35843592
}
35853593

3586-
public int GetNumVertices()
3594+
public bool ContainsVertex(T vertex)
35873595
{
3588-
return graph.Count;
3596+
return vertexIndexMap.Keys.Contains(vertex);
35893597
}
35903598

3591-
public int GetNumNeighbors(int vertex)
3599+
public int GetNumNeighbors(T vertex)
35923600
{
3593-
return GetNeighbors(vertex).Count();
3601+
ValidateVertexArgument(vertex);
3602+
return graph[GetIndex(vertex)].Count;
35943603
}
35953604

3596-
public IEnumerable<int> GetNeighbors(int vertex)
3605+
public Digraph()
35973606
{
3598-
ValidateVertex(vertex);
3599-
return graph[vertex];
3607+
graph = new List<List<int>> ();
3608+
vertexIndexMap = new Dictionary<T, int>();
36003609
}
36013610

3602-
public bool ContainsVertex(int vertex)
3611+
public Digraph(IEqualityComparer<T> comparer) : this()
36033612
{
3604-
return vertex >= 0 && vertex < graph.Count;
3613+
vertexIndexMap = new Dictionary<T, int> (comparer);
36053614
}
36063615

3607-
protected void AddVertex()
3616+
public void AddVertex(T vertex)
36083617
{
3618+
if (vertex == null)
3619+
{
3620+
throw new ArgumentNullException("vertex");
3621+
}
3622+
3623+
if (GetIndex(vertex) != -1)
3624+
{
3625+
throw new ArgumentException("Vertex already present! Cannot add it to the Digraph", "vertex");
3626+
}
3627+
3628+
vertexIndexMap.Add(vertex, graph.Count);
36093629
graph.Add(new List<int>());
36103630
}
36113631

3612-
protected void AddEdge(int fromVertex, int toVertex)
3632+
public void AddEdge(T fromVertex, T toVertex)
36133633
{
3614-
ValidateVertex(fromVertex);
3615-
ValidateVertex(toVertex);
3616-
if (graph[fromVertex].Contains(toVertex))
3634+
ValidateVertexArgument(fromVertex);
3635+
ValidateVertexArgument(toVertex);
3636+
3637+
var toIdx = GetIndex(toVertex);
3638+
var fromVertexList = graph[GetIndex(fromVertex)];
3639+
if (fromVertexList.Contains(toIdx))
36173640
{
3618-
throw new ArgumentException(String.Format("Edge from {0} to {1} already present", fromVertex, toVertex));
3641+
throw new ArgumentException(String.Format(
3642+
"Edge from {0} to {1} already present.",
3643+
fromVertex.ToString(),
3644+
toVertex.ToString()));
3645+
}
3646+
else
3647+
{
3648+
fromVertexList.Add(toIdx);
36193649
}
3620-
graph[fromVertex].Add(toVertex);
36213650
}
36223651

3623-
public bool IsConnected(int vertex1, int vertex2)
3652+
public bool IsConnected(T vertex1, T vertex2)
36243653
{
3625-
ValidateVertex(vertex1);
3626-
ValidateVertex(vertex2);
3654+
ValidateVertexArgument(vertex1);
3655+
ValidateVertexArgument(vertex2);
36273656
var visited = new bool[graph.Count];
3628-
return IsConnected(vertex1, vertex2, ref visited);
3657+
return IsConnected(GetIndex(vertex1), GetIndex(vertex2), ref visited);
36293658
}
36303659

36313660
private bool IsConnected(int fromIdx, int toIdx, ref bool[] visited)
@@ -3653,12 +3682,26 @@ private bool IsConnected(int fromIdx, int toIdx, ref bool[] visited)
36533682
return isConnected;
36543683
}
36553684

3656-
private void ValidateVertex(int vertex)
3685+
private void ValidateNotNull(T vertex)
36573686
{
3658-
if (!ContainsVertex(vertex))
3687+
if (vertex == null)
3688+
{
3689+
throw new ArgumentNullException("vertex");
3690+
}
3691+
}
3692+
3693+
private void ValidateVertexPresence(T vertex)
3694+
{
3695+
if (GetIndex(vertex) == -1)
36593696
{
36603697
throw new ArgumentOutOfRangeException("vertex not present in the Digraph.", "vertex");
36613698
}
36623699
}
3700+
3701+
private void ValidateVertexArgument(T vertex)
3702+
{
3703+
ValidateNotNull(vertex);
3704+
ValidateVertexPresence(vertex);
3705+
}
36633706
}
36643707
}

Rules/UseShouldProcessCorrectly.cs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//
1212

1313
using System;
14+
using System.Linq;
1415
using System.Collections.Generic;
1516
using System.Management.Automation.Language;
1617
using Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic;
@@ -130,6 +131,103 @@ public string GetSourceName()
130131
}
131132
}
132133

134+
135+
136+
class FunctionReferenceDigraphCreator : AstVisitor
137+
{
138+
private Digraph<string> digraph;
139+
140+
private bool isWithinFunctionDefinition;
141+
private string functionName;
142+
143+
public Digraph<string> GetDigraph()
144+
{
145+
return digraph;
146+
}
147+
public FunctionReferenceDigraphCreator()
148+
{
149+
digraph = new Digraph<string>(StringComparer.OrdinalIgnoreCase);
150+
isWithinFunctionDefinition = false;
151+
}
152+
153+
public override AstVisitAction VisitCommand(CommandAst ast)
154+
{
155+
if (ast == null)
156+
{
157+
return AstVisitAction.SkipChildren;
158+
}
159+
160+
var cmdName = ast.GetCommandName();
161+
AddVertex(cmdName);
162+
if (isWithinFunctionDefinition)
163+
{
164+
AddEdge(functionName, cmdName);
165+
}
166+
return AstVisitAction.Continue;
167+
}
168+
169+
public void AddVertex(string name)
170+
{
171+
if (!digraph.ContainsVertex(name))
172+
{
173+
digraph.AddVertex(name);
174+
}
175+
}
176+
177+
public void AddEdge(string fromV, string toV)
178+
{
179+
if (!digraph.GetNeighbors(fromV).Contains(toV, StringComparer.OrdinalIgnoreCase))
180+
{
181+
digraph.AddEdge(fromV, toV);
182+
}
183+
}
184+
185+
public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst ast)
186+
{
187+
if (ast == null)
188+
{
189+
return AstVisitAction.SkipChildren;
190+
}
191+
192+
isWithinFunctionDefinition = true;
193+
functionName = ast.Name;
194+
AddVertex(ast.Name);
195+
ast.Body.Visit(this);
196+
isWithinFunctionDefinition = false;
197+
return AstVisitAction.SkipChildren;
198+
}
199+
200+
public override AstVisitAction VisitInvokeMemberExpression(InvokeMemberExpressionAst ast)
201+
{
202+
if (ast == null)
203+
{
204+
return AstVisitAction.SkipChildren;
205+
}
206+
207+
var expr = ast.Expression.Extent.Text;
208+
var memberExprAst = ast.Member as StringConstantExpressionAst;
209+
if (memberExprAst == null)
210+
{
211+
return AstVisitAction.Continue;
212+
}
213+
214+
var member = memberExprAst.Value;
215+
if (string.IsNullOrWhiteSpace(member))
216+
{
217+
return AstVisitAction.Continue;
218+
}
219+
220+
AddVertex(expr);
221+
AddVertex(member);
222+
AddEdge(expr, member);
223+
if (isWithinFunctionDefinition)
224+
{
225+
AddEdge(functionName, expr);
226+
}
227+
228+
return AstVisitAction.Continue;
229+
}
230+
}
133231
}
134232

135233

Tests/Engine/Helpers.tests.ps1

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,31 @@
11
Import-Module PSScriptAnalyzer
22

3-
4-
Function ConvertType($x)
5-
{
6-
$z = [System.Collections.Generic.List[Tuple[int,int]]]::new()
7-
$x | ForEach-Object {$z.Add([System.Tuple[int,int]]::new($_[0], $_[1]))}
8-
return $z
9-
}
10-
113
Describe "Test Directed Graph" {
124
Context "When a graph is created" {
13-
$edges = ConvertType (0,1),(0,4),(1,3)
14-
$digraph = New-Object -TypeName 'Microsoft.Windows.PowerShell.ScriptAnalyzer.DiGraph' -ArgumentList 5,$edges
5+
$digraph = New-Object -TypeName 'Microsoft.Windows.PowerShell.ScriptAnalyzer.DiGraph[string]'
6+
$digraph.AddVertex('v1');
7+
$digraph.AddVertex('v2');
8+
$digraph.AddVertex('v3');
9+
$digraph.AddVertex('v4');
10+
$digraph.AddVertex('v5');
11+
12+
$digraph.AddEdge('v1', 'v2');
13+
$digraph.AddEdge('v1', 'v5');
14+
$digraph.AddEdge('v2', 'v4');
15+
1516
It "correctly adds the vertices" {
16-
$digraph.GetNumVertices() | Should Be 5
17+
$digraph.NumVertices | Should Be 5
1718
}
1819

1920
It "correctly adds the edges" {
20-
$digraph.GetNumNeighbors(0) | Should Be 2
21-
$neighbors = $digraph.GetNeighbors(0)
22-
$neighbors -contains 1 | Should Be $true
23-
$neighbors -contains 4 | Should Be $true
21+
$digraph.GetNumNeighbors('v1') | Should Be 2
22+
$neighbors = $digraph.GetNeighbors('v1')
23+
$neighbors -contains 'v2' | Should Be $true
24+
$neighbors -contains 'v5' | Should Be $true
2425
}
2526

2627
It "finds the connection" {
27-
$digraph.IsConnected(0, 3) | Should Be $true
28+
$digraph.IsConnected('v1', 'v4') | Should Be $true
2829
}
2930
}
3031
}

0 commit comments

Comments
 (0)