Skip to content

Commit efab3bf

Browse files
committed
C#: Make an extractor class in the standalone project with some of the specifics for the standalone extractor.
1 parent d2c8720 commit efab3bf

File tree

3 files changed

+153
-136
lines changed

3 files changed

+153
-136
lines changed
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
using System;
2+
using System.Collections.Concurrent;
3+
using System.Collections.Generic;
4+
using System.Diagnostics;
5+
using System.Linq;
6+
using Microsoft.CodeAnalysis;
7+
using Microsoft.CodeAnalysis.CSharp;
8+
using Semmle.Util;
9+
using Semmle.Util.Logging;
10+
11+
namespace Semmle.Extraction.CSharp.Standalone
12+
{
13+
public static class Extractor
14+
{
15+
16+
private static IEnumerable<Action> GetResolvedReferencesStandalone(IEnumerable<string> referencePaths, BlockingCollection<MetadataReference> references)
17+
{
18+
return referencePaths.Select<string, Action>(path => () =>
19+
{
20+
var reference = MetadataReference.CreateFromFile(path);
21+
references.Add(reference);
22+
});
23+
}
24+
25+
private static void AnalyseStandalone(
26+
StandaloneAnalyser analyser,
27+
IEnumerable<string> sources,
28+
IEnumerable<string> referencePaths,
29+
CommonOptions options,
30+
IProgressMonitor progressMonitor,
31+
Stopwatch stopwatch)
32+
{
33+
CSharp.Extractor.Analyse(stopwatch, analyser, options,
34+
references => GetResolvedReferencesStandalone(referencePaths, references),
35+
(analyser, syntaxTrees) => CSharp.Extractor.ReadSyntaxTrees(sources, analyser, null, null, syntaxTrees),
36+
(syntaxTrees, references) => CSharpCompilation.Create("csharp.dll", syntaxTrees, references),
37+
(compilation, options) => analyser.InitializeStandalone(compilation, options),
38+
() => { },
39+
_ => { },
40+
() =>
41+
{
42+
foreach (var type in analyser.MissingNamespaces)
43+
{
44+
progressMonitor.MissingNamespace(type);
45+
}
46+
47+
foreach (var type in analyser.MissingTypes)
48+
{
49+
progressMonitor.MissingType(type);
50+
}
51+
52+
progressMonitor.MissingSummary(analyser.MissingTypes.Count(), analyser.MissingNamespaces.Count());
53+
});
54+
}
55+
56+
private static void ExtractStandalone(
57+
IEnumerable<string> sources,
58+
IEnumerable<string> referencePaths,
59+
IProgressMonitor pm,
60+
ILogger logger,
61+
CommonOptions options)
62+
{
63+
var stopwatch = new Stopwatch();
64+
stopwatch.Start();
65+
66+
var canonicalPathCache = CanonicalPathCache.Create(logger, 1000);
67+
var pathTransformer = new PathTransformer(canonicalPathCache);
68+
69+
using var analyser = new StandaloneAnalyser(pm, logger, false, pathTransformer);
70+
try
71+
{
72+
AnalyseStandalone(analyser, sources, referencePaths, options, pm, stopwatch);
73+
}
74+
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
75+
{
76+
analyser.Logger.Log(Severity.Error, " Unhandled exception: {0}", ex);
77+
}
78+
}
79+
80+
private class ExtractionProgress : IProgressMonitor
81+
{
82+
public ExtractionProgress(ILogger output)
83+
{
84+
logger = output;
85+
}
86+
87+
private readonly ILogger logger;
88+
89+
public void Analysed(int item, int total, string source, string output, TimeSpan time, AnalysisAction action)
90+
{
91+
logger.Log(Severity.Info, "[{0}/{1}] {2} ({3})", item, total, source,
92+
action == AnalysisAction.Extracted
93+
? time.ToString()
94+
: action == AnalysisAction.Excluded
95+
? "excluded"
96+
: "up to date");
97+
}
98+
99+
public void MissingType(string type)
100+
{
101+
logger.Log(Severity.Debug, "Missing type {0}", type);
102+
}
103+
104+
public void MissingNamespace(string @namespace)
105+
{
106+
logger.Log(Severity.Info, "Missing namespace {0}", @namespace);
107+
}
108+
109+
public void MissingSummary(int missingTypes, int missingNamespaces)
110+
{
111+
logger.Log(Severity.Info, "Failed to resolve {0} types in {1} namespaces", missingTypes, missingNamespaces);
112+
}
113+
}
114+
115+
public static ExitCode Run(Options options)
116+
{
117+
var stopwatch = new Stopwatch();
118+
stopwatch.Start();
119+
120+
using var logger = new ConsoleLogger(options.Verbosity);
121+
logger.Log(Severity.Info, "Running C# standalone extractor");
122+
using var a = new Analysis(logger, options);
123+
var sourceFileCount = a.Extraction.Sources.Count;
124+
125+
if (sourceFileCount == 0)
126+
{
127+
logger.Log(Severity.Error, "No source files found");
128+
return ExitCode.Errors;
129+
}
130+
131+
if (!options.SkipExtraction)
132+
{
133+
using var fileLogger = CSharp.Extractor.MakeLogger(options.Verbosity, false);
134+
135+
logger.Log(Severity.Info, "");
136+
logger.Log(Severity.Info, "Extracting...");
137+
ExtractStandalone(
138+
a.Extraction.Sources,
139+
a.References,
140+
new ExtractionProgress(logger),
141+
fileLogger,
142+
options);
143+
logger.Log(Severity.Info, $"Extraction completed in {stopwatch.Elapsed}");
144+
}
145+
146+
return ExitCode.Ok;
147+
}
148+
}
149+
}

