Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b600255
C#: Enable overlay compilation in lib/qlpack.yml.
michaelnebel Oct 21, 2025
bcc6234
C#: Fix bad join due to overlay compilation.
michaelnebel Oct 29, 2025
b48ce8d
C#: Add overlay builtins to the dbscheme.
michaelnebel Sep 12, 2025
cfb6843
C#: Add upgrade- and downgrade scripts.
michaelnebel Sep 12, 2025
9026a5a
C#: Turn on overlay support in codeql-extractor.yml.
michaelnebel Sep 12, 2025
aa80558
C#: Add functionality to detect overlay mode and integrate in extract…
michaelnebel Sep 12, 2025
cab9d81
C#: Add unit test.
michaelnebel Sep 12, 2025
61f6512
C#: Sprinkle uses of OnlyScaffold to extract less when in overlay mode.
michaelnebel Sep 17, 2025
76ac2df
C#: Write overlay metadata at end of extraction.
michaelnebel Oct 21, 2025
121c150
C#: Define discarding predicates for expressions, statements, locatio…
michaelnebel Oct 23, 2025
8a34421
C#: Add QL overlay tests.
michaelnebel Oct 27, 2025
40035d2
C#: Add a locatable type to the dbscheme.
michaelnebel Oct 27, 2025
8927b0a
C#: Simplify the discarding and also discard type mentions and comments.
michaelnebel Oct 27, 2025
04d33cb
C#: Add discarding for diagnostics and extractor messages.
michaelnebel Oct 28, 2025
1d2f154
C#: Add change-note.
michaelnebel Oct 30, 2025
504bb9c
C#: Only scaffold assemblies in overlay mode, only extract expression…
michaelnebel Nov 3, 2025
d95ebc7
C#: Add using directives and type mentions as star entities.
michaelnebel Nov 3, 2025
7c670cd
C#: Address review comments and make more early returns in Populate.
michaelnebel Nov 7, 2025
1657dfb
C#: Remove expression population safeguard and guard creation of cons…
michaelnebel Nov 7, 2025
9d300e3
C#: Address comments in the QL implementation.
michaelnebel Nov 7, 2025
ded1328
C#: Do not extract comments when scaffolding.
michaelnebel Nov 10, 2025
43118ec
C#: The extraction of the TypeMentions for return type and explicit i…
michaelnebel Nov 10, 2025
0a16cf6
C#: Do not require that comments and type locations are in source in …
michaelnebel Nov 10, 2025
c44b747
C#: Minor code quality improvements.
michaelnebel Nov 10, 2025
d6b7424
C#: Add the same strategy in as in Java for XML element discarding.
michaelnebel Nov 10, 2025
3492811
C#: Add XML overlay tests.
michaelnebel Nov 10, 2025
0541dcc
C#: Add discarding for ASP elements.
michaelnebel Nov 10, 2025
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
Prev Previous commit
Next Next commit
C#: Define discarding predicates for expressions, statements, locatio…
…ns and some named TRAP entities.
  • Loading branch information
michaelnebel committed Nov 4, 2025
commit 121c1500cab7b3c4064a27a9e59b1912221815c3
1 change: 1 addition & 0 deletions csharp/ql/lib/csharp.qll
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import semmle.code.csharp.controlflow.ControlFlowGraph
import semmle.code.csharp.dataflow.DataFlow
import semmle.code.csharp.dataflow.TaintTracking
import semmle.code.csharp.dataflow.SSA
private import semmle.code.csharp.Overlay

/** Whether the source was extracted without a build command. */
predicate extractionIsStandalone() { exists(SourceFile f | f.extractedStandalone()) }
227 changes: 227 additions & 0 deletions csharp/ql/lib/semmle/code/csharp/Overlay.qll
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps move this into csharp/ql/lib/semmle/code/csharp/internal/Overlay.qll?

Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
/**
* Defines entity discard predicates for C# overlay analysis.
*/

/**
* Holds always for the overlay variant and never for the base variant.
* This local predicate is used to define local predicates that behave
* differently for the base and overlay variant.
*/
overlay[local]
predicate isOverlay() { databaseMetadata("isOverlay", "true") }

/**
* An abstract base class for all elements that can be discarded from the base.
*/
overlay[local]
abstract private class DiscardableEntity extends @element {
/** Gets the path to the file in which this element occurs. */
abstract string getPath();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getFilePath would be better, I think.


/** Holds if this element exists in the base variant. */
predicate existsInBase() { not isOverlay() and exists(this) }

/** Holds if this element exists in the overlay variant. */
predicate existsInOverlay() { isOverlay() and exists(this) }

/** Gets a textual representation of this discardable element. */
string toString() { none() }
}

/**
* A class of C# database entities that use `*` IDs.
* The rest use named TRAP IDs.
*/
overlay[local]
private class StarEntity = @expr or @stmt;

