Skip to content

Commit fb0520c

Browse files
committed
C#: Adjust trap location, database ID and archiving of generated sources
1 parent dcd84f4 commit fb0520c

File tree

8 files changed

+124
-42
lines changed

8 files changed

+124
-42
lines changed

csharp/extractor/Semmle.Extraction.CSharp/Entities/File.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,14 @@ public override void Populate(TextWriter trapFile)
3434
lineCounts.Total++;
3535

3636
trapFile.numlines(this, lineCounts);
37-
Context.TrapWriter.Archive(originalPath, TransformedPath, text.Encoding ?? System.Text.Encoding.Default);
37+
if (BinaryLogExtractionContext.GetAdjustedPath(Context.ExtractionContext, originalPath) is not null)
38+
{
39+
Context.TrapWriter.ArchiveContent(rawText, TransformedPath);
40+
}
41+
else
42+
{
43+
Context.TrapWriter.Archive(originalPath, TransformedPath, text.Encoding ?? System.Text.Encoding.Default);
44+
}
3845
}
3946
}
4047
else if (IsPossiblyTextFile())

csharp/extractor/Semmle.Extraction.CSharp/Extractor/Analyser.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,8 @@ private void DoExtractTree(SyntaxTree tree)
185185
{
186186
var stopwatch = new Stopwatch();
187187
stopwatch.Start();
188-
var sourcePath = tree.FilePath;
188+
var sourcePath = BinaryLogExtractionContext.GetAdjustedPath(ExtractionContext, tree.FilePath) ?? tree.FilePath;
189+
189190
var transformedSourcePath = PathTransformer.Transform(sourcePath);
190191

191192
var trapPath = transformedSourcePath.GetTrapPath(Logger, options.TrapCompression);

csharp/extractor/Semmle.Extraction.CSharp/Extractor/BinaryLogAnalyser.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Collections.Generic;
12
using Microsoft.CodeAnalysis.CSharp;
23
using Semmle.Util;
34
using Semmle.Util.Logging;
@@ -11,10 +12,15 @@ public BinaryLogAnalyser(IProgressMonitor pm, ILogger logger, PathTransformer pa
1112
{
1213
}
1314

14-
public void Initialize(string cwd, string[] args, string outputPath, CSharpCompilation compilationIn, CommonOptions options)
15+
public void Initialize(
16+
string cwd, string[] args, string outputPath, CSharpCompilation compilation,
17+
IEnumerable<Microsoft.CodeAnalysis.SyntaxTree> generatedSyntaxTrees,
18+
string compilationIdentifier, CommonOptions options)
1519
{
16-
compilation = compilationIn;
17-
ExtractionContext = new ExtractionContext(cwd, args, outputPath, [], Logger, PathTransformer, ExtractorMode.BinaryLog, options.QlTest);
20+
base.compilation = compilation;
21+
ExtractionContext = new BinaryLogExtractionContext(
22+
cwd, args, outputPath, generatedSyntaxTrees, compilationIdentifier,
23+
Logger, PathTransformer, options.QlTest);
1824
this.options = options;
1925
LogExtractorInfo();
2026
SetReferencePaths();

csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,23 @@ static bool filter(CompilerCall compilerCall)
158158
var compilerArgs = compilerCall.GetArguments();
159159
var args = reader.ReadCommandLineArguments(compilerCall);
160160

161+
// Generated syntax trees are always added to the end of the list of syntax trees.
162+
var generatedSyntaxTrees = compilation.SyntaxTrees.Skip(compilationData.Compilation.SyntaxTrees.Count());
163+
161164
using var analyser = new BinaryLogAnalyser(new LogProgressMonitor(logger), logger, pathTransformer, canonicalPathCache, options.AssemblySensitiveTrap);
162165

163166
var exit = Analyse(stopwatch, analyser, options,
164167
references => [() => compilation.References.ForEach(r => references.Add(r))],
165168
(analyser, syntaxTrees) => [() => syntaxTrees.AddRange(compilation.SyntaxTrees)],
166169
(syntaxTrees, references) => compilation,
167-
(compilation, options) => analyser.Initialize(compilerCall.ProjectDirectory, compilerArgs?.ToArray() ?? [], TracingAnalyser.GetOutputName(compilation, args), compilation, options),
170+
(compilation, options) => analyser.Initialize(
171+
compilerCall.ProjectDirectory,
172+
compilerArgs?.ToArray() ?? [],
173+
TracingAnalyser.GetOutputName(compilation, args),
174+
compilation,
175+
generatedSyntaxTrees,
176+
diagnosticName,
177+
options),
168178
() => { });
169179

170180
switch (exit)

csharp/extractor/Semmle.Extraction/Entities/File.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ protected File(Context cx, string path)
88
: base(cx, path)
99
{
1010
originalPath = path;
11-
transformedPathLazy = new Lazy<PathTransformer.ITransformedPath>(() => Context.ExtractionContext.PathTransformer.Transform(originalPath));
11+
var adjustedPath = BinaryLogExtractionContext.GetAdjustedPath(Context.ExtractionContext, originalPath) ?? path;
12+
transformedPathLazy = new Lazy<PathTransformer.ITransformedPath>(() => Context.ExtractionContext.PathTransformer.Transform(adjustedPath));
1213
}
1314

1415
protected readonly string originalPath;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using System.Collections.Generic;
2+
using System.IO;
3+
using System.Linq;
4+
using Microsoft.CodeAnalysis;
5+
using Semmle.Util.Logging;
6+
7+
namespace Semmle.Extraction
8+
{
9+
public class BinaryLogExtractionContext : ExtractionContext
10+
{
11+
private readonly IEnumerable<SyntaxTree> generatedSyntaxTrees;
12+
private readonly string compilationIdentifier;
13+
private readonly string generatedFolderName;
14+
15+
public BinaryLogExtractionContext(string cwd, string[] args, string outputPath,
16+
IEnumerable<SyntaxTree> generatedSyntaxTrees, string compilationIdentifier,
17+
ILogger logger, PathTransformer pathTransformer, bool isQlTest)
18+
: base(cwd, args, outputPath, [], logger, pathTransformer, ExtractorMode.BinaryLog, isQlTest)
19+
{
20+
this.generatedSyntaxTrees = generatedSyntaxTrees;
21+
this.compilationIdentifier = compilationIdentifier;
22+
23+
// Compute a unique folder name for the generated files:
24+
generatedFolderName = "generated";
25+
26+
if (Directory.Exists(generatedFolderName))
27+
{
28+
var counter = 0;
29+
do
30+
{
31+
generatedFolderName = $"generated{counter++}";
32+
}
33+
while (Directory.Exists(generatedFolderName));
34+
}
35+
}
36+
37+
private string? GetAdjustedPath(string path)
38+
{
39+
var syntaxTree = generatedSyntaxTrees.FirstOrDefault(t => t.FilePath == path);
40+
if (syntaxTree is null)
41+
{
42+
return null;
43+
}
44+
45+
return Path.Join(generatedFolderName, compilationIdentifier, path);
46+
}
47+
48+
public static string? GetAdjustedPath(ExtractionContext extractionContext, string sourcePath)
49+
{
50+
if (extractionContext.Mode.HasFlag(ExtractorMode.BinaryLog)
51+
&& extractionContext is BinaryLogExtractionContext binaryLogExtractionContext
52+
&& binaryLogExtractionContext.GetAdjustedPath(sourcePath) is string adjustedPath)
53+
{
54+
return adjustedPath;
55+
}
56+
57+
return null;
58+
}
59+
}
60+
}

csharp/extractor/Semmle.Extraction/TrapWriter.cs

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,42 @@ public TrapWriter(ILogger logger, PathTransformer.ITransformedPath outputfile, s
105105
/// <param name="transformedPath">The transformed path to the input file.</param>
106106
/// <param name="inputEncoding">The encoding used by the input file.</param>
107107
public void Archive(string originalPath, PathTransformer.ITransformedPath transformedPath, Encoding inputEncoding)
108+
{
109+
Archive(() =>
110+
{
111+
var fullInputPath = Path.GetFullPath(originalPath);
112+
return File.ReadAllText(fullInputPath, inputEncoding);
113+
}, transformedPath);
114+
}
115+
116+
public void ArchiveContent(string contents, PathTransformer.ITransformedPath transformedPath)
117+
{
118+
Archive(() => contents, transformedPath);
119+
}
120+
121+
private void Archive(Func<string> getContent, PathTransformer.ITransformedPath transformedPath)
108122
{
109123
if (string.IsNullOrEmpty(archive))
124+
{
110125
return;
126+
}
111127

112-
// Calling GetFullPath makes this use the canonical capitalisation, if the file exists.
113-
var fullInputPath = Path.GetFullPath(originalPath);
128+
var dest = FileUtils.NestPaths(logger, archive, transformedPath.Value);
129+
try
130+
{
131+
var tmpSrcFile = Path.GetTempFileName();
132+
File.WriteAllText(tmpSrcFile, getContent(), utf8);
114133

115-
ArchivePath(fullInputPath, transformedPath, inputEncoding);
134+
FileUtils.MoveOrReplace(tmpSrcFile, dest);
135+
}
136+
catch (Exception ex)
137+
{
138+
// If this happened, it was probably because
139+
// - the same file was compiled multiple times, or
140+
// - the file doesn't exist (due to wrong #line directive or because it's an in-memory source generated AST).
141+
// In any case, this is not a fatal error.
142+
logger.LogWarning("Problem archiving " + dest + ": " + ex);
143+
}
116144
}
117145

118146
/// <summary>
@@ -185,37 +213,6 @@ public void Emit(ITrapEmitter emitter)
185213
emitter.EmitTrap(Writer);
186214
}
187215

188-
/// <summary>
189-
/// Attempts to archive the specified input file to the normal area of the source archive.
190-
/// The file's path must be sufficiently short so as to render the path of its copy in the
191-
/// source archive less than the system path limit of 260 characters.
192-
/// </summary>
193-
/// <param name="fullInputPath">The full path to the input file.</param>
194-
/// <param name="transformedPath">The transformed path to the input file.</param>
195-
/// <param name="inputEncoding">The encoding used by the input file.</param>
196-
/// <exception cref="PathTooLongException">If the output path in the source archive would
197-
/// exceed the system path limit of 260 characters.</exception>
198-
private void ArchivePath(string fullInputPath, PathTransformer.ITransformedPath transformedPath, Encoding inputEncoding)
199-
{
200-
var dest = FileUtils.NestPaths(logger, archive, transformedPath.Value);
201-
try
202-
{
203-
var contents = File.ReadAllText(fullInputPath, inputEncoding);
204-
var tmpSrcFile = Path.GetTempFileName();
205-
File.WriteAllText(tmpSrcFile, contents, utf8);
206-
207-
FileUtils.MoveOrReplace(tmpSrcFile, dest);
208-
}
209-
catch (Exception ex)
210-
{
211-
// If this happened, it was probably because
212-
// - the same file was compiled multiple times, or
213-
// - the file doesn't exist (due to wrong #line directive or because it's an in-memory source generated AST).
214-
// In any case, this is not a fatal error.
215-
logger.LogWarning("Problem archiving " + dest + ": " + ex);
216-
}
217-
}
218-
219216
private static string TrapExtension(CompressionMode compression)
220217
{
221218
switch (compression)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
| Program.cs:0:0:0:0 | Program.cs |
2-
| System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs:0:0:0:0 | System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs |
2+
| generated/test.csproj (net8.0)/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs:0:0:0:0 | generated/test.csproj (net8.0)/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs |
33
| obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs:0:0:0:0 | obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs |
44
| obj/Debug/net8.0/test.AssemblyInfo.cs:0:0:0:0 | obj/Debug/net8.0/test.AssemblyInfo.cs |
55
| obj/Debug/net8.0/test.GlobalUsings.g.cs:0:0:0:0 | obj/Debug/net8.0/test.GlobalUsings.g.cs |

0 commit comments

Comments
 (0)