Skip to content

Commit 5fca946

Browse files
committed
C#: Split 'Context' class between CIL and source extraction
1 parent bf66bdb commit 5fca946

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+624
-576
lines changed

csharp/extractor/Semmle.Extraction.CIL/Entities/Base/Tuple.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public Tuple(string name, params object[] args)
1414

1515
public void Extract(Context cx)
1616
{
17-
cx.Cx.Emit(tuple);
17+
cx.Cx.TrapWriter.Emit(tuple);
1818
}
1919

2020
public override string ToString() => tuple.ToString();

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ private void DoAnalyseReferenceAssembly(PortableExecutableReference r)
292292
AnalyseNamespace(cx, module.GlobalNamespace);
293293
}
294294

295-
Entities.Attribute.ExtractAttributes(cx, assembly, Extraction.Entities.Assembly.Create(cx, assembly.GetSymbolLocation()));
295+
Entities.Attribute.ExtractAttributes(cx, assembly, Entities.Assembly.Create(cx, assembly.GetSymbolLocation()));
296296

297297
cx.PopulateAll();
298298
}
@@ -374,7 +374,7 @@ private void DoExtractTree(SyntaxTree tree)
374374
var cx = new Context(extractor, compilation.Clone(), trapWriter, new SourceScope(tree), AddAssemblyTrapPrefix);
375375
// Ensure that the file itself is populated in case the source file is totally empty
376376
var root = tree.GetRoot();
377-
Extraction.Entities.File.Create(cx, root.SyntaxTree.FilePath);
377+
Entities.File.Create(cx, root.SyntaxTree.FilePath);
378378

