Skip to content

Commit cb8c5e8

Browse files
authored
Merge pull request github#4663 from tamasvajk/feature/patterns
C#: Refactor pattern extraction
2 parents 4746320 + dee1690 commit cb8c5e8

File tree

7 files changed

+156
-174
lines changed

7 files changed

+156
-174
lines changed

csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/IsPattern.cs

Lines changed: 2 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -1,135 +1,9 @@
1-
using Microsoft.CodeAnalysis;
2-
using Microsoft.CodeAnalysis.CSharp.Syntax;
3-
using Microsoft.CodeAnalysis.CSharp;
1+
using Microsoft.CodeAnalysis.CSharp.Syntax;
42
using Semmle.Extraction.Kinds;
5-
using Semmle.Extraction.Entities;
63
using System.IO;
74

85
namespace Semmle.Extraction.CSharp.Entities.Expressions
96
{
10-
internal static class PatternExtensions
11-
{
12-
public static Expression CreatePattern(this Context cx, PatternSyntax syntax, IExpressionParentEntity parent, int child)
13-
{
14-
switch (syntax)
15-
{
16-
case ConstantPatternSyntax constantPattern:
17-
return Expression.Create(cx, constantPattern.Expression, parent, child);
18-
19-
case DeclarationPatternSyntax declPattern:
20-
// Creates a single local variable declaration.
21-
{
22-
if (declPattern.Designation is VariableDesignationSyntax designation)
23-
{
24-
if (cx.GetModel(syntax).GetDeclaredSymbol(designation) is ILocalSymbol symbol)
25-
{
26-
var type = Type.Create(cx, symbol.GetAnnotatedType());
27-
return VariableDeclaration.Create(cx, symbol, type, declPattern.Type, cx.Create(syntax.GetLocation()), false, parent, child);
28-
}
29-
if (designation is DiscardDesignationSyntax)
30-
{
31-
return Expressions.TypeAccess.Create(cx, declPattern.Type, parent, child);
32-
}
33-
throw new InternalError(designation, "Designation pattern not handled");
34-
}
35-
throw new InternalError(declPattern, "Declaration pattern not handled");
36-
}
37-
38-
case RecursivePatternSyntax recPattern:
39-
return new RecursivePattern(cx, recPattern, parent, child);
40-
41-
case VarPatternSyntax varPattern:
42-
switch (varPattern.Designation)
43-
{
44-
case ParenthesizedVariableDesignationSyntax parDesignation:
45-
return VariableDeclaration.CreateParenthesized(cx, varPattern, parDesignation, parent, child);
46-
case SingleVariableDesignationSyntax varDesignation:
47-
if (cx.GetModel(syntax).GetDeclaredSymbol(varDesignation) is ILocalSymbol symbol)
48-
{
49-
var type = Type.Create(cx, symbol.GetAnnotatedType());
50-
51-
return VariableDeclaration.Create(cx, symbol, type, null, cx.Create(syntax.GetLocation()), true, parent, child);
52-
}
53-
54-
throw new InternalError(varPattern, "Unable to get the declared symbol of the var pattern designation.");
55-
default:
56-
throw new InternalError("var pattern designation is unhandled");
57-
}
58-
59-
case DiscardPatternSyntax dp:
60-
return new Discard(cx, dp, parent, child);
61-
62-
default:
63-
throw new InternalError(syntax, "Pattern not handled");
64-
}
65-
}
66-
}
67-
68-
internal class PropertyPattern : Expression
69-
{
70-
internal PropertyPattern(Context cx, PropertyPatternClauseSyntax pp, IExpressionParentEntity parent, int child) :
71-
base(new ExpressionInfo(cx, Entities.NullType.Create(cx), cx.Create(pp.GetLocation()), ExprKind.PROPERTY_PATTERN, parent, child, false, null))
72-
{
73-
child = 0;
74-
var trapFile = cx.TrapWriter.Writer;
75-
foreach (var sub in pp.Subpatterns)
76-
{
77-
var p = cx.CreatePattern(sub.Pattern, this, child++);
78-
trapFile.exprorstmt_name(p, sub.NameColon.Name.ToString());
79-
}
80-
}
81-
}
82-
83-
internal class PositionalPattern : Expression
84-
{
85-
internal PositionalPattern(Context cx, PositionalPatternClauseSyntax posPc, IExpressionParentEntity parent, int child) :
86-
base(new ExpressionInfo(cx, Entities.NullType.Create(cx), cx.Create(posPc.GetLocation()), ExprKind.POSITIONAL_PATTERN, parent, child, false, null))
87-
{
88-
child = 0;
89-
foreach (var sub in posPc.Subpatterns)
90-
{
91-
cx.CreatePattern(sub.Pattern, this, child++);
92-
}
93-
}
94-
}
95-
96-
internal class RecursivePattern : Expression
97-
{
98-
/// <summary>
99-
/// Creates and populates a recursive pattern.
100-
/// </summary>
101-
/// <param name="cx">The extraction context.</param>
102-
/// <param name="syntax">The syntax node of the recursive pattern.</param>
103-
/// <param name="parent">The parent pattern/expression.</param>
104-
/// <param name="child">The child index of this pattern.</param>
105-
/// <param name="isTopLevel">If this pattern is in the top level of a case/is. In that case, the variable and type access are populated elsewhere.</param>
106-
public RecursivePattern(Context cx, RecursivePatternSyntax syntax, IExpressionParentEntity parent, int child) :
107-
base(new ExpressionInfo(cx, Entities.NullType.Create(cx), cx.Create(syntax.GetLocation()), ExprKind.RECURSIVE_PATTERN, parent, child, false, null))
108-
{
109-
// Extract the type access
110-
if (syntax.Type is TypeSyntax t)
111-
Expressions.TypeAccess.Create(cx, t, this, 1);
112-
113-
// Extract the local variable declaration
114-
if (syntax.Designation is VariableDesignationSyntax designation && cx.GetModel(syntax).GetDeclaredSymbol(designation) is ILocalSymbol symbol)
115-
{
116-
var type = Entities.Type.Create(cx, symbol.GetAnnotatedType());
117-
118-
VariableDeclaration.Create(cx, symbol, type, null, cx.Create(syntax.GetLocation()), false, this, 0);
119-
}
120-
121-
if (syntax.PositionalPatternClause is PositionalPatternClauseSyntax posPc)
122-
{
123-
new PositionalPattern(cx, posPc, this, 2);
124-
}
125-
126-
if (syntax.PropertyPatternClause is PropertyPatternClauseSyntax pc)
127-
{
128-
new PropertyPattern(cx, pc, this, 3);
129-
}
130-
}
131-
}
132-
1337
internal class IsPattern : Expression<IsPatternExpressionSyntax>
1348
{
1359
private IsPattern(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.IS))
@@ -139,7 +13,7 @@ private IsPattern(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.IS))
13913
protected override void PopulateExpression(TextWriter trapFile)
14014
{
14115
Create(cx, Syntax.Expression, this, 0);
142-
cx.CreatePattern(Syntax.Pattern, this, 1);
16+
Expressions.Pattern.Create(cx, Syntax.Pattern, this, 1);
14317
}
14418

