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`).