Skip to content

Commit 1c2b9f9

Browse files
authored
Merge pull request github#4669 from tamasvajk/feature/csharp9-global-stmt
C#: Extract global statements
2 parents eb8309a + 9c2ca93 commit 1c2b9f9

File tree

18 files changed

+260
-61
lines changed

18 files changed

+260
-61
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,14 @@ public override void Populate(TextWriter trapFile)
112112
foreach (var l in symbol.Locations)
113113
trapFile.param_location(this, Context.CreateLocation(l));
114114

115+
if (!symbol.Locations.Any() &&
116+
symbol.ContainingSymbol is IMethodSymbol ms &&
117+
ms.Name == WellKnownMemberNames.TopLevelStatementsEntryPointMethodName &&
118+
ms.ContainingType.Name == WellKnownMemberNames.TopLevelStatementsEntryPointTypeName)
119+
{
120+
trapFile.param_location(this, Context.CreateLocation());
121+
}
122+
115123
if (!IsSourceDeclaration || !symbol.FromSource())
116124
return;
117125

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,41 @@
11
using Microsoft.CodeAnalysis.CSharp.Syntax;
22
using Microsoft.CodeAnalysis.CSharp;
3+
using System.IO;
34

45
namespace Semmle.Extraction.CSharp.Entities
56
{
67
internal abstract class Statement : FreshEntity, IExpressionParentEntity, IStatementParentEntity
78
{
8-
protected Statement(Context cx) : base(cx) { }
9-
10-
public static Statement Create(Context cx, StatementSyntax node, Statement parent, int child) =>
9+
private readonly int child;
10+
private readonly Kinds.StmtKind kind;
11+
private readonly IStatementParentEntity parent;
12+
13+
protected Statement(Context cx, Kinds.StmtKind kind, IStatementParentEntity parent, int child)
14+
: base(cx)
15+
{
16+
this.kind = kind;
17+
this.parent = parent;
18+
this.child = child;
19+
}
20+
21+
protected override void Populate(TextWriter trapFile)
22+
{
23+
trapFile.statements(this, kind);
24+
if (parent.IsTopLevelParent)
25+
{
26+
trapFile.stmt_parent_top_level(this, child, parent);
27+
}
28+
else
29+
{
30+
trapFile.stmt_parent(this, child, parent);
31+
}
32+
33+
PopulateStatement(trapFile);
34+
}
35+
36+
protected abstract void PopulateStatement(TextWriter trapFile);
37+
38+
public static Statement Create(Context cx, StatementSyntax node, IStatementParentEntity parent, int child) =>
1139
Statements.Factory.Create(cx, node, parent, child);
1240

1341
/// <summary>
@@ -16,14 +44,10 @@ public static Statement Create(Context cx, StatementSyntax node, Statement paren
1644
/// </summary>
1745
public virtual int NumberOfStatements => 1;
1846

19-
public override Microsoft.CodeAnalysis.Location ReportingLocation => GetStatementSyntax().GetLocation();
20-
2147
bool IExpressionParentEntity.IsTopLevelParent => false;
2248

2349
bool IStatementParentEntity.IsTopLevelParent => false;
2450

25-
protected abstract CSharpSyntaxNode GetStatementSyntax();
26-
2751
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NeedsLabel;
2852
}
2953
}

csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,39 +8,27 @@ namespace Semmle.Extraction.CSharp.Entities
88
internal abstract class Statement<TSyntax> : Statement where TSyntax : CSharpSyntaxNode
99
{
1010
protected readonly TSyntax Stmt;
11-
private readonly int child;
12-
private readonly Kinds.StmtKind kind;
13-
private readonly IStatementParentEntity parent;
1411
private readonly Location location;
1512

16-
protected override CSharpSyntaxNode GetStatementSyntax() => Stmt;
17-
1813
protected Statement(Context cx, TSyntax stmt, Kinds.StmtKind kind, IStatementParentEntity parent, int child, Location location)
19-
: base(cx)
14+
: base(cx, kind, parent, child)
2015
{
2116
Stmt = stmt;
22-
this.parent = parent;
23-
this.child = child;
2417
this.location = location;
25-
this.kind = kind;
2618
cx.BindComments(this, location.symbol);
2719
}
2820

21+
protected Statement(Context cx, TSyntax stmt, Kinds.StmtKind kind, IStatementParentEntity parent, int child)
22+
: this(cx, stmt, kind, parent, child, cx.CreateLocation(stmt.FixedLocation())) { }
23+
2924
protected sealed override void Populate(TextWriter trapFile)
3025
{
31-
trapFile.statements(this, kind);
32-
if (parent.IsTopLevelParent)
33-
trapFile.stmt_parent_top_level(this, child, parent);
34-
else
35-
trapFile.stmt_parent(this, child, parent);
26+
base.Populate(trapFile);
27+
3628
trapFile.stmt_location(this, location);
37-
PopulateStatement(trapFile);
3829
}
3930

40-
protected abstract void PopulateStatement(TextWriter trapFile);
41-
42-
protected Statement(Context cx, TSyntax stmt, Kinds.StmtKind kind, IStatementParentEntity parent, int child)
43-
: this(cx, stmt, kind, parent, child, cx.CreateLocation(stmt.FixedLocation())) { }
31+
public override Microsoft.CodeAnalysis.Location ReportingLocation => Stmt.GetLocation();
4432

4533
public override string ToString() => Label.ToString();
4634
}

csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Factory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
55
{
66
internal static class Factory
77
{
8-
internal static Statement Create(Context cx, StatementSyntax node, Statement parent, int child)
8+
internal static Statement Create(Context cx, StatementSyntax node, IStatementParentEntity parent, int child)
99
{
1010
switch (node.Kind())
1111
{
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using Semmle.Extraction.Kinds;
2+
using System.Linq;
3+
using System.IO;
4+
using Semmle.Extraction.Entities;
5+
6+
namespace Semmle.Extraction.CSharp.Entities.Statements
7+
{
8+
internal class GlobalStatementsBlock : Statement
9+
{
10+
private readonly Method parent;
11+
12+
private GlobalStatementsBlock(Context cx, Method parent)
13+
: base(cx, StmtKind.BLOCK, parent, 0)
14+
{
15+
this.parent = parent;
16+
}
17+
18+
public override Microsoft.CodeAnalysis.Location ReportingLocation
19+
{
20+
get
21+
{
22+
return parent.symbol
23+
?.DeclaringSyntaxReferences
24+
.FirstOrDefault()
25+
?.GetSyntax()
26+
.GetLocation();
27+
}
28+
}
29+
30+
public static GlobalStatementsBlock Create(Context cx, Method parent)
31+
{
32+
var ret = new GlobalStatementsBlock(cx, parent);
33+
ret.TryPopulate();
34+
return ret;
35+
}
36+
37+
protected override void PopulateStatement(TextWriter trapFile)
38+
{
39+
trapFile.stmt_location(this, cx.CreateLocation(ReportingLocation));
40+
}
41+
}
42+
}

csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Labeled.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,18 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
66
{
77
internal class Labeled : Statement<LabeledStatementSyntax>
88
{
9-
private readonly Statement parent;
9+
private readonly IStatementParentEntity parent;
1010
private readonly int child;
11+
private Statement labelledStmt;
1112

12-
private Labeled(Context cx, LabeledStatementSyntax stmt, Statement parent, int child)
13+
private Labeled(Context cx, LabeledStatementSyntax stmt, IStatementParentEntity parent, int child)
1314
: base(cx, stmt, StmtKind.LABEL, parent, child)
1415
{
1516
this.parent = parent;
1617
this.child = child;
1718
}
1819

19-
public static Labeled Create(Context cx, LabeledStatementSyntax node, Statement parent, int child)
20+
public static Labeled Create(Context cx, LabeledStatementSyntax node, IStatementParentEntity parent, int child)
2021
{
2122
var ret = new Labeled(cx, node, parent, child);
2223
ret.TryPopulate();
@@ -27,13 +28,11 @@ protected override void PopulateStatement(TextWriter trapFile)
2728
{
2829
trapFile.exprorstmt_name(this, Stmt.Identifier.ToString());
2930

30-
// For compatilibty with the Mono extractor, make insert the labelled statement into the same block
31+
// For compatibility with the Mono extractor, make insert the labelled statement into the same block
3132
// as this one. The parent MUST be a block statement.
3233
labelledStmt = Statement.Create(cx, Stmt.Statement, parent, child + 1);
3334
}
3435

35-
private Statement labelledStmt;
36-
3736
public override int NumberOfStatements => 1 + labelledStmt.NumberOfStatements;
3837
}
3938
}

csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
using Microsoft.CodeAnalysis.CSharp;
33
using Microsoft.CodeAnalysis.CSharp.Syntax;
44
using Semmle.Util.Logging;
5+
using Semmle.Extraction.CSharp.Entities;
6+
using Semmle.Extraction.CSharp.Entities.Statements;
7+
using System.Linq;
58

69
namespace Semmle.Extraction.CSharp.Populators
710
{
@@ -13,30 +16,57 @@ public CompilationUnitVisitor(Context cx)
1316
public override void VisitExternAliasDirective(ExternAliasDirectiveSyntax node)
1417
{
1518
// This information is not yet extracted.
16-
cx.ExtractionError("Not implemented extern alias directive", node.ToFullString(), cx.CreateLocation(node.GetLocation()), "", Severity.Info);
19+
Cx.ExtractionError("Not implemented extern alias directive", node.ToFullString(), Cx.CreateLocation(node.GetLocation()), "", Severity.Info);
1720
}
1821

1922
public override void VisitCompilationUnit(CompilationUnitSyntax compilationUnit)
2023
{
2124
foreach (var m in compilationUnit.ChildNodes())
2225
{
23-
cx.Try(m, null, () => ((CSharpSyntaxNode)m).Accept(this));
26+
Cx.Try(m, null, () => ((CSharpSyntaxNode)m).Accept(this));
2427
}
2528

29+
ExtractGlobalStatements(compilationUnit);
30+
2631
// Gather comments:
2732
foreach (var trivia in compilationUnit.DescendantTrivia(compilationUnit.Span, descendIntoTrivia: true))
2833
{
29-
CommentPopulator.ExtractComment(cx, trivia);
34+
CommentPopulator.ExtractComment(Cx, trivia);
3035
}
3136

3237
foreach (var trivia in compilationUnit.GetLeadingTrivia())
3338
{
34-
CommentPopulator.ExtractComment(cx, trivia);
39+
CommentPopulator.ExtractComment(Cx, trivia);
3540
}
3641

3742
foreach (var trivia in compilationUnit.GetTrailingTrivia())
3843
{
39-
CommentPopulator.ExtractComment(cx, trivia);
44+
CommentPopulator.ExtractComment(Cx, trivia);
45+
}
46+
}
47+
48+
private void ExtractGlobalStatements(CompilationUnitSyntax compilationUnit)
49+
{
50+
var globalStatements = compilationUnit
51+
.ChildNodes()
52+
.OfType<GlobalStatementSyntax>()
53+
.ToList();
54+
55+
if (!globalStatements.Any())
56+
{
57+
return;
58+
}
59+
60+
var entryPoint = Cx.Compilation.GetEntryPoint(System.Threading.CancellationToken.None);
61+
var entryMethod = Method.Create(Cx, entryPoint);
62+
var block = GlobalStatementsBlock.Create(Cx, entryMethod);
63+
64+
for (var i = 0; i < globalStatements.Count; i++)
65+
{
66+
if (globalStatements[i].Statement is object)
67+
{
68+
Statement.Create(Cx, globalStatements[i].Statement, block, i);
69+
}
4070
}
4171
}
4272
}

csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeContainerVisitor.cs

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,17 @@ namespace Semmle.Extraction.CSharp.Populators
1111
{
1212
public class TypeContainerVisitor : CSharpSyntaxVisitor
1313
{
14-
protected Context cx { get; }
15-
protected IEntity parent { get; }
16-
protected TextWriter trapFile { get; }
14+
protected Context Cx { get; }
15+
protected IEntity Parent { get; }
16+
protected TextWriter TrapFile { get; }
1717
private readonly Lazy<Func<SyntaxNode, AttributeData>> attributeLookup;
1818

1919
public TypeContainerVisitor(Context cx, TextWriter trapFile, IEntity parent)
2020
{
21-
this.cx = cx;
22-
this.parent = parent;
23-
this.trapFile = trapFile;
21+
Cx = cx;
22+
Parent = parent;
23+
TrapFile = trapFile;
24+
2425
attributeLookup = new Lazy<Func<SyntaxNode, AttributeData>>(() =>
2526
{
2627
var dict = new Dictionary<SyntaxNode, AttributeData>();
@@ -38,48 +39,59 @@ public override void DefaultVisit(SyntaxNode node)
3839
throw new InternalError(node, "Unhandled top-level syntax node");
3940
}
4041

42+
public override void VisitGlobalStatement(GlobalStatementSyntax node)
43+
{
44+
// Intentionally left empty.
45+
// Global statements are handled in CompilationUnitVisitor
46+
}
47+
4148
public override void VisitDelegateDeclaration(DelegateDeclarationSyntax node)
4249
{
43-
Entities.NamedType.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent);
50+
Entities.NamedType.Create(Cx, Cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(TrapFile, Parent);
4451
}
4552

4653
public override void VisitRecordDeclaration(RecordDeclarationSyntax node)
4754
{
48-
Entities.Type.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent);
55+
ExtractTypeDeclaration(node);
4956
}
5057

51-
public override void VisitClassDeclaration(ClassDeclarationSyntax classDecl)
58+
public override void VisitClassDeclaration(ClassDeclarationSyntax node)
5259
{
53-
Entities.Type.Create(cx, cx.GetModel(classDecl).GetDeclaredSymbol(classDecl)).ExtractRecursive(trapFile, parent);
60+
ExtractTypeDeclaration(node);
5461
}
5562

5663
public override void VisitStructDeclaration(StructDeclarationSyntax node)
5764
{
58-
Entities.Type.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent);
65+
ExtractTypeDeclaration(node);
5966
}
6067

6168
public override void VisitEnumDeclaration(EnumDeclarationSyntax node)
6269
{
63-
Entities.Type.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent);
70+
ExtractTypeDeclaration(node);
6471
}
6572

6673
public override void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node)
6774
{
68-
Entities.Type.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent);
75+
ExtractTypeDeclaration(node);
76+
}
77+
78+
private void ExtractTypeDeclaration(BaseTypeDeclarationSyntax node)
79+
{
80+
Entities.Type.Create(Cx, Cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(TrapFile, Parent);
6981
}
7082

7183
public override void VisitAttributeList(AttributeListSyntax node)
7284
{
73-
if (cx.Extractor.Standalone)
85+
if (Cx.Extractor.Standalone)
7486
return;
7587

76-
var outputAssembly = Assembly.CreateOutputAssembly(cx);
88+
var outputAssembly = Assembly.CreateOutputAssembly(Cx);
7789
foreach (var attribute in node.Attributes)
7890
{
7991
if (attributeLookup.Value(attribute) is AttributeData attributeData)
8092
{
81-
var ae = Semmle.Extraction.CSharp.Entities.Attribute.Create(cx, attributeData, outputAssembly);
82-
cx.BindComments(ae, attribute.GetLocation());
93+
var ae = Entities.Attribute.Create(Cx, attributeData, outputAssembly);
94+
Cx.BindComments(ae, attribute.GetLocation());
8395
}
8496
}
8597
}

csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeOrNamespaceVisitor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ public override void VisitUsingDirective(UsingDirectiveSyntax usingDirective)
1313
{
1414
// Only deal with "using namespace" not "using X = Y"
1515
if (usingDirective.Alias == null)
16-
new UsingDirective(cx, usingDirective, (NamespaceDeclaration)parent);
16+
new UsingDirective(Cx, usingDirective, (NamespaceDeclaration)Parent);
1717
}
1818

1919
public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node)
2020
{
21-
NamespaceDeclaration.Create(cx, node, (NamespaceDeclaration)parent);
21+
NamespaceDeclaration.Create(Cx, node, (NamespaceDeclaration)Parent);
2222
}
2323
}
2424
}

0 commit comments

Comments
 (0)