Skip to content

Commit ee51e15

Browse files
authored
Merge pull request github#6217 from hvitved/csharp/dataflow/csv-override-fix
C#: Fix CSV overrides logic
2 parents f83f950 + 7a475eb commit ee51e15

File tree

4 files changed

+65
-26
lines changed

4 files changed

+65
-26
lines changed

csharp/ql/src/semmle/code/csharp/dataflow/ExternalFlow.qll

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -325,33 +325,49 @@ private predicate elementSpec(
325325
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _)
326326
}
327327

328+
private predicate elementSpec(
329+
string namespace, string type, boolean subtypes, string name, string signature, string ext,
330+
UnboundValueOrRefType t
331+
) {
332+
elementSpec(namespace, type, subtypes, name, signature, ext) and
333+
t.hasQualifiedName(namespace, type)
334+
}
335+
328336
private class UnboundValueOrRefType extends ValueOrRefType {
329337
UnboundValueOrRefType() { this.isUnboundDeclaration() }
330338

331-
UnboundValueOrRefType getASubTypeUnbound() { result = this.getASubType().getUnboundDeclaration() }
339+
UnboundValueOrRefType getASubTypeUnbound() {
340+
exists(Type t |
341+
result.getABaseType() = t and
342+
this = t.getUnboundDeclaration()
343+
)
344+
}
332345
}
333346

