diff --git a/MSBuildLocator.sln b/MSBuildLocator.sln
index 4540e62d..e20b3d07 100644
--- a/MSBuildLocator.sln
+++ b/MSBuildLocator.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.26730.10
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30807.9
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Build.Locator", "src\MSBuildLocator\Microsoft.Build.Locator.csproj", "{2F4700C6-A6F6-49DF-ABF1-6213AAC4BCFD}"
EndProject
@@ -9,6 +9,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Build.Locator.Tes
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BuilderApp", "samples\BuilderApp\BuilderApp.csproj", "{70F35A21-43E2-47CB-8B96-B160C6758EAA}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSBuildLocatorAnalyzer", "src\MSBuildLocatorAnalyzer\MSBuildLocatorAnalyzer.csproj", "{BFF38CC3-651E-4BCF-BD06-792DE348EA2C}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSBuildLocatorAnalyzer.CodeFixes", "src\MSBuildLocatorAnalyzer.CodeFixes\MSBuildLocatorAnalyzer.CodeFixes.csproj", "{78A91E45-74F2-438A-8B4B-8DEDE153E1E5}"
+EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{872EA464-8296-4ECA-932F-FC33841252EF}"
ProjectSection(SolutionItems) = preProject
Directory.Build.props = Directory.Build.props
@@ -33,6 +37,14 @@ Global
{70F35A21-43E2-47CB-8B96-B160C6758EAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{70F35A21-43E2-47CB-8B96-B160C6758EAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{70F35A21-43E2-47CB-8B96-B160C6758EAA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BFF38CC3-651E-4BCF-BD06-792DE348EA2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BFF38CC3-651E-4BCF-BD06-792DE348EA2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BFF38CC3-651E-4BCF-BD06-792DE348EA2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BFF38CC3-651E-4BCF-BD06-792DE348EA2C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {78A91E45-74F2-438A-8B4B-8DEDE153E1E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {78A91E45-74F2-438A-8B4B-8DEDE153E1E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {78A91E45-74F2-438A-8B4B-8DEDE153E1E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {78A91E45-74F2-438A-8B4B-8DEDE153E1E5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/samples/BuilderApp/Program.cs b/samples/BuilderApp/Program.cs
index 0ec2f0bc..8caac6f0 100644
--- a/samples/BuilderApp/Program.cs
+++ b/samples/BuilderApp/Program.cs
@@ -42,8 +42,18 @@ private static void Main(string[] args)
MSBuildLocator.RegisterMSBuildPath(msbuildDeploymentToUse.MSBuildPath);
}
+ var assembly = typeof(Project).Assembly;
+ FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
+
+ Console.WriteLine();
+ Console.WriteLine($"BuildApp running using MSBuild version {fvi.FileVersion}");
+ Console.WriteLine(Path.GetDirectoryName(assembly.Location));
+ Console.WriteLine();
- var result = new Builder().Build(projectFilePath);
+ var pre = ProjectRootElement.Open(projectFilePath);
+ var project = new Project(pre);
+ var result = project.Build(new Builder.Logger());
+ //var result = new Builder().Build(projectFilePath);
Console.WriteLine();
Console.ForegroundColor = result ? ConsoleColor.Green : ConsoleColor.Red;
@@ -154,7 +164,7 @@ public bool Build(string projectFile)
return project.Build(new Logger());
}
- private class Logger : ILogger
+ public class Logger : ILogger
{
public void Initialize(IEventSource eventSource)
{
diff --git a/src/MSBuildLocatorAnalyzer.CodeFixes/CodeFixResources.Designer.cs b/src/MSBuildLocatorAnalyzer.CodeFixes/CodeFixResources.Designer.cs
new file mode 100644
index 00000000..749477d4
--- /dev/null
+++ b/src/MSBuildLocatorAnalyzer.CodeFixes/CodeFixResources.Designer.cs
@@ -0,0 +1,72 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace MSBuildLocatorAnalyzer {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class CodeFixResources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal CodeFixResources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MSBuildLocatorAnalyzer.CodeFixResources", typeof(CodeFixResources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Make uppercase.
+ ///
+ internal static string CodeFixTitle {
+ get {
+ return ResourceManager.GetString("CodeFixTitle", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/src/MSBuildLocatorAnalyzer.CodeFixes/CodeFixResources.resx b/src/MSBuildLocatorAnalyzer.CodeFixes/CodeFixResources.resx
new file mode 100644
index 00000000..97abe689
--- /dev/null
+++ b/src/MSBuildLocatorAnalyzer.CodeFixes/CodeFixResources.resx
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Make uppercase
+ The title of the code fix.
+
+
\ No newline at end of file
diff --git a/src/MSBuildLocatorAnalyzer.CodeFixes/MSBuildLocatorAnalyzer.CodeFixes.csproj b/src/MSBuildLocatorAnalyzer.CodeFixes/MSBuildLocatorAnalyzer.CodeFixes.csproj
new file mode 100644
index 00000000..559d53de
--- /dev/null
+++ b/src/MSBuildLocatorAnalyzer.CodeFixes/MSBuildLocatorAnalyzer.CodeFixes.csproj
@@ -0,0 +1,37 @@
+
+
+
+ net48;netcoreapp3.1
+ true
+ MSBuildLocatorAnalyzer
+ false
+ True
+
+
+
+ Microsoft.Build.Locator.Analyzer.CodeFixes
+ 1.0.0
+ Microsoft
+ https://github.com/microsoft/MSBuildLocator
+ false
+ A code fix for the MSBuildLocator analyzer.
+ Code fix for the analyzer.
+ Copyright
+ MSBuild, MSBuildLocator, Microsoft Build, code fix, analyzers
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/MSBuildLocatorAnalyzer.CodeFixes/MSBuildLocatorAnalyzerCodeFixProvider.cs b/src/MSBuildLocatorAnalyzer.CodeFixes/MSBuildLocatorAnalyzerCodeFixProvider.cs
new file mode 100644
index 00000000..60ba7cfc
--- /dev/null
+++ b/src/MSBuildLocatorAnalyzer.CodeFixes/MSBuildLocatorAnalyzerCodeFixProvider.cs
@@ -0,0 +1,62 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Formatting;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Composition;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace MSBuildLocatorAnalyzer
+{
+ [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(MSBuildLocatorAnalyzerCodeFixProvider)), Shared]
+ public class MSBuildLocatorAnalyzerCodeFixProvider : CodeFixProvider
+ {
+ private const string title = "Move MSBuild use to separate method";
+
+ public sealed override ImmutableArray FixableDiagnosticIds
+ {
+ get { return ImmutableArray.Create(MSBuildLocatorAnalyzerAnalyzer.DiagnosticId); }
+ }
+
+ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+ var diagnostic = context.Diagnostics.First();
+
+ // Register a code action that will invoke the fix.
+ context.RegisterCodeFix(
+ CodeAction.Create(
+ title: title,
+ createChangedDocument: c => MoveMSBuildUseToSeparateMethod(context.Document, diagnostic, root),
+ equivalenceKey: title),
+ diagnostic);
+ }
+
+ Task MoveMSBuildUseToSeparateMethod(Document document, Diagnostic diagnostic, SyntaxNode root)
+ {
+ StatementSyntax statement = root.FindNode(diagnostic.Location.SourceSpan).FirstAncestorOrSelf();
+ SyntaxNode method;
+ for (method = root.FindNode(diagnostic.Location.SourceSpan); !(method is MethodDeclarationSyntax); method = method.Parent);
+ SyntaxTokenList modifiers = (method as MethodDeclarationSyntax).Modifiers.Any(mod => mod.ValueText.Equals("static")) ?
+ SyntaxFactory.TokenList(SyntaxFactory.Identifier("private"), SyntaxFactory.Identifier("static")) :
+ SyntaxFactory.TokenList(SyntaxFactory.Identifier("private"));
+ MethodDeclarationSyntax toInsert = SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("void"), "UseMSBuild")
+ .WithModifiers(modifiers)
+ .WithBody(SyntaxFactory.Block(statement))
+ .WithAdditionalAnnotations(Formatter.Annotation);
+ var newRoot = root.InsertNodesAfter(method, new List() { toInsert });
+
+ statement = newRoot.FindNode(diagnostic.Location.SourceSpan).FirstAncestorOrSelf();
+ ExpressionStatementSyntax expression = SyntaxFactory.ExpressionStatement(SyntaxFactory.InvocationExpression(SyntaxFactory.IdentifierName(toInsert.Identifier.ValueText))
+ .WithArgumentList(SyntaxFactory.ArgumentList()
+ .WithOpenParenToken(SyntaxFactory.Token(SyntaxKind.OpenParenToken))
+ .WithCloseParenToken(SyntaxFactory.Token(SyntaxKind.CloseParenToken))));
+ newRoot = newRoot.ReplaceNode(statement, expression);
+ return Task.FromResult(document.WithSyntaxRoot(newRoot));
+ }
+ }
+}
diff --git a/src/MSBuildLocatorAnalyzer/MSBuildLocatorAnalyzer.csproj b/src/MSBuildLocatorAnalyzer/MSBuildLocatorAnalyzer.csproj
new file mode 100644
index 00000000..536dcc53
--- /dev/null
+++ b/src/MSBuildLocatorAnalyzer/MSBuildLocatorAnalyzer.csproj
@@ -0,0 +1,31 @@
+
+
+
+ net48;netcoreapp3.1
+ true
+ false
+ True
+
+
+ Microsoft.Build.Locator.Analyzer
+ 1.0.0
+ Microsoft
+ https://github.com/microsoft/MSBuildLocator
+ false
+ Analyzers for MSBuildLocator
+ An analyzer that identifies the common problem in MSBuildLocator of registering MSBuild in the same method that uses it.
+ Copyright
+ MSBuildLocator, Build, MSBuild, Analyzers
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/MSBuildLocatorAnalyzer/MSBuildLocatorAnalyzerAnalyzer.cs b/src/MSBuildLocatorAnalyzer/MSBuildLocatorAnalyzerAnalyzer.cs
new file mode 100644
index 00000000..539b2bb8
--- /dev/null
+++ b/src/MSBuildLocatorAnalyzer/MSBuildLocatorAnalyzerAnalyzer.cs
@@ -0,0 +1,75 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Operations;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+
+namespace MSBuildLocatorAnalyzer
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class MSBuildLocatorAnalyzerAnalyzer : DiagnosticAnalyzer
+ {
+ public const string DiagnosticId = "MSBuildLocatorAnalyzer";
+
+ // You can change these strings in the Resources.resx file. If you do not want your analyzer to be localize-able, you can use regular strings for Title and MessageFormat.
+ // See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/Localizing%20Analyzers.md for more on localization
+ private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.AnalyzerTitle), Resources.ResourceManager, typeof(Resources));
+ private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.AnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources));
+ private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.AnalyzerDescription), Resources.ResourceManager, typeof(Resources));
+ private const string Category = "Naming";
+
+ private readonly string[] msBuildAssemblies =
+ {
+ "Microsoft.Build",
+ "Microsoft.Build.Engine",
+ "Microsoft.Build.Framework",
+ "Microsoft.Build.Tasks.Core",
+ "Microsoft.Build.Utilities.Core"
+ };
+
+ private readonly string[] msbuildLocatorRegisterMethods =
+ {
+ "RegisterDefaults",
+ "RegisterInstance",
+ "RegisterMSBuildPath"
+ };
+
+ private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description);
+
+ public override ImmutableArray SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.RegisterOperationAction(opact =>
+ {
+ var invocation = (IInvocationOperation)opact.Operation;
+ var targetMethod = invocation.TargetMethod;
+ if (targetMethod?.ContainingAssembly != null)
+ {
+ if (targetMethod.ContainingAssembly.Name.Equals("Microsoft.Build.Locator") && msbuildLocatorRegisterMethods.Contains(targetMethod.Name))
+ {
+ MethodDeclarationSyntax method = (MethodDeclarationSyntax)invocation.Syntax.FirstAncestorOrSelf((Func)(a => a is MethodDeclarationSyntax));
+ if (method != null)
+ {
+ IOperation symbolParent;
+ for (symbolParent = invocation; symbolParent.Parent != null && symbolParent.Kind != OperationKind.MethodBody; symbolParent = symbolParent.Parent);
+ foreach (var child in symbolParent.Descendants())
+ {
+ if ((child is IInvocationOperation op && msBuildAssemblies.Contains(op.TargetMethod?.ContainingAssembly?.Name)) ||
+ (child is ITypeOfOperation toOp && msBuildAssemblies.Contains(toOp.TypeOperand.ContainingAssembly?.Name)) ||
+ (msBuildAssemblies.Contains(child.Type?.ContainingAssembly?.Name)))
+ {
+ opact.ReportDiagnostic(Diagnostic.Create(Rule, child.Syntax.GetLocation()));
+ }
+ }
+ }
+ }
+ }
+ }, OperationKind.Invocation);
+ }
+ }
+}
diff --git a/src/MSBuildLocatorAnalyzer/NuGet.config b/src/MSBuildLocatorAnalyzer/NuGet.config
new file mode 100644
index 00000000..cba8a3e3
--- /dev/null
+++ b/src/MSBuildLocatorAnalyzer/NuGet.config
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/MSBuildLocatorAnalyzer/Resources.Designer.cs b/src/MSBuildLocatorAnalyzer/Resources.Designer.cs
new file mode 100644
index 00000000..2443d5ad
--- /dev/null
+++ b/src/MSBuildLocatorAnalyzer/Resources.Designer.cs
@@ -0,0 +1,90 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace MSBuildLocatorAnalyzer {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MSBuildLocatorAnalyzer.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to References to MSBuild types and methods should be in a separate method from the call to MSBuildLocator.RegisterMSBuildPath, MSBuildLocator.RegisterInstance, or MSBuildLocator.RegisterDefaults..
+ ///
+ internal static string AnalyzerDescription {
+ get {
+ return ResourceManager.GetString("AnalyzerDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Use of MSBuild type or method is in the same method as call to register MSBuild..
+ ///
+ internal static string AnalyzerMessageFormat {
+ get {
+ return ResourceManager.GetString("AnalyzerMessageFormat", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to MSBuild type or method used before being registered..
+ ///
+ internal static string AnalyzerTitle {
+ get {
+ return ResourceManager.GetString("AnalyzerTitle", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/src/MSBuildLocatorAnalyzer/Resources.resx b/src/MSBuildLocatorAnalyzer/Resources.resx
new file mode 100644
index 00000000..6714893e
--- /dev/null
+++ b/src/MSBuildLocatorAnalyzer/Resources.resx
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ References to MSBuild types and methods should be in a separate method from the call to MSBuildLocator.RegisterMSBuildPath, MSBuildLocator.RegisterInstance, or MSBuildLocator.RegisterDefaults.
+ An optional longer localizable description of the diagnostic.
+
+
+ Use of MSBuild type or method is in the same method as call to register MSBuild.
+ The format-able message the diagnostic displays.
+
+
+ MSBuild type or method used before being registered.
+ The title of the diagnostic.
+
+
\ No newline at end of file