Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
dca10f8
C#: Add extended_type to the DB scheme.
michaelnebel Feb 4, 2026
c68cd58
C#: Add parameter marker interface, allow a type to a parent for para…
michaelnebel Feb 4, 2026
60bb9a9
C#: Move some populate methods and location writing methods.
michaelnebel Feb 4, 2026
ab505e3
C#: Add class for making synthetic parameter entities.
michaelnebel Feb 4, 2026
edfdc98
C#: Extract extension types and members. Replacing invocations to sta…
michaelnebel Feb 4, 2026
9a4a6cf
C#: Add ExtensionType to the QL library.
michaelnebel Feb 4, 2026
b9f36f3
C#: Add extension callable and accessor classes.
michaelnebel Feb 4, 2026
5e02a86
C#: Add extension call classes.
michaelnebel Feb 4, 2026
e831c80
C#: Replace extension parameter access with the corresponding synthet…
michaelnebel Feb 4, 2026
849823e
C#: Add dispatch logic for calling extensions accessors as methods.
michaelnebel Feb 4, 2026
c040daa
C#: Add extensions test.
michaelnebel Feb 4, 2026
6cbe000
C#: Add PrintAst test for extensions.
michaelnebel Feb 4, 2026
4b6a53b
C#: Add extension data flow test.
michaelnebel Feb 4, 2026
bd3e4d3
C#: Add MaD tests for extensions.
michaelnebel Feb 4, 2026
02e4a8b
C#: Add change-note.
michaelnebel Feb 5, 2026
fe94b3b
C#: Address review comments.
michaelnebel Feb 9, 2026
bcdbd6e
C#: Use the fully qualified name for the extension type when printing…
michaelnebel Feb 9, 2026
d9fea15
C#: Update MaD models for extension members.
michaelnebel Feb 9, 2026
eff9f99
C#: Update test expected output.
michaelnebel Feb 9, 2026
42d2de8
C#: Add DB upgrade script.
michaelnebel Feb 9, 2026
3e914f7
C#: Add DB downgrade script.
michaelnebel Feb 9, 2026
bee1718
QL4QL: Allow Impl classes to implement getAPrimaryQLClass with non Im…
michaelnebel Feb 9, 2026
25b836b
C#: Apply suggestions from code review
michaelnebel Feb 10, 2026
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
75 changes: 66 additions & 9 deletions csharp/ql/lib/semmle/code/csharp/Callable.qll
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,23 @@ class Callable extends Parameterizable, ExprOrStmtParent, @callable {

/** Gets a `Call` that has this callable as a target. */
Call getACall() { this = result.getTarget() }

/** Holds if this callable is declared in an extension type. */
predicate isInExtension() { this.getDeclaringType() instanceof ExtensionType }
}

/**
* A callable that is declared as an extension.
*
* Either an extension method (`ExtensionMethod`), an extension operator
* (`ExtensionOperator`) or an extension accessor (`ExtensionAccessor`).
*/
abstract class ExtensionCallable extends Callable {
/** Gets the type being extended by this method. */
pragma[noinline]
Type getExtendedType() { result = this.getDeclaringType().(ExtensionType).getExtendedType() }

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

/**
Expand Down Expand Up @@ -267,8 +284,11 @@ class Method extends Callable, Virtualizable, Attributable, @method {

override Location getALocation() { method_location(this.getUnboundDeclaration(), result) }

/** Holds if this method is a classic extension method. */
predicate isClassicExtensionMethod() { this.getParameter(0).hasExtensionMethodModifier() }

/** Holds if this method is an extension method. */
predicate isExtensionMethod() { this.getParameter(0).hasExtensionMethodModifier() }
predicate isExtensionMethod() { this.isClassicExtensionMethod() or this.isInExtension() }

/** Gets the type of the `params` parameter of this method, if any. */
Type getParamsType() {
Expand Down Expand Up @@ -296,24 +316,46 @@ class Method extends Callable, Virtualizable, Attributable, @method {
}

/**
* An extension method, for example
* An extension method.
*
* Either a classic extension method (`ClassicExtensionMethod`) or an extension
* type extension method (`ExtensionTypeExtensionMethod`).
*/
abstract class ExtensionMethod extends ExtensionCallable, Method {
override string getAPrimaryQlClass() { result = "ExtensionMethod" }
}

/**
* An extension method, for example
*
* ```csharp
* static bool IsDefined(this Widget w) {
* ...
* }
* ```
*/
class ExtensionMethod extends Method {
ExtensionMethod() { this.isExtensionMethod() }

override predicate isStatic() { any() }
class ClassicExtensionMethod extends ExtensionMethod {
ClassicExtensionMethod() { this.isClassicExtensionMethod() }

/** Gets the type being extended by this method. */
pragma[noinline]
Type getExtendedType() { result = this.getParameter(0).getType() }
override Type getExtendedType() { result = this.getParameter(0).getType() }

override string getAPrimaryQlClass() { result = "ExtensionMethod" }
override predicate isStatic() { any() }
}

/**
* An extension method declared in an extension type, for example `IsNullOrEmpty` in
*
* ```csharp
* static class MyExtensions {
* extension(string s) {
* public bool IsNullOrEmpty() { ... }
* }
* }
* ```
*/
class ExtensionTypeExtensionMethod extends ExtensionMethod {
ExtensionTypeExtensionMethod() { this.isInExtension() }
}

/**
Expand Down Expand Up @@ -536,6 +578,21 @@ class RecordCloneMethod extends Method {
}
}

/**
* An extension operator, for example `*` in
*
* ```csharp
* static class MyExtensions {
* extension(string s) {
* public static string operator *(int s1, string s2) { ... }
* }
* }
* ```
*/
class ExtensionOperator extends ExtensionCallable, Operator {
ExtensionOperator() { this.isInExtension() }
}

/**
* A user-defined unary operator - an operator taking one operand.
*
Expand Down
31 changes: 31 additions & 0 deletions csharp/ql/lib/semmle/code/csharp/Property.qll
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,21 @@ class Property extends DeclarationWithGetSetAccessors, @property {
override string getAPrimaryQlClass() { result = "Property" }
}

/**
* An extension property, for example `FirstChar` in
*
* ```csharp
* static class MyExtensions {
* extension(string s) {
* public char FirstChar { get { ... } }
* }
* }
* ```
*/
class ExtensionProperty extends Property {
ExtensionProperty() { this.getDeclaringType() instanceof ExtensionType }
}

/**
* An indexer, for example `string this[int i]` on line 2 in
*
Expand Down Expand Up @@ -413,6 +428,22 @@ class Accessor extends Callable, Modifiable, Attributable, Overridable, @callabl
override string toString() { result = this.getName() }
}

/**
* An extension accessor. Either a getter (`Getter`) or a setter (`Setter`) of an
* extension property, for example `get` in
*
* ```csharp
* static class MyExtensions {
* extension(string s) {
* public char FirstChar { get { ... } }
* }
* }
* ```
*/
class ExtensionAccessor extends ExtensionCallable, Accessor {
ExtensionAccessor() { this.getDeclaringType() instanceof ExtensionType }
}

/**
* A `get` accessor, for example `get { return p; }` in
*
Expand Down