379379
var csNode = (CSharpSyntaxNode)root;
380380
csNode.Accept(new CompilationUnitVisitor(cx));
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using Microsoft.CodeAnalysis;
2+
3+
namespace Semmle.Extraction.CSharp
4+
{
5+
/// <summary>
6+
/// A factory for creating cached entities.
7+
/// </summary>
8+
public abstract class CachedEntityFactory<TInit, TEntity>
9+
: Extraction.CachedEntityFactory<TInit, TEntity> where TEntity : CachedEntity
10+
{
11+
/// <summary>
12+
/// Initializes the entity, but does not generate any trap code.
13+
/// </summary>
14+
public sealed override TEntity Create(Extraction.Context cx, TInit init)
15+
{
16+
return Create((Context)cx, init);
17+
}
18+
19+
public abstract TEntity Create(Context cx, TInit init);
20+
}
21+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace Semmle.Extraction.CSharp
2+
{
3+
/// <summary>
4+
/// Describes the relationship between a comment and a program element.
5+
/// </summary>
6+
public enum CommentBinding
7+
{
8+
Parent, // The parent element of a comment
9+
Best, // The most likely element associated with a comment
10+
Before, // The element before the comment
11+
After // The element after the comment
12+
};
13+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.Text;
3+
using Semmle.Extraction.CSharp.Entities;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
7+
namespace Semmle.Extraction.CSharp.Comments
8+
{
9+
internal class CommentBlock
10+
{
11+
private readonly List<CommentLine> lines;
12+
13+
public IEnumerable<CommentLine> CommentLines => lines;
14+
15+
public Location Location { get; private set; }
16+
17+
public CommentBlock(CommentLine firstLine)
18+
{
19+
lines = new List<CommentLine> { firstLine };
20+
Location = firstLine.Location;
21+
}
22+
23+
/// <summary>
24+
/// Determine whether commentlines should be merged.
25+
/// </summary>
26+
/// <param name="newLine">A comment line to be appended to this comment block.</param>
27+
/// <returns>Whether the new line should be appended to this block.</returns>
28+
public bool CombinesWith(CommentLine newLine)
29+
{
30+
if (!CommentLines.Any())
31+
return true;
32+
33+
var sameFile = Location.SourceTree == newLine.Location.SourceTree;
34+
var sameRow = Location.EndLine() == newLine.Location.StartLine();
35+
var sameColumn = Location.EndLine() + 1 == newLine.Location.StartLine();
36+
var nextRow = Location.StartColumn() == newLine.Location.StartColumn();
37+
var adjacent = sameFile && (sameRow || (sameColumn && nextRow));
38+
39+
return
40+
newLine.Type == CommentLineType.MultilineContinuation ||
41+
adjacent;
42+
}
43+
44+
/// <summary>
45+
/// Adds a comment line to the this comment block.
46+
/// </summary>
47+
/// <param name="line">The line to add.</param>
48+
public void AddCommentLine(CommentLine line)
49+
{
50+
Location = !lines.Any()
51+
? line.Location
52+
: Location.Create(
53+
line.Location.SourceTree!,
54+
new TextSpan(Location.SourceSpan.Start, line.Location.SourceSpan.End - Location.SourceSpan.Start));
55+
56+
lines.Add(line);
57+
}
58+
}
59+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace Semmle.Extraction.CSharp
2+
{
3+
/// <summary>
4+
/// The type of a single comment line.
5+
/// </summary>
6+
public enum CommentLineType
7+
{
8+
Singleline, // Comment starting // ...
9+
XmlDoc, // Comment starting /// ...
10+
Multiline, // Comment starting /* ..., even if the comment only spans one line.
11+
MultilineContinuation // The second and subsequent lines of comment in a multiline comment.
12+
};
13+
}

csharp/extractor/Semmle.Extraction/CommentProcessing.cs renamed to csharp/extractor/Semmle.Extraction.CSharp/Comments/CommentProcessor.cs

Lines changed: 25 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
11
using Microsoft.CodeAnalysis;
2-
using Microsoft.CodeAnalysis.Text;
2+
using Semmle.Extraction.CSharp.Entities;
33
using Semmle.Util;
44
using System.Collections.Generic;
55
using System.Linq;
66

7-
namespace Semmle.Extraction.CommentProcessing
7+
namespace Semmle.Extraction.CSharp
88
{
99
/// <summary>
1010
/// Implements the comment processor for associating comments with program elements.
1111
/// Registers locations of comments and program elements,
1212
/// then generates binding information.
1313
/// </summary>
14-
internal class CommentProcessor : ICommentGenerator
14+
internal class CommentProcessor
1515
{
16-
public void AddComment(ICommentLine comment)
16+
public void AddComment(CommentLine comment)
1717
{
1818
comments[comment.Location] = comment;
1919
}
2020

2121
// Comments sorted by location.
22-
private readonly SortedDictionary<Location, ICommentLine> comments = new SortedDictionary<Location, ICommentLine>(new LocationComparer());
22+
private readonly SortedDictionary<Location, CommentLine> comments = new SortedDictionary<Location, CommentLine>(new LocationComparer());
2323

2424
// Program elements sorted by location.
2525
private readonly SortedDictionary<Location, Label> elements = new SortedDictionary<Location, Label>(new LocationComparer());
2626

2727
private readonly Dictionary<Label, Key> duplicationGuardKeys = new Dictionary<Label, Key>();
2828

29-
private Key? GetDuplicationGuardKey(Label label)
29+
private Key GetDuplicationGuardKey(Label label)
3030
{
3131
if (duplicationGuardKeys.TryGetValue(label, out var duplicationGuardKey))
3232
return duplicationGuardKey;
@@ -35,7 +35,7 @@ public void AddComment(ICommentLine comment)
3535

3636
private class LocationComparer : IComparer<Location>
3737
{
38-
public int Compare(Location? l1, Location? l2) => CommentProcessor.Compare(l1, l2);
38+
public int Compare(Location l1, Location l2) => CommentProcessor.Compare(l1, l2);
3939
}
4040

4141
/// <summary>
@@ -44,7 +44,7 @@ private class LocationComparer : IComparer<Location>
4444
/// <param name="l1">First location</param>
4545
/// <param name="l2">Second location</param>
4646
/// <returns>&lt;0 if l1 before l2, &gt;0 if l1 after l2, else 0.</returns>
47-
private static int Compare(Location? l1, Location? l2)
47+
private static int Compare(Location l1, Location l2)
4848
{
4949
if (object.ReferenceEquals(l1, l2))
5050
return 0;
@@ -68,7 +68,7 @@ private static int Compare(Location? l1, Location? l2)
6868
/// <param name="elementLabel">The label of the element in the trap file.</param>
6969
/// <param name="duplicationGuardKey">The duplication guard key of the element, if any.</param>
7070
/// <param name="loc">The location of the element.</param>
71-
public void AddElement(Label elementLabel, Key? duplicationGuardKey, Location loc)
71+
public void AddElement(Label elementLabel, Key duplicationGuardKey, Location loc)
7272
{
7373
if (loc != null && loc.IsInSource)
7474
elements[loc] = elementLabel;
@@ -78,7 +78,7 @@ public void AddElement(Label elementLabel, Key? duplicationGuardKey, Location lo
7878

7979
// Ensure that commentBlock and element refer to the same file
8080
// which can happen when processing multiple files.
81-
private static void EnsureSameFile(ICommentBlock commentBlock, ref KeyValuePair<Location, Label>? element)
81+
private static void EnsureSameFile(Comments.CommentBlock commentBlock, ref KeyValuePair<Location, Label>? element)
8282
{
8383
if (element != null && element.Value.Key.SourceTree != commentBlock.Location.SourceTree)
8484
element = null;
@@ -95,7 +95,7 @@ private static void EnsureSameFile(ICommentBlock commentBlock, ref KeyValuePair<
9595
/// <param name="parentElement">The parent element of the comment block.</param>
9696
/// <param name="callback">Output binding information.</param>
9797
private void GenerateBindings(
98-
ICommentBlock commentBlock,
98+
Comments.CommentBlock commentBlock,
9999
KeyValuePair<Location, Label>? previousElement,
100100
KeyValuePair<Location, Label>? nextElement,
101101
KeyValuePair<Location, Label>? parentElement,
@@ -231,7 +231,7 @@ public void Push(KeyValuePair<Location, Label> value)
231231

232232
// Generate binding information for one CommentBlock.
233233
private void GenerateBindings(
234-
ICommentBlock block,
234+
Comments.CommentBlock block,
235235
ElementStack elementStack,
236236
KeyValuePair<Location, Label>? nextElement,
237237
CommentBindingCallback cb
@@ -259,25 +259,25 @@ CommentBindingCallback cb
259259
/// <param name="cb">Where to send the results.</param>
260260
/// <returns>true if there are more comments to process, false otherwise.</returns>
261261
private bool GenerateBindings(
262-
IEnumerator<KeyValuePair<Location, ICommentLine>> commentEnumerator,
262+
IEnumerator<KeyValuePair<Location, CommentLine>> commentEnumerator,
263263
KeyValuePair<Location, Label>? nextElement,
264264
ElementStack elementStack,
265265
CommentBindingCallback cb
266266
)
267267
{
268-
CommentBlock? block = null;
268+
Comments.CommentBlock block = null;
269269

270270
// Iterate comments until the commentEnumerator has gone past nextElement
271271
while (nextElement == null || Compare(commentEnumerator.Current.Value.Location, nextElement.Value.Key) < 0)
272272
{
273273
if (block is null)
274-
block = new CommentBlock(commentEnumerator.Current.Value);
274+
block = new Comments.CommentBlock(commentEnumerator.Current.Value);
275275

276276
if (!block.CombinesWith(commentEnumerator.Current.Value))
277277
{
278278
// Start of a new block, so generate the bindings for the old block first.
279279
GenerateBindings(block, elementStack, nextElement, cb);
280-
block = new CommentBlock(commentEnumerator.Current.Value);
280+
block = new Comments.CommentBlock(commentEnumerator.Current.Value);
281281
}
282282
else
283283
{
@@ -320,7 +320,7 @@ public void GenerateBindings(CommentBindingCallback cb)
320320
var elementStack = new ElementStack();
321321

322322
using IEnumerator<KeyValuePair<Location, Label>> elementEnumerator = elements.GetEnumerator();
323-
using IEnumerator<KeyValuePair<Location, ICommentLine>> commentEnumerator = comments.GetEnumerator();
323+
using IEnumerator<KeyValuePair<Location, CommentLine>> commentEnumerator = comments.GetEnumerator();
324324
if (!commentEnumerator.MoveNext())
325325
{
326326
// There are no comments to process.
@@ -343,54 +343,12 @@ public void GenerateBindings(CommentBindingCallback cb)
343343
}
344344
}
345345

346-
internal class CommentBlock : ICommentBlock
347-
{
348-
private readonly List<ICommentLine> lines;
349-
350-
public IEnumerable<ICommentLine> CommentLines => lines;
351-
352-
public Location Location { get; private set; }
353-
354-
public CommentBlock(ICommentLine firstLine)
355-
{
356-
lines = new List<ICommentLine> { firstLine };
357-
Location = firstLine.Location;
358-
}
359-
360-
/// <summary>
361-
/// Determine whether commentlines should be merged.
362-
/// </summary>
363-
/// <param name="newLine">A comment line to be appended to this comment block.</param>
364-
/// <returns>Whether the new line should be appended to this block.</returns>
365-
public bool CombinesWith(ICommentLine newLine)
366-
{
367-
if (!CommentLines.Any())
368-
return true;
369-
370-
var sameFile = Location.SourceTree == newLine.Location.SourceTree;
371-
var sameRow = Location.EndLine() == newLine.Location.StartLine();
372-
var sameColumn = Location.EndLine() + 1 == newLine.Location.StartLine();
373-
var nextRow = Location.StartColumn() == newLine.Location.StartColumn();
374-
var adjacent = sameFile && (sameRow || (sameColumn && nextRow));
375-
376-
return
377-
newLine.Type == CommentLineType.MultilineContinuation ||
378-
adjacent;
379-
}
380-
381-
/// <summary>
382-
/// Adds a comment line to the this comment block.
383-
/// </summary>
384-
/// <param name="line">The line to add.</param>
385-
public void AddCommentLine(ICommentLine line)
386-
{
387-
Location = !lines.Any()
388-
? line.Location
389-
: Location.Create(
390-
line.Location.SourceTree!,
391-
new TextSpan(Location.SourceSpan.Start, line.Location.SourceSpan.End - Location.SourceSpan.Start));
392-
393-
lines.Add(line);
394-
}
395-
}
346+
/// <summary>
347+
/// Callback for generated comment associations.
348+
/// </summary>
349+
/// <param name="elementLabel">The label of the element</param>
350+
/// <param name="duplicationGuardKey">The duplication guard key of the element, if any</param>
351+
/// <param name="commentBlock">The comment block associated with the element</param>
352+
/// <param name="binding">The relationship between the commentblock and the element</param>
353+
internal delegate void CommentBindingCallback(Label elementLabel, Key duplicationGuardKey, Comments.CommentBlock commentBlock, CommentBinding binding);
396354
}

0 commit comments

Comments
 (0)