Skip to content

C# 11: Generic attributes #11814

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jan 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions csharp/ql/lib/change-notes/2023-01-03-genericattributes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
category: majorAnalysis
---
* Added library support for generic attributes (also for CIL extracted attributes).
* `cil.ConstructedType::getName` was changed to include printing of the type arguments.
16 changes: 16 additions & 0 deletions csharp/ql/lib/semmle/code/cil/Attribute.qll
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,19 @@ class Attribute extends Element, @cil_attribute {

override CS::Location getLocation() { result = getDeclaration().getLocation() }
}

/** A generic attribute to a declaration. */
class GenericAttribute extends Attribute {
private ConstructedType type;

GenericAttribute() { type = this.getType() }

/** Gets the total number of type arguments. */
int getNumberOfTypeArguments() { result = count(int i | cil_type_argument(type, i, _)) }

/** Gets the `i`th type argument, if any. */
Type getTypeArgument(int i) { result = type.getTypeArgument(i) }

/** Get a type argument. */
Type getATypeArgument() { result = this.getTypeArgument(_) }
}
10 changes: 10 additions & 0 deletions csharp/ql/lib/semmle/code/cil/Generics.qll
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ class ConstructedGeneric extends Generic, DotNet::ConstructedGeneric {
final override Type getTypeArgument(int n) { cil_type_argument(this, n, result) }
}

/** Gets the concatenation of the `getName()` of type arguments. */
language[monotonicAggregates]
private string getTypeArgumentsNames(ConstructedGeneric cg) {
result = strictconcat(Type t, int i | t = cg.getTypeArgument(i) | t.getName(), "," order by i)
}

/** An unbound generic type. */
class UnboundGenericType extends UnboundGeneric, Type { }

Expand All @@ -41,6 +47,10 @@ class ConstructedType extends ConstructedGeneric, Type {
override predicate isInterface() { this.getUnboundType().isInterface() }

override predicate isClass() { this.getUnboundType().isClass() }

final override string getName() {
result = this.getUndecoratedName() + "<" + getTypeArgumentsNames(this) + ">"
}
}

/** A constructed generic method. */
Expand Down
77 changes: 75 additions & 2 deletions csharp/ql/lib/semmle/code/csharp/Attribute.qll
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,14 @@ class Attributable extends @attributable {
}

private string getAttributeName(Attribute a) {
exists(string type | type = a.getType().getName() |
if type.matches("%Attribute") then result = type.prefix(type.length() - 9) else result = type
exists(string type, string pattern |
type = a.getType().getName() and pattern = "(.*)Attribute(<.*>)?"
|
type.regexpMatch(pattern) and
result = concat(int i | i = [1, 2] | type.regexpCapture(pattern, i) order by i)
or
not type.regexpMatch(pattern) and
result = type
)
}

Expand Down Expand Up @@ -99,6 +105,31 @@ class Attribute extends TopLevelExprParent, @attribute {
override string getAPrimaryQlClass() { result = "Attribute" }
}

/**
* A generic attribute, for example `[...]` on line 1 in
*
* ```csharp
* [MyGenericAttribute<int>(0)]
* public void SomeMethod(string s) { }
* ```
*/
class GenericAttribute extends Attribute {
private ConstructedClass type;

GenericAttribute() { type = this.getType() }

/** Gets the total number of type arguments. */
int getNumberOfTypeArguments() { result = count(int i | type_arguments(_, i, type)) }

/** Gets the `i`th type argument, if any. */
Type getTypeArgument(int i) { result = type.getTypeArgument(i) }

/** Get a type argument. */
Type getATypeArgument() { result = this.getTypeArgument(_) }

override string getAPrimaryQlClass() { result = "GenericAttribute" }
}

/**
* An attribute with default kind, for example `[...]` on line 1 in
* ```csharp
Expand All @@ -110,6 +141,17 @@ class DefaultAttribute extends Attribute, @attribute_default {
override string getAPrimaryQlClass() { result = "DefaultAttribute" }
}

/**
* A generic attribute with default kind, for example `[...]` on line 1 in
* ```csharp
* [MyAttribute<string>(0)]
* int SomeMethod() { return 1; }
* ```
*/
class GenericDefaultAttribute extends GenericAttribute, DefaultAttribute {
override string getAPrimaryQlClass() { result = "GenericDefaultAttribute" }
}

/**
* An attribute with return kind, for example `[...]` on line 1 in
* ```csharp
Expand All @@ -123,6 +165,17 @@ class ReturnAttribute extends Attribute, @attribute_return {
override string getAPrimaryQlClass() { result = "ReturnAttribute" }
}

/**
* A generic attribute with return kind, for example `[...]` on line 1 in
* ```csharp
* [return: MyAttribute<object>(0)]
* int SomeMethod() { return 1; }
* ```
*/
class GenericReturnAttribute extends GenericAttribute, ReturnAttribute {
override string getAPrimaryQlClass() { result = "GenericReturnAttribute" }
}

/**
* An attribute with assembly kind, for example `[...]` on line 1 in
* ```csharp
Expand All @@ -135,6 +188,16 @@ class AssemblyAttribute extends Attribute, @attribute_assembly {
override string getAPrimaryQlClass() { result = "AssemblyAttribute" }
}

/**
* A generic attribute with assembly kind, for example `[...]` on line 1 in
* ```csharp
* [assembly: MyAttribute<string>(0)]
* ```
*/
class GenericAssemblyAttribute extends GenericAttribute, AssemblyAttribute {
override string getAPrimaryQlClass() { result = "GenericAssemblyAttribute" }
}

/**
* An attribute with module kind, for example `[...]` on line 1 in
* ```csharp
Expand All @@ -146,3 +209,13 @@ class ModuleAttribute extends Attribute, @attribute_module {

override string getAPrimaryQlClass() { result = "ModuleAttribute" }
}

/**
* A generic attribute with module kind, for example `[...]` on line 1 in
* ```csharp
* [module: MyAttribute<string>(0)]
* ```
*/
class GenericModuleAttribute extends GenericAttribute, ModuleAttribute {
override string getAPrimaryQlClass() { result = "GenericModuleAttribute" }
}
Loading