overlay[discard_entity]
private predicate discardStarEntity(@element e) {
e instanceof StarEntity and
// Entities with *-ids can exist either in base or overlay, but not both.
exists(DiscardableEntity de | de = e |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e = any(DiscardableEntity de | is slightly less verbose.

overlayChangedFiles(de.getPath()) and
de.existsInBase()
)
}

overlay[discard_entity]
private predicate discardNamedEntity(@element e) {
not e instanceof StarEntity and
// Entities with named IDs can exist both in base, overlay, or both.
exists(DiscardableEntity de | de = e |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

overlayChangedFiles(de.getPath()) and
not de.existsInOverlay()
)
}

overlay[local]
private string getLocationPath(@location_default loc) {
exists(@file file | locations_default(loc, file, _, _, _, _) | files(file, result))
}

overlay[local]
private predicate discardableLocation(@location_default loc, string path) {
not isOverlay() and
path = getLocationPath(loc)
}

// Discard locations that are in changed files from the base variant.
overlay[discard_entity]
private predicate discardLocation(@location_default loc) {
exists(string path | discardableLocation(loc, path) | overlayChangedFiles(path))
}

overlay[local]
private class ExprEntity extends DiscardableEntity instanceof @expr {
override string getPath() {
exists(@location_default loc | expr_location(this, loc) | result = getLocationPath(loc))
}
}

overlay[local]
private class StmtEntity extends DiscardableEntity instanceof @stmt {
override string getPath() {
exists(@location_default loc | stmt_location(this, loc) | result = getLocationPath(loc))
}
}

overlay[local]
private class UsingDirectiveEntity extends DiscardableEntity instanceof @using_directive {
override string getPath() {
exists(@location_default loc | using_directive_location(this, loc) |
result = getLocationPath(loc)
)
}
}

overlay[local]
private class NamespaceDeclarationEntity extends DiscardableEntity instanceof @namespace_declaration
{
override string getPath() {
exists(@location_default loc | namespace_declaration_location(this, loc) |
result = getLocationPath(loc)
)
}
}

overlay[local]
private class PreprocessorDirectiveEntity extends DiscardableEntity instanceof @preprocessor_directive
{
override string getPath() {
exists(@location_default loc | preprocessor_directive_location(this, loc) |
result = getLocationPath(loc)
)
}
}

overlay[local]
private class TypeEntity extends DiscardableEntity instanceof @type {
override string getPath() {
exists(@location_default loc | type_location(this, loc) | result = getLocationPath(loc))
}
}

overlay[local]
private class AttributeEntity extends DiscardableEntity instanceof @attribute {
override string getPath() {
exists(@location_default loc | attribute_location(this, loc) | result = getLocationPath(loc))
}
}

overlay[local]
private class TypeParameterConstraintsEntity extends DiscardableEntity instanceof @type_parameter_constraints
{
override string getPath() {
exists(@location_default loc | type_parameter_constraints_location(this, loc) |
result = getLocationPath(loc)
)
}
}

overlay[local]
private class PropertyEntity extends DiscardableEntity instanceof @property {
override string getPath() {
exists(@location_default loc | property_location(this, loc) | result = getLocationPath(loc))
}
}

overlay[local]
private class IndexerEntity extends DiscardableEntity instanceof @indexer {
override string getPath() {
exists(@location_default loc | indexer_location(this, loc) | result = getLocationPath(loc))
}
}

overlay[local]
private class AccessorEntity extends DiscardableEntity instanceof @accessor {
override string getPath() {
exists(@location_default loc | accessor_location(this, loc) | result = getLocationPath(loc))
}
}

overlay[local]
private class EventEntity extends DiscardableEntity instanceof @event {
override string getPath() {
exists(@location_default loc | event_location(this, loc) | result = getLocationPath(loc))
}
}

overlay[local]
private class EventAccessorEntity extends DiscardableEntity instanceof @event_accessor {
override string getPath() {
exists(@location_default loc | event_accessor_location(this, loc) |
result = getLocationPath(loc)
)
}
}

overlay[local]
private class OperatorEntity extends DiscardableEntity instanceof @operator {
override string getPath() {
exists(@location_default loc | operator_location(this, loc) | result = getLocationPath(loc))
}
}

overlay[local]
private class MethodEntity extends DiscardableEntity instanceof @method {
override string getPath() {
exists(@location_default loc | method_location(this, loc) | result = getLocationPath(loc))
}
}

overlay[local]
private class ConstructorEntity extends DiscardableEntity instanceof @constructor {
override string getPath() {
exists(@location_default loc | constructor_location(this, loc) | result = getLocationPath(loc))
}
}

overlay[local]
private class DestructorEntity extends DiscardableEntity instanceof @destructor {
override string getPath() {
exists(@location_default loc | destructor_location(this, loc) | result = getLocationPath(loc))
}
}

overlay[local]
private class FieldEntity extends DiscardableEntity instanceof @field {
override string getPath() {
exists(@location_default loc | field_location(this, loc) | result = getLocationPath(loc))
}
}

overlay[local]
private class LocalVariableEntity extends DiscardableEntity instanceof @local_variable {
override string getPath() {
exists(@location_default loc | localvar_location(this, loc) | result = getLocationPath(loc))
}
}

overlay[local]
private class ParameterEntity extends DiscardableEntity instanceof @parameter {
override string getPath() {
exists(@location_default loc | param_location(this, loc) | result = getLocationPath(loc))
}
}
// TODO: We Still need to handle commentline, comment block entities and type mentions.