|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable disable
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FlowAnalysis.SymbolUsageAnalysis;
internal readonly struct SymbolUsageResult(
ImmutableDictionary<(ISymbol symbol, IOperation write), bool> symbolWritesMap,
ImmutableHashSet<ISymbol> symbolsRead)
{
/// <summary>
/// Map from each symbol write to a boolean indicating if the value assinged
/// at write is used/read on some control flow path.
/// For example, consider the following code:
/// <code>
/// int x = 0;
/// x = 1;
/// Console.WriteLine(x);
/// </code>
/// This map will have two entries for 'x':
/// 1. Key = (symbol: x, write: 'int x = 0')
/// Value = 'false', because value assigned to 'x' here **is never** read.
/// 2. Key = (symbol: x, write: 'x = 1')
/// Value = 'true', because value assigned to 'x' here **may be** read on
/// some control flow path.
/// </summary>
public ImmutableDictionary<(ISymbol symbol, IOperation write), bool> SymbolWritesMap { get; } = symbolWritesMap;
/// <summary>
/// Set of locals/parameters that are read at least once.
/// </summary>
public ImmutableHashSet<ISymbol> SymbolsRead { get; } = symbolsRead;
public bool HasUnreadSymbolWrites()
=> SymbolWritesMap.Values.Any(value => !value);
/// <summary>
/// Gets symbol writes that have are never read.
/// WriteOperation will be null for the initial value write to parameter symbols from the callsite.
/// </summary>
public IEnumerable<(ISymbol Symbol, IOperation WriteOperation)> GetUnreadSymbolWrites()
=> SymbolWritesMap.Where(kvp => !kvp.Value).Select(kvp => kvp.Key);
/// <summary>
/// Returns true if the initial value of the parameter from the caller is used.
/// </summary>
public bool IsInitialParameterValueUsed(IParameterSymbol parameter)
{
foreach (var kvp in SymbolWritesMap)
{
// 'write' operation is 'null' for the initial write of the parameter,
// which may be from the caller's argument or parameter initializer.
if (kvp.Key.write == null && Equals(kvp.Key.symbol, parameter))
{
return kvp.Value;
}
}
throw ExceptionUtilities.Unreachable();
}
/// <summary>
/// Gets the write count for a given local/parameter symbol.
/// </summary>
public int GetSymbolWriteCount(ISymbol symbol)
{
var count = 0;
foreach (var kvp in SymbolWritesMap)
{
if (Equals(kvp.Key.symbol, symbol))
{
count++;
}
}
return count;
}
}
|