Skip to content
This repository was archived by the owner on Jul 15, 2023. It is now read-only.
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
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ public class DGMLOutputWriter : IReportWriter
FileExtension = ".dgml"
};

private readonly DGMLManager dgml = new DGMLManager();
private DGMLManager dgml;

public Task WriteStreamAsync(Stream stream, AnalyzeResponse response)
{
// Create a new dgml every time write to a new stream.
dgml = new DGMLManager();
ReferenceGraph rg = ReferenceGraph.CreateGraph(response);

ReportingResult analysisResult = response.ReportingResult;
Expand Down
80 changes: 31 additions & 49 deletions src/lib/Microsoft.Fx.Portability.Reports.DGML/ReferenceNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ namespace Microsoft.Fx.Portability.Reports.DGML
{
internal class ReferenceNode
{
private bool _searchInGraph = false;

public List<TargetUsageInfo> UsageData { get; set; }

public string Assembly { get; }
Expand Down Expand Up @@ -66,65 +64,49 @@ public double GetPortabilityIndexForReferences(int target)
if (Nodes.Count == 0)
return 1;

// HashSet keep track of the node went through to prevent duplicated counting in the reference graph and circular reference
HashSet<ReferenceNode> searchedNodes = new HashSet<ReferenceNode>();

// sum up the number of calls to available APIs and the ones for not available APIs for references.
if (!TryGetAPICountFromReferences(target, out int availableApis, out int unavailableApis))
{
// Cycle detected
return 1;
}
else
{
// remove the calls from the current node.
availableApis -= UsageData[target].GetAvailableAPICalls();
unavailableApis -= UsageData[target].GetUnavailableAPICalls();
GetAPICountFromReferences(target, searchedNodes, out int availableApis, out int unavailableApis);

// prevent Div/0
if (availableApis == 0 && unavailableApis == 0)
return 0;
// prevent Div/0. When availableApis is 0 and unavailableApis is 0, it likely means that it's references are all not resulted assemblies, return 0.
if (availableApis == 0 && unavailableApis == 0)
return 0;

return availableApis / ((double)availableApis + unavailableApis);
}
return availableApis / ((double)availableApis + unavailableApis);
}

public bool TryGetAPICountFromReferences(int target, out int availAPIs, out int unavailAPIs)
private void GetAPICountFromReferences(int target, HashSet<ReferenceNode> searchedNodes, out int availAPIs, out int unavailAPIs)
{
availAPIs = UsageData[target].GetAvailableAPICalls();
unavailAPIs = UsageData[target].GetUnavailableAPICalls();

// We are going to use a flag on the object to detect if we have a reference cycle while computing the APIs for the references.
if (_searchInGraph == true)
{
// Cycle!!!
_searchInGraph = false; // Reset this flag
return false;
}
else
{
_searchInGraph = true;
}
availAPIs = 0;
unavailAPIs = 0;

foreach (var item in Nodes)
{
if (item.UsageData == null)
// searchedNodes.Add(item) return false if the same node has been added before, which means its ApiCounts has been counted as well, we should keep the node,
// because we want to only count a reference node once if it is referenced in the graph more than once. This also avoids cycular reference as well.
if (searchedNodes.Add(item))
{
// skip the Node with no UsageData
continue;
if (item.UsageData != null)
{
try
{
availAPIs += item.UsageData[target].GetAvailableAPICalls();
unavailAPIs += item.UsageData[target].GetUnavailableAPICalls();
}
catch (Exception)
{
// for any exception like item.UsageData[target] is null or item.UsageData[target] throws IndexOutOfRangeException. Ignore it and continue.
}
}

item.GetAPICountFromReferences(target, searchedNodes, out int refCountAvail, out int refCountUnavail);

availAPIs += refCountAvail;
unavailAPIs += refCountUnavail;
}

if (!item.TryGetAPICountFromReferences(target, out int refCountAvail, out int refCountUnavail))
{
// Cycle!
_searchInGraph = false; // Reset this flag

return false;
}

availAPIs += refCountAvail;
unavailAPIs += refCountUnavail;
}

_searchInGraph = false;
return true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
namespace Microsoft.Fx.Portability.Utils.JsonConverters
{
/// <summary>
/// Json.NET does not handle <see cref="IDictionary{TKey, TValue}"/> when TKey is a type other than string. This provides
/// Json.NET does not handle <see cref="IDictionary&lt;TKey, TValue&gt;"/> when TKey is a type other than string. This provides
/// a wrapper for these types to serialize in a Key/Value system (like DCJS).
/// </summary>
internal class JsonMultiDictionaryConverter<TKey, TValue> : JsonConverter<IDictionary<TKey, ICollection<TValue>>>
Expand Down