14519
public static Expression Create(ExpressionNodeInfo info) => new IsPattern(info).TryPopulate();
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.CSharp.Syntax;
3+
using Microsoft.CodeAnalysis.CSharp;
4+
using Semmle.Extraction.Entities;
5+
6+
namespace Semmle.Extraction.CSharp.Entities.Expressions
7+
{
8+
public static class Pattern
9+
{
10+
internal static Expression Create(Context cx, PatternSyntax syntax, IExpressionParentEntity parent, int child)
11+
{
12+
switch (syntax)
13+
{
14+
case ConstantPatternSyntax constantPattern:
15+
return Expression.Create(cx, constantPattern.Expression, parent, child);
16+
17+
case DeclarationPatternSyntax declPattern:
18+
// Creates a single local variable declaration.
19+
{
20+
if (declPattern.Designation is VariableDesignationSyntax designation)
21+
{
22+
if (cx.GetModel(syntax).GetDeclaredSymbol(designation) is ILocalSymbol symbol)
23+
{
24+
var type = Type.Create(cx, symbol.GetAnnotatedType());
25+
return VariableDeclaration.Create(cx, symbol, type, declPattern.Type, cx.Create(syntax.GetLocation()), false, parent, child);
26+
}
27+
if (designation is DiscardDesignationSyntax)
28+
{
29+
return Expressions.TypeAccess.Create(cx, declPattern.Type, parent, child);
30+
}
31+
throw new InternalError(designation, "Designation pattern not handled");
32+
}
33+
throw new InternalError(declPattern, "Declaration pattern not handled");
34+
}
35+
36+
case RecursivePatternSyntax recPattern:
37+
return new RecursivePattern(cx, recPattern, parent, child);
38+
39+
case VarPatternSyntax varPattern:
40+
switch (varPattern.Designation)
41+
{
42+
case ParenthesizedVariableDesignationSyntax parDesignation:
43+
return VariableDeclaration.CreateParenthesized(cx, varPattern, parDesignation, parent, child);
44+
case SingleVariableDesignationSyntax varDesignation:
45+
if (cx.GetModel(syntax).GetDeclaredSymbol(varDesignation) is ILocalSymbol symbol)
46+
{
47+
var type = Type.Create(cx, symbol.GetAnnotatedType());
48+
49+
return VariableDeclaration.Create(cx, symbol, type, null, cx.Create(syntax.GetLocation()), true, parent, child);
50+
}
51+
52+
throw new InternalError(varPattern, "Unable to get the declared symbol of the var pattern designation.");
53+
case DiscardDesignationSyntax discard:
54+
return new Expressions.Discard(cx, discard, parent, child);
55+
default:
56+
throw new InternalError("var pattern designation is unhandled");
57+
}
58+
59+
case DiscardPatternSyntax dp:
60+
return new Discard(cx, dp, parent, child);
61+
62+
default:
63+
throw new InternalError(syntax, "Pattern not handled");
64+
}
65+
}
66+
}
67+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using Microsoft.CodeAnalysis.CSharp.Syntax;
2+
using Semmle.Extraction.Kinds;
3+
using Semmle.Extraction.Entities;
4+
5+
namespace Semmle.Extraction.CSharp.Entities.Expressions
6+
{
7+
internal class PositionalPattern : Expression
8+
{
9+
internal PositionalPattern(Context cx, PositionalPatternClauseSyntax posPc, IExpressionParentEntity parent, int child) :
10+
base(new ExpressionInfo(cx, Entities.NullType.Create(cx), cx.Create(posPc.GetLocation()), ExprKind.POSITIONAL_PATTERN, parent, child, false, null))
11+
{
12+
child = 0;
13+
foreach (var sub in posPc.Subpatterns)
14+
{
15+
Expressions.Pattern.Create(cx, sub.Pattern, this, child++);
16+
}
17+
}
18+
}
19+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using Microsoft.CodeAnalysis.CSharp.Syntax;
2+
using Semmle.Extraction.Kinds;
3+
using Semmle.Extraction.Entities;
4+
5+
namespace Semmle.Extraction.CSharp.Entities.Expressions
6+
{
7+
internal class PropertyPattern : Expression
8+
{
9+
internal PropertyPattern(Context cx, PropertyPatternClauseSyntax pp, IExpressionParentEntity parent, int child) :
10+
base(new ExpressionInfo(cx, Entities.NullType.Create(cx), cx.Create(pp.GetLocation()), ExprKind.PROPERTY_PATTERN, parent, child, false, null))
11+
{
12+
child = 0;
13+
var trapFile = cx.TrapWriter.Writer;
14+
foreach (var sub in pp.Subpatterns)
15+
{
16+
var p = Expressions.Pattern.Create(cx, sub.Pattern, this, child++);
17+
trapFile.exprorstmt_name(p, sub.NameColon.Name.ToString());
18+
}
19+
}
20+
}
21+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.CSharp.Syntax;
3+
using Microsoft.CodeAnalysis.CSharp;
4+
using Semmle.Extraction.Kinds;
5+
using Semmle.Extraction.Entities;
6+
7+
namespace Semmle.Extraction.CSharp.Entities.Expressions
8+
{
9+
internal class RecursivePattern : Expression
10+
{
11+
/// <summary>
12+
/// Creates and populates a recursive pattern.
13+
/// </summary>
14+
/// <param name="cx">The extraction context.</param>
15+
/// <param name="syntax">The syntax node of the recursive pattern.</param>
16+
/// <param name="parent">The parent pattern/expression.</param>
17+
/// <param name="child">The child index of this pattern.</param>
18+
/// <param name="isTopLevel">If this pattern is in the top level of a case/is. In that case, the variable and type access are populated elsewhere.</param>
19+
public RecursivePattern(Context cx, RecursivePatternSyntax syntax, IExpressionParentEntity parent, int child) :
20+
base(new ExpressionInfo(cx, Entities.NullType.Create(cx), cx.Create(syntax.GetLocation()), ExprKind.RECURSIVE_PATTERN, parent, child, false, null))
21+
{
22+
// Extract the type access
23+
if (syntax.Type is TypeSyntax t)
24+
Expressions.TypeAccess.Create(cx, t, this, 1);
25+
26+
// Extract the local variable declaration
27+
if (syntax.Designation is VariableDesignationSyntax designation && cx.GetModel(syntax).GetDeclaredSymbol(designation) is ILocalSymbol symbol)
28+
{
29+
var type = Entities.Type.Create(cx, symbol.GetAnnotatedType());
30+
31+
VariableDeclaration.Create(cx, symbol, type, null, cx.Create(syntax.GetLocation()), false, this, 0);
32+
}
33+
34+
if (syntax.PositionalPatternClause is PositionalPatternClauseSyntax posPc)
35+
{
36+
new PositionalPattern(cx, posPc, this, 2);
37+
}
38+
39+
if (syntax.PropertyPatternClause is PropertyPatternClauseSyntax pc)
40+
{
41+
new PropertyPattern(cx, pc, this, 3);
42+
}
43+
}
44+
}
45+
}

csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ internal SwitchCase(Context cx, SwitchExpressionArmSyntax arm, Switch parent, in
3232
cx, Entities.Type.Create(cx, cx.GetType(arm.Expression)), cx.Create(arm.GetLocation()),
3333
ExprKind.SWITCH_CASE, parent, child, false, null))
3434
{
35-
cx.CreatePattern(arm.Pattern, this, 0);
35+
Expressions.Pattern.Create(cx, arm.Pattern, this, 0);
3636
if (arm.WhenClause is WhenClauseSyntax when)
3737
Expression.Create(cx, when.Condition, this, 1);
3838
Expression.Create(cx, arm.Expression, this, 2);

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

Lines changed: 1 addition & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -68,53 +68,9 @@ internal class CasePattern : Case<CasePatternSwitchLabelSyntax>
6868
private CasePattern(Context cx, CasePatternSwitchLabelSyntax node, Switch parent, int child)
6969
: base(cx, node, parent, child) { }
7070

71-
private void PopulatePattern(PatternSyntax pattern, TypeSyntax optionalType, VariableDesignationSyntax designation)
72-
{
73-
var isVar = optionalType is null;
74-
switch (designation)
75-
{
76-
case SingleVariableDesignationSyntax _:
77-
if (cx.GetModel(pattern).GetDeclaredSymbol(designation) is ILocalSymbol symbol)
78-
{
79-
var type = Type.Create(cx, symbol.GetAnnotatedType());
80-
Expressions.VariableDeclaration.Create(cx, symbol, type, optionalType, cx.Create(pattern.GetLocation()), isVar, this, 0);
81-
}
82-
break;
83-
case DiscardDesignationSyntax discard:
84-
if (isVar)
85-
new Expressions.Discard(cx, discard, this, 0);
86-
else
87-
Expressions.TypeAccess.Create(cx, optionalType, this, 0);
88-
break;
89-
case null:
90-
break;
91-
case ParenthesizedVariableDesignationSyntax paren:
92-
Expressions.VariableDeclaration.CreateParenthesized(cx, (VarPatternSyntax)pattern, paren, this, 0);
93-
break;
94-
default:
95-
throw new InternalError(pattern, "Unhandled designation in case statement");
96-
}
97-
}
98-
9971
protected override void PopulateStatement(TextWriter trapFile)
10072
{
101-
switch (Stmt.Pattern)
102-
{
103-
case VarPatternSyntax varPattern:
104-
PopulatePattern(varPattern, null, varPattern.Designation);
105-
break;
106-
case DeclarationPatternSyntax declarationPattern:
107-
PopulatePattern(declarationPattern, declarationPattern.Type, declarationPattern.Designation);
108-
break;
109-
case ConstantPatternSyntax pattern:
110-
Expression.Create(cx, pattern.Expression, this, 0);
111-
break;
112-
case RecursivePatternSyntax recPattern:
113-
new Expressions.RecursivePattern(cx, recPattern, this, 0);
114-
break;
115-
default:
116-
throw new InternalError(Stmt, "Case pattern not handled");
117-
}
73+
Expressions.Pattern.Create(cx, Stmt.Pattern, this, 0);
11874

11975
if (Stmt.WhenClause != null)
12076
{

0 commit comments

Comments
 (0)