Skip to content

Commit 5677681

Browse files
authored
Merge pull request github#7792 from michaelnebel/csharp/attributes
C#: Attribute kind and return value attributes.
2 parents eee03eb + 6487b54 commit 5677681

28 files changed

+14559
-5824
lines changed

csharp/downgrades/ab09ac8287516082b7a7367f8fda1862b1be47c5/old.dbscheme

Lines changed: 2054 additions & 0 deletions
Large diffs are not rendered by default.

csharp/downgrades/ab09ac8287516082b7a7367f8fda1862b1be47c5/semmlecode.csharp.dbscheme

Lines changed: 2046 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
description: Remove 'kind' from 'attributes'.
2+
compatability: full
3+
attributes.rel: reorder attributes.rel (int id, int kind, int type_id, int target) id type_id target

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

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System;
2+
using System.Collections.Generic;
13
using System.IO;
24
using System.Linq;
35
using Microsoft.CodeAnalysis;
@@ -6,18 +8,28 @@
68

79
namespace Semmle.Extraction.CSharp.Entities
810
{
11+
internal enum AttributeKind
12+
{
13+
Default = 0,
14+
Return = 1,
15+
Assembly = 2,
16+
Module = 3,
17+
}
18+
919
internal class Attribute : CachedEntity<AttributeData>, IExpressionParentEntity
1020
{
1121
bool IExpressionParentEntity.IsTopLevelParent => true;
1222

1323
private readonly AttributeSyntax? attributeSyntax;
1424
private readonly IEntity entity;
25+
private readonly AttributeKind kind;
1526

16-
private Attribute(Context cx, AttributeData attributeData, IEntity entity)
27+
private Attribute(Context cx, AttributeData attributeData, IEntity entity, AttributeKind kind)
1728
: base(cx, attributeData)
1829
{
1930
this.attributeSyntax = attributeData.ApplicationSyntaxReference?.GetSyntax() as AttributeSyntax;
2031
this.entity = entity;
32+
this.kind = kind;
2133
}
2234

2335
public override void WriteId(EscapingTextWriter trapFile)
@@ -48,7 +60,7 @@ public sealed override void WriteQuotedId(EscapingTextWriter trapFile)
4860
public override void Populate(TextWriter trapFile)
4961
{
5062
var type = Type.Create(Context, Symbol.AttributeClass);
51-
trapFile.attributes(this, type.TypeRef, entity);
63+
trapFile.attributes(this, kind, type.TypeRef, entity);
5264
trapFile.attribute_location(this, Location);
5365

5466
if (attributeSyntax is not null)
@@ -125,26 +137,36 @@ private void ExtractArguments(TextWriter trapFile)
125137

126138
public override bool NeedsPopulation => true;
127139

140+
private static void ExtractAttributes(Context cx, IEnumerable<AttributeData> attributes, IEntity entity, AttributeKind kind)
141+
{
142+
foreach (var attribute in attributes)
143+
{
144+
Create(cx, attribute, entity, kind);
145+
}
146+
}
147+
128148
public static void ExtractAttributes(Context cx, ISymbol symbol, IEntity entity)
129149
{
130-
foreach (var attribute in symbol.GetAttributes())
150+
ExtractAttributes(cx, symbol.GetAttributes(), entity, AttributeKind.Default);
151+
if (symbol is IMethodSymbol method)
131152
{
132-
Create(cx, attribute, entity);
153+
ExtractAttributes(cx, method.GetReturnTypeAttributes(), entity, AttributeKind.Return);
133154
}
134155
}
135156

136-
public static Attribute Create(Context cx, AttributeData attributeData, IEntity entity)
157+
158+
public static Attribute Create(Context cx, AttributeData attributeData, IEntity entity, AttributeKind kind)
137159
{
138-
var init = (attributeData, entity);
160+
var init = (attributeData, entity, kind);
139161
return AttributeFactory.Instance.CreateEntity(cx, attributeData, init);
140162
}
141163

142-
private class AttributeFactory : CachedEntityFactory<(AttributeData attributeData, IEntity receiver), Attribute>
164+
private class AttributeFactory : CachedEntityFactory<(AttributeData attributeData, IEntity receiver, AttributeKind kind), Attribute>
143165
{
144166
public static readonly AttributeFactory Instance = new AttributeFactory();
145167

146-
public override Attribute Create(Context cx, (AttributeData attributeData, IEntity receiver) init) =>
147-
new Attribute(cx, init.attributeData, init.receiver);
168+
public override Attribute Create(Context cx, (AttributeData attributeData, IEntity receiver, AttributeKind kind) init) =>
169+
new Attribute(cx, init.attributeData, init.receiver, init.kind);
148170
}
149171
}
150172
}

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,17 @@ public override void VisitAttributeList(AttributeListSyntax node)
8686
return;
8787

8888
var outputAssembly = Assembly.CreateOutputAssembly(Cx);
89+
var kind = node.Target?.Identifier.Kind() switch
90+
{
91+
SyntaxKind.AssemblyKeyword => Entities.AttributeKind.Assembly,
92+
SyntaxKind.ModuleKeyword => Entities.AttributeKind.Module,
93+
_ => throw new InternalError(node, "Unhandled global target")
94+
};
8995
foreach (var attribute in node.Attributes)
9096
{
9197
if (attributeLookup.Value(attribute) is AttributeData attributeData)
9298
{
93-
var ae = Entities.Attribute.Create(Cx, attributeData, outputAssembly);
99+
var ae = Entities.Attribute.Create(Cx, attributeData, outputAssembly, kind);
94100
Cx.BindComments(ae, attribute.GetLocation());
95101
}
96102
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ internal static void init_only_accessors(this TextWriter trapFile, Accessor acce
3232
internal static void array_element_type(this TextWriter trapFile, ArrayType array, int dimension, int rank, Type elementType) =>
3333
trapFile.WriteTuple("array_element_type", array, dimension, rank, elementType);
3434

35-
internal static void attributes(this TextWriter trapFile, Attribute attribute, Type attributeType, IEntity entity) =>
36-
trapFile.WriteTuple("attributes", attribute, attributeType, entity);
35+
internal static void attributes(this TextWriter trapFile, Attribute attribute, AttributeKind kind, Type attributeType, IEntity entity) =>
36+
trapFile.WriteTuple("attributes", attribute, kind, attributeType, entity);
3737

3838
internal static void attribute_location(this TextWriter trapFile, Attribute attribute, Location location) =>
3939
trapFile.WriteTuple("attribute_location", attribute, location);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
category: majorAnalysis
3+
---
4+
* Return value attributes are extracted.
5+
* The QL `Attribute` class now has subclasses for each kind of attribute.

csharp/ql/lib/semmle/code/csharp/Attribute.qll

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ class Attributable extends @attributable {
3636
}
3737
}
3838

39+
private string getAttributeName(Attribute a) {
40+
exists(string type | type = a.getType().getName() |
41+
if type.matches("%Attribute") then result = type.prefix(type.length() - 9) else result = type
42+
)
43+
}
44+
3945
/**
4046
* An attribute, for example `[...]` on line 1 in
4147
*
@@ -50,10 +56,10 @@ class Attributable extends @attributable {
5056
*/
5157
class Attribute extends TopLevelExprParent, @attribute {
5258
/** Gets the type of this attribute. */
53-
Class getType() { attributes(this, getTypeRef(result), _) }
59+
Class getType() { attributes(this, _, getTypeRef(result), _) }
5460

5561
/** Gets the element that this attribute is attached to. */
56-
Attributable getTarget() { attributes(this, _, result) }
62+
Attributable getTarget() { attributes(this, _, _, result) }
5763

5864
/**
5965
* Gets the `i`th argument of this attribute. This includes both constructor
@@ -88,12 +94,55 @@ class Attribute extends TopLevelExprParent, @attribute {
8894

8995
override Location getALocation() { attribute_location(this, result) }
9096

91-
override string toString() {
92-
exists(string type, string name | type = this.getType().getName() |
93-
(if type.matches("%Attribute") then name = type.prefix(type.length() - 9) else name = type) and
94-
result = "[" + name + "(...)]"
95-
)
96-
}
97+
override string toString() { result = "[" + getAttributeName(this) + "(...)]" }
9798

9899
override string getAPrimaryQlClass() { result = "Attribute" }
99100
}
101+
102+
/**
103+
* An attribute with default kind, for example `[...]` on line 1 in
104+
* ```csharp
105+
* [MyAttribute(0)]
106+
* int SomeMethod() { return 1; }
107+
* ```
108+
*/
109+
class DefaultAttribute extends Attribute, @attribute_default {
110+
override string getAPrimaryQlClass() { result = "DefaultAttribute" }
111+
}
112+
113+
/**
114+
* An attribute with return kind, for example `[...]` on line 1 in
115+
* ```csharp
116+
* [return: MyAttribute(0)]
117+
* int SomeMethod() { return 1; }
118+
* ```
119+
*/
120+
class ReturnAttribute extends Attribute, @attribute_return {
121+
override string toString() { result = "[return: " + getAttributeName(this) + "(...)]" }
122+
123+
override string getAPrimaryQlClass() { result = "ReturnAttribute" }
124+
}
125+
126+
/**
127+
* An attribute with assembly kind, for example `[...]` on line 1 in
128+
* ```csharp
129+
* [assembly: MyAttribute(0)]
130+
* ```
131+
*/
132+
class AssemblyAttribute extends Attribute, @attribute_assembly {
133+
override string toString() { result = "[assembly: " + getAttributeName(this) + "(...)]" }
134+
135+
override string getAPrimaryQlClass() { result = "AssemblyAttribute" }
136+
}
137+
138+
/**
139+
* An attribute with module kind, for example `[...]` on line 1 in
140+
* ```csharp
141+
* [module: MyAttribute(0)]
142+
* ```
143+
*/
144+
class ModuleAttribute extends Attribute, @attribute_module {
145+
override string toString() { result = "[module: " + getAttributeName(this) + "(...)]" }
146+
147+
override string getAPrimaryQlClass() { result = "ModuleAttribute" }
148+
}

csharp/ql/lib/semmlecode.csharp.dbscheme

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,9 +520,17 @@ tuple_element(
520520

521521
attributes(
522522
unique int id: @attribute,
523+
int kind: int ref,
523524
int type_id: @type_or_ref ref,
524525
int target: @attributable ref);
525526

527+
case @attribute.kind of
528+
0 = @attribute_default
529+
| 1 = @attribute_return
530+
| 2 = @attribute_assembly
531+
| 3 = @attribute_module
532+
;
533+
526534
attribute_location(
527535
int id: @attribute ref,
528536
int loc: @location ref);

0 commit comments

Comments
 (0)