csharp/extractor/Semmle.Extraction.CSharp.Standalone/Program.cs

Lines changed: 2 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -51,42 +51,9 @@ public void Dispose()
5151

5252
public class Program
5353
{
54-
public static ExitCode Run(Options options)
55-
{
56-
var stopwatch = new Stopwatch();
57-
stopwatch.Start();
58-
59-
using var logger = new ConsoleLogger(options.Verbosity);
60-
logger.Log(Severity.Info, "Running C# standalone extractor");
61-
using var a = new Analysis(logger, options);
62-
var sourceFileCount = a.Extraction.Sources.Count;
63-
64-
if (sourceFileCount == 0)
65-
{
66-
logger.Log(Severity.Error, "No source files found");
67-
return ExitCode.Errors;
68-
}
69-
70-
if (!options.SkipExtraction)
71-
{
72-
using var fileLogger = Extractor.MakeLogger(options.Verbosity, false);
73-
74-
logger.Log(Severity.Info, "");
75-
logger.Log(Severity.Info, "Extracting...");
76-
Extractor.ExtractStandalone(
77-
a.Extraction.Sources,
78-
a.References,
79-
new ExtractionProgress(logger),
80-
fileLogger,
81-
options);
82-
logger.Log(Severity.Info, $"Extraction completed in {stopwatch.Elapsed}");
83-
}
84-
return ExitCode.Ok;
85-
}
86-
8754
public static int Main(string[] args)
8855
{
89-
Extractor.SetInvariantCulture();
56+
CSharp.Extractor.SetInvariantCulture();
9057

9158
var options = Options.Create(args);
9259
// options.CIL = true; // To do: Enable this
@@ -100,42 +67,7 @@ public static int Main(string[] args)
10067
if (options.Errors)
10168
return 1;
10269

103-
return (int)Run(options);
104-
}
105-
106-
private class ExtractionProgress : IProgressMonitor
107-
{
108-
public ExtractionProgress(ILogger output)
109-
{
110-
logger = output;
111-
}
112-
113-
private readonly ILogger logger;
114-
115-
public void Analysed(int item, int total, string source, string output, TimeSpan time, AnalysisAction action)
116-
{
117-
logger.Log(Severity.Info, "[{0}/{1}] {2} ({3})", item, total, source,
118-
action == AnalysisAction.Extracted
119-
? time.ToString()
120-
: action == AnalysisAction.Excluded
121-
? "excluded"
122-
: "up to date");
123-
}
124-
125-
public void MissingType(string type)
126-
{
127-
logger.Log(Severity.Debug, "Missing type {0}", type);
128-
}
129-
130-
public void MissingNamespace(string @namespace)
131-
{
132-
logger.Log(Severity.Info, "Missing namespace {0}", @namespace);
133-
}
134-
135-
public void MissingSummary(int missingTypes, int missingNamespaces)
136-
{
137-
logger.Log(Severity.Info, "Failed to resolve {0} types in {1} namespaces", missingTypes, missingNamespaces);
138-
}
70+
return (int)Extractor.Run(options);
13971
}
14072
}
14173
}

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

