Merge pull request #3150 from calumgrant/cs/enable-nullability

C#: Enable nullability for Autobuilder and Utils projects
This commit is contained in:
Tom Hvitved
2020-04-07 08:51:43 +02:00
committed by GitHub
31 changed files with 186 additions and 145 deletions

View File

@@ -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);
}

View File

@@ -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").

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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();

View File

@@ -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 =>

View File

@@ -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>

View File

@@ -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);
}
}
}
}

View File

@@ -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)).

View File

@@ -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)
{

View File

@@ -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;
}
}
}

View File

@@ -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;
});

View File

@@ -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);

View File

@@ -9,6 +9,7 @@
<StartupObject />
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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).

View File

@@ -5,6 +5,7 @@
<TargetFramework>netcoreapp3.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>

View File

@@ -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;
}

View File

@@ -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;
}
}
}
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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));

View File

@@ -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();

View File

@@ -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();

View File

@@ -6,6 +6,7 @@
<RootNamespace>Semmle.Util</RootNamespace>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>

View File

@@ -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; }
}
}