mirror of
https://github.com/github/codeql.git
synced 2026-04-26 17:25:19 +02:00
C#: Move source code generators to dedicated classes
This commit is contained in:
@@ -149,24 +149,20 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
logger.LogDebug($"Unresolved reference {r.Key} in project {r.Value}");
|
||||
}
|
||||
|
||||
var webViewExtractionOption = Environment.GetEnvironmentVariable(EnvironmentVariableNames.WebViewGeneration);
|
||||
if (webViewExtractionOption == null ||
|
||||
bool.TryParse(webViewExtractionOption, out var shouldExtractWebViews) &&
|
||||
shouldExtractWebViews)
|
||||
var sourceGenerators = new ISourceGenerator[]
|
||||
{
|
||||
CompilationInfos.Add(("WebView extraction enabled", "1"));
|
||||
GenerateSourceFilesFromWebViews();
|
||||
}
|
||||
else
|
||||
new ImplicitUsingsGenerator(fileContent, logger, tempWorkingDirectory),
|
||||
new WebViewGenerator(fileProvider, fileContent, dotnet, this, logger, tempWorkingDirectory, usedReferences.Keys)
|
||||
};
|
||||
|
||||
foreach (var sourceGenerator in sourceGenerators)
|
||||
{
|
||||
CompilationInfos.Add(("WebView extraction enabled", "0"));
|
||||
this.generatedSources.AddRange(sourceGenerator.Generate());
|
||||
}
|
||||
|
||||
CompilationInfos.Add(("UseWPF set", fileContent.UseWpf ? "1" : "0"));
|
||||
CompilationInfos.Add(("UseWindowsForms set", fileContent.UseWindowsForms ? "1" : "0"));
|
||||
|
||||
GenerateSourceFileFromImplicitUsings();
|
||||
|
||||
const int align = 6;
|
||||
logger.LogInfo("");
|
||||
logger.LogInfo("Build analysis summary:");
|
||||
@@ -365,14 +361,9 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsAspNetCoreDetected()
|
||||
{
|
||||
return fileContent.IsNewProjectStructureUsed && fileContent.UseAspNetCoreDlls;
|
||||
}
|
||||
|
||||
private void AddAspNetCoreFrameworkDlls(ISet<AssemblyLookupLocation> dllLocations, ISet<string> frameworkLocations)
|
||||
{
|
||||
if (!IsAspNetCoreDetected())
|
||||
if (!fileContent.IsAspNetCoreDetected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -413,103 +404,6 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
.FullName;
|
||||
}
|
||||
|
||||
private void GenerateSourceFileFromImplicitUsings()
|
||||
{
|
||||
var usings = new HashSet<string>();
|
||||
if (!fileContent.UseImplicitUsings)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Hardcoded values from https://learn.microsoft.com/en-us/dotnet/core/project-sdk/overview#implicit-using-directives
|
||||
usings.UnionWith([ "System", "System.Collections.Generic", "System.IO", "System.Linq", "System.Net.Http", "System.Threading",
|
||||
"System.Threading.Tasks" ]);
|
||||
|
||||
if (fileContent.UseAspNetCoreDlls)
|
||||
{
|
||||
usings.UnionWith([ "System.Net.Http.Json", "Microsoft.AspNetCore.Builder", "Microsoft.AspNetCore.Hosting",
|
||||
"Microsoft.AspNetCore.Http", "Microsoft.AspNetCore.Routing", "Microsoft.Extensions.Configuration",
|
||||
"Microsoft.Extensions.DependencyInjection", "Microsoft.Extensions.Hosting", "Microsoft.Extensions.Logging" ]);
|
||||
}
|
||||
|
||||
if (fileContent.UseWindowsForms)
|
||||
{
|
||||
usings.UnionWith(["System.Drawing", "System.Windows.Forms"]);
|
||||
}
|
||||
|
||||
usings.UnionWith(fileContent.CustomImplicitUsings);
|
||||
|
||||
logger.LogInfo($"Generating source file for implicit usings. Namespaces: {string.Join(", ", usings.OrderBy(u => u))}");
|
||||
|
||||
if (usings.Count > 0)
|
||||
{
|
||||
var tempDir = GetTemporaryWorkingDirectory("implicitUsings");
|
||||
var path = Path.Combine(tempDir, "GlobalUsings.g.cs");
|
||||
using (var writer = new StreamWriter(path))
|
||||
{
|
||||
writer.WriteLine("// <auto-generated/>");
|
||||
writer.WriteLine("");
|
||||
|
||||
foreach (var u in usings.OrderBy(u => u))
|
||||
{
|
||||
writer.WriteLine($"global using global::{u};");
|
||||
}
|
||||
}
|
||||
|
||||
this.generatedSources.Add(path);
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateSourceFilesFromWebViews()
|
||||
{
|
||||
var views = fileProvider.RazorViews;
|
||||
if (views.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
logger.LogInfo($"Found {views.Count} cshtml and razor files.");
|
||||
|
||||
if (!IsAspNetCoreDetected())
|
||||
{
|
||||
logger.LogInfo("Generating source files from cshtml files is only supported for new (SDK-style) project files");
|
||||
return;
|
||||
}
|
||||
|
||||
logger.LogInfo("Generating source files from cshtml and razor files...");
|
||||
|
||||
var sdk = new Sdk(dotnet).GetNewestSdk();
|
||||
if (sdk != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var razor = new Razor(sdk, dotnet, logger);
|
||||
var targetDir = GetTemporaryWorkingDirectory("razor");
|
||||
var generatedFiles = razor.GenerateFiles(views, usedReferences.Keys, targetDir);
|
||||
this.generatedSources.AddRange(generatedFiles);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// It's okay, we tried our best to generate source files from cshtml files.
|
||||
logger.LogInfo($"Failed to generate source files from cshtml files: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a temporary directory with the given subfolder name.
|
||||
/// The created directory might be inside the repo folder, and it is deleted when the object is disposed.
|
||||
/// </summary>
|
||||
/// <param name="subfolder"></param>
|
||||
/// <returns></returns>
|
||||
private string GetTemporaryWorkingDirectory(string subfolder)
|
||||
{
|
||||
var temp = Path.Combine(tempWorkingDirectory.ToString(), subfolder);
|
||||
Directory.CreateDirectory(temp);
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves conflicts between all of the resolved references.
|
||||
/// If the same assembly name is duplicated with different versions,
|
||||
|
||||
@@ -50,6 +50,14 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAspNetCoreDetected
|
||||
{
|
||||
get
|
||||
{
|
||||
return IsNewProjectStructureUsed && UseAspNetCoreDlls;
|
||||
}
|
||||
}
|
||||
|
||||
private bool useImplicitUsings = false;
|
||||
|
||||
public bool UseImplicitUsings
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
public interface ISourceGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the paths to the generated source files.
|
||||
/// </summary>
|
||||
IEnumerable<string> Generate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Semmle.Util;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
internal class ImplicitUsingsGenerator : SourceGeneratorBase
|
||||
{
|
||||
private readonly FileContent fileContent;
|
||||
|
||||
public ImplicitUsingsGenerator(FileContent fileContent, ILogger logger, TemporaryDirectory tempWorkingDirectory)
|
||||
: base(logger, tempWorkingDirectory)
|
||||
{
|
||||
this.fileContent = fileContent;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Generate()
|
||||
{
|
||||
var usings = new HashSet<string>();
|
||||
if (!fileContent.UseImplicitUsings)
|
||||
{
|
||||
logger.LogDebug("Skipping implicit usings generation");
|
||||
return [];
|
||||
}
|
||||
|
||||
// Hardcoded values from https://learn.microsoft.com/en-us/dotnet/core/project-sdk/overview#implicit-using-directives
|
||||
usings.UnionWith([ "System", "System.Collections.Generic", "System.IO", "System.Linq", "System.Net.Http", "System.Threading",
|
||||
"System.Threading.Tasks" ]);
|
||||
|
||||
if (fileContent.UseAspNetCoreDlls)
|
||||
{
|
||||
usings.UnionWith([ "System.Net.Http.Json", "Microsoft.AspNetCore.Builder", "Microsoft.AspNetCore.Hosting",
|
||||
"Microsoft.AspNetCore.Http", "Microsoft.AspNetCore.Routing", "Microsoft.Extensions.Configuration",
|
||||
"Microsoft.Extensions.DependencyInjection", "Microsoft.Extensions.Hosting", "Microsoft.Extensions.Logging" ]);
|
||||
}
|
||||
|
||||
if (fileContent.UseWindowsForms)
|
||||
{
|
||||
usings.UnionWith(["System.Drawing", "System.Windows.Forms"]);
|
||||
}
|
||||
|
||||
usings.UnionWith(fileContent.CustomImplicitUsings);
|
||||
|
||||
logger.LogInfo($"Generating source file for implicit usings. Namespaces: {string.Join(", ", usings.OrderBy(u => u))}");
|
||||
|
||||
if (usings.Count > 0)
|
||||
{
|
||||
var tempDir = GetTemporaryWorkingDirectory("implicitUsings");
|
||||
var path = Path.Combine(tempDir, "GlobalUsings.g.cs");
|
||||
using (var writer = new StreamWriter(path))
|
||||
{
|
||||
writer.WriteLine("// <auto-generated/>");
|
||||
writer.WriteLine("");
|
||||
|
||||
foreach (var u in usings.OrderBy(u => u))
|
||||
{
|
||||
writer.WriteLine($"global using global::{u};");
|
||||
}
|
||||
}
|
||||
|
||||
return [path];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Semmle.Util;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
internal abstract class SourceGeneratorBase : ISourceGenerator
|
||||
{
|
||||
protected readonly ILogger logger;
|
||||
protected readonly TemporaryDirectory tempWorkingDirectory;
|
||||
|
||||
public SourceGeneratorBase(ILogger logger, TemporaryDirectory tempWorkingDirectory)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.tempWorkingDirectory = tempWorkingDirectory;
|
||||
}
|
||||
|
||||
public abstract IEnumerable<string> Generate();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a temporary directory with the given subfolder name.
|
||||
/// The created directory might be inside the repo folder, and it is deleted when the temporary working directory is disposed.
|
||||
/// </summary>
|
||||
protected string GetTemporaryWorkingDirectory(string subfolder)
|
||||
{
|
||||
var temp = Path.Combine(tempWorkingDirectory.ToString(), subfolder);
|
||||
Directory.CreateDirectory(temp);
|
||||
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Semmle.Util;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
internal class WebViewGenerator : SourceGeneratorBase
|
||||
{
|
||||
private readonly FileProvider fileProvider;
|
||||
private readonly FileContent fileContent;
|
||||
private readonly IDotNet dotnet;
|
||||
private readonly ICompilationInfoContainer compilationInfoContainer;
|
||||
private readonly IEnumerable<string> references;
|
||||
|
||||
public WebViewGenerator(
|
||||
FileProvider fileProvider,
|
||||
FileContent fileContent,
|
||||
IDotNet dotnet,
|
||||
ICompilationInfoContainer compilationInfoContainer,
|
||||
ILogger logger,
|
||||
TemporaryDirectory tempWorkingDirectory,
|
||||
IEnumerable<string> references) : base(logger, tempWorkingDirectory)
|
||||
{
|
||||
this.fileProvider = fileProvider;
|
||||
this.fileContent = fileContent;
|
||||
this.dotnet = dotnet;
|
||||
this.compilationInfoContainer = compilationInfoContainer;
|
||||
this.references = references;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Generate()
|
||||
{
|
||||
var webViewExtractionOption = Environment.GetEnvironmentVariable(EnvironmentVariableNames.WebViewGeneration);
|
||||
if (webViewExtractionOption == null ||
|
||||
bool.TryParse(webViewExtractionOption, out var shouldExtractWebViews) &&
|
||||
shouldExtractWebViews)
|
||||
{
|
||||
compilationInfoContainer.CompilationInfos.Add(("WebView extraction enabled", "1"));
|
||||
return GenerateSourceFilesFromWebViews();
|
||||
}
|
||||
|
||||
compilationInfoContainer.CompilationInfos.Add(("WebView extraction enabled", "0"));
|
||||
return [];
|
||||
}
|
||||
|
||||
private IEnumerable<string> GenerateSourceFilesFromWebViews()
|
||||
{
|
||||
var views = fileProvider.RazorViews;
|
||||
if (views.Count == 0)
|
||||
{
|
||||
logger.LogDebug("No cshtml or razor files found.");
|
||||
return [];
|
||||
}
|
||||
|
||||
logger.LogInfo($"Found {views.Count} cshtml and razor files.");
|
||||
|
||||
if (!fileContent.IsAspNetCoreDetected)
|
||||
{
|
||||
logger.LogInfo("Generating source files from cshtml files is only supported for new (SDK-style) project files");
|
||||
return [];
|
||||
}
|
||||
|
||||
logger.LogInfo("Generating source files from cshtml and razor files...");
|
||||
|
||||
var sdk = new Sdk(dotnet).GetNewestSdk();
|
||||
if (sdk != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var razor = new Razor(sdk, dotnet, logger);
|
||||
var targetDir = GetTemporaryWorkingDirectory("razor");
|
||||
var generatedFiles = razor.GenerateFiles(views, references, targetDir);
|
||||
return generatedFiles ?? [];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// It's okay, we tried our best to generate source files from cshtml files.
|
||||
logger.LogInfo($"Failed to generate source files from cshtml files: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user