// 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; } } }