Lines changed: 2 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ private static IEnumerable<Action> ResolveReferences(Microsoft.CodeAnalysis.Comm
281281
/// The constructed syntax trees will be added (thread-safely) to the supplied
282282
/// list <paramref name="ret"/>.
283283
/// </summary>
284-
private static IEnumerable<Action> ReadSyntaxTrees(IEnumerable<string> sources, Analyser analyser, CSharpParseOptions? parseOptions, Encoding? encoding, IList<SyntaxTree> ret)
284+
public static IEnumerable<Action> ReadSyntaxTrees(IEnumerable<string> sources, Analyser analyser, CSharpParseOptions? parseOptions, Encoding? encoding, IList<SyntaxTree> ret)
285285
{
286286
return sources.Select<string, Action>(path => () =>
287287
{
@@ -303,31 +303,7 @@ private static IEnumerable<Action> ReadSyntaxTrees(IEnumerable<string> sources,
303303
});
304304
}
305305

306-
public static void ExtractStandalone(
307-
IEnumerable<string> sources,
308-
IEnumerable<string> referencePaths,
309-
IProgressMonitor pm,
310-
ILogger logger,
311-
CommonOptions options)
312-
{
313-
var stopwatch = new Stopwatch();
314-
stopwatch.Start();
315-
316-
var canonicalPathCache = CanonicalPathCache.Create(logger, 1000);
317-
var pathTransformer = new PathTransformer(canonicalPathCache);
318-
319-
using var analyser = new StandaloneAnalyser(pm, logger, false, pathTransformer);
320-
try
321-
{
322-
AnalyseStandalone(analyser, sources, referencePaths, options, pm, stopwatch);
323-
}
324-
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
325-
{
326-
analyser.Logger.Log(Severity.Error, " Unhandled exception: {0}", ex);
327-
}
328-
}
329-
330-
private static ExitCode Analyse(Stopwatch stopwatch, Analyser analyser, CommonOptions options,
306+
public static ExitCode Analyse(Stopwatch stopwatch, Analyser analyser, CommonOptions options,
331307
Func<BlockingCollection<MetadataReference>, IEnumerable<Action>> getResolvedReferenceTasks,
332308
Func<Analyser, List<SyntaxTree>, IEnumerable<Action>> getSyntaxTreeTasks,
333309
Func<IEnumerable<SyntaxTree>, IEnumerable<MetadataReference>, CSharpCompilation> getCompilation,
@@ -400,37 +376,6 @@ private static ExitCode Analyse(Stopwatch stopwatch, Analyser analyser, CommonOp
400376
return analyser.TotalErrors == 0 ? ExitCode.Ok : ExitCode.Errors;
401377
}
402378

403-
private static void AnalyseStandalone(
404-
StandaloneAnalyser analyser,
405-
IEnumerable<string> sources,
406-
IEnumerable<string> referencePaths,
407-
CommonOptions options,
408-
IProgressMonitor progressMonitor,
409-
Stopwatch stopwatch)
410-
{
411-
Analyse(stopwatch, analyser, options,
412-
references => GetResolvedReferencesStandalone(referencePaths, references),
413-
(analyser, syntaxTrees) => ReadSyntaxTrees(sources, analyser, null, null, syntaxTrees),
414-
(syntaxTrees, references) => CSharpCompilation.Create("csharp.dll", syntaxTrees, references),
415-
(compilation, options) => analyser.InitializeStandalone(compilation, options),
416-
() => { },
417-
_ => { },
418-
() =>
419-
{
420-
foreach (var type in analyser.MissingNamespaces)
421-
{
422-
progressMonitor.MissingNamespace(type);
423-
}
424-
425-
foreach (var type in analyser.MissingTypes)
426-
{
427-
progressMonitor.MissingType(type);
428-
}
429-
430-
progressMonitor.MissingSummary(analyser.MissingTypes.Count(), analyser.MissingNamespaces.Count());
431-
});
432-
}
433-
434379
private static ExitCode AnalyseTracing(
435380
TracingAnalyser analyser,
436381
CSharpCommandLineArguments compilerArguments,
@@ -473,15 +418,6 @@ private static ExitCode AnalyseTracing(
473418
() => { });
474419
}
475420

476-
private static IEnumerable<Action> GetResolvedReferencesStandalone(IEnumerable<string> referencePaths, BlockingCollection<MetadataReference> references)
477-
{
478-
return referencePaths.Select<string, Action>(path => () =>
479-
{
480-
var reference = MetadataReference.CreateFromFile(path);
481-
references.Add(reference);
482-
});
483-
}
484-
485421
/// <summary>
486422
/// Gets the path to the `csharp.log` file written to by the C# extractor.
487423
/// </summary>

0 commit comments

Comments
 (0)