// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.IO; using System.Linq; using EpicGames.Core; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using UnrealBuildBase; using UnrealBuildTool.Tests.TestUtilities; namespace UnrealBuildTool.Tests { [TestClass] public class CppCompileWarningsTests { internal class TestBuildSettingsProvider : IBuildContextProvider { internal BuildSettingsVersion _testBuildSettings = BuildSettingsVersion.V1; public BuildSettingsVersion GetBuildSettings() { return _testBuildSettings; } } [DataTestMethod] [DataRow(WarningLevel.Default, null, true, WarningLevel.Default)] // Null applied, no overwrite [DataRow(WarningLevel.Default, WarningLevel.Off, true, WarningLevel.Off)] // Overwrite with Off [DataRow(WarningLevel.Default, WarningLevel.Warning, true, WarningLevel.Warning)] // Overwrite with Warning [DataRow(WarningLevel.Default, WarningLevel.Error, true, WarningLevel.Error)] // Overwrite with Error [DataRow(WarningLevel.Default, WarningLevel.Default, true, WarningLevel.Default)] // Applied is Default, no change [DataRow(WarningLevel.Default, WarningLevel.Warning, false, WarningLevel.Warning)] // Default, non-overwrite, change [DataRow(WarningLevel.Default, WarningLevel.Error, false, WarningLevel.Error)] // Default, non-overwrite, change [DataRow(WarningLevel.Off, null, true, WarningLevel.Off)] // Null applied, no change [DataRow(WarningLevel.Off, WarningLevel.Default, true, WarningLevel.Off)] // Applied Default, no change [DataRow(WarningLevel.Off, WarningLevel.Warning, true, WarningLevel.Warning)] // Overwrite with Warning [DataRow(WarningLevel.Off, WarningLevel.Error, true, WarningLevel.Error)] // Overwrite with Error [DataRow(WarningLevel.Off, WarningLevel.Warning, false, WarningLevel.Off)] // No overwrite, no change [DataRow(WarningLevel.Warning, WarningLevel.Error, true, WarningLevel.Error)] // Overwrite with Error [DataRow(WarningLevel.Warning, WarningLevel.Off, true, WarningLevel.Off)] // Overwrite with Off [DataRow(WarningLevel.Warning, WarningLevel.Off, false, WarningLevel.Warning)] // No overwrite, remains Warning [DataRow(WarningLevel.Error, WarningLevel.Off, true, WarningLevel.Off)] // Overwrite with Off [DataRow(WarningLevel.Error, WarningLevel.Warning, true, WarningLevel.Warning)] // Overwrite with Warning [DataRow(WarningLevel.Error, WarningLevel.Off, false, WarningLevel.Error)] // No overwrite, remains Error public void TestApplyWarnings(WarningLevel inSourceWarningLevel, WarningLevel? appliedWarningLevel, bool overwriteSourceValue, WarningLevel expected) { WarningLevel sourceWarningLevel = inSourceWarningLevel; sourceWarningLevel.ApplyWarning(appliedWarningLevel, overwriteSourceValue); Assert.AreEqual(expected, sourceWarningLevel); } [TestMethod] public void TestDefaultBuildSettings() { CppCompileWarnings defaultBuildSettings = new CppCompileWarnings(); Assert.AreEqual(WarningLevel.Warning, defaultBuildSettings.ShadowVariableWarningLevel); Assert.AreEqual(WarningLevel.Off, defaultBuildSettings.UndefinedIdentifierWarningLevel); Assert.AreEqual(WarningLevel.Off, defaultBuildSettings.UnsafeTypeCastWarningLevel); Assert.AreEqual(WarningLevel.Off, defaultBuildSettings.SwitchUnhandledEnumeratorWarningLevel); } [TestMethod] public void TestClonedMutableReturn() { CppCompileWarnings defaultBuildSettings = new CppCompileWarnings(); defaultBuildSettings.ShadowVariableWarningLevel = WarningLevel.Error; defaultBuildSettings.UndefinedIdentifierWarningLevel = WarningLevel.Warning; defaultBuildSettings.UnsafeTypeCastWarningLevel = WarningLevel.Error; defaultBuildSettings.SwitchUnhandledEnumeratorWarningLevel = WarningLevel.Warning; ReadOnlyCppCompileWarnings wrapper = new ReadOnlyCppCompileWarnings(defaultBuildSettings); CppCompileWarnings cloned = wrapper.CloneAsWriteable(); { Assert.AreEqual(defaultBuildSettings.ShadowVariableWarningLevel, cloned.ShadowVariableWarningLevel); Assert.AreEqual(defaultBuildSettings.UndefinedIdentifierWarningLevel, cloned.UndefinedIdentifierWarningLevel); Assert.AreEqual(defaultBuildSettings.UnsafeTypeCastWarningLevel, cloned.UnsafeTypeCastWarningLevel); Assert.AreEqual(defaultBuildSettings.SwitchUnhandledEnumeratorWarningLevel, cloned.SwitchUnhandledEnumeratorWarningLevel); } // Modify and assert != to each other - the same underyling reference has not been returned { cloned.ShadowVariableWarningLevel = WarningLevel.Warning; cloned.UndefinedIdentifierWarningLevel = WarningLevel.Error; cloned.UnsafeTypeCastWarningLevel = WarningLevel.Warning; cloned.SwitchUnhandledEnumeratorWarningLevel = WarningLevel.Error; Assert.AreNotEqual(defaultBuildSettings.ShadowVariableWarningLevel, cloned.ShadowVariableWarningLevel); Assert.AreNotEqual(defaultBuildSettings.UndefinedIdentifierWarningLevel, cloned.UndefinedIdentifierWarningLevel); Assert.AreNotEqual(defaultBuildSettings.UnsafeTypeCastWarningLevel, cloned.UnsafeTypeCastWarningLevel); Assert.AreNotEqual(defaultBuildSettings.SwitchUnhandledEnumeratorWarningLevel, cloned.SwitchUnhandledEnumeratorWarningLevel); } } [TestMethod] public void TestContextBuildSettingsOverride() { TestBuildSettingsProvider buildContextProvider = new TestBuildSettingsProvider(); buildContextProvider._testBuildSettings = BuildSettingsVersion.V1; CppCompileWarnings newWarnings = new CppCompileWarnings(buildContextProvider, null); // Shadow Variable build setting defaults { Assert.AreEqual(WarningLevel.Default, newWarnings.ShadowVariableWarningLevel); // Boundary analysis buildContextProvider._testBuildSettings = BuildSettingsVersion.V2; CppCompileWarnings.ApplyTargetDefaults(newWarnings, true); Assert.AreEqual(WarningLevel.Error, newWarnings.ShadowVariableWarningLevel); buildContextProvider._testBuildSettings = BuildSettingsVersion.V3; CppCompileWarnings.ApplyTargetDefaults(newWarnings, true); Assert.AreEqual(WarningLevel.Error, newWarnings.ShadowVariableWarningLevel); } } [TestMethod] public void TestParentSettings() { TestBuildSettingsProvider buildContextProvider = new TestBuildSettingsProvider(); buildContextProvider._testBuildSettings = BuildSettingsVersion.V1; CppCompileWarnings parentWarnings = new CppCompileWarnings(buildContextProvider, null); CppCompileWarnings newWarnings = new CppCompileWarnings(buildContextProvider, null, new ReadOnlyCppCompileWarnings(parentWarnings)); // Assert invariants { Assert.AreEqual(WarningLevel.Default, newWarnings.ShadowVariableWarningLevel); Assert.AreEqual(WarningLevel.Default, newWarnings.UnsafeTypeCastWarningLevel); Assert.AreEqual(WarningLevel.Default, newWarnings.UndefinedIdentifierWarningLevel); } // Assert new parent values { parentWarnings.ShadowVariableWarningLevel = WarningLevel.Error; parentWarnings.UndefinedIdentifierWarningLevel = WarningLevel.Error; parentWarnings.UnsafeTypeCastWarningLevel = WarningLevel.Error; Assert.AreEqual(WarningLevel.Error, newWarnings.ShadowVariableWarningLevel); Assert.AreEqual(WarningLevel.Error, newWarnings.UnsafeTypeCastWarningLevel); Assert.AreEqual(WarningLevel.Error, newWarnings.UndefinedIdentifierWarningLevel); } } [TestMethod] public void TestReparentOperations() { TestBuildSettingsProvider buildContextProvider = new TestBuildSettingsProvider(); buildContextProvider._testBuildSettings = BuildSettingsVersion.V1; CppCompileWarnings parentWarnings = new CppCompileWarnings(buildContextProvider, null); CppCompileWarnings newWarnings = new CppCompileWarnings(buildContextProvider, null, new ReadOnlyCppCompileWarnings(parentWarnings)); // Assert invariant parent values { parentWarnings.ShadowVariableWarningLevel = WarningLevel.Error; parentWarnings.UndefinedIdentifierWarningLevel = WarningLevel.Error; parentWarnings.UnsafeTypeCastWarningLevel = WarningLevel.Error; Assert.AreEqual(WarningLevel.Error, newWarnings.ShadowVariableWarningLevel); Assert.AreEqual(WarningLevel.Error, newWarnings.UnsafeTypeCastWarningLevel); Assert.AreEqual(WarningLevel.Error, newWarnings.UndefinedIdentifierWarningLevel); } // Assert reparenting CppCompileWarnings parentWarnings2 = new CppCompileWarnings(buildContextProvider, null); { newWarnings.AddParent(parentWarnings2); parentWarnings2.ShadowVariableWarningLevel = WarningLevel.Warning; parentWarnings2.UndefinedIdentifierWarningLevel = WarningLevel.Warning; parentWarnings2.UnsafeTypeCastWarningLevel = WarningLevel.Warning; Assert.AreEqual(WarningLevel.Warning, newWarnings.ShadowVariableWarningLevel); Assert.AreEqual(WarningLevel.Warning, newWarnings.UnsafeTypeCastWarningLevel); Assert.AreEqual(WarningLevel.Warning, newWarnings.UndefinedIdentifierWarningLevel); } // Assert transitive to eldest ancestor { parentWarnings2.ShadowVariableWarningLevel = WarningLevel.Default; Assert.AreEqual(parentWarnings.ShadowVariableWarningLevel, newWarnings.ShadowVariableWarningLevel); } // Assert removal of parentWarnings2 - UnsafeTypeCastWarningLevel & UndefinedIdentifierWarningLevel will now be the reoslved items { newWarnings.RemoveParent(); Assert.AreEqual(parentWarnings.UnsafeTypeCastWarningLevel, newWarnings.UnsafeTypeCastWarningLevel); Assert.AreEqual(parentWarnings.UndefinedIdentifierWarningLevel, newWarnings.UndefinedIdentifierWarningLevel); } // Removal of only parent; should only be default values { newWarnings.RemoveParent(); Assert.AreEqual(WarningLevel.Default, newWarnings.ShadowVariableWarningLevel); Assert.AreEqual(WarningLevel.Default, newWarnings.UnsafeTypeCastWarningLevel); Assert.AreEqual(WarningLevel.Default, newWarnings.UndefinedIdentifierWarningLevel); } } [TestMethod] public void TestChildOverrides() { TestBuildSettingsProvider buildContextProvider = new TestBuildSettingsProvider(); buildContextProvider._testBuildSettings = BuildSettingsVersion.V1; CppCompileWarnings parentWarnings = new CppCompileWarnings(buildContextProvider, null); CppCompileWarnings newWarnings = new CppCompileWarnings(buildContextProvider, null, new ReadOnlyCppCompileWarnings(parentWarnings)); parentWarnings.ShadowVariableWarningLevel = WarningLevel.Error; parentWarnings.UndefinedIdentifierWarningLevel = WarningLevel.Error; parentWarnings.UnsafeTypeCastWarningLevel = WarningLevel.Error; // Assert invariants { Assert.AreEqual(WarningLevel.Error, newWarnings.ShadowVariableWarningLevel); Assert.AreEqual(WarningLevel.Error, newWarnings.UnsafeTypeCastWarningLevel); Assert.AreEqual(WarningLevel.Error, newWarnings.UndefinedIdentifierWarningLevel); } // Child overrides; newWarnings.ShadowVariableWarningLevel = WarningLevel.Warning; newWarnings.UndefinedIdentifierWarningLevel = WarningLevel.Warning; newWarnings.UnsafeTypeCastWarningLevel = WarningLevel.Warning; // Assert new parent values { Assert.AreEqual(WarningLevel.Warning, newWarnings.ShadowVariableWarningLevel); Assert.AreEqual(WarningLevel.Warning, newWarnings.UnsafeTypeCastWarningLevel); Assert.AreEqual(WarningLevel.Warning, newWarnings.UndefinedIdentifierWarningLevel); } } [TestMethod] public void TestGenerateWarningCommandLineAgsOrder() { DirectoryReference programsDirectory = DirectoryReference.Combine(Unreal.EngineSourceDirectory, "Programs"); FileReference testStubsDirectory = FileReference.Combine(programsDirectory, "Shared", "UnrealBuildTool.Tests", "UBT"); // Generate ephemeral TargetRules & uproject files using (SafeTestDirectory testRootDirectory = SafeTestDirectory.CreateTestDirectory(Path.Combine(StaticTargetRulesInitializer.UBTTestFolderRoot, $"{StaticTargetRulesInitializer.UBTTestFolderPrefix}{Guid.NewGuid().ToString()}"))) using (SafeTestDirectory testSourceDirectory = SafeTestDirectory.CreateTestDirectory(Path.Combine(testRootDirectory.TemporaryDirectory, "Source"))) using (SafeTestFile testEditorTargetTestFile = new SafeTestFile(File.ReadAllText(Path.Combine(testStubsDirectory.FullName, "TargetStubs", "TestStubEditor.Target.ubttest")), "TestStubEditor.Target.cs", testSourceDirectory.TemporaryDirectory)) using (SafeTestFile testTargetTestFile = new SafeTestFile(File.ReadAllText(Path.Combine(testStubsDirectory.FullName, "TargetStubs", "TestStub.Target.ubttest")), "TestStub.Target.cs", testSourceDirectory.TemporaryDirectory)) using (SafeTestFile testUprojectTestFile = new SafeTestFile(File.ReadAllText(Path.Combine(testStubsDirectory.FullName, "UprojectStubs", "TestStub.uproject.ubttest")), "TestStub.uproject", testRootDirectory.TemporaryDirectory)) { CppCompileEnvironment newCompileEnvironment = new CppCompileEnvironment(UnrealTargetPlatform.Win64, CppConfiguration.Development, new UnrealArchitectures(UnrealArch.X64), null!); FileReference testUproject = new FileReference(testUprojectTestFile.TemporaryFile); IEnumerable args = null!; RulesAssembly generatedTestGameRulesAssembly = RulesCompiler.CreateTargetRulesAssembly(testUproject, "TestStub", false, false, false, null, false, new TestLogger()); TargetRules testTargetRulesNonWin64 = generatedTestGameRulesAssembly.CreateTargetRules("TestStub", UnrealTargetPlatform.Android, UnrealTargetConfiguration.Development, null, testUproject, null, new TestLogger()); CppCompileWarnings specializedWarnings = new CppCompileWarnings(testTargetRulesNonWin64, null); // Verify the ordering { VersionNumber newVersionNumber = new VersionNumber(18, 9, 9); specializedWarnings.DeprecatedCopyWarningLevel = WarningLevel.Off; specializedWarnings.DeprecatedCopyWithUserProvidedCopyWarningLevel = WarningLevel.Error; args = specializedWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Count() == 2); Assert.IsTrue(args.First() == "-Wno-deprecated-copy"); Assert.IsTrue(args.Last() == "-Wdeprecated-copy-with-user-provided-copy"); } } } [TestMethod] public void TestGenerateWarningCommandLineAgs() { DirectoryReference programsDirectory = DirectoryReference.Combine(Unreal.EngineSourceDirectory, "Programs"); FileReference testStubsDirectory = FileReference.Combine(programsDirectory, "Shared", "UnrealBuildTool.Tests", "UBT"); // Generate ephemeral TargetRules & uproject files using (SafeTestDirectory testRootDirectory = SafeTestDirectory.CreateTestDirectory(Path.Combine(StaticTargetRulesInitializer.UBTTestFolderRoot, $"{StaticTargetRulesInitializer.UBTTestFolderPrefix}{Guid.NewGuid().ToString()}"))) using (SafeTestDirectory testSourceDirectory = SafeTestDirectory.CreateTestDirectory(Path.Combine(testRootDirectory.TemporaryDirectory, "Source"))) using (SafeTestFile testEditorTargetTestFile = new SafeTestFile(File.ReadAllText(Path.Combine(testStubsDirectory.FullName, "TargetStubs", "TestStubEditor.Target.ubttest")), "TestStubEditor.Target.cs", testSourceDirectory.TemporaryDirectory)) using (SafeTestFile testTargetTestFile = new SafeTestFile(File.ReadAllText(Path.Combine(testStubsDirectory.FullName, "TargetStubs", "TestStub.Target.ubttest")), "TestStub.Target.cs", testSourceDirectory.TemporaryDirectory)) using (SafeTestFile testUprojectTestFile = new SafeTestFile(File.ReadAllText(Path.Combine(testStubsDirectory.FullName, "UprojectStubs", "TestStub.uproject.ubttest")), "TestStub.uproject", testRootDirectory.TemporaryDirectory)) { CppCompileEnvironment newCompileEnvironment = new CppCompileEnvironment(UnrealTargetPlatform.Win64, CppConfiguration.Development, new UnrealArchitectures(UnrealArch.X64), null!); FileReference testUproject = new FileReference(testUprojectTestFile.TemporaryFile); // Generate rules assembly & subsequent targets RulesAssembly generatedTestRulesAssembly = RulesCompiler.CreateTargetRulesAssembly(testUproject, "TestStubEditor", false, false, false, null, false, new TestLogger()); TargetRules testTargetRules = generatedTestRulesAssembly.CreateTargetRules("TestStubEditor", UnrealTargetPlatform.Win64, UnrealTargetConfiguration.Development, null, testUproject, null, new TestLogger()); testTargetRules.WindowsPlatform.Compiler = WindowsCompiler.VisualStudio2022; CppCompileWarnings baseWarnings = new CppCompileWarnings(testTargetRules, null); IEnumerable args = null!; // No args, base check { args = baseWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(VCToolChain)); Assert.IsFalse(args.Any()); } // VC toolchain check; { baseWarnings.UnsafeTypeCastWarningLevel = WarningLevel.Warning; args = baseWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(VCToolChain)); Assert.IsTrue(args.Count() == 2); Assert.IsTrue(args.Contains("/w44244")); Assert.IsTrue(args.Contains("/w44838")); baseWarnings.UnsafeTypeCastWarningLevel = WarningLevel.Default; } // MSVC compiler check; { baseWarnings.ShadowVariableWarningLevel = WarningLevel.Error; args = baseWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(VCToolChain)); Assert.IsTrue(args.Count() == 3); Assert.IsTrue(args.Contains("/we4456")); Assert.IsTrue(args.Contains("/we4458")); Assert.IsTrue(args.Contains("/we4459")); WindowsCompiler previousCompiler = testTargetRules.WindowsPlatform.Compiler; testTargetRules.WindowsPlatform.Compiler = WindowsCompiler.Intel; args = baseWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(VCToolChain)); Assert.IsFalse(args.Any()); testTargetRules.WindowsPlatform.Compiler = previousCompiler; baseWarnings.ShadowVariableWarningLevel = WarningLevel.Default; } // Specialized VC toolchain check; UndefinedIdentifier { baseWarnings.UndefinedIdentifierWarningLevel = WarningLevel.Warning; args = baseWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(VCToolChain)); Assert.IsTrue(args.Count() == 1); Assert.IsTrue(args.Contains("/w44668")); CppCompileEnvironment preprocessOnlyCompileEnvironment = new CppCompileEnvironment(newCompileEnvironment); preprocessOnlyCompileEnvironment.bPreprocessOnly = true; args = baseWarnings.GenerateWarningCommandLineArgs(preprocessOnlyCompileEnvironment, typeof(VCToolChain)); Assert.IsFalse(args.Any()); baseWarnings.UndefinedIdentifierWarningLevel = WarningLevel.Default; } { // DeterministicWarningLevel VersionNumber newVersionNumber = new VersionNumber(18, 9, 9); CppCompileEnvironment deterministicCompileEnvironment = new CppCompileEnvironment(UnrealTargetPlatform.Win64, CppConfiguration.Debug, new UnrealArchitectures(UnrealArch.X64), null!); deterministicCompileEnvironment.bDeterministic = false; args = baseWarnings.GenerateWarningCommandLineArgs(deterministicCompileEnvironment, typeof(VCToolChain), newVersionNumber); Assert.IsFalse(args.Any()); deterministicCompileEnvironment.bDeterministic = true; args = baseWarnings.GenerateWarningCommandLineArgs(deterministicCompileEnvironment, typeof(VCToolChain), newVersionNumber); Assert.IsFalse(args.Any()); baseWarnings.DeterministicWarningLevel = WarningLevel.Off; args = baseWarnings.GenerateWarningCommandLineArgs(deterministicCompileEnvironment, typeof(VCToolChain), newVersionNumber); Assert.AreEqual(1, args.Count()); Assert.IsTrue(args.Contains("/wd5048")); baseWarnings.DeterministicWarningLevel = WarningLevel.Warning; args = baseWarnings.GenerateWarningCommandLineArgs(deterministicCompileEnvironment, typeof(VCToolChain), newVersionNumber); Assert.AreEqual(0, args.Count()); Assert.IsFalse(args.Any()); baseWarnings.DeterministicWarningLevel = WarningLevel.Error; args = baseWarnings.GenerateWarningCommandLineArgs(deterministicCompileEnvironment, typeof(VCToolChain), newVersionNumber); Assert.AreEqual(1, args.Count()); Assert.IsTrue(args.Contains("/we5048")); } // Specialized VC toolchain check; UnsafeTypeCast { RulesAssembly generatedTestGameRulesAssembly = RulesCompiler.CreateTargetRulesAssembly(testUproject, "TestStub", false, false, false, null, false, new TestLogger()); TargetRules testTargetRulesNonWin64 = generatedTestGameRulesAssembly.CreateTargetRules("TestStub", UnrealTargetPlatform.Android, UnrealTargetConfiguration.Development, null, testUproject, null, new TestLogger()); CppCompileWarnings specializedWarnings = new CppCompileWarnings(testTargetRulesNonWin64, null); specializedWarnings.UnsafeTypeCastWarningLevel = WarningLevel.Warning; args = specializedWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(VCToolChain)); Assert.IsTrue(args.Count() == 2); Assert.IsTrue(args.Contains("/wd4244")); Assert.IsTrue(args.Contains("/wd4838")); baseWarnings.UnsafeTypeCastWarningLevel = WarningLevel.Warning; args = baseWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(VCToolChain)); Assert.IsTrue(args.Count() == 2); Assert.IsTrue(args.Contains("/w44244")); Assert.IsTrue(args.Contains("/w44838")); baseWarnings.UnsafeTypeCastWarningLevel = WarningLevel.Default; } // Clang toolchain version check - no version; should disable Shadow { testTargetRules.WindowsPlatform.Compiler = WindowsCompiler.Clang; baseWarnings.ShadowVariableWarningLevel = WarningLevel.Error; args = baseWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(ClangToolChain)); Assert.IsTrue(args.Count() == 1); Assert.IsTrue(args.Contains("-Wno-shadow")); baseWarnings.ShadowVariableWarningLevel = WarningLevel.Default; } // Clang toolchain version check - valid versions; { testTargetRules.WindowsPlatform.Compiler = WindowsCompiler.Clang; baseWarnings.ShadowVariableWarningLevel = WarningLevel.Error; VersionNumber newVersionNumber = new VersionNumber(16, 9, 5); args = baseWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Count() == 1); Assert.IsTrue(args.Contains("-Wshadow")); newVersionNumber = new VersionNumber(17); args = baseWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Count() == 1); Assert.IsTrue(args.Contains("-Wno-shadow")); newVersionNumber = new VersionNumber(17, 1); args = baseWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Count() == 1); Assert.IsTrue(args.Contains("-Wno-shadow")); newVersionNumber = new VersionNumber(18, 1, 2); args = baseWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Count() == 1); Assert.IsTrue(args.Contains("-Wno-shadow")); newVersionNumber = new VersionNumber(18, 1, 3); args = baseWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Count() == 1); Assert.IsTrue(args.Contains("-Wshadow")); baseWarnings.ShadowVariableWarningLevel = WarningLevel.Default; } // ToolChainVersionConstrainedFilterAttribute { testTargetRules.WindowsPlatform.Compiler = WindowsCompiler.Clang; baseWarnings.Shorten64To32WarningLevel = WarningLevel.Off; VersionNumber newVersionNumber = new VersionNumber(18, 9, 9); args = baseWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsFalse(args.Any()); // newVersionNumber = new VersionNumber(19, 0, 0); args = baseWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Count() == 1); Assert.IsTrue(args.Contains("-Wno-shorten-64-to-32")); baseWarnings.Shorten64To32WarningLevel = WarningLevel.Default; } // ConfigurationFilterAttribute { testTargetRules.WindowsPlatform.Compiler = WindowsCompiler.Clang; baseWarnings.UnusedValueWarningLevel = WarningLevel.Off; VersionNumber newVersionNumber = new VersionNumber(18, 9, 9); CppCompileEnvironment invalidCompileEnvironment = new CppCompileEnvironment(UnrealTargetPlatform.Win64, CppConfiguration.Debug, new UnrealArchitectures(UnrealArch.X64), null!); CppCompileEnvironment validCompileEnvironment = new CppCompileEnvironment(UnrealTargetPlatform.Win64, CppConfiguration.Shipping, new UnrealArchitectures(UnrealArch.X64), null!); args = baseWarnings.GenerateWarningCommandLineArgs(invalidCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsFalse(args.Any()); args = baseWarnings.GenerateWarningCommandLineArgs(validCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Count() == 2); Assert.IsTrue(args.Contains("-Wno-unused-value")); baseWarnings.UnusedValueWarningLevel = WarningLevel.Default; } // CppStandardConstrainedFilterAttribute { testTargetRules.WindowsPlatform.Compiler = WindowsCompiler.Clang; baseWarnings.AmbiguousReversedOperatorWarningLevel = WarningLevel.Off; VersionNumber newVersionNumber = new VersionNumber(18, 9, 9); CppCompileEnvironment cppStandardCompileEnvironment = new CppCompileEnvironment(UnrealTargetPlatform.Win64, CppConfiguration.Debug, new UnrealArchitectures(UnrealArch.X64), null!); #pragma warning disable CS0618 // Type or member is obsolete cppStandardCompileEnvironment.CppStandard = CppStandardVersion.Cpp17; #pragma warning restore CS0618 // Type or member is obsolete args = baseWarnings.GenerateWarningCommandLineArgs(cppStandardCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsFalse(args.Any()); cppStandardCompileEnvironment.CppStandard = CppStandardVersion.Cpp20; args = baseWarnings.GenerateWarningCommandLineArgs(cppStandardCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Count() == 1); Assert.IsTrue(args.Contains("-Wno-ambiguous-reversed-operator")); cppStandardCompileEnvironment.CppStandard = CppStandardVersion.Latest; args = baseWarnings.GenerateWarningCommandLineArgs(cppStandardCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Count() == 1); Assert.IsTrue(args.Contains("-Wno-ambiguous-reversed-operator")); baseWarnings.AmbiguousReversedOperatorWarningLevel = WarningLevel.Default; } // DeterministcFlagSetFilter { testTargetRules.WindowsPlatform.Compiler = WindowsCompiler.Clang; baseWarnings.DeterministicWarningLevel = WarningLevel.Off; VersionNumber newVersionNumber = new VersionNumber(18, 9, 9); CppCompileEnvironment deterministicCompileEnvironment = new CppCompileEnvironment(UnrealTargetPlatform.Win64, CppConfiguration.Debug, new UnrealArchitectures(UnrealArch.X64), null!); deterministicCompileEnvironment.bDeterministic = false; args = baseWarnings.GenerateWarningCommandLineArgs(deterministicCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsFalse(args.Any()); deterministicCompileEnvironment.bDeterministic = true; args = baseWarnings.GenerateWarningCommandLineArgs(deterministicCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Count() == 1); Assert.IsTrue(args.Contains("-Wno-date-time")); deterministicCompileEnvironment.bDeterministic = false; baseWarnings.DeterministicWarningLevel = WarningLevel.Warning; args = baseWarnings.GenerateWarningCommandLineArgs(deterministicCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsFalse(args.Any()); deterministicCompileEnvironment.bDeterministic = true; args = baseWarnings.GenerateWarningCommandLineArgs(deterministicCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Count() == 2); Assert.IsTrue(args.Contains("-Wdate-time")); Assert.IsTrue(args.Contains("-Wno-error=date-time")); baseWarnings.DeterministicWarningLevel = WarningLevel.Error; args = baseWarnings.GenerateWarningCommandLineArgs(deterministicCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Count() == 1); Assert.IsTrue(args.Contains("-Wdate-time")); baseWarnings.DeterministicWarningLevel = WarningLevel.Default; } // PGOOptimizedFilter { testTargetRules.WindowsPlatform.Compiler = WindowsCompiler.Clang; baseWarnings.ProfileInstructWarningLevel = WarningLevel.Off; VersionNumber newVersionNumber = new VersionNumber(18, 9, 9); CppCompileEnvironment pgoOptimizedCompileEnvironment = new CppCompileEnvironment(UnrealTargetPlatform.Win64, CppConfiguration.Debug, new UnrealArchitectures(UnrealArch.X64), null!); pgoOptimizedCompileEnvironment.bPGOOptimize = false; args = baseWarnings.GenerateWarningCommandLineArgs(pgoOptimizedCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsFalse(args.Any()); pgoOptimizedCompileEnvironment.bPGOOptimize = true; args = baseWarnings.GenerateWarningCommandLineArgs(pgoOptimizedCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Count() == 2); Assert.IsTrue(args.Contains("-Wno-profile-instr-out-of-date")); Assert.IsTrue(args.Contains("-Wno-profile-instr-unprofiled")); baseWarnings.ProfileInstructWarningLevel = WarningLevel.Off; } // AndroidNDKR28ToolChainVersionExclusion { testTargetRules.WindowsPlatform.Compiler = WindowsCompiler.Clang; baseWarnings.CastFunctionTypeMismatchWarningLevel = WarningLevel.Off; VersionNumber newVersionNumber = new VersionNumber(19, 0, 0); CppCompileEnvironment androidCompileEnvironment = new CppCompileEnvironment(UnrealTargetPlatform.Android, CppConfiguration.Development, new UnrealArchitectures(UnrealArch.X64), null!); args = baseWarnings.GenerateWarningCommandLineArgs(androidCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsFalse(args.Any()); args = baseWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Count() == 1); Assert.IsTrue(args.Contains("-Wno-cast-function-type-mismatch")); newVersionNumber = new VersionNumber(19, 0, 1); args = baseWarnings.GenerateWarningCommandLineArgs(androidCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Count() == 1); Assert.IsTrue(args.Contains("-Wno-cast-function-type-mismatch")); baseWarnings.CastFunctionTypeMismatchWarningLevel = WarningLevel.Default; } // AndroidNDKR26ToolChainVersionExclusion { testTargetRules.WindowsPlatform.Compiler = WindowsCompiler.Clang; baseWarnings.InvalidUnevaluatedStringWarningLevel = WarningLevel.Off; CppCompileEnvironment androidCompileEnvironment = new CppCompileEnvironment(UnrealTargetPlatform.Android, CppConfiguration.Development, new UnrealArchitectures(UnrealArch.X64), null!); // Exclusion cases { VersionNumber newVersionNumber = new VersionNumber(17, 0, 2); args = baseWarnings.GenerateWarningCommandLineArgs(androidCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Count() == 1 && args.Contains("-Wno-shadow")); newVersionNumber = new VersionNumber(16); args = baseWarnings.GenerateWarningCommandLineArgs(androidCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsFalse(args.Any()); newVersionNumber = new VersionNumber(17, 1); androidCompileEnvironment.CppStandard = CppStandardVersion.Latest; args = baseWarnings.GenerateWarningCommandLineArgs(androidCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Count() == 1 && args.Contains("-Wno-shadow")); } // Inclusion cases { VersionNumber newVersionNumber = new VersionNumber(17, 1); androidCompileEnvironment.CppStandard = CppStandardVersion.Cpp20; args = baseWarnings.GenerateWarningCommandLineArgs(androidCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Contains("-Wno-invalid-unevaluated-string")); newVersionNumber = new VersionNumber(17, 0, 2); args = baseWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(ClangToolChain), newVersionNumber); Assert.IsTrue(args.Contains("-Wno-invalid-unevaluated-string")); } baseWarnings.InvalidUnevaluatedStringWarningLevel = WarningLevel.Default; } // UnusedValueClangToolChainAttribute { testTargetRules.WindowsPlatform.Compiler = WindowsCompiler.Clang; baseWarnings.UnusedValueWarningLevel = WarningLevel.Off; VersionNumber newVersionNumber = new VersionNumber(18, 9, 9); CppCompileEnvironment invalidCompileEnvironment = new CppCompileEnvironment(UnrealTargetPlatform.Win64, CppConfiguration.Debug, new UnrealArchitectures(UnrealArch.X64), null!); CppCompileEnvironment validCompileEnvironment = new CppCompileEnvironment(UnrealTargetPlatform.Win64, CppConfiguration.Shipping, new UnrealArchitectures(UnrealArch.X64), null!); args = baseWarnings.GenerateWarningCommandLineArgs(invalidCompileEnvironment, typeof(ClangToolChain), newVersionNumber, StaticAnalyzer.None); Assert.IsFalse(args.Any()); args = baseWarnings.GenerateWarningCommandLineArgs(validCompileEnvironment, typeof(ClangToolChain), newVersionNumber, StaticAnalyzer.None); Assert.IsTrue(args.Count() == 2 && args.Contains("-Wno-unused-value")); args = baseWarnings.GenerateWarningCommandLineArgs(validCompileEnvironment, typeof(ClangToolChain), newVersionNumber, StaticAnalyzer.Clang); Assert.IsTrue(args.Count() == 2 && args.Contains("-Wno-unused-value")); } // VCClangCompilerFilter { testTargetRules.WindowsPlatform.Compiler = WindowsCompiler.Clang; baseWarnings.MicrosoftGroupWarningLevel = WarningLevel.Off; args = baseWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(VCToolChain)); Assert.IsTrue(args.Any()); Assert.IsTrue(args.Contains("-Wno-microsoft")); // make sure exclusively ONLY the clang stuff is in: testTargetRules.WindowsPlatform.Compiler = WindowsCompiler.VisualStudio2022; args = baseWarnings.GenerateWarningCommandLineArgs(newCompileEnvironment, typeof(VCToolChain)); Assert.IsFalse(args.Any()); } } } } }