Skip to content

Commit 87ba9d5

Browse files
authored
Merge pull request #4687 from tamasvajk/feature/csharp9-records
C#: Extract record declarations
2 parents 649bd03 + 83f0fad commit 87ba9d5

File tree

16 files changed

+749
-106
lines changed

16 files changed

+749
-106
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* Record types (`Record`) are extracted.

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ public override void VisitDelegateDeclaration(DelegateDeclarationSyntax node)
4343
Entities.NamedType.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent);
4444
}
4545

46+
public override void VisitRecordDeclaration(RecordDeclarationSyntax node)
47+
{
48+
Entities.Type.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent);
49+
}
50+
4651
public override void VisitClassDeclaration(ClassDeclarationSyntax classDecl)
4752
{
4853
Entities.Type.Create(cx, cx.GetModel(classDecl).GetDeclaredSymbol(classDecl)).ExtractRecursive(trapFile, parent);

csharp/ql/src/semmle/code/cil/Declaration.qll

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,30 +51,23 @@ private predicate toCSharpTypeParameterJoin(TypeParameter tp, int i, CS::Unbound
5151
* A member of a type. Either a type (`Type`), a method (`Method`), a property (`Property`), or an event (`Event`).
5252
*/
5353
class Member extends DotNet::Member, Declaration, @cil_member {
54-
/** Holds if this member is declared `public`. */
55-
predicate isPublic() { cil_public(this) }
54+
override predicate isPublic() { cil_public(this) }
5655

57-
/** Holds if this member is declared `protected.` */
58-
predicate isProtected() { cil_protected(this) }
56+
override predicate isProtected() { cil_protected(this) }
5957

60-
/** Holds if this member is `private`. */
61-
predicate isPrivate() { cil_private(this) }
58+
override predicate isPrivate() { cil_private(this) }
6259

63-
/** Holds if this member is `internal`. */
64-
predicate isInternal() { cil_internal(this) }
60+
override predicate isInternal() { cil_internal(this) }
6561

66-
/** Holds if this member is `sealed`. */
67-
predicate isSealed() { cil_sealed(this) }
62+
override predicate isSealed() { cil_sealed(this) }
6863

69-
/** Holds if this member is `abstract`. */
70-
predicate isAbstract() { cil_abstract(this) }
64+
override predicate isAbstract() { cil_abstract(this) }
65+
66+
override predicate isStatic() { cil_static(this) }
7167

7268
/** Holds if this member has a security attribute. */
7369
predicate hasSecurity() { cil_security(this) }
7470

75-
/** Holds if this member is `static`. */
76-
predicate isStatic() { cil_static(this) }
77-
7871
override Location getLocation() { result = getDeclaringType().getLocation() }
7972
}
8073

csharp/ql/src/semmle/code/cil/Types.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ class Class extends ValueOrRefType {
6060
Class() { this.isClass() }
6161
}
6262

63+
/** A `record`. */
64+
class Record extends Class {
65+
Record() { this.isRecord() }
66+
}
67+
6368
/** An `interface`. */
6469
class Interface extends ValueOrRefType {
6570
Interface() { this.isInterface() }

csharp/ql/src/semmle/code/csharp/Member.qll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,20 @@ class Modifiable extends Declaration, @modifiable {
120120
class Member extends DotNet::Member, Modifiable, @member {
121121
/** Gets an access to this member. */
122122
MemberAccess getAnAccess() { result.getTarget() = this }
123+
124+
override predicate isPublic() { Modifiable.super.isPublic() }
125+
126+
override predicate isProtected() { Modifiable.super.isProtected() }
127+
128+
override predicate isPrivate() { Modifiable.super.isPrivate() }
129+
130+
override predicate isInternal() { Modifiable.super.isInternal() }
131+
132+
override predicate isSealed() { Modifiable.super.isSealed() }
133+
134+
override predicate isAbstract() { Modifiable.super.isAbstract() }
135+
136+
override predicate isStatic() { Modifiable.super.isStatic() }
123137
}
124138

125139
/**

csharp/ql/src/semmle/code/csharp/PrintAst.qll

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,15 +102,16 @@ private ValueOrRefType getAnInterestingBaseType(ValueOrRefType type) {
102102
not type instanceof ArrayType and
103103
not type instanceof NullableType and
104104
result = type.getABaseType() and
105-
isInterestingBaseType(result)
105+
isInterestingBaseType(type, result)
106106
}
107107

108-
private predicate isInterestingBaseType(ValueOrRefType base) {
108+
private predicate isInterestingBaseType(ValueOrRefType type, ValueOrRefType base) {
109109
not base instanceof ObjectType and
110110
not base.getQualifiedName() = "System.ValueType" and
111111
not base.getQualifiedName() = "System.Delegate" and
112112
not base.getQualifiedName() = "System.MulticastDelegate" and
113-
not base.getQualifiedName() = "System.Enum"
113+
not base.getQualifiedName() = "System.Enum" and
114+
exists(TypeMention tm | tm.getTarget() = type and tm.getType() = base)
114115
}
115116

116117
/**
@@ -570,11 +571,12 @@ final class TypeNode extends ElementNode {
570571
result.(BaseTypesNode).getValueOrRefType() = type
571572
or
572573
result.(ElementNode).getElement() =
573-
rank[childIndex - 3](Member m, string file, int line, int column |
574+
rank[childIndex - 3](Member m, string file, int line, int column, string name |
574575
m = type.getAMember() and
576+
name = m.getName() and
575577
locationSortKeys(m, file, line, column)
576578
|
577-
m order by file, line, column
579+
m order by file, line, column, name
578580
)
579581
}
580582
}

csharp/ql/src/semmle/code/csharp/Type.qll

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,21 @@ class Class extends RefType, @class_type {
736736
override string getAPrimaryQlClass() { result = "Class" }
737737
}
738738

739+
/**
740+
* A `record`, for example
741+
*
742+
* ```csharp
743+
* record R(object Prop) {
744+
* ...
745+
* }
746+
* ```
747+
*/
748+
class Record extends Class {
749+
Record() { this.isRecord() }
750+
751+
override string getAPrimaryQlClass() { result = "Record" }
752+
}
753+
739754
/**
740755
* A class generated by the compiler from an anonymous object creation.
741756
*

csharp/ql/src/semmle/code/dotnet/Declaration.qll

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,28 @@ class Declaration extends NamedElement, @dotnet_declaration {
5858
}
5959

6060
/** A member of a type. */
61-
class Member extends Declaration, @dotnet_member { }
61+
class Member extends Declaration, @dotnet_member {
62+
/** Holds if this member is declared `public`. */
63+
predicate isPublic() { none() }
64+
65+
/** Holds if this member is declared `protected.` */
66+
predicate isProtected() { none() }
67+
68+
/** Holds if this member is `private`. */
69+
predicate isPrivate() { none() }
70+
71+
/** Holds if this member is `internal`. */
72+
predicate isInternal() { none() }
73+
74+
/** Holds if this member is `sealed`. */
75+
predicate isSealed() { none() }
76+
77+
/** Holds if this member is `abstract`. */
78+
predicate isAbstract() { none() }
79+
80+
/** Holds if this member is `static`. */
81+
predicate isStatic() { none() }
82+
}
6283

6384
/** A property. */
6485
class Property extends Member, @dotnet_property {

csharp/ql/src/semmle/code/dotnet/Type.qll

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,18 @@ class ValueOrRefType extends Type, @dotnet_valueorreftype {
4949

5050
/** Gets a base type of this type, if any. */
5151
ValueOrRefType getABaseType() { none() }
52+
53+
/** Holds if this type is a `record`. */
54+
predicate isRecord() {
55+
exists(Callable c |
56+
c.getDeclaringType() = this and
57+
c.hasName("<Clone>$") and
58+
c.getNumberOfParameters() = 0 and
59+
c.getReturnType() = this.getABaseType*() and
60+
c.(Member).isPublic() and
61+
not c.(Member).isStatic()
62+
)
63+
}
5264
}
5365

5466
/**

csharp/ql/test/library-tests/csharp9/InitOnlyProperty.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
11
using System;
22

3-
namespace System.Runtime.CompilerServices
4-
{
5-
public sealed class IsExternalInit
6-
{
7-
}
8-
}
9-
103
public class Base
114
{
125
public int Prop0 { get { return 1; } init { Prop1 = value; } }

0 commit comments

Comments
 (0)