334-
bindingset[namespace, type, subtypes]
335-
private UnboundValueOrRefType interpretType(string namespace, string type, boolean subtypes) {
336-
exists(UnboundValueOrRefType t |
337-
t.hasQualifiedName(namespace, type) and
338-
if subtypes = true then result = t.getASubTypeUnbound*() else result = t
339-
)
340-
}
347+
private class UnboundCallable extends Callable, Virtualizable {
348+
UnboundCallable() { this.isUnboundDeclaration() }
341349

342-
private Member interpretMember(
343-
string namespace, string type, boolean subtypes, string name, string signature
344-
) {
345-
elementSpec(namespace, type, subtypes, name, signature, _) and
346-
exists(UnboundValueOrRefType t |
347-
t = interpretType(namespace, type, subtypes) and
348-
result.getDeclaringType() = t and
349-
result.hasName(name)
350-
)
350+
predicate overridesOrImplementsUnbound(UnboundCallable that) {
351+
exists(Callable c |
352+
this.overridesOrImplementsOrEquals(c) and
353+
this != c and
354+
that = c.getUnboundDeclaration()
355+
)
356+
}
351357
}
352358

353359
private class InterpretedCallable extends Callable {
354-
InterpretedCallable() { this = interpretMember(_, _, _, _, _) }
360+
InterpretedCallable() {
361+
exists(UnboundValueOrRefType t, boolean subtypes, string name |
362+
elementSpec(_, _, subtypes, name, _, _, t) and
363+
this.hasName(name)
364+
|
365+
this.getDeclaringType() = t
366+
or
367+
subtypes = true and
368+
this.getDeclaringType() = t.getASubTypeUnbound+()
369+
)
370+
}
355371
}
356372

357373
private string paramsStringPartA(InterpretedCallable c, int i) {
@@ -388,10 +404,13 @@ private string paramsString(InterpretedCallable c) {
388404
private Element interpretElement0(
389405
string namespace, string type, boolean subtypes, string name, string signature
390406
) {
391-
elementSpec(namespace, type, subtypes, name, signature, _) and
392-
exists(UnboundValueOrRefType t | t = interpretType(namespace, type, subtypes) |
407+
exists(UnboundValueOrRefType t | elementSpec(namespace, type, subtypes, name, signature, _, t) |
393408
exists(Member m |
394-
result = m and
409+
(
410+
result = m
411+
or
412+
subtypes = true and result.(UnboundCallable).overridesOrImplementsUnbound(m)
413+
) and
395414
m.getDeclaringType() = t and
396415
m.hasName(name)
397416
|
@@ -400,6 +419,12 @@ private Element interpretElement0(
400419
paramsString(m) = signature
401420
)
402421
or
422+
(
423+
result = t
424+
or
425+
subtypes = true and
426+
result = t.(UnboundValueOrRefType).getASubTypeUnbound+()
427+
) and
403428
result = t and
404429
name = "" and
405430
signature = ""

csharp/ql/test/library-tests/dataflow/external-models/Steps.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ void Foo()
4040
var gen = new Generic<int>();
4141
gen.StepGeneric(0);
4242
gen.StepGeneric2(false);
43+
44+
new Sub().StepOverride("string");
4345
}
4446

4547
object StepArgRes(object x) { return null; }
@@ -74,5 +76,15 @@ class Generic<T>
7476

7577
public T StepGeneric2<S>(S s) => throw null;
7678
}
79+
80+
class Base<T>
81+
{
82+
public virtual T StepOverride(T t) => throw null;
83+
}
84+
85+
class Sub : Base<string>
86+
{
87+
public override string StepOverride(string i) => throw null;
88+
}
7789
}
7890
}

csharp/ql/test/library-tests/dataflow/external-models/steps.expected

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ summaryThroughStep
1010
| Steps.cs:26:13:26:31 | this access | Steps.cs:26:25:26:30 | [post] access to local variable argOut | false |
1111
| Steps.cs:41:29:41:29 | 0 | Steps.cs:41:13:41:30 | call to method StepGeneric | true |
1212
| Steps.cs:42:30:42:34 | false | Steps.cs:42:13:42:35 | call to method StepGeneric2 | true |
13+
| Steps.cs:44:36:44:43 | "string" | Steps.cs:44:13:44:44 | call to method StepOverride | true |
1314
summaryGetterStep
14-
| Steps.cs:28:13:28:16 | this access | Steps.cs:28:13:28:34 | call to method StepFieldGetter | Steps.cs:55:13:55:17 | field Field |
15-
| Steps.cs:32:13:32:16 | this access | Steps.cs:32:13:32:37 | call to method StepPropertyGetter | Steps.cs:61:13:61:20 | property Property |
15+
| Steps.cs:28:13:28:16 | this access | Steps.cs:28:13:28:34 | call to method StepFieldGetter | Steps.cs:57:13:57:17 | field Field |
16+
| Steps.cs:32:13:32:16 | this access | Steps.cs:32:13:32:37 | call to method StepPropertyGetter | Steps.cs:63:13:63:20 | property Property |
1617
| Steps.cs:36:13:36:16 | this access | Steps.cs:36:13:36:36 | call to method StepElementGetter | file://:0:0:0:0 | element |
1718
summarySetterStep
18-
| Steps.cs:30:34:30:34 | 0 | Steps.cs:30:13:30:16 | [post] this access | Steps.cs:55:13:55:17 | field Field |
19-
| Steps.cs:34:37:34:37 | 0 | Steps.cs:34:13:34:16 | [post] this access | Steps.cs:61:13:61:20 | property Property |
19+
| Steps.cs:30:34:30:34 | 0 | Steps.cs:30:13:30:16 | [post] this access | Steps.cs:57:13:57:17 | field Field |
20+
| Steps.cs:34:37:34:37 | 0 | Steps.cs:34:13:34:16 | [post] this access | Steps.cs:63:13:63:20 | property Property |
2021
| Steps.cs:38:36:38:36 | 0 | Steps.cs:38:13:38:16 | [post] this access | file://:0:0:0:0 | element |

csharp/ql/test/library-tests/dataflow/external-models/steps.ql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ class SummaryModelTest extends SummaryModelCsv {
2121
"My.Qltest;C;false;StepElementGetter;();;Element of Argument[-1];ReturnValue;value",
2222
"My.Qltest;C;false;StepElementSetter;(System.Int32);;Argument[0];Element of Argument[-1];value",
2323
"My.Qltest;C+Generic<>;false;StepGeneric;(T);;Argument[0];ReturnValue;value",
24-
"My.Qltest;C+Generic<>;false;StepGeneric2;(S);;Argument[0];ReturnValue;value"
24+
"My.Qltest;C+Generic<>;false;StepGeneric2;(S);;Argument[0];ReturnValue;value",
25+
"My.Qltest;C+Base<>;true;StepOverride;(T);;Argument[0];ReturnValue;value"
2526
]
2627
}
2728
}

0 commit comments

Comments
 (0)