diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs index d277331b12e9..6bbe706d9544 100644 --- a/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs @@ -424,8 +424,7 @@ private CSharpAutobuilder CreateAutoBuilder(bool isWindows, return new CSharpAutobuilder(actions, options); } - [Fact] - public void TestDefaultCSharpAutoBuilder() + private void SetupActionForDotnet() { actions.RunProcess["cmd.exe /C dotnet --info"] = 0; actions.RunProcess[@"cmd.exe /C dotnet clean C:\Project\test.csproj"] = 0; @@ -438,20 +437,80 @@ public void TestDefaultCSharpAutoBuilder() actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SCRATCH_DIR"] = "scratch"; actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbar.cs\ntest.csproj"; actions.EnumerateDirectories[@"C:\Project"] = ""; - var xml = new XmlDocument(); - xml.LoadXml(@" - - Exe - netcoreapp2.1 - + } -"); + private void CreateAndVerifyDotnetScript(XmlDocument xml) + { actions.LoadXml[@"C:\Project\test.csproj"] = xml; var autobuilder = CreateAutoBuilder(true); TestAutobuilderScript(autobuilder, 0, 4); } + [Fact] + public void TestDefaultCSharpAutoBuilder1() + { + SetupActionForDotnet(); + var xml = new XmlDocument(); + xml.LoadXml( + """ + + + Exe + netcoreapp2.1 + + + """); + CreateAndVerifyDotnetScript(xml); + } + + [Fact] + public void TestDefaultCSharpAutoBuilder2() + { + SetupActionForDotnet(); + var xml = new XmlDocument(); + + xml.LoadXml( + """ + + + + + Exe + net9.0 + enable + enable + + + """ + ); + CreateAndVerifyDotnetScript(xml); + } + + [Fact] + public void TestDefaultCSharpAutoBuilder3() + { + SetupActionForDotnet(); + var xml = new XmlDocument(); + + xml.LoadXml( + """ + + + + + Exe + net9.0 + enable + enable + + + + """ + ); + CreateAndVerifyDotnetScript(xml); + } + [Fact] public void TestLinuxCSharpAutoBuilder() { diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs index c318ef09805d..37a8feee186c 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs @@ -3,7 +3,6 @@ using System.IO; using System.Linq; using System.Xml; -using Semmle.Util.Logging; namespace Semmle.Autobuild.Shared { @@ -26,6 +25,26 @@ public class Project : ProjectOrSolution w private readonly Lazy>> includedProjectsLazy; public override IEnumerable IncludedProjects => includedProjectsLazy.Value; + private static bool HasSdkAttribute(XmlElement xml) => + xml.HasAttribute("Sdk"); + + private static bool AnyElement(XmlNodeList l, Func f) => + l.OfType().Any(f); + + /// + /// According to https://learn.microsoft.com/en-us/visualstudio/msbuild/how-to-use-project-sdk?view=vs-2022#reference-a-project-sdk + /// there are three ways to reference a project SDK: + /// 1. As an attribute on the . + /// 2. As a top level element of . + /// 3. As an attribute on an element. + /// + /// Returns true, if the Sdk attribute is used, otherwise false. + /// + private static bool ReferencesSdk(XmlElement xml) => + HasSdkAttribute(xml) || // Case 1 + AnyElement(xml.ChildNodes, e => e.Name == "Sdk") || // Case 2 + AnyElement(xml.GetElementsByTagName("Import"), HasSdkAttribute); // Case 3 + public Project(Autobuilder builder, string path) : base(builder, path) { ToolsVersion = new Version(); @@ -49,7 +68,7 @@ public Project(Autobuilder builder, string path) : base(build if (root?.Name == "Project") { - if (root.HasAttribute("Sdk")) + if (ReferencesSdk(root)) { DotNetProject = true; return; diff --git a/csharp/ql/lib/change-notes/2025-04-11-auto-builder-sdk.md b/csharp/ql/lib/change-notes/2025-04-11-auto-builder-sdk.md new file mode 100644 index 000000000000..1ab0153786fd --- /dev/null +++ b/csharp/ql/lib/change-notes/2025-04-11-auto-builder-sdk.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Improved autobuilder logic for detecting whether a project references a SDK (and should be built using `dotnet`).