Skip to content

Commit 9fb9f56

Browse files
committed
Initial demonstration version
1 parent 97651a2 commit 9fb9f56

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1236
-8
lines changed

MSBuild.sln

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StringTools.Benchmark", "sr
7878
EndProject
7979
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSBuild.VSSetup.Arm64", "src\Package\MSBuild.VSSetup.Arm64\MSBuild.VSSetup.Arm64.csproj", "{71E59632-D644-491B-AF93-22BC93167C56}"
8080
EndProject
81+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Build.Analyzers", "src\Analyzers\Microsoft.Build.Analyzers.csproj", "{512E01F7-2899-433B-93E2-D63B43AF0420}"
82+
EndProject
8183
Global
8284
GlobalSection(SolutionConfigurationPlatforms) = preSolution
8385
Debug|Any CPU = Debug|Any CPU
@@ -1342,6 +1344,46 @@ Global
13421344
{71E59632-D644-491B-AF93-22BC93167C56}.Release-MONO|x64.Build.0 = Release-MONO|x64
13431345
{71E59632-D644-491B-AF93-22BC93167C56}.Release-MONO|x86.ActiveCfg = Release-MONO|Any CPU
13441346
{71E59632-D644-491B-AF93-22BC93167C56}.Release-MONO|x86.Build.0 = Release-MONO|Any CPU
1347+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1348+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Debug|Any CPU.Build.0 = Debug|Any CPU
1349+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Debug|ARM64.ActiveCfg = Debug|arm64
1350+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Debug|ARM64.Build.0 = Debug|arm64
1351+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Debug|x64.ActiveCfg = Debug|x64
1352+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Debug|x64.Build.0 = Debug|x64
1353+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Debug|x86.ActiveCfg = Debug|Any CPU
1354+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Debug|x86.Build.0 = Debug|Any CPU
1355+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Debug-MONO|Any CPU.ActiveCfg = Debug-MONO|Any CPU
1356+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Debug-MONO|Any CPU.Build.0 = Debug-MONO|Any CPU
1357+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Debug-MONO|ARM64.ActiveCfg = Debug-MONO|arm64
1358+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Debug-MONO|ARM64.Build.0 = Debug-MONO|arm64
1359+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Debug-MONO|x64.ActiveCfg = Debug-MONO|x64
1360+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Debug-MONO|x64.Build.0 = Debug-MONO|x64
1361+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Debug-MONO|x86.ActiveCfg = Debug-MONO|Any CPU
1362+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Debug-MONO|x86.Build.0 = Debug-MONO|Any CPU
1363+
{512E01F7-2899-433B-93E2-D63B43AF0420}.MachineIndependent|Any CPU.ActiveCfg = MachineIndependent|Any CPU
1364+
{512E01F7-2899-433B-93E2-D63B43AF0420}.MachineIndependent|Any CPU.Build.0 = MachineIndependent|Any CPU
1365+
{512E01F7-2899-433B-93E2-D63B43AF0420}.MachineIndependent|ARM64.ActiveCfg = MachineIndependent|arm64
1366+
{512E01F7-2899-433B-93E2-D63B43AF0420}.MachineIndependent|ARM64.Build.0 = MachineIndependent|arm64
1367+
{512E01F7-2899-433B-93E2-D63B43AF0420}.MachineIndependent|x64.ActiveCfg = MachineIndependent|x64
1368+
{512E01F7-2899-433B-93E2-D63B43AF0420}.MachineIndependent|x64.Build.0 = MachineIndependent|x64
1369+
{512E01F7-2899-433B-93E2-D63B43AF0420}.MachineIndependent|x86.ActiveCfg = MachineIndependent|Any CPU
1370+
{512E01F7-2899-433B-93E2-D63B43AF0420}.MachineIndependent|x86.Build.0 = MachineIndependent|Any CPU
1371+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Release|Any CPU.ActiveCfg = Release|Any CPU
1372+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Release|Any CPU.Build.0 = Release|Any CPU
1373+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Release|ARM64.ActiveCfg = Release|arm64
1374+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Release|ARM64.Build.0 = Release|arm64
1375+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Release|x64.ActiveCfg = Release|x64
1376+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Release|x64.Build.0 = Release|x64
1377+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Release|x86.ActiveCfg = Release|Any CPU
1378+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Release|x86.Build.0 = Release|Any CPU
1379+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Release-MONO|Any CPU.ActiveCfg = Release-MONO|Any CPU
1380+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Release-MONO|Any CPU.Build.0 = Release-MONO|Any CPU
1381+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Release-MONO|ARM64.ActiveCfg = Release-MONO|arm64
1382+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Release-MONO|ARM64.Build.0 = Release-MONO|arm64
1383+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Release-MONO|x64.ActiveCfg = Release-MONO|x64
1384+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Release-MONO|x64.Build.0 = Release-MONO|x64
1385+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Release-MONO|x86.ActiveCfg = Release-MONO|Any CPU
1386+
{512E01F7-2899-433B-93E2-D63B43AF0420}.Release-MONO|x86.Build.0 = Release-MONO|Any CPU
13451387
EndGlobalSection
13461388
GlobalSection(SolutionProperties) = preSolution
13471389
HideSolutionNode = FALSE
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
using Microsoft.Build.Analyzers.Infrastructure;
10+
using Microsoft.Build.BackEnd.Logging;
11+
using Microsoft.Build.Experimental;
12+
using Microsoft.Build.Framework;
13+
14+
namespace Microsoft.Build.Experimental;
15+
16+
public class BuildAnalysisContext
17+
{
18+
private protected readonly LoggingContext _loggingContext;
19+
20+
internal BuildAnalysisContext(LoggingContext loggingContext) => _loggingContext = loggingContext;
21+
22+
public void ReportResult(BuildAnalysisResult result)
23+
{
24+
BuildEventArgs eventArgs = result.ToEventArgs(ConfigurationProvider.GetMergedConfiguration(result.BuildAnalysisRule).Severity);
25+
eventArgs.BuildEventContext = _loggingContext.BuildEventContext;
26+
_loggingContext.LogBuildEvent(eventArgs);
27+
}
28+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
using Microsoft.Build.Analyzers.Infrastructure;
10+
using Microsoft.Build.Framework;
11+
12+
namespace Microsoft.Build.Experimental;
13+
14+
public class BuildAnalysisLoggerFactory : IBuildAnalysisLoggerFactory
15+
{
16+
public ILogger CreateBuildAnalysisLogger(IBuildAnalysisLoggingContextFactory loggingContextFactory)
17+
{
18+
return new AnalyzersConnectorLogger(loggingContextFactory, BuildAnalysisManager.Instance);
19+
}
20+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.IO;
6+
using Microsoft.Build.Construction;
7+
using Microsoft.Build.Framework;
8+
9+
namespace Microsoft.Build.Experimental;
10+
11+
public class BuildAnalysisResult
12+
{
13+
public static BuildAnalysisResult Create(BuildAnalysisRule rule, ElementLocation location, params string[] messageArgs)
14+
{
15+
return new BuildAnalysisResult(rule, location, messageArgs);
16+
}
17+
18+
public BuildAnalysisResult(BuildAnalysisRule buildAnalysisRule, ElementLocation location, string[] messageArgs)
19+
{
20+
BuildAnalysisRule = buildAnalysisRule;
21+
Location = location;
22+
MessageArgs = messageArgs;
23+
}
24+
25+
internal BuildEventArgs ToEventArgs(BuildAnalysisResultSeverity severity)
26+
=> severity switch
27+
{
28+
BuildAnalysisResultSeverity.Info => new BuildAnalysisResultMessage(this),
29+
BuildAnalysisResultSeverity.Warning => new BuildAnalysisResultWarning(this),
30+
BuildAnalysisResultSeverity.Error => new BuildAnalysisResultError(this),
31+
_ => throw new ArgumentOutOfRangeException(nameof(severity), severity, null),
32+
};
33+
34+
public BuildAnalysisRule BuildAnalysisRule { get; }
35+
public ElementLocation Location { get; }
36+
public string[] MessageArgs { get; }
37+
38+
private string? _message;
39+
public string Message => _message ??= $"{(Equals(Location ?? ElementLocation.EmptyLocation, ElementLocation.EmptyLocation) ? string.Empty : (Location!.LocationString + ": "))}{BuildAnalysisRule.Id}: {string.Format(BuildAnalysisRule.MessageFormat, MessageArgs)}";
40+
}
41+
42+
public sealed class BuildAnalysisResultWarning : BuildWarningEventArgs
43+
{
44+
public BuildAnalysisResultWarning(BuildAnalysisResult result)
45+
{
46+
this.Message = result.Message;
47+
}
48+
49+
50+
internal override void WriteToStream(BinaryWriter writer)
51+
{
52+
base.WriteToStream(writer);
53+
54+
writer.Write(Message!);
55+
}
56+
57+
internal override void CreateFromStream(BinaryReader reader, int version)
58+
{
59+
base.CreateFromStream(reader, version);
60+
61+
Message = reader.ReadString();
62+
}
63+
64+
public override string? Message { get; protected set; }
65+
}
66+
67+
public sealed class BuildAnalysisResultError : BuildErrorEventArgs
68+
{
69+
public BuildAnalysisResultError(BuildAnalysisResult result)
70+
{
71+
this.Message = result.Message;
72+
}
73+
74+
75+
internal override void WriteToStream(BinaryWriter writer)
76+
{
77+
base.WriteToStream(writer);
78+
79+
writer.Write(Message!);
80+
}
81+
82+
internal override void CreateFromStream(BinaryReader reader, int version)
83+
{
84+
base.CreateFromStream(reader, version);
85+
86+
Message = reader.ReadString();
87+
}
88+
89+
public override string? Message { get; protected set; }
90+
}
91+
92+
public sealed class BuildAnalysisResultMessage : BuildMessageEventArgs
93+
{
94+
public BuildAnalysisResultMessage(BuildAnalysisResult result)
95+
{
96+
this.Message = result.Message;
97+
}
98+
99+
100+
internal override void WriteToStream(BinaryWriter writer)
101+
{
102+
base.WriteToStream(writer);
103+
104+
writer.Write(Message!);
105+
}
106+
107+
internal override void CreateFromStream(BinaryReader reader, int version)
108+
{
109+
base.CreateFromStream(reader, version);
110+
111+
Message = reader.ReadString();
112+
}
113+
114+
public override string? Message { get; protected set; }
115+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.Build.Experimental;
5+
6+
public enum BuildAnalysisResultSeverity
7+
{
8+
Info,
9+
Warning,
10+
Error,
11+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.Build.Experimental;
5+
6+
public class BuildAnalysisRule
7+
{
8+
public BuildAnalysisRule(string id, string title, string description, string category, string messageFormat,
9+
BuildAnalyzerConfiguration defaultConfiguration)
10+
{
11+
Id = id;
12+
Title = title;
13+
Description = description;
14+
Category = category;
15+
MessageFormat = messageFormat;
16+
DefaultConfiguration = defaultConfiguration;
17+
}
18+
19+
public string Id { get; }
20+
public string Title { get; }
21+
public string Description { get; }
22+
23+
// or maybe enum? eval, syntax, etc
24+
public string Category { get; }
25+
public string MessageFormat { get; }
26+
public BuildAnalyzerConfiguration DefaultConfiguration { get; }
27+
}

src/Analyzers/API/BuildAnalyzer.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Collections.Immutable;
5+
6+
namespace Microsoft.Build.Experimental;
7+
8+
public abstract class BuildAnalyzer
9+
{
10+
public abstract string FriendlyName { get; }
11+
public abstract ImmutableArray<BuildAnalysisRule> SupportedRules { get; }
12+
public abstract void Initialize(ConfigurationContext configurationContext);
13+
14+
public abstract void RegisterActions(IBuildAnalyzerContext context);
15+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.Build.Experimental;
5+
6+
public class BuildAnalyzerConfiguration
7+
{
8+
public static BuildAnalyzerConfiguration Default { get; } = new()
9+
{
10+
LifeTimeScope = Experimental.LifeTimeScope.PerProject,
11+
SupportedInvocationConcurrency = InvocationConcurrency.Parallel,
12+
PerformanceWeightClass = Experimental.PerformanceWeightClass.Normal,
13+
EvaluationAnalysisScope = Experimental.EvaluationAnalysisScope.AnalyzedProjectOnly,
14+
Severity = BuildAnalysisResultSeverity.Info,
15+
IsEnabled = false,
16+
};
17+
18+
public static BuildAnalyzerConfiguration Null { get; } = new();
19+
20+
public LifeTimeScope? LifeTimeScope { get; internal init; }
21+
public InvocationConcurrency? SupportedInvocationConcurrency { get; internal init; }
22+
public PerformanceWeightClass? PerformanceWeightClass { get; internal init; }
23+
public EvaluationAnalysisScope? EvaluationAnalysisScope { get; internal init; }
24+
public BuildAnalysisResultSeverity? Severity { get; internal init; }
25+
public bool? IsEnabled { get; internal init; }
26+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Collections.Generic;
5+
6+
namespace Microsoft.Build.Experimental;
7+
8+
/// <summary>
9+
/// Holder of an optional configuration from .editorconfig file (not recognized by infrastructure)
10+
/// </summary>
11+
public class ConfigurationContext
12+
{
13+
public static ConfigurationContext Null { get; } = new();
14+
15+
public IReadOnlyDictionary<string, string>? ConfigurationData { get; init; }
16+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.Build.Experimental;
5+
6+
public enum EvaluationAnalysisScope
7+
{
8+
AnalyzedProjectOnly,
9+
AnalyzedProjectWithImportsFromCurrentWorkTree,
10+
AnalyzedProjectWithImportsWithoutSdks,
11+
AnalyzedProjectWithAllImports,
12+
}

0 commit comments

Comments
 (0)