Skip to content

Commit

Permalink
Use Microsoft.CodeAnalysis.CSharp and Microsoft.CodeAnalysis.VisualBa…
Browse files Browse the repository at this point in the history
…sic to parse.
  • Loading branch information
Corniel committed Feb 22, 2024
1 parent c9a0eb3 commit 5a4a681
Show file tree
Hide file tree
Showing 10 changed files with 262 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/Buildalyzer/Buildalyzer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="4.4.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageReference Include="MsBuildPipeLogger.Server" Version="1.1.6" />
<PackageReference Include="Microsoft.Build" Version="17.0.1" />
Expand Down
32 changes: 32 additions & 0 deletions src/Buildalyzer/Compiler/CSharpCompilerCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

namespace Buildalyzer;

public sealed record CSharpCompilerCommand : CompilerCommand
{
public CSharpCompilerCommand(CSharpCommandLineArguments arguments)
{
Arguments = Guard.NotNull(arguments);
PreprocessorSymbolNames = Arguments.ParseOptions.PreprocessorSymbolNames.ToImmutableArray();
}

public CSharpCommandLineArguments Arguments { get; }

public override CompilerLanguage Language => CompilerLanguage.CSharp;

public override ImmutableArray<Diagnostic> Errors => Arguments.Errors;

public override ImmutableArray<CommandLineSourceFile> SourceFiles => Arguments.SourceFiles;

public override ImmutableArray<CommandLineSourceFile> AdditionalFiles => Arguments.AdditionalFiles;

public override ImmutableArray<CommandLineSourceFile> EmbeddedFiles => Arguments.EmbeddedFiles;

public override ImmutableArray<CommandLineAnalyzerReference> AnalyzerReferences => Arguments.AnalyzerReferences;

public override ImmutableArray<string> PreprocessorSymbolNames { get; }

public override ImmutableArray<string> ReferencePaths => Arguments.ReferencePaths;
}
58 changes: 58 additions & 0 deletions src/Buildalyzer/Compiler/Compiler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#nullable enable

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.VisualBasic;

namespace Buildalyzer;

public static class Compiler
{
public static class CommandLine
{
[Pure]
public static string[]? Tokenize(string commandline, CompilerLanguage language)
{
var args = CommandLineParser.SplitCommandLineIntoArguments(commandline, removeHashComments: true).ToArray();

Check warning on line 16 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (windows-latest)

([deprecated] Use RCS1264 instead) Use explicit type instead of 'var' (https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1008)

Check warning on line 16 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

([deprecated] Use RCS1264 instead) Use explicit type instead of 'var' (https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1008)

Check warning on line 16 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

([deprecated] Use RCS1264 instead) Use explicit type instead of 'var' (https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1008)

return language switch
{
CompilerLanguage.CSharp => Split(args, "csc.dll", "csc.exe"),
CompilerLanguage.VisualBasic => Split(args, "vbc.dll", "vbc.exe"),
CompilerLanguage.FSharp => Split(args, "fsc.dll", "fsc.exe"),
_ => throw new NotSupportedException($"The {language} language is not supported."),
};

static string[]? Split(string[] args, params string[] execs)
{
foreach (var exec in execs)

Check warning on line 28 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (windows-latest)

([deprecated] Use RCS1264 instead) Use explicit type instead of 'var' (https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1009)

Check warning on line 28 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

([deprecated] Use RCS1264 instead) Use explicit type instead of 'var' (https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1009)

Check warning on line 28 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

([deprecated] Use RCS1264 instead) Use explicit type instead of 'var' (https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1009)
{
for (var i = 0; i < args.Length - 1; i++)

Check warning on line 30 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (windows-latest)

([deprecated] Use RCS1264 instead) Use explicit type instead of 'var' (https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1008)

Check warning on line 30 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

([deprecated] Use RCS1264 instead) Use explicit type instead of 'var' (https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1008)

Check warning on line 30 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

([deprecated] Use RCS1264 instead) Use explicit type instead of 'var' (https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1008)
{
if (args[i].EndsWith(exec, StringComparison.OrdinalIgnoreCase))
{
return args[(i + 1)..];
}
}
}
return null;
}
}

[Pure]
public static CompilerCommand Parse(string commandline, CompilerLanguage language)
{
var tokens = Tokenize(commandline, language) ?? throw new FormatException("Commandline could not be parsed.");

Check warning on line 45 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (windows-latest)

([deprecated] Use RCS1264 instead) Use explicit type instead of 'var' (https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1008)

Check warning on line 45 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

([deprecated] Use RCS1264 instead) Use explicit type instead of 'var' (https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1008)

Check warning on line 45 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

([deprecated] Use RCS1264 instead) Use explicit type instead of 'var' (https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1008)

Check warning on line 46 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (windows-latest)

Check warning on line 46 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

Check warning on line 46 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

var root = tokens[0];

Check warning on line 47 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (windows-latest)

([deprecated] Use RCS1264 instead) Use explicit type instead of 'var' (https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1008)

Check warning on line 47 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

([deprecated] Use RCS1264 instead) Use explicit type instead of 'var' (https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1008)

Check warning on line 47 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

([deprecated] Use RCS1264 instead) Use explicit type instead of 'var' (https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1008)
var args = tokens[1..];

Check warning on line 48 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (windows-latest)

([deprecated] Use RCS1264 instead) Use explicit type instead of 'var' (https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1008)

Check warning on line 48 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

([deprecated] Use RCS1264 instead) Use explicit type instead of 'var' (https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1008)

Check warning on line 48 in src/Buildalyzer/Compiler/Compiler.cs

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

([deprecated] Use RCS1264 instead) Use explicit type instead of 'var' (https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1008)

return language switch
{
CompilerLanguage.CSharp => new CSharpCompilerCommand(CSharpCommandLineParser.Default.Parse(args, ".", root)),
CompilerLanguage.VisualBasic => new VisualBasicCompilerCommand(VisualBasicCommandLineParser.Default.Parse(args, ".", root)),
_ => throw new NotSupportedException($"The {language} language is not supported."),
};
}
}
}
23 changes: 23 additions & 0 deletions src/Buildalyzer/Compiler/CompilerCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;

