mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge pull request #3150 from calumgrant/cs/enable-nullability
C#: Enable nullability for Autobuilder and Utils projects
This commit is contained in:
@@ -341,6 +341,8 @@ namespace Semmle.Extraction.Tests
|
||||
string cwd = @"C:\Project")
|
||||
{
|
||||
Actions.GetEnvironmentVariable["CODEQL_AUTOBUILDER_CSHARP_NO_INDEXING"] = "false";
|
||||
Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = "";
|
||||
Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = "";
|
||||
Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_ROOT"] = @"C:\codeql\csharp";
|
||||
Actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java";
|
||||
Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa";
|
||||
@@ -364,8 +366,7 @@ namespace Semmle.Extraction.Tests
|
||||
Actions.GetCurrentDirectory = cwd;
|
||||
Actions.IsWindows = isWindows;
|
||||
|
||||
var options = new AutobuildOptions();
|
||||
options.ReadEnvironment(Actions);
|
||||
var options = new AutobuildOptions(Actions);
|
||||
return new Autobuilder(Actions, options);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,10 +7,9 @@
|
||||
{
|
||||
public BuildScript Analyse(Autobuilder builder, bool auto)
|
||||
{
|
||||
(var javaHome, var dist) =
|
||||
builder.CodeQLJavaHome != null ?
|
||||
(builder.CodeQLJavaHome, builder.CodeQLExtractorCSharpRoot) :
|
||||
(builder.SemmleJavaHome, builder.SemmleDist);
|
||||
var javaHome = builder.JavaHome;
|
||||
var dist = builder.Distribution;
|
||||
|
||||
var command = new CommandBuilder(builder.Actions).
|
||||
RunCommand(builder.Actions.PathCombine(javaHome, "bin", "java")).
|
||||
Argument("-jar").
|
||||
|
||||
@@ -10,40 +10,40 @@ namespace Semmle.Autobuild
|
||||
public class AutobuildOptions
|
||||
{
|
||||
public readonly int SearchDepth = 3;
|
||||
public string RootDirectory = null;
|
||||
static readonly string prefix = "LGTM_INDEX_";
|
||||
public readonly string RootDirectory;
|
||||
private const string prefix = "LGTM_INDEX_";
|
||||
|
||||
public string VsToolsVersion;
|
||||
public string MsBuildArguments;
|
||||
public string MsBuildPlatform;
|
||||
public string MsBuildConfiguration;
|
||||
public string MsBuildTarget;
|
||||
public string DotNetArguments;
|
||||
public string DotNetVersion;
|
||||
public string BuildCommand;
|
||||
public string[] Solution;
|
||||
public readonly string? VsToolsVersion;
|
||||
public readonly string? MsBuildArguments;
|
||||
public readonly string? MsBuildPlatform;
|
||||
public readonly string? MsBuildConfiguration;
|
||||
public readonly string? MsBuildTarget;
|
||||
public readonly string? DotNetArguments;
|
||||
public readonly string? DotNetVersion;
|
||||
public readonly string? BuildCommand;
|
||||
public readonly string[] Solution;
|
||||
|
||||
public bool IgnoreErrors;
|
||||
public bool Buildless;
|
||||
public bool AllSolutions;
|
||||
public bool NugetRestore;
|
||||
public readonly bool IgnoreErrors;
|
||||
public readonly bool Buildless;
|
||||
public readonly bool AllSolutions;
|
||||
public readonly bool NugetRestore;
|
||||
|
||||
public Language Language;
|
||||
public bool Indexing;
|
||||
public readonly Language Language;
|
||||
public readonly bool Indexing;
|
||||
|
||||
/// <summary>
|
||||
/// Reads options from environment variables.
|
||||
/// Throws ArgumentOutOfRangeException for invalid arguments.
|
||||
/// </summary>
|
||||
public void ReadEnvironment(IBuildActions actions)
|
||||
public AutobuildOptions(IBuildActions actions)
|
||||
{
|
||||
RootDirectory = actions.GetCurrentDirectory();
|
||||
VsToolsVersion = actions.GetEnvironmentVariable(prefix + "VSTOOLS_VERSION");
|
||||
MsBuildArguments = actions.GetEnvironmentVariable(prefix + "MSBUILD_ARGUMENTS").AsStringWithExpandedEnvVars(actions);
|
||||
MsBuildArguments = actions.GetEnvironmentVariable(prefix + "MSBUILD_ARGUMENTS")?.AsStringWithExpandedEnvVars(actions);
|
||||
MsBuildPlatform = actions.GetEnvironmentVariable(prefix + "MSBUILD_PLATFORM");
|
||||
MsBuildConfiguration = actions.GetEnvironmentVariable(prefix + "MSBUILD_CONFIGURATION");
|
||||
MsBuildTarget = actions.GetEnvironmentVariable(prefix + "MSBUILD_TARGET");
|
||||
DotNetArguments = actions.GetEnvironmentVariable(prefix + "DOTNET_ARGUMENTS").AsStringWithExpandedEnvVars(actions);
|
||||
DotNetArguments = actions.GetEnvironmentVariable(prefix + "DOTNET_ARGUMENTS")?.AsStringWithExpandedEnvVars(actions);
|
||||
DotNetVersion = actions.GetEnvironmentVariable(prefix + "DOTNET_VERSION");
|
||||
BuildCommand = actions.GetEnvironmentVariable(prefix + "BUILD_COMMAND");
|
||||
Solution = actions.GetEnvironmentVariable(prefix + "SOLUTION").AsListWithExpandedEnvVars(actions, new string[0]);
|
||||
@@ -60,7 +60,7 @@ namespace Semmle.Autobuild
|
||||
|
||||
public static class OptionsExtensions
|
||||
{
|
||||
public static bool AsBool(this string value, string param, bool defaultValue)
|
||||
public static bool AsBool(this string? value, string param, bool defaultValue)
|
||||
{
|
||||
if (value == null) return defaultValue;
|
||||
switch (value.ToLower())
|
||||
@@ -80,7 +80,7 @@ namespace Semmle.Autobuild
|
||||
}
|
||||
}
|
||||
|
||||
public static Language AsLanguage(this string key)
|
||||
public static Language AsLanguage(this string? key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
@@ -95,7 +95,7 @@ namespace Semmle.Autobuild
|
||||
}
|
||||
}
|
||||
|
||||
public static string[] AsListWithExpandedEnvVars(this string value, IBuildActions actions, string[] defaultValue)
|
||||
public static string[] AsListWithExpandedEnvVars(this string? value, IBuildActions actions, string[] defaultValue)
|
||||
{
|
||||
if (value == null)
|
||||
return defaultValue;
|
||||
|
||||
@@ -20,6 +20,14 @@ namespace Semmle.Autobuild
|
||||
BuildScript Analyse(Autobuilder builder, bool auto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exception indicating that environment variables are missing or invalid.
|
||||
/// </summary>
|
||||
class InvalidEnvironmentException : Exception
|
||||
{
|
||||
public InvalidEnvironmentException(string m) : base(m) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Main application logic, containing all data
|
||||
/// gathered from the project and filesystem.
|
||||
@@ -69,7 +77,7 @@ namespace Semmle.Autobuild
|
||||
/// List of project/solution files to build.
|
||||
/// </summary>
|
||||
public IList<IProjectOrSolution> ProjectsOrSolutionsToBuild => projectsOrSolutionsToBuildLazy.Value;
|
||||
readonly Lazy<IList<IProjectOrSolution>> projectsOrSolutionsToBuildLazy;
|
||||
private readonly Lazy<IList<IProjectOrSolution>> projectsOrSolutionsToBuildLazy;
|
||||
|
||||
/// <summary>
|
||||
/// Holds if a given path was found.
|
||||
@@ -129,7 +137,7 @@ namespace Semmle.Autobuild
|
||||
|
||||
projectsOrSolutionsToBuildLazy = new Lazy<IList<IProjectOrSolution>>(() =>
|
||||
{
|
||||
List<IProjectOrSolution> ret;
|
||||
List<IProjectOrSolution>? ret;
|
||||
if (options.Solution.Any())
|
||||
{
|
||||
ret = new List<IProjectOrSolution>();
|
||||
@@ -143,7 +151,7 @@ namespace Semmle.Autobuild
|
||||
return ret;
|
||||
}
|
||||
|
||||
IEnumerable<IProjectOrSolution> FindFiles(string extension, Func<string, ProjectOrSolution> create)
|
||||
IEnumerable<IProjectOrSolution>? FindFiles(string extension, Func<string, ProjectOrSolution> create)
|
||||
{
|
||||
var matchingFiles = GetExtensions(extension).
|
||||
Select(p => (ProjectOrSolution: create(p.Item1), DistanceFromRoot: p.Item2)).
|
||||
@@ -177,19 +185,34 @@ namespace Semmle.Autobuild
|
||||
});
|
||||
|
||||
CodeQLExtractorCSharpRoot = Actions.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_ROOT");
|
||||
|
||||
CodeQLJavaHome = Actions.GetEnvironmentVariable("CODEQL_JAVA_HOME");
|
||||
|
||||
SemmleDist = Actions.GetEnvironmentVariable("SEMMLE_DIST");
|
||||
|
||||
SemmleJavaHome = Actions.GetEnvironmentVariable("SEMMLE_JAVA_HOME");
|
||||
|
||||
SemmlePlatformTools = Actions.GetEnvironmentVariable("SEMMLE_PLATFORM_TOOLS");
|
||||
|
||||
if (CodeQLExtractorCSharpRoot == null && SemmleDist == null)
|
||||
Log(Severity.Error, "The environment variables CODEQL_EXTRACTOR_CSHARP_ROOT and SEMMLE_DIST have not been set.");
|
||||
JavaHome =
|
||||
Actions.GetEnvironmentVariable("CODEQL_JAVA_HOME") ??
|
||||
Actions.GetEnvironmentVariable("SEMMLE_JAVA_HOME") ??
|
||||
throw new InvalidEnvironmentException("The environment variable CODEQL_JAVA_HOME or SEMMLE_JAVA_HOME has not been set.");
|
||||
|
||||
Distribution =
|
||||
CodeQLExtractorCSharpRoot ??
|
||||
SemmleDist ??
|
||||
throw new InvalidEnvironmentException("The environment variable CODEQL_EXTRACTOR_CSHARP_ROOT or SEMMLE_DIST has not been set.");
|
||||
|
||||
TrapDir =
|
||||
Actions.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_TRAP_DIR") ??
|
||||
Actions.GetEnvironmentVariable("TRAP_FOLDER") ??
|
||||
throw new InvalidEnvironmentException("The environment variable CODEQL_EXTRACTOR_CSHARP_TRAP_DIR or TRAP_FOLDER has not been set.");
|
||||
|
||||
SourceArchiveDir =
|
||||
Actions.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR") ??
|
||||
Actions.GetEnvironmentVariable("SOURCE_ARCHIVE") ??
|
||||
throw new InvalidEnvironmentException("The environment variable CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR or SOURCE_ARCHIVE has not been set.");
|
||||
}
|
||||
|
||||
private string TrapDir { get; }
|
||||
|
||||
private string SourceArchiveDir { get; }
|
||||
|
||||
readonly ILogger logger = new ConsoleLogger(Verbosity.Info);
|
||||
|
||||
/// <summary>
|
||||
@@ -271,9 +294,9 @@ namespace Semmle.Autobuild
|
||||
break;
|
||||
case CSharpBuildStrategy.Auto:
|
||||
var cleanTrapFolder =
|
||||
BuildScript.DeleteDirectory(Actions.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_TRAP_DIR") ?? Actions.GetEnvironmentVariable("TRAP_FOLDER"));
|
||||
BuildScript.DeleteDirectory(TrapDir);
|
||||
var cleanSourceArchive =
|
||||
BuildScript.DeleteDirectory(Actions.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR") ?? Actions.GetEnvironmentVariable("SOURCE_ARCHIVE"));
|
||||
BuildScript.DeleteDirectory(SourceArchiveDir);
|
||||
var tryCleanExtractorArgsLogs =
|
||||
BuildScript.Create(actions =>
|
||||
{
|
||||
@@ -376,38 +399,33 @@ namespace Semmle.Autobuild
|
||||
/// <summary>
|
||||
/// Value of CODEQL_EXTRACTOR_CSHARP_ROOT environment variable.
|
||||
/// </summary>
|
||||
public string CodeQLExtractorCSharpRoot { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Value of CODEQL_JAVA_HOME environment variable.
|
||||
/// </summary>
|
||||
public string CodeQLJavaHome { get; private set; }
|
||||
private string? CodeQLExtractorCSharpRoot { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Value of SEMMLE_DIST environment variable.
|
||||
/// </summary>
|
||||
public string SemmleDist { get; private set; }
|
||||
private string? SemmleDist { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Value of SEMMLE_JAVA_HOME environment variable.
|
||||
/// </summary>
|
||||
public string SemmleJavaHome { get; private set; }
|
||||
public string Distribution { get; }
|
||||
|
||||
public string JavaHome { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Value of SEMMLE_PLATFORM_TOOLS environment variable.
|
||||
/// </summary>
|
||||
public string SemmlePlatformTools { get; private set; }
|
||||
public string? SemmlePlatformTools { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The absolute path of the odasa executable.
|
||||
/// null if we are running in CodeQL.
|
||||
/// </summary>
|
||||
public string Odasa => SemmleDist == null ? null : Actions.PathCombine(SemmleDist, "tools", "odasa");
|
||||
public string? Odasa => SemmleDist is null ? null : Actions.PathCombine(SemmleDist, "tools", "odasa");
|
||||
|
||||
/// <summary>
|
||||
/// Construct a command that executed the given <paramref name="cmd"/> wrapped in
|
||||
/// an <code>odasa --index</code>, unless indexing has been disabled, in which case
|
||||
/// <paramref name="cmd"/> is run directly.
|
||||
/// </summary>
|
||||
internal CommandBuilder MaybeIndex(CommandBuilder builder, string cmd) => Options.Indexing ? builder.IndexCommand(Odasa, cmd) : builder.RunCommand(cmd);
|
||||
internal CommandBuilder MaybeIndex(CommandBuilder builder, string cmd) => Options.Indexing && !(Odasa is null) ? builder.IndexCommand(Odasa, cmd) : builder.RunCommand(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Semmle.Autobuild
|
||||
/// <param name="env">Additional environment variables.</param>
|
||||
/// <param name="stdOut">The lines of stdout.</param>
|
||||
/// <returns>The process exit code.</returns>
|
||||
int RunProcess(string exe, string args, string workingDirectory, IDictionary<string, string> env, out IList<string> stdOut);
|
||||
int RunProcess(string exe, string args, string? workingDirectory, IDictionary<string, string>? env, out IList<string> stdOut);
|
||||
|
||||
/// <summary>
|
||||
/// Runs a process but does not capture its output.
|
||||
@@ -31,7 +31,7 @@ namespace Semmle.Autobuild
|
||||
/// <param name="workingDirectory">The working directory (<code>null</code> for current directory).</param>
|
||||
/// <param name="env">Additional environment variables.</param>
|
||||
/// <returns>The process exit code.</returns>
|
||||
int RunProcess(string exe, string args, string workingDirectory, IDictionary<string, string> env);
|
||||
int RunProcess(string exe, string args, string? workingDirectory, IDictionary<string, string>? env);
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether a file exists, File.Exists().
|
||||
@@ -63,7 +63,7 @@ namespace Semmle.Autobuild
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the variable.</param>
|
||||
/// <returns>The string value, or null if the variable is not defined.</returns>
|
||||
string GetEnvironmentVariable(string name);
|
||||
string? GetEnvironmentVariable(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current directory, Directory.GetCurrentDirectory().
|
||||
@@ -130,7 +130,7 @@ namespace Semmle.Autobuild
|
||||
|
||||
bool IBuildActions.FileExists(string file) => File.Exists(file);
|
||||
|
||||
ProcessStartInfo GetProcessStartInfo(string exe, string arguments, string workingDirectory, IDictionary<string, string> environment, bool redirectStandardOutput)
|
||||
ProcessStartInfo GetProcessStartInfo(string exe, string arguments, string? workingDirectory, IDictionary<string, string>? environment, bool redirectStandardOutput)
|
||||
{
|
||||
var pi = new ProcessStartInfo(exe, arguments)
|
||||
{
|
||||
@@ -146,7 +146,7 @@ namespace Semmle.Autobuild
|
||||
return pi;
|
||||
}
|
||||
|
||||
int IBuildActions.RunProcess(string cmd, string args, string workingDirectory, IDictionary<string, string> environment)
|
||||
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? environment)
|
||||
{
|
||||
var pi = GetProcessStartInfo(cmd, args, workingDirectory, environment, false);
|
||||
using (var p = Process.Start(pi))
|
||||
@@ -156,7 +156,7 @@ namespace Semmle.Autobuild
|
||||
}
|
||||
}
|
||||
|
||||
int IBuildActions.RunProcess(string cmd, string args, string workingDirectory, IDictionary<string, string> environment, out IList<string> stdOut)
|
||||
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? environment, out IList<string> stdOut)
|
||||
{
|
||||
var pi = GetProcessStartInfo(cmd, args, workingDirectory, environment, true);
|
||||
return pi.ReadOutput(out stdOut);
|
||||
@@ -166,7 +166,7 @@ namespace Semmle.Autobuild
|
||||
|
||||
bool IBuildActions.DirectoryExists(string dir) => Directory.Exists(dir);
|
||||
|
||||
string IBuildActions.GetEnvironmentVariable(string name) => Environment.GetEnvironmentVariable(name);
|
||||
string? IBuildActions.GetEnvironmentVariable(string name) => Environment.GetEnvironmentVariable(name);
|
||||
|
||||
string IBuildActions.GetCurrentDirectory() => Directory.GetCurrentDirectory();
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Semmle.Autobuild
|
||||
chmod.RunCommand("/bin/chmod", $"u+x {scriptPath}");
|
||||
var chmodScript = builder.Actions.IsWindows() ? BuildScript.Success : BuildScript.Try(chmod.Script);
|
||||
|
||||
var dir = Path.GetDirectoryName(scriptPath);
|
||||
string? dir = Path.GetDirectoryName(scriptPath);
|
||||
|
||||
// A specific .NET Core version may be required
|
||||
return chmodScript & DotNetRule.WithDotNet(builder, environment =>
|
||||
|
||||
@@ -48,8 +48,9 @@ namespace Semmle.Autobuild
|
||||
|
||||
class BuildCommand : BuildScript
|
||||
{
|
||||
readonly string exe, arguments, workingDirectory;
|
||||
readonly IDictionary<string, string> environment;
|
||||
readonly string exe, arguments;
|
||||
readonly string? workingDirectory;
|
||||
readonly IDictionary<string, string>? environment;
|
||||
readonly bool silent;
|
||||
|
||||
/// <summary>
|
||||
@@ -60,7 +61,7 @@ namespace Semmle.Autobuild
|
||||
/// <param name="silent">Whether this command should run silently.</param>
|
||||
/// <param name="workingDirectory">The working directory (<code>null</code> for current directory).</param>
|
||||
/// <param name="environment">Additional environment variables.</param>
|
||||
public BuildCommand(string exe, string argumentsOpt, bool silent, string workingDirectory = null, IDictionary<string, string> environment = null)
|
||||
public BuildCommand(string exe, string argumentsOpt, bool silent, string? workingDirectory = null, IDictionary<string, string>? environment = null)
|
||||
{
|
||||
this.exe = exe;
|
||||
this.arguments = argumentsOpt ?? "";
|
||||
@@ -131,8 +132,8 @@ namespace Semmle.Autobuild
|
||||
class BindBuildScript : BuildScript
|
||||
{
|
||||
readonly BuildScript s1;
|
||||
readonly Func<IList<string>, int, BuildScript> s2a;
|
||||
readonly Func<int, BuildScript> s2b;
|
||||
readonly Func<IList<string>, int, BuildScript>? s2a;
|
||||
readonly Func<int, BuildScript>? s2b;
|
||||
public BindBuildScript(BuildScript s1, Func<IList<string>, int, BuildScript> s2)
|
||||
{
|
||||
this.s1 = s1;
|
||||
@@ -154,14 +155,19 @@ namespace Semmle.Autobuild
|
||||
return s2a(stdout1, ret1).Run(actions, startCallback, exitCallBack);
|
||||
}
|
||||
|
||||
ret1 = s1.Run(actions, startCallback, exitCallBack);
|
||||
return s2b(ret1).Run(actions, startCallback, exitCallBack);
|
||||
if (s2b != null)
|
||||
{
|
||||
ret1 = s1.Run(actions, startCallback, exitCallBack);
|
||||
return s2b(ret1).Run(actions, startCallback, exitCallBack);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Unexpected error");
|
||||
}
|
||||
|
||||
public override int Run(IBuildActions actions, Action<string, bool> startCallback, Action<int, string, bool> exitCallBack, out IList<string> stdout)
|
||||
{
|
||||
var ret1 = s1.Run(actions, startCallback, exitCallBack, out var stdout1);
|
||||
var ret2 = (s2a != null ? s2a(stdout1, ret1) : s2b(ret1)).Run(actions, startCallback, exitCallBack, out var stdout2);
|
||||
var ret2 = (s2a != null ? s2a(stdout1, ret1) : s2b!(ret1)).Run(actions, startCallback, exitCallBack, out var stdout2);
|
||||
var @out = new List<string>();
|
||||
@out.AddRange(stdout1);
|
||||
@out.AddRange(stdout2);
|
||||
@@ -177,7 +183,7 @@ namespace Semmle.Autobuild
|
||||
/// <param name="silent">Whether the executable should run silently.</param>
|
||||
/// <param name="workingDirectory">The working directory (<code>null</code> for current directory).</param>
|
||||
/// <param name="environment">Additional environment variables.</param>
|
||||
public static BuildScript Create(string exe, string argumentsOpt, bool silent, string workingDirectory, IDictionary<string, string> environment) =>
|
||||
public static BuildScript Create(string exe, string argumentsOpt, bool silent, string? workingDirectory, IDictionary<string, string>? environment) =>
|
||||
new BuildCommand(exe, argumentsOpt, silent, workingDirectory, environment);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -13,10 +13,10 @@ namespace Semmle.Autobuild
|
||||
|
||||
readonly StringBuilder arguments;
|
||||
bool firstCommand;
|
||||
string executable;
|
||||
string? executable;
|
||||
readonly EscapeMode escapingMode;
|
||||
readonly string workingDirectory;
|
||||
readonly IDictionary<string, string> environment;
|
||||
readonly string? workingDirectory;
|
||||
readonly IDictionary<string, string>? environment;
|
||||
readonly bool silent;
|
||||
|
||||
/// <summary>
|
||||
@@ -25,7 +25,7 @@ namespace Semmle.Autobuild
|
||||
/// <param name="workingDirectory">The working directory (<code>null</code> for current directory).</param>
|
||||
/// <param name="environment">Additional environment variables.</param>
|
||||
/// <param name="silent">Whether this command should be run silently.</param>
|
||||
public CommandBuilder(IBuildActions actions, string workingDirectory = null, IDictionary<string, string> environment = null, bool silent = false)
|
||||
public CommandBuilder(IBuildActions actions, string? workingDirectory = null, IDictionary<string, string>? environment = null, bool silent = false)
|
||||
{
|
||||
arguments = new StringBuilder();
|
||||
if (actions.IsWindows())
|
||||
@@ -50,7 +50,7 @@ namespace Semmle.Autobuild
|
||||
RunCommand(odasa, "index --auto");
|
||||
}
|
||||
|
||||
public CommandBuilder CallBatFile(string batFile, string argumentsOpt = null)
|
||||
public CommandBuilder CallBatFile(string batFile, string? argumentsOpt = null)
|
||||
{
|
||||
NextCommand();
|
||||
arguments.Append(" CALL");
|
||||
@@ -66,7 +66,7 @@ namespace Semmle.Autobuild
|
||||
/// <param name="command">The command to run.</param>
|
||||
/// <param name="argumentsOpt">Additional arguments.</param>
|
||||
/// <returns>this for chaining calls.</returns>
|
||||
public CommandBuilder IndexCommand(string odasa, string command, string argumentsOpt = null)
|
||||
public CommandBuilder IndexCommand(string odasa, string command, string? argumentsOpt = null)
|
||||
{
|
||||
OdasaIndex(odasa);
|
||||
QuoteArgument(command);
|
||||
@@ -151,7 +151,7 @@ namespace Semmle.Autobuild
|
||||
arguments.Append(' ');
|
||||
}
|
||||
|
||||
public CommandBuilder Argument(string argumentsOpt)
|
||||
public CommandBuilder Argument(string? argumentsOpt)
|
||||
{
|
||||
if (argumentsOpt != null)
|
||||
{
|
||||
@@ -169,7 +169,7 @@ namespace Semmle.Autobuild
|
||||
arguments.Append(" &&");
|
||||
}
|
||||
|
||||
public CommandBuilder RunCommand(string exe, string argumentsOpt = null)
|
||||
public CommandBuilder RunCommand(string exe, string? argumentsOpt = null)
|
||||
{
|
||||
var (exe0, arg0) =
|
||||
escapingMode == EscapeMode.Process && exe.EndsWith(".exe", System.StringComparison.Ordinal)
|
||||
@@ -193,6 +193,14 @@ namespace Semmle.Autobuild
|
||||
/// <summary>
|
||||
/// Returns a build script that contains just this command.
|
||||
/// </summary>
|
||||
public BuildScript Script => BuildScript.Create(executable, arguments.ToString(), silent, workingDirectory, environment);
|
||||
public BuildScript Script
|
||||
{
|
||||
get
|
||||
{
|
||||
if (executable is null)
|
||||
throw new System.InvalidOperationException("executable is null");
|
||||
return BuildScript.Create(executable, arguments.ToString(), silent, workingDirectory, environment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,13 +56,13 @@ namespace Semmle.Autobuild
|
||||
});
|
||||
}
|
||||
|
||||
static BuildScript WithDotNet(Autobuilder builder, Func<string, IDictionary<string, string>, bool, BuildScript> f)
|
||||
static BuildScript WithDotNet(Autobuilder builder, Func<string?, IDictionary<string, string>?, bool, BuildScript> f)
|
||||
{
|
||||
var installDir = builder.Actions.PathCombine(builder.Options.RootDirectory, ".dotnet");
|
||||
string? installDir = builder.Actions.PathCombine(builder.Options.RootDirectory, ".dotnet");
|
||||
var installScript = DownloadDotNet(builder, installDir);
|
||||
return BuildScript.Bind(installScript, installed =>
|
||||
{
|
||||
Dictionary<string, string> env;
|
||||
Dictionary<string, string>? env;
|
||||
if (installed == 0)
|
||||
{
|
||||
// The installation succeeded, so use the newly installed .NET Core
|
||||
@@ -120,7 +120,7 @@ namespace Semmle.Autobuild
|
||||
/// variables needed by the installed .NET Core (<code>null</code> when no variables
|
||||
/// are needed).
|
||||
/// </summary>
|
||||
public static BuildScript WithDotNet(Autobuilder builder, Func<IDictionary<string, string>, BuildScript> f)
|
||||
public static BuildScript WithDotNet(Autobuilder builder, Func<IDictionary<string, string>?, BuildScript> f)
|
||||
=> WithDotNet(builder, (_1, env, _2) => f(env));
|
||||
|
||||
/// <summary>
|
||||
@@ -265,10 +265,10 @@ Invoke-Command -ScriptBlock $ScriptBlock";
|
||||
return listSdks.Script;
|
||||
}
|
||||
|
||||
static string DotNetCommand(IBuildActions actions, string dotNetPath) =>
|
||||
static string DotNetCommand(IBuildActions actions, string? dotNetPath) =>
|
||||
dotNetPath != null ? actions.PathCombine(dotNetPath, "dotnet") : "dotnet";
|
||||
|
||||
BuildScript GetInfoCommand(IBuildActions actions, string dotNetPath, IDictionary<string, string> environment)
|
||||
BuildScript GetInfoCommand(IBuildActions actions, string? dotNetPath, IDictionary<string, string>? environment)
|
||||
{
|
||||
var info = new CommandBuilder(actions, null, environment).
|
||||
RunCommand(DotNetCommand(actions, dotNetPath)).
|
||||
@@ -276,7 +276,7 @@ Invoke-Command -ScriptBlock $ScriptBlock";
|
||||
return info.Script;
|
||||
}
|
||||
|
||||
CommandBuilder GetCleanCommand(IBuildActions actions, string dotNetPath, IDictionary<string, string> environment)
|
||||
CommandBuilder GetCleanCommand(IBuildActions actions, string? dotNetPath, IDictionary<string, string>? environment)
|
||||
{
|
||||
var clean = new CommandBuilder(actions, null, environment).
|
||||
RunCommand(DotNetCommand(actions, dotNetPath)).
|
||||
@@ -284,7 +284,7 @@ Invoke-Command -ScriptBlock $ScriptBlock";
|
||||
return clean;
|
||||
}
|
||||
|
||||
CommandBuilder GetRestoreCommand(IBuildActions actions, string dotNetPath, IDictionary<string, string> environment)
|
||||
CommandBuilder GetRestoreCommand(IBuildActions actions, string? dotNetPath, IDictionary<string, string>? environment)
|
||||
{
|
||||
var restore = new CommandBuilder(actions, null, environment).
|
||||
RunCommand(DotNetCommand(actions, dotNetPath)).
|
||||
@@ -292,7 +292,7 @@ Invoke-Command -ScriptBlock $ScriptBlock";
|
||||
return restore;
|
||||
}
|
||||
|
||||
static BuildScript GetInstalledRuntimesScript(IBuildActions actions, string dotNetPath, IDictionary<string, string> environment)
|
||||
static BuildScript GetInstalledRuntimesScript(IBuildActions actions, string? dotNetPath, IDictionary<string, string>? environment)
|
||||
{
|
||||
var listSdks = new CommandBuilder(actions, environment: environment, silent: true).
|
||||
RunCommand(DotNetCommand(actions, dotNetPath)).
|
||||
@@ -309,7 +309,7 @@ Invoke-Command -ScriptBlock $ScriptBlock";
|
||||
/// hence the need for CLR tracing), by adding a
|
||||
/// `/p:UseSharedCompilation=false` argument.
|
||||
/// </summary>
|
||||
BuildScript GetBuildScript(Autobuilder builder, string dotNetPath, IDictionary<string, string> environment, bool compatibleClr, string projOrSln)
|
||||
BuildScript GetBuildScript(Autobuilder builder, string? dotNetPath, IDictionary<string, string>? environment, bool compatibleClr, string projOrSln)
|
||||
{
|
||||
var build = new CommandBuilder(builder.Actions, null, environment);
|
||||
var script = builder.MaybeIndex(build, DotNetCommand(builder.Actions, dotNetPath)).
|
||||
|
||||
@@ -67,10 +67,10 @@ namespace Semmle.Autobuild
|
||||
string target = builder.Options.MsBuildTarget != null
|
||||
? builder.Options.MsBuildTarget
|
||||
: "rebuild";
|
||||
string platform = builder.Options.MsBuildPlatform != null
|
||||
string? platform = builder.Options.MsBuildPlatform != null
|
||||
? builder.Options.MsBuildPlatform
|
||||
: projectOrSolution is ISolution s1 ? s1.DefaultPlatformName : null;
|
||||
string configuration = builder.Options.MsBuildConfiguration != null
|
||||
string? configuration = builder.Options.MsBuildConfiguration != null
|
||||
? builder.Options.MsBuildConfiguration
|
||||
: projectOrSolution is ISolution s2 ? s2.DefaultConfigurationName : null;
|
||||
|
||||
@@ -96,9 +96,9 @@ namespace Semmle.Autobuild
|
||||
///
|
||||
/// Returns <code>null</code> when no version is specified.
|
||||
/// </summary>
|
||||
public static VcVarsBatFile GetVcVarsBatFile(Autobuilder builder)
|
||||
public static VcVarsBatFile? GetVcVarsBatFile(Autobuilder builder)
|
||||
{
|
||||
VcVarsBatFile vsTools = null;
|
||||
VcVarsBatFile? vsTools = null;
|
||||
|
||||
if (builder.Options.VsToolsVersion != null)
|
||||
{
|
||||
|
||||
@@ -6,23 +6,27 @@ namespace Semmle.Autobuild
|
||||
{
|
||||
static int Main()
|
||||
{
|
||||
var options = new AutobuildOptions();
|
||||
var actions = SystemBuildActions.Instance;
|
||||
|
||||
try
|
||||
{
|
||||
options.ReadEnvironment(actions);
|
||||
var actions = SystemBuildActions.Instance;
|
||||
var options = new AutobuildOptions(actions);
|
||||
try
|
||||
{
|
||||
Console.WriteLine($"Semmle autobuilder for {options.Language}");
|
||||
var builder = new Autobuilder(actions, options);
|
||||
return builder.AttemptBuild();
|
||||
}
|
||||
catch(InvalidEnvironmentException ex)
|
||||
{
|
||||
Console.WriteLine("The environment is invalid: {0}", ex.Message);
|
||||
}
|
||||
}
|
||||
catch (ArgumentOutOfRangeException ex)
|
||||
{
|
||||
Console.WriteLine("The value \"{0}\" for parameter \"{1}\" is invalid", ex.ActualValue, ex.ParamName);
|
||||
}
|
||||
|
||||
var builder = new Autobuilder(actions, options);
|
||||
|
||||
Console.WriteLine($"Semmle autobuilder for {options.Language}");
|
||||
|
||||
return builder.AttemptBuild();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace Semmle.Autobuild
|
||||
foreach (var include in projectFileIncludes.Concat(projectFilesIncludes))
|
||||
{
|
||||
var includePath = builder.Actions.PathCombine(include.Value.Split('\\', StringSplitOptions.RemoveEmptyEntries));
|
||||
ret.Add(new Project(builder, builder.Actions.PathCombine(Path.GetDirectoryName(this.FullPath), includePath)));
|
||||
ret.Add(new Project(builder, builder.Actions.PathCombine(DirectoryName, includePath)));
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
@@ -24,6 +25,8 @@ namespace Semmle.Autobuild
|
||||
{
|
||||
public string FullPath { get; private set; }
|
||||
|
||||
public string DirectoryName => Path.GetDirectoryName(FullPath) ?? "";
|
||||
|
||||
protected ProjectOrSolution(Autobuilder builder, string path)
|
||||
{
|
||||
FullPath = builder.Actions.GetFullPath(path);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<StartupObject />
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace Semmle.Autobuild
|
||||
/// </summary>
|
||||
class Solution : ProjectOrSolution, ISolution
|
||||
{
|
||||
readonly SolutionFile solution;
|
||||
readonly SolutionFile? solution;
|
||||
|
||||
readonly IEnumerable<Project> includedProjects;
|
||||
public override IEnumerable<IProjectOrSolution> IncludedProjects => includedProjects;
|
||||
@@ -81,7 +81,7 @@ namespace Semmle.Autobuild
|
||||
includedProjects =
|
||||
solution.ProjectsInOrder.
|
||||
Where(p => p.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat).
|
||||
Select(p => builder.Actions.PathCombine(Path.GetDirectoryName(path), builder.Actions.PathCombine(p.RelativePath.Split('\\', StringSplitOptions.RemoveEmptyEntries)))).
|
||||
Select(p => builder.Actions.PathCombine(DirectoryName, builder.Actions.PathCombine(p.RelativePath.Split('\\', StringSplitOptions.RemoveEmptyEntries)))).
|
||||
Select(p => new Project(builder, p)).
|
||||
ToArray();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Autobuild
|
||||
namespace Semmle.Autobuild
|
||||
{
|
||||
/// <summary>
|
||||
/// Build using standalone extraction.
|
||||
@@ -9,8 +7,11 @@ namespace Semmle.Autobuild
|
||||
{
|
||||
public BuildScript Analyse(Autobuilder builder, bool auto)
|
||||
{
|
||||
BuildScript GetCommand(string solution)
|
||||
BuildScript GetCommand(string? solution)
|
||||
{
|
||||
if (builder.SemmlePlatformTools is null)
|
||||
return BuildScript.Failure;
|
||||
|
||||
var standalone = builder.Actions.PathCombine(builder.SemmlePlatformTools, "csharp", "Semmle.Extraction.CSharp.Standalone");
|
||||
var cmd = new CommandBuilder(builder.Actions);
|
||||
cmd.RunCommand(standalone);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
{
|
||||
public BuildScript Analyse(Autobuilder builder, bool auto)
|
||||
{
|
||||
if (!builder.Options.Indexing)
|
||||
if (!builder.Options.Indexing || builder.Odasa is null)
|
||||
return BuildScript.Success;
|
||||
|
||||
var command = new CommandBuilder(builder.Actions).
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -9,20 +9,19 @@ namespace Semmle.Util
|
||||
/// </summary>
|
||||
/// <typeparam name="Key"></typeparam>
|
||||
/// <typeparam name="Value"></typeparam>
|
||||
public class ActionMap<Key, Value>
|
||||
public class ActionMap<Key, Value> where Key : notnull
|
||||
{
|
||||
public void Add(Key key, Value value)
|
||||
{
|
||||
Action<Value> a;
|
||||
if (actions.TryGetValue(key, out a))
|
||||
|
||||
if (actions.TryGetValue(key, out var a))
|
||||
a(value);
|
||||
values[key] = value;
|
||||
}
|
||||
|
||||
public void OnAdd(Key key, Action<Value> action)
|
||||
{
|
||||
Action<Value> a;
|
||||
if (actions.TryGetValue(key, out a))
|
||||
if (actions.TryGetValue(key, out var a))
|
||||
{
|
||||
actions[key] = a + action;
|
||||
}
|
||||
|
||||
@@ -127,8 +127,8 @@ namespace Semmle.Util
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
string name = Path.GetFileName(path);
|
||||
string parentPath = cache.GetCanonicalPath(parent.FullName);
|
||||
var name = Path.GetFileName(path);
|
||||
var parentPath = cache.GetCanonicalPath(parent.FullName);
|
||||
try
|
||||
{
|
||||
string[] entries = Directory.GetFileSystemEntries(parentPath, name);
|
||||
@@ -313,14 +313,15 @@ namespace Semmle.Util
|
||||
/// <returns>The canonical path.</returns>
|
||||
public string GetCanonicalPath(string path)
|
||||
{
|
||||
string canonicalPath;
|
||||
lock (cache)
|
||||
if (!cache.TryGetValue(path, out canonicalPath))
|
||||
{
|
||||
if (!cache.TryGetValue(path, out var canonicalPath))
|
||||
{
|
||||
canonicalPath = pathStrategy.GetCanonicalPath(path, this);
|
||||
AddToCache(path, canonicalPath);
|
||||
}
|
||||
return canonicalPath;
|
||||
return canonicalPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Semmle.Util
|
||||
var found = false;
|
||||
foreach (var arg in commandLineArguments.Where(arg => arg.StartsWith('@')).Select(arg => arg.Substring(1)))
|
||||
{
|
||||
string line;
|
||||
string? line;
|
||||
using (StreamReader file = new StreamReader(arg))
|
||||
while ((line = file.ReadLine()) != null)
|
||||
textWriter.WriteLine(line);
|
||||
|
||||
@@ -9,10 +9,9 @@ namespace Semmle.Util
|
||||
/// dictionary. If a list does not already exist, a new list is
|
||||
/// created.
|
||||
/// </summary>
|
||||
public static void AddAnother<T1, T2>(this Dictionary<T1, List<T2>> dict, T1 key, T2 element)
|
||||
public static void AddAnother<T1, T2>(this Dictionary<T1, List<T2>> dict, T1 key, T2 element) where T1:notnull
|
||||
{
|
||||
List<T2> list;
|
||||
if (!dict.TryGetValue(key, out list))
|
||||
if (!dict.TryGetValue(key, out var list))
|
||||
{
|
||||
list = new List<T2>();
|
||||
dict[key] = list;
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Semmle.Util
|
||||
///
|
||||
/// Returns <code>null</code> of no path can be found.
|
||||
/// </summary>
|
||||
public static string FindProgramOnPath(string prog)
|
||||
public static string? FindProgramOnPath(string prog)
|
||||
{
|
||||
var paths = Environment.GetEnvironmentVariable("PATH")?.Split(Path.PathSeparator);
|
||||
string[] exes;
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Semmle.Util
|
||||
/// </remarks>
|
||||
///
|
||||
/// <typeparam name="T">The value type.</typeparam>
|
||||
public class FuzzyDictionary<T>
|
||||
public class FuzzyDictionary<T> where T:class
|
||||
{
|
||||
// All data items indexed by the "base string" (stripped of numbers)
|
||||
readonly Dictionary<string, List<KeyValuePair<string, T>>> index = new Dictionary<string, List<KeyValuePair<string, T>>>();
|
||||
@@ -61,7 +61,7 @@ namespace Semmle.Util
|
||||
/// <param name="v1">Vector 1</param>
|
||||
/// <param name="v2">Vector 2</param>
|
||||
/// <returns>The Hamming Distance.</returns>
|
||||
static int HammingDistance<U>(IEnumerable<U> v1, IEnumerable<U> v2)
|
||||
static int HammingDistance<U>(IEnumerable<U> v1, IEnumerable<U> v2) where U: notnull
|
||||
{
|
||||
return v1.Zip(v2, (x, y) => x.Equals(y) ? 0 : 1).Sum();
|
||||
}
|
||||
@@ -72,11 +72,10 @@ namespace Semmle.Util
|
||||
/// <param name="query">The query string.</param>
|
||||
/// <param name="distance">The distance between the query string and the stored string.</param>
|
||||
/// <returns>The best match, or null (default).</returns>
|
||||
public T FindMatch(string query, out int distance)
|
||||
public T? FindMatch(string query, out int distance)
|
||||
{
|
||||
string root = StripDigits(query);
|
||||
List<KeyValuePair<string, T>> list;
|
||||
if (!index.TryGetValue(root, out list))
|
||||
if (!index.TryGetValue(root, out var list))
|
||||
{
|
||||
distance = 0;
|
||||
return default(T);
|
||||
@@ -93,9 +92,9 @@ namespace Semmle.Util
|
||||
/// <param name="distance">The distance function.</param>
|
||||
/// <param name="bestDistance">The distance between the query and the stored string.</param>
|
||||
/// <returns>The stored value.</returns>
|
||||
static T BestMatch(string query, IEnumerable<KeyValuePair<string, T>> candidates, Func<string, string, int> distance, out int bestDistance)
|
||||
static T? BestMatch(string query, IEnumerable<KeyValuePair<string, T>> candidates, Func<string, string, int> distance, out int bestDistance)
|
||||
{
|
||||
T bestMatch = default(T);
|
||||
T? bestMatch = default(T);
|
||||
bestDistance = 0;
|
||||
bool first = true;
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace Semmle.Util
|
||||
/// <typeparam name="T">The type of the item.</typeparam>
|
||||
/// <param name="items">The list of items to hash.</param>
|
||||
/// <returns>The hash code.</returns>
|
||||
public static int SequenceHash<T>(this IEnumerable<T> items)
|
||||
public static int SequenceHash<T>(this IEnumerable<T> items) where T: notnull
|
||||
{
|
||||
int h = 0;
|
||||
foreach (var i in items)
|
||||
|
||||
@@ -31,9 +31,9 @@ namespace Semmle.Util
|
||||
//#################### PUBLIC METHODS ####################
|
||||
#region
|
||||
|
||||
public override bool Equals(Object other)
|
||||
public override bool Equals(object? other)
|
||||
{
|
||||
LineCounts rhs = other as LineCounts;
|
||||
var rhs = other as LineCounts;
|
||||
return rhs != null && Total == rhs.Total && Code == rhs.Code && Comment == rhs.Comment;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,8 +67,8 @@ namespace Semmle.Util.Logging
|
||||
|
||||
try
|
||||
{
|
||||
var dir = Path.GetDirectoryName(outputFile);
|
||||
if (dir.Length > 0 && !System.IO.Directory.Exists(dir))
|
||||
string? dir = Path.GetDirectoryName(outputFile);
|
||||
if (!string.IsNullOrEmpty(dir) && !System.IO.Directory.Exists(dir))
|
||||
Directory.CreateDirectory(dir);
|
||||
writer = new PidStreamWriter(new FileStream(outputFile, FileMode.Append, FileAccess.Write,
|
||||
FileShare.ReadWrite, 8192));
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Semmle.Util
|
||||
|
||||
private readonly string prefix = "[" + Process.GetCurrentProcess().Id + "] ";
|
||||
|
||||
public override void WriteLine(string value)
|
||||
public override void WriteLine(string? value)
|
||||
{
|
||||
lock (mutex)
|
||||
{
|
||||
@@ -29,9 +29,9 @@ namespace Semmle.Util
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteLine(string value, object[] args)
|
||||
public override void WriteLine(string? value, object?[] args)
|
||||
{
|
||||
WriteLine(String.Format(value, args));
|
||||
WriteLine(value is null ? value : String.Format(value, args));
|
||||
}
|
||||
|
||||
readonly object mutex = new object();
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Semmle.Util
|
||||
stdout = new List<string>();
|
||||
using (var process = Process.Start(pi))
|
||||
{
|
||||
string s;
|
||||
string? s;
|
||||
do
|
||||
{
|
||||
s = process.StandardOutput.ReadLine();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<RootNamespace>Semmle.Util</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -13,6 +13,6 @@ namespace Semmle.Util
|
||||
/// <summary>
|
||||
/// The shared object to which different parts of the code want to refer.
|
||||
/// </summary>
|
||||
public T Obj { get; set; }
|
||||
public T? Obj { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user