Skip to content

Enhance PSShouldProcess rule to check for ShouldProcess in nested functions #625

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

Merged
merged 19 commits into from
Oct 4, 2016
Merged
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
235 changes: 235 additions & 0 deletions Engine/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3555,4 +3555,239 @@ public object VisitUsingExpression(UsingExpressionAst usingExpressionAst)
return null;
}
}

/// Class to represent a directed graph
public class Digraph<T>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider making this an internal class for now. We can open it up as public as the scenarios evolve.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use Pester for our testing purposes. If I make it internal, how do I go about testing? I do not think I will be able find the type in Pester tests if it is internal.

{
private List<List<int>> graph;
private Dictionary<T, int> vertexIndexMap;

/// <summary>
/// Public constructor
/// </summary>
public Digraph()
{
graph = new List<List<int>>();
vertexIndexMap = new Dictionary<T, int>();
}

/// <summary>
/// Construct a directed graph that uses an EqualityComparer object for comparison with its vertices
///
/// The class allows its client to use their choice of vertex type. To allow comparison for such a
/// vertex type, client can pass their own EqualityComparer object
/// </summary>
/// <param name="equalityComparer"></param>
public Digraph(IEqualityComparer<T> equalityComparer) : this()
{
if (equalityComparer == null)
{
throw new ArgumentNullException("equalityComparer");
}

vertexIndexMap = new Dictionary<T, int>(equalityComparer);
}

/// <summary>
/// Return the number of vertices in the graph
/// </summary>
public int NumVertices
{
get { return graph.Count; }
}

/// <summary>
/// Return an enumerator over the vertices in the graph
/// </summary>
public IEnumerable<T> GetVertices()
{
return vertexIndexMap.Keys;
}

/// <summary>
/// Check if the given vertex is part of the graph.
///
/// If the vertex is null, it will throw an ArgumentNullException.
/// If the vertex is non-null but not present in the graph, it will throw an ArgumentOutOfRangeException

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just return null in this case instead of throwing an exception

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 3608 is not applicable for this method (ContainsVertex). I will remove it. The method ContainsVertex expects a non-null object for comparison and returns a bool type.

/// </summary>
/// <param name="vertex"></param>
/// <returns>True if the graph contains the vertex, otherwise false</returns>
public bool ContainsVertex(T vertex)
{
return vertexIndexMap.ContainsKey(vertex);
}

/// <summary>
/// Get the neighbors of a given vertex
///
/// If the vertex is null, it will throw an ArgumentNullException.
/// If the vertex is non-null but not present in the graph, it will throw an ArgumentOutOfRangeException
/// </summary>
/// <param name="vertex"></param>
/// <returns>An enumerator over the neighbors of the vertex</returns>
public IEnumerable<T> GetNeighbors(T vertex)
{
ValidateVertexArgument(vertex);
var idx = GetIndex(vertex);
var idxVertexMap = vertexIndexMap.ToDictionary(x => x.Value, x => x.Key);
foreach (var neighbor in graph[idx])
{
yield return idxVertexMap[neighbor];
}
}

/// <summary>
/// Gets the number of neighbors of the given vertex
///
/// If the vertex is null, it will throw an ArgumentNullException.
/// If the vertex is non-null but not present in the graph, it will throw an ArgumentOutOfRangeException
/// </summary>
/// <param name="vertex"></param>
/// <returns></returns>
public int GetOutDegree(T vertex)
{
ValidateVertexArgument(vertex);
return graph[GetIndex(vertex)].Count;
}

/// <summary>
/// Add a vertex to the graph
///
/// If the vertex is null, it will throw an ArgumentNullException.
/// If the vertex is non-null but already present in the graph, it will throw an ArgumentException
/// </summary>
/// <param name="vertex"></param>
public void AddVertex(T vertex)
{
ValidateNotNull(vertex);
if (GetIndex(vertex) != -1)
{
throw new ArgumentException(
String.Format(
Strings.DigraphVertexAlreadyExists,
vertex),
"vertex");
}

vertexIndexMap.Add(vertex, graph.Count);
graph.Add(new List<int>());
}

/// <summary>
/// Add an edge from one vertex to another
///
/// If any input vertex is null, it will throw an ArgumentNullException
/// If an edge is already present between the given vertices, it will throw an ArgumentException
/// </summary>
/// <param name="fromVertex"></param>
/// <param name="toVertex"></param>
public void AddEdge(T fromVertex, T toVertex)
{
ValidateVertexArgument(fromVertex);
ValidateVertexArgument(toVertex);

var toIdx = GetIndex(toVertex);
var fromVertexList = graph[GetIndex(fromVertex)];
if (fromVertexList.Contains(toIdx))
{
throw new ArgumentException(String.Format(
Strings.DigraphEdgeAlreadyExists,
fromVertex.ToString(),
toVertex.ToString()));
}
else
{
fromVertexList.Add(toIdx);
}
}

/// <summary>
/// Checks if a vertex is connected to another vertex within the graph
/// </summary>
/// <param name="vertex1"></param>
/// <param name="vertex2"></param>
/// <returns></returns>
public bool IsConnected(T vertex1, T vertex2)
{
ValidateVertexArgument(vertex1);
ValidateVertexArgument(vertex2);

var visited = new bool[graph.Count];
return IsConnected(GetIndex(vertex1), GetIndex(vertex2), ref visited);
}

/// <summary>
/// Check if two vertices are connected
/// </summary>
/// <param name="fromIdx">Origin vertex</param>
/// <param name="toIdx">Destination vertex</param>
/// <param name="visited">A boolean array indicating whether a vertex has been visited or not</param>
/// <returns>True if the vertices are conneted, otherwise false</returns>
private bool IsConnected(int fromIdx, int toIdx, ref bool[] visited)
{
visited[fromIdx] = true;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand you are doing the marking here..but i dont see where the cleanup happens.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

visited is cleaned up when public bool IsConnected(T vertex1, T vertex2) returns.

if (fromIdx == toIdx)
{
return true;
}

foreach(var vertexIdx in graph[fromIdx])
{
if (!visited[vertexIdx])
{
if(IsConnected(vertexIdx, toIdx, ref visited))
{
return true;
}
}
}

return false;
}

/// <summary>
/// Throw an ArgumentNullException if vertex is null
/// </summary>
private void ValidateNotNull(T vertex)
{
if (vertex == null)
{
throw new ArgumentNullException("vertex");
}
}

/// <summary>
/// Throw an ArgumentOutOfRangeException if vertex is not present in the graph
/// </summary>
private void ValidateVertexPresence(T vertex)
{
if (GetIndex(vertex) == -1)
{
throw new ArgumentOutOfRangeException(
String.Format(
Strings.DigraphVertexDoesNotExists,
vertex.ToString()),
"vertex");
}
}

/// <summary>
/// Throw exception if vertex is null or not present in graph
/// </summary>
private void ValidateVertexArgument(T vertex)
{
ValidateNotNull(vertex);
ValidateVertexPresence(vertex);
}

/// <summary>
/// Get the index of the vertex in the graph array
/// </summary>
private int GetIndex(T vertex)
{
int idx;
return vertexIndexMap.TryGetValue(vertex, out idx) ? idx : -1;
}

}
}
63 changes: 36 additions & 27 deletions Engine/Strings.resx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
<!--
Microsoft ResX Schema

Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes

The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.

Example:

... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
Expand All @@ -26,36 +26,36 @@
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple

There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the

Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not

The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can

Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.

mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.

mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.

mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
Expand Down Expand Up @@ -243,4 +243,13 @@
<data name="WrongValueHashTable" xml:space="preserve">
<value>Value {0} for key {1} has the wrong data type. Value in the settings hashtable should be a string or an array of strings.</value>
</data>
<data name="DigraphVertexAlreadyExists" xml:space="preserve">
<value>Vertex {0} already exists! Cannot add it to the digraph.</value>
</data>
<data name="DigraphEdgeAlreadyExists" xml:space="preserve">
<value>Edge from {0} to {1} already exists.</value>
</data>
<data name="DigraphVertexDoesNotExists" xml:space="preserve">
<value>Vertex {0} does not exist in the digraph.</value>
</data>
</root>
Loading