Skip to content

Commit 53c4b29

Browse files
authored
Merge pull request #19289 from michaelnebel/csharp/improveautobuilder
C#: Improve auto-builder to better detect SDK references.
2 parents c245459 + f349048 commit 53c4b29

File tree

3 files changed

+93
-11
lines changed

3 files changed

+93
-11
lines changed

csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -424,8 +424,7 @@ private CSharpAutobuilder CreateAutoBuilder(bool isWindows,
424424
return new CSharpAutobuilder(actions, options);
425425
}
426426

427-
[Fact]
428-
public void TestDefaultCSharpAutoBuilder()
427+
private void SetupActionForDotnet()
429428
{
430429
actions.RunProcess["cmd.exe /C dotnet --info"] = 0;
431430
actions.RunProcess[@"cmd.exe /C dotnet clean C:\Project\test.csproj"] = 0;
@@ -438,20 +437,80 @@ public void TestDefaultCSharpAutoBuilder()
438437
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SCRATCH_DIR"] = "scratch";
439438
actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbar.cs\ntest.csproj";
440439
actions.EnumerateDirectories[@"C:\Project"] = "";
441-
var xml = new XmlDocument();
442-
xml.LoadXml(@"<Project Sdk=""Microsoft.NET.Sdk"">
443-
<PropertyGroup>
444-
<OutputType>Exe</OutputType>
445-
<TargetFramework>netcoreapp2.1</TargetFramework>
446-
</PropertyGroup>
440+
}
447441

448-
</Project>");
442+
private void CreateAndVerifyDotnetScript(XmlDocument xml)
443+
{
449444
actions.LoadXml[@"C:\Project\test.csproj"] = xml;
450445

451446
var autobuilder = CreateAutoBuilder(true);
452447
TestAutobuilderScript(autobuilder, 0, 4);
453448
}
454449

450+
[Fact]
451+
public void TestDefaultCSharpAutoBuilder1()
452+
{
453+
SetupActionForDotnet();
454+
var xml = new XmlDocument();
455+
xml.LoadXml(
456+
"""
457+
<Project Sdk="Microsoft.NET.Sdk">
458+
<PropertyGroup>
459+
<OutputType>Exe</OutputType>
460+
<TargetFramework>netcoreapp2.1</TargetFramework>
461+
</PropertyGroup>
462+
</Project>
463+
""");
464+
CreateAndVerifyDotnetScript(xml);
465+
}
466+
467+
[Fact]
468+
public void TestDefaultCSharpAutoBuilder2()
469+
{
470+
SetupActionForDotnet();
471+
var xml = new XmlDocument();
472+
473+
xml.LoadXml(
474+
"""
475+
<Project>
476+
<Sdk Name="Microsoft.NET.Sdk" />
477+
478+
<PropertyGroup>
479+
<OutputType>Exe</OutputType>
480+
<TargetFramework>net9.0</TargetFramework>
481+
<ImplicitUsings>enable</ImplicitUsings>
482+
<Nullable>enable</Nullable>
483+
</PropertyGroup>
484+
</Project>
485+
"""
486+
);
487+
CreateAndVerifyDotnetScript(xml);
488+
}
489+
490+
[Fact]
491+
public void TestDefaultCSharpAutoBuilder3()
492+
{
493+
SetupActionForDotnet();
494+
var xml = new XmlDocument();
495+
496+
xml.LoadXml(
497+
"""
498+
<Project>
499+
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
500+
501+
<PropertyGroup>
502+
<OutputType>Exe</OutputType>
503+
<TargetFramework>net9.0</TargetFramework>
504+
<ImplicitUsings>enable</ImplicitUsings>
505+
<Nullable>enable</Nullable>
506+
</PropertyGroup>
507+
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
508+
</Project>
509+
"""
510+
);
511+
CreateAndVerifyDotnetScript(xml);
512+
}
513+
455514
[Fact]
456515
public void TestLinuxCSharpAutoBuilder()
457516
{

csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using System.IO;
44
using System.Linq;
55
using System.Xml;
6-
using Semmle.Util.Logging;
76

87
namespace Semmle.Autobuild.Shared
98
{
@@ -26,6 +25,26 @@ public class Project<TAutobuildOptions> : ProjectOrSolution<TAutobuildOptions> w
2625
private readonly Lazy<List<Project<TAutobuildOptions>>> includedProjectsLazy;
2726
public override IEnumerable<IProjectOrSolution> IncludedProjects => includedProjectsLazy.Value;
2827

28+
private static bool HasSdkAttribute(XmlElement xml) =>
29+
xml.HasAttribute("Sdk");
30+
31+
private static bool AnyElement(XmlNodeList l, Func<XmlElement, bool> f) =>
32+
l.OfType<XmlElement>().Any(f);
33+
34+
/// <summary>
35+
/// According to https://learn.microsoft.com/en-us/visualstudio/msbuild/how-to-use-project-sdk?view=vs-2022#reference-a-project-sdk
36+
/// there are three ways to reference a project SDK:
37+
/// 1. As an attribute on the <Project/>.
38+
/// 2. As a top level element of <Project>.
39+
/// 3. As an attribute on an <Import> element.
40+
///
41+
/// Returns true, if the Sdk attribute is used, otherwise false.
42+
/// </summary>
43+
private static bool ReferencesSdk(XmlElement xml) =>
44+
HasSdkAttribute(xml) || // Case 1
45+
AnyElement(xml.ChildNodes, e => e.Name == "Sdk") || // Case 2
46+
AnyElement(xml.GetElementsByTagName("Import"), HasSdkAttribute); // Case 3
47+
2948
public Project(Autobuilder<TAutobuildOptions> builder, string path) : base(builder, path)
3049
{
3150
ToolsVersion = new Version();
@@ -49,7 +68,7 @@ public Project(Autobuilder<TAutobuildOptions> builder, string path) : base(build
4968

5069
if (root?.Name == "Project")
5170
{
52-
if (root.HasAttribute("Sdk"))
71+
if (ReferencesSdk(root))
5372
{
5473
DotNetProject = true;
5574
return;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Improved autobuilder logic for detecting whether a project references a SDK (and should be built using `dotnet`).

0 commit comments

Comments
 (0)