namespace Buildalyzer;

public abstract record CompilerCommand
{
public abstract CompilerLanguage Language { get; }

public abstract ImmutableArray<Diagnostic> Errors { get; }

public abstract ImmutableArray<CommandLineSourceFile> SourceFiles { get; }

public abstract ImmutableArray<CommandLineSourceFile> AdditionalFiles { get; }

public abstract ImmutableArray<CommandLineSourceFile> EmbeddedFiles { get; }

public abstract ImmutableArray<CommandLineAnalyzerReference> AnalyzerReferences { get; }

public abstract ImmutableArray<string> PreprocessorSymbolNames { get; }

public abstract ImmutableArray<string> ReferencePaths { get; }
}
17 changes: 17 additions & 0 deletions src/Buildalyzer/Compiler/CompilerLanguage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Buildalyzer;

/// <summary>The compiler language.</summary>
public enum CompilerLanguage
{
/// <summary>None.</summary>
None = 0,

/// <summary>C#.</summary>
CSharp = 1,

/// <summary>VB .NET.</summary>
VisualBasic = 2,

/// <summary>F#.</summary>
FSharp = 3,
}
32 changes: 32 additions & 0 deletions src/Buildalyzer/Compiler/VisualBasicCompilerCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.VisualBasic;

namespace Buildalyzer;

public sealed record VisualBasicCompilerCommand : CompilerCommand
{
public VisualBasicCompilerCommand(VisualBasicCommandLineArguments arguments)
{
Arguments = Guard.NotNull(arguments);
PreprocessorSymbolNames = Arguments.ParseOptions.PreprocessorSymbolNames.ToImmutableArray();
}

public VisualBasicCommandLineArguments Arguments { get; }

public override CompilerLanguage Language => CompilerLanguage.VisualBasic;

public override ImmutableArray<Diagnostic> Errors => Arguments.Errors;

public override ImmutableArray<CommandLineSourceFile> SourceFiles => Arguments.SourceFiles;

public override ImmutableArray<CommandLineSourceFile> AdditionalFiles => Arguments.AdditionalFiles;

public override ImmutableArray<CommandLineSourceFile> EmbeddedFiles => Arguments.EmbeddedFiles;

public override ImmutableArray<CommandLineAnalyzerReference> AnalyzerReferences => Arguments.AnalyzerReferences;

public override ImmutableArray<string> PreprocessorSymbolNames { get; }

public override ImmutableArray<string> ReferencePaths => Arguments.ReferencePaths;
}
42 changes: 42 additions & 0 deletions src/Buildalyzer/Guard.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#nullable enable

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;

namespace Buildalyzer;

/// <summary>Supplies parameter guarding for methods and constructors.</summary>
/// <remarks>
/// Advised usage:
/// * Change the namespace to maximum shared namespace amongst the using projects
/// * Keep it internal and use [assembly: InternalsVisibleTo] to open up access
/// * Add specific Guard methods if you software needs them.
/// * Keep the checks cheap so that you also can run them in production code.
/// </remarks>
[ExcludeFromCodeCoverage]
internal static class Guard
{
/// <summary>Guards the parameter if not null, otherwise throws an argument (null) exception.</summary>
/// <typeparam name="T">The type to guard; cannot be a structure.</typeparam>
/// <param name="parameter">The parameter to guard.</param>
/// <param name="paramName">The name of the parameter.</param>
/// <returns>
/// The guarded parameter.
/// </returns>
[DebuggerStepThrough]
public static T NotNull<T>([ValidatedNotNull] T? parameter, [CallerArgumentExpression(nameof(parameter))] string? paramName = null)
where T : class
=> parameter ?? throw new ArgumentNullException(paramName);

/// <summary>Marks the NotNull argument as being validated for not being null, to satisfy the static code analysis.</summary>
/// <remarks>
/// Notice that it does not matter what this attribute does, as long as
/// it is named ValidatedNotNullAttribute.
///
/// It is marked as conditional, as does not add anything to have the attribute compiled.
/// </remarks>
[Conditional("Analysis")]
[AttributeUsage(AttributeTargets.Parameter)]
private sealed class ValidatedNotNullAttribute : Attribute { }

Check warning on line 41 in src/Buildalyzer/Guard.cs

View workflow job for this annotation

GitHub Actions / Build (windows-latest)

Check warning on line 41 in src/Buildalyzer/Guard.cs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

Check warning on line 41 in src/Buildalyzer/Guard.cs

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

}
5 changes: 5 additions & 0 deletions src/Buildalyzer/Properties/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
global using System;
global using System.Collections.Generic;
global using System.Linq;
global using System.Text;
global using System.Diagnostics.Contracts;
47 changes: 47 additions & 0 deletions tests/Buildalyzer.Tests/Compiler/CompilerCommandFixture.cs

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions tests/Buildalyzer.Tests/Properties/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
global using System;
global using System.Collections.Generic;
global using System.Linq;
global using NUnit.Framework;

0 comments on commit 5a4a681

Please sign in to comment.