Compare commits

..

2 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
f3c85c0ff7 Extend C# control flow elements with type mentions 2026-06-22 13:17:44 +00:00
copilot-swe-agent[bot]
d7ec468e2e Add type mentions to control flow element handling 2026-06-22 12:29:48 +00:00
6 changed files with 20 additions and 46 deletions

View File

@@ -121,6 +121,13 @@ private module Cached {
result = getAChildExpr(parent)
or
result = parent.getAChildStmt()
or
result =
any(TypeMention tm |
tm.getTarget() = parent
or
tm.getParent+().getTarget() = parent
)
}
private predicate parent(ControlFlowElement child, ExprOrStmtParent parent) {

View File

@@ -6,6 +6,7 @@ import Generics
import Location
import Namespace
import Property
import semmle.code.csharp.controlflow.ControlFlowElement
private import Conversion
private import semmle.code.csharp.metrics.Coupling
private import TypeRef
@@ -1286,7 +1287,7 @@ class TupleType extends ValueType, @tuple_type {
* A type mention, that is, any mention of a type in a source code file.
* For example, `int` is mentioned in `int M() { return 1; }`.
*/
class TypeMention extends @type_mention {
class TypeMention extends ControlFlowElement, @type_mention {
Type type;
@type_mention_parent parent;
@@ -1319,13 +1320,13 @@ class TypeMention extends @type_mention {
* }
* ```
*/
TypeMention getParent() { result = parent }
override TypeMention getParent() { result = parent }
/** Gets a textual representation of this type mention. */
string toString() { result = type.toString() }
override string toString() { result = type.toString() }
/** Gets the location of this type mention. */
Location getLocation() { type_mention_location(this, result) }
override Location getALocation() { type_mention_location(this, result) }
}
/**

View File

@@ -20,7 +20,7 @@ class ControlFlowElementOrCallable extends ExprOrStmtParent, TControlFlowElement
*/
class ControlFlowElement extends ControlFlowElementOrCallable, @control_flow_element {
/** Gets the enclosing callable of this element, if any. */
Callable getEnclosingCallable() { none() }
Callable getEnclosingCallable() { enclosingCallable(this, result) }
/** Gets the assembly that this element was compiled into. */
Assembly getAssembly() {

View File

@@ -219,7 +219,7 @@ overlayChangedFiles(
/** ELEMENTS **/
@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration
| @using_directive | @type_parameter_constraints | @externalDataElement
| @using_directive | @type_parameter_constraints | @type_mention | @externalDataElement
| @xmllocatable | @asp_element | @namespace | @preprocessor_directive;
@declaration = @callable | @generic | @assignable | @namespace;
@@ -1369,7 +1369,7 @@ compiler_generated(unique int id: @element ref);
/** CONTROL/DATA FLOW **/
@control_flow_element = @stmt | @expr | @parameter;
@control_flow_element = @stmt | @expr | @parameter | @type_mention;
/* XML Files */

View File

@@ -9,19 +9,7 @@ private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.internal.ImportStar
private import semmle.python.dataflow.new.TypeTracking
private import semmle.python.dataflow.new.internal.DataFlowPrivate
/**
* Holds if `init` is a package's `__init__.py` and `var` is a global variable in
* `init` whose name matches a submodule of the package.
*
* Inlined from `SsaSource::init_module_submodule_defn` to avoid pulling
* `semmle.python.essa.SsaDefinitions` into the new dataflow stack.
*/
private predicate initModuleSubmoduleDefn(GlobalVariable var, Module init) {
init.isPackageInit() and
exists(init.getPackage().getSubModule(var.getId())) and
var.getScope() = init
}
private import semmle.python.essa.SsaDefinitions
/**
* Python modules and the way imports are resolved are... complicated. Here's a crash course in how
@@ -338,7 +326,7 @@ module ImportResolution {
// imported yet.
exists(string submodule, Module package, EssaVariable var |
submodule = var.getName() and
initModuleSubmoduleDefn(var.getSourceVariable(), package) and
SsaSource::init_module_submodule_defn(var.getSourceVariable(), package.getEntryNode()) and
m = getModuleFromName(package.getPackageName() + "." + submodule) and
result.asCfgNode() = var.getDefinition().(EssaNodeDefinition).getDefiningNode()
)

View File

@@ -224,13 +224,6 @@ signature module AstSig<LocationSig Location> {
*/
default AstNode getTryElse(TryStmt try) { none() }
/**
* Gets the `else` block of loop statement `loop`, if any.
*
* Only some languages (e.g. Python) support `for-else` constructs.
*/
default AstNode getLoopElse(LoopStmt loop) { none() }
/** A catch clause in a try statement. */
class CatchClause extends AstNode {
/** Gets the variable declared by this catch clause. */
@@ -1585,17 +1578,10 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
n2.isBefore(loopstmt.getBody())
or
n1.isAfterValue(cond, any(BooleanSuccessor b | b.getValue() = while.booleanNot())) and
(
n2.isBefore(getLoopElse(loopstmt))
or
not exists(getLoopElse(loopstmt)) and n2.isAfter(loopstmt)
)
n2.isAfter(loopstmt)
or
n1.isAfter(loopstmt.getBody()) and
n2.isAdditional(loopstmt, loopHeaderTag())
or
n1.isAfter(getLoopElse(loopstmt)) and
n2.isAfter(loopstmt)
)
or
exists(ForeachStmt foreachstmt |
@@ -1604,11 +1590,7 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
or
n1.isAfterValue(foreachstmt.getCollection(),
any(EmptinessSuccessor t | t.getValue() = true)) and
(
n2.isBefore(getLoopElse(foreachstmt))
or
not exists(getLoopElse(foreachstmt)) and n2.isAfter(foreachstmt)
)
n2.isAfter(foreachstmt)
or
n1.isAfterValue(foreachstmt.getCollection(),
any(EmptinessSuccessor t | t.getValue() = false)) and
@@ -1621,11 +1603,7 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
n2.isAdditional(foreachstmt, loopHeaderTag())
or
n1.isAdditional(foreachstmt, loopHeaderTag()) and
(
n2.isBefore(getLoopElse(foreachstmt))
or
not exists(getLoopElse(foreachstmt)) and n2.isAfter(foreachstmt)
)
n2.isAfter(foreachstmt)
or
n1.isAdditional(foreachstmt, loopHeaderTag()) and
n2.isBefore(foreachstmt.getVariable())