Skip to content

Commit

Permalink
IsSubSet check
Browse files Browse the repository at this point in the history
  • Loading branch information
emgarten committed Aug 26, 2017
1 parent cac363e commit 1ab17fc
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 4 deletions.
12 changes: 12 additions & 0 deletions build/Shared/EqualityUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ internal static bool SetEqualWithNullCheck<T>(
return identityEquals;
}

// Verify they could be equal by count
if (self.Count != other.Count)
{
return false;
}

if (comparer == null)
{
comparer = EqualityComparer<T>.Default;
Expand All @@ -99,6 +105,12 @@ internal static bool DictionaryEquals<TKey, TValue>(
return identityEquals;
}

// Verify they could be equal by count
if (self.Count != other.Count)
{
return false;
}

if (!self.Keys.OrderedEquals(
other.Keys,
s => s,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ private static PackageSpecificWarningProperties ExtractTransitiveNoWarnPropertie
{
var dependencyMapping = new Dictionary<string, LookUpNode>(StringComparer.OrdinalIgnoreCase);
var queue = new Queue<DependencyNode>();
var seen = new HashSet<DependencyNode>();
var seen = new Dictionary<string, HashSet<DependencyNode>>(StringComparer.OrdinalIgnoreCase);
var resultWarningProperties = new PackageSpecificWarningProperties();
var packageNoWarn = new Dictionary<string, HashSet<NuGetLogCode>>(StringComparer.OrdinalIgnoreCase);

Expand Down Expand Up @@ -147,7 +147,7 @@ private static PackageSpecificWarningProperties ExtractTransitiveNoWarnPropertie
parentPackageSpecificNoWarn);

// Add the parent project to the seen set to prevent adding it back to the queue
seen.Add(new DependencyNode(id: parentProjectName,
AddToSeen(seen, new DependencyNode(id: parentProjectName,
isProject: true,
projectWideNoWarn: parentProjectWideNoWarn,
packageSpecificNoWarn: parentPackageSpecificNoWarn));
Expand All @@ -156,7 +156,11 @@ private static PackageSpecificWarningProperties ExtractTransitiveNoWarnPropertie
while (queue.Count > 0)
{
var node = queue.Dequeue();
if (seen.Add(node) && dependencyMapping.TryGetValue(node.Id, out var nodeLookUp))

// Check if the node has already been visited, or if the node is a NoWarn superset of
// an existing node. If this is a superset it will not provide any new paths where a
// warning should be shown.
if (AddToSeen(seen, node) && dependencyMapping.TryGetValue(node.Id, out var nodeLookUp))
{
var nodeId = node.Id;
var nodeIsProject = node.IsProject;
Expand Down Expand Up @@ -262,6 +266,44 @@ private static WarningPropertiesCollection GetNodeWarningProperties(
return collection;
}

/// <summary>
/// Add to the seen list for tracking.
/// </summary>
/// <returns>True if the node should be walked</returns>
private static bool AddToSeen(Dictionary<string, HashSet<DependencyNode>> seen, DependencyNode node)
{
var id = node.Id;

if (!seen.TryGetValue(id, out var visitedNodes))
{
// New id
visitedNodes = new HashSet<DependencyNode>() { node };
seen.Add(id, visitedNodes);
return true;
}

// Add the node for tracking, if a subset of this node
// has already been walked then skip it, it will not provide
// any new warning possibilities.
if (!visitedNodes.Add(node))
{
var nodeProps = node.NodeWarningProperties;

if (nodeProps != null)
{
foreach (var existingNode in visitedNodes)
{
if (nodeProps.IsSubSetOf(existingNode.NodeWarningProperties))
{
return false;
}
}
}
}

return true;
}

private static void AddDependenciesToQueue(IEnumerable<LibraryDependency> dependencies,
Queue<DependencyNode> queue,
HashSet<NuGetLogCode> projectWideNoWarn,
Expand Down Expand Up @@ -728,6 +770,79 @@ public bool Equals(NodeWarningProperties other)
return EqualityUtility.SetEqualWithNullCheck(ProjectWide, other.ProjectWide) &&
EqualityUtility.DictionaryEquals(PackageSpecific, other.PackageSpecific, (s, o) => EqualityUtility.SetEqualWithNullCheck(s, o));
}

/// <summary>
/// True if the given set is a subset of this set, or equal to it.
/// </summary>
/// <remarks>Null is considered an empty set, and will return true.</remarks>
public bool IsSubSetOf(NodeWarningProperties other)

This comment has been minimized.

Copy link
@mishra14

mishra14 Aug 26, 2017

Contributor

rename to issuperset

This comment has been minimized.

Copy link
@emgarten

emgarten Aug 26, 2017

Author Member

It matches ISet.IsSubSetOf unless I have it backwards. It is confusing on that api also

{
if (other == null)
{
return true;
}

if (ReferenceEquals(this, other))
{
return true;
}

if (IsSubSetOfWithNullCheck(ProjectWide, other.ProjectWide))
{
var package = PackageSpecific;
var otherPackage = other.PackageSpecific;

if (otherPackage == null || otherPackage.Count == 0)
{
return true;
}

if (package == null || package.Count == 0)
{
return false;
}

if (otherPackage.Count <= package.Count)
{
// To be subset this set of package specific warnings must contain
// every id and code found in other. A single miss will fail the check.
foreach (var pair in otherPackage)
{
if (!package.TryGetValue(pair.Key, out var codes)
|| !codes.IsSubsetOf(pair.Value))
{
return false;
}
}
}

return true;
}

return false;
}

private static bool IsSubSetOfWithNullCheck(HashSet<NuGetLogCode> parent, HashSet<NuGetLogCode> other)
{
// Null is empty and always a subset.
if (other == null || other.Count == 0)
{
return true;
}

// A null or empty parent cannot be a superset.
if (parent == null || parent.Count == 0)
{
return false;
}

if (other.Count <= parent.Count)
{
return parent.IsSubsetOf(other);
}

return false;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
Expand Down Expand Up @@ -47,6 +47,7 @@ public async Task StandaloneProject_BasicRestore()
spec.RestoreMetadata.OutputPath = Path.Combine(pathContext.SolutionRoot, "x");
spec.RestoreMetadata.ProjectUniqueName = "x";
spec.RestoreMetadata.ProjectName = "x";
spec.RestoreMetadata.ProjectPath = Path.Combine(pathContext.SolutionRoot, "x.csproj");

dgFile.AddProject(spec);
dgFile.AddRestore("x");
Expand Down

0 comments on commit 1ab17fc

Please sign in to comment.