// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using EpicGames.Core;
namespace UnrealBuildTool
{
///
/// Denotes the position of a resolved compile warnings argument relative to other warnings.
///
public enum ArgPosition
{
///
/// At the beginning of the argument list.
///
Beginning,
///
/// In the middle of the argument list.
///
Middle,
///
/// At the end of the argument list.
///
End
}
///
/// Attribute used to mark fields which describes a set of arguments.
///
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
internal abstract class ApplyWarningsAttribute : Attribute
{
private readonly string[]? _offArgs;
private readonly string[]? _warningArgs;
private readonly string[]? _errorArgs;
protected readonly List ActiveFilters = [];
public readonly ArgPosition Position;
///
/// Defines the argument metadata around a property.
///
/// The arguments to use when the property is defined as .
/// The arguments to use when the property is defined as .
/// The arguments to use when the property is defined as .
/// The applicable filter criteria.
/// The phase of when to apply the warning.
internal ApplyWarningsAttribute(string[]? offArgs = null, string[]? warningArgs = null, string[]? errorArgs = null, string[]? applicableFilters = null, ArgPosition argPosition = ArgPosition.Middle)
{
_offArgs = offArgs;
_warningArgs = warningArgs;
_errorArgs = errorArgs;
AppendNewFilters(applicableFilters);
Position = argPosition;
}
///
/// Applies the warnings to the provided arguments list.
///
/// The warning level to use when applying.
/// The toolchain context to use in application.
/// The arugments list to add values to.
internal void ApplyWarningsToArguments(WarningLevel level, CompilerWarningsToolChainContext toolChainContext, List arguments)
{
ApplyWarningsToArgumentsInternal(level, toolChainContext, arguments);
}
///
/// Applies the warnings to the provided arguments list.
///
/// The warning level to use when applying.
/// The toolchain context to use in application.
/// The arugments list to add values to.
/// Used to provide custom overriding logic.
protected virtual void ApplyWarningsToArgumentsInternal(WarningLevel level, CompilerWarningsToolChainContext toolChainContext, List arguments)
{
switch (level)
{
case WarningLevel.Off:
if (_offArgs != null)
{
arguments.AddRange(_offArgs);
}
break;
case WarningLevel.Warning:
if (_warningArgs != null)
{
arguments.AddRange(_warningArgs);
}
break;
case WarningLevel.Error:
if (_errorArgs != null)
{
arguments.AddRange(_errorArgs);
}
break;
}
}
///
/// Whether the given can be applied to the provided context.
///
/// The toolchain context to be applied to.
/// True if applicable, false otherwise.
internal virtual bool CanApplyToContext(CompilerWarningsToolChainContext toolChainContext)
{
return (ActiveFilters == null || ActiveFilters.TrueForAll(x => x.CanApply(toolChainContext)));
}
protected bool TryAppendNewFilter(string rawFilterName)
{
IApplyWarningsFilter? filter = ApplyWarningsFilterRegistry.RequestFilter(rawFilterName);
if (filter != null && !ActiveFilters.Contains(filter))
{
ActiveFilters.Add(filter);
return true;
}
return false;
}
protected void AppendNewFilters(IEnumerable? newFilters)
{
if (newFilters != null)
{
foreach (string rawFilterName in newFilters)
{
TryAppendNewFilter(rawFilterName);
}
}
}
protected void AppendNewFilters(IEnumerable? newFilters)
{
if (newFilters != null)
{
foreach (FilterID filterID in newFilters)
{
TryAppendNewFilter(filterID.ToString());
}
}
}
///
/// The list of off arugments corresponding to
///
internal string[]? OffArgs => _offArgs;
///
/// The list of off arugments corresponding to
///
internal string[]? WarningArgs => _warningArgs;
///
/// The list of off arugments corresponding to
///
internal string[]? ErrorArgs => _errorArgs;
}
#region -- ToolChains --
#pragma warning disable CA1813
internal class WarningsVCToolChainAttribute : ApplyWarningsAttribute
#pragma warning restore CA1813
{
///
internal WarningsVCToolChainAttribute(string[]? offArgs = null, string[]? warningArgs = null, string[]? errorArgs = null, string[]? filterNames = null, ArgPosition argPosition = ArgPosition.Middle) : base(offArgs, warningArgs, errorArgs, filterNames, argPosition)
{
AppendNewFilters([nameof(FilterID.VCToolChain)]);
}
}
#pragma warning disable CA1813
internal class WarningsClangToolChainAttribute : ApplyWarningsAttribute
{
#pragma warning restore CA1813
///
internal WarningsClangToolChainAttribute(string[]? offArgs = null, string[]? warningArgs = null, string[]? errorArgs = null, string[]? filterNames = null, ArgPosition argPosition = ArgPosition.Middle) : base(offArgs, warningArgs, errorArgs, filterNames, argPosition)
{
AppendNewFilters([nameof(FilterID.ClangToolChain)]);
}
}
#pragma warning disable CA1813
internal class WarningsIntelCompilerAttribute : ApplyWarningsAttribute
#pragma warning restore CA1813
{
///
internal WarningsIntelCompilerAttribute(string[]? offArgs = null, string[]? warningArgs = null, string[]? errorArgs = null, string[]? filterNames = null, ArgPosition argPosition = ArgPosition.Middle) : base(offArgs, warningArgs, errorArgs, filterNames, argPosition)
{
AppendNewFilters([nameof(StandardFilters.IntelCompilerFilter)]);
}
}
#endregion -- ToolChains --
#region -- Compiler Specializations --
///
/// Specialized for MSVC compiler within the .
///
internal sealed class WarningsMSCVAttribute : WarningsVCToolChainAttribute
{
///
internal WarningsMSCVAttribute(string[]? offArgs = null, string[]? warningArgs = null, string[]? errorArgs = null, string[]? filterNames = null, ArgPosition argPosition = ArgPosition.Middle) : base(offArgs, warningArgs, errorArgs, filterNames, argPosition)
{
AppendNewFilters([nameof(StandardFilters.MSVCCompilerFilter)]);
}
}
///
/// Specialized for Clang compiler within the .
///
internal sealed class WarningsVCClangAttribute : WarningsVCToolChainAttribute
{
///
internal WarningsVCClangAttribute(string[]? offArgs = null, string[]? warningArgs = null, string[]? errorArgs = null, ArgPosition argPosition = ArgPosition.Middle) : base(offArgs, warningArgs, errorArgs, argPosition: argPosition)
{
AppendNewFilters([nameof(StandardFilters.VCClangCompilerFilter)]);
}
}
#endregion -- Compiler Specializations --
#region -- ToolChain Specializations --
///
/// / Specialized for Unused Value.
///
internal sealed class UnusedValueClangToolChainAttribute : WarningsClangToolChainAttribute
{
///
internal UnusedValueClangToolChainAttribute(string[]? offArgs = null, string[]? warningArgs = null, string[]? errorArgs = null) : base(offArgs, warningArgs, errorArgs)
{
AppendNewFilters([FilterID.ConfigShipping]);
}
///
internal override bool CanApplyToContext(CompilerWarningsToolChainContext toolChainContext)
{
return base.CanApplyToContext(toolChainContext) || (toolChainContext._analyzer != StaticAnalyzer.None);
}
}
///
/// Specialized for Shadow Variable Warnings.
///
internal sealed class ShadowVariableWarningsClangToolChainAttribute : WarningsClangToolChainAttribute
{
///
internal ShadowVariableWarningsClangToolChainAttribute(string[]? offArgs, string[]? warningArgs, string[]? errorArgs) : base(offArgs, warningArgs, errorArgs) { }
///
/// No matter what our is, in the clang 17-18.1.3 range we always disable.
protected override void ApplyWarningsToArgumentsInternal(WarningLevel level, CompilerWarningsToolChainContext toolChainContext, List arguments)
{
if (toolChainContext._toolChainVersion == null || (toolChainContext._toolChainVersion >= new EpicGames.Core.VersionNumber(17) && toolChainContext._toolChainVersion < new VersionNumber(18, 1, 3)))
{
if (OffArgs != null)
{
arguments.AddRange(OffArgs);
}
}
else
{
// Explicitly remove the OffArgs for consideration
switch (level)
{
case WarningLevel.Warning:
if (WarningArgs != null)
{
arguments.AddRange(WarningArgs);
}
break;
case WarningLevel.Error:
if (ErrorArgs != null)
{
arguments.AddRange(ErrorArgs);
}
break;
}
}
}
}
///
/// Specialized for Undefined identifier.
///
internal sealed class UndefinedIdentifierWarningsVCToolChainAttribute : WarningsVCToolChainAttribute
{
///
internal UndefinedIdentifierWarningsVCToolChainAttribute(string[]? offArgs, string[]? warningArgs, string[]? errorArgs) : base(offArgs, warningArgs, errorArgs) { }
///
protected override void ApplyWarningsToArgumentsInternal(WarningLevel level, CompilerWarningsToolChainContext toolChainContext, List arguments)
{
if (!toolChainContext._compileEnvironment.bPreprocessOnly)
{
base.ApplyWarningsToArgumentsInternal(level, toolChainContext, arguments);
}
}
}
///
/// Specialized for Unsafe Type Casts.
///
internal sealed class UnsafeTypeCastWarningsVCToolChainAttribute : WarningsVCToolChainAttribute
{
///
internal UnsafeTypeCastWarningsVCToolChainAttribute(string[] offArgs, string[] warningArgs, string[] errorArgs) : base(offArgs, warningArgs, errorArgs) { }
///
protected override void ApplyWarningsToArgumentsInternal(WarningLevel level, CompilerWarningsToolChainContext toolChainContext, List arguments)
{
WarningLevel effectiveCastWarningLevel = (toolChainContext._buildSystemContext.GetReadOnlyTargetRules()?.Platform == UnrealTargetPlatform.Win64) ? level : WarningLevel.Off;
base.ApplyWarningsToArgumentsInternal(effectiveCastWarningLevel, toolChainContext, arguments);
}
}
#endregion -- ToolChain Specializations --
}