// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using EpicGames.Core;
using Microsoft.Extensions.Logging;
namespace UnrealBuildTool.Configuration.CompileWarnings
{
///
/// Flag used to communicate which context the should be applied.
///
internal enum InitializationContext
{
///
/// Apply the in all contexts.
///
Any,
///
/// Apply the exclusively in the context.
///
Target,
///
/// Apply the exclusively in the context.
///
Constructor
}
///
/// Attribute used to set the default values of a under the context of context and context.
///
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
internal sealed class WarningLevelDefaultAttribute : Attribute
{
private static readonly ILogger? s_logger = Log.Logger;
///
/// The lower bound (inclusive) of which to apply this to.
///
public BuildSettingsVersion MinVersion { get; }
///
/// The upper bound (inclusive) of which to apply this to.
///
public BuildSettingsVersion MaxVersion { get; }
///
/// The default warning level.
///
public WarningLevel DefaultLevel { get; }
///
/// The context in which this attribute should be applied.
///
public InitializationContext Context { get; }
///
/// Constructs a ApplyWarningsDefaultValueAttribute.
///
/// Minimum version of the bound to apply this setting to. Inclusive.
/// Maximum version of the bound to apply this setting to. Inclusive.
/// The default warning level to apply for this bound.
/// The context in which to apply this default.
public WarningLevelDefaultAttribute(WarningLevel defaultLevel = WarningLevel.Default, BuildSettingsVersion minVersion = BuildSettingsVersion.V1, BuildSettingsVersion maxVersion = BuildSettingsVersion.Latest, InitializationContext context = InitializationContext.Any)
{
MinVersion = minVersion;
MaxVersion = maxVersion;
DefaultLevel = defaultLevel;
Context = context;
}
///
/// Resolves the set of to a provided the current .
///
/// The set of attributes to consider.
/// The current build settings version.
/// The corresponding of which to apply to the property with the default value attributes.
/// Will invoke on the input .
internal static WarningLevel ResolveWarningLevelDefault(IList unsortedDefaultValueAttributes, BuildSettingsVersion activeVersion)
{
List sortedAndMerged = EnsureWarningLevelDefaultBounds(unsortedDefaultValueAttributes);
WarningLevel returnWarningLevel = WarningLevel.Default;
foreach (WarningLevelDefaultAttribute attr in sortedAndMerged)
{
// If we find our appropriate range, we early out.
if (attr.MinVersion <= activeVersion && activeVersion <= attr.MaxVersion)
{
returnWarningLevel = attr.DefaultLevel;
break;
}
}
return returnWarningLevel;
}
///
/// Ensures the attributes collection represents a contiguous, non-overlapping range.
///
/// The list of attributes to verify.
/// A list of attributes that has no overlaps, and is contiguous.
internal static List EnsureWarningLevelDefaultBounds(IList attributes)
{
List sorted = attributes.OrderBy(a => a.MinVersion).ToList();
List merged = new List(sorted.Count);
for (int i = 0; i < sorted.Count - 1; i++)
{
WarningLevelDefaultAttribute current = sorted[i];
WarningLevelDefaultAttribute next = sorted[i + 1];
if (current.MaxVersion < next.MinVersion - 1)
{
s_logger?.LogWarning("Malformed ApplyWarningsDefaultValueAttribute collection; taking corrective action to address gap in range (CurrentMax: {CurrentMax} NextMin: {NextMin}-1).", next.MinVersion, current.MaxVersion);
// Extend current range to cover the gap up to the next MinVersion,using the old build settings version standard.
current = new WarningLevelDefaultAttribute(
current.DefaultLevel,
current.MinVersion,
next.MinVersion - 1
);
}
else if (next.MinVersion <= current.MaxVersion)
{
s_logger?.LogWarning("Malformed ApplyWarningsDefaultValueAttribute collection; taking corrective action to address overlap in range (NextMin: {NextMin} <= CurrentMax: {CurrentMax}).", next.MinVersion, current.MaxVersion);
// Reduce next range to be more constrained, leaving the larger current range at the old build settings version standard.
next = new WarningLevelDefaultAttribute(
next.DefaultLevel,
current.MaxVersion + 1,
next.MaxVersion
);
// Flatten the old value with the updated one.
sorted[i + 1] = next;
}
merged.Add(current);
}
merged.Add(sorted.Last());
return merged;
}
}
}