Skip to content

Commit fdc9436

Browse files
authored
Merge pull request #7178 from michaelnebel/csharp-flowsummary-pp-csv
C#: Initial implementation of csv printing in FlowSummaries test
2 parents 00ee34c + d4f3a6d commit fdc9436

File tree

12 files changed

+3306
-2981
lines changed

12 files changed

+3306
-2981
lines changed

csharp/ql/lib/semmle/code/csharp/Member.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ class Parameterizable extends DotNet::Parameterizable, Declaration, @parameteriz
383383
override Parameter getParameter(int i) { params(result, _, _, i, _, this, _) }
384384

385385
/**
386-
* Gets the name of this parameter followed by its type, possibly prefixed
386+
* Gets the type of the parameter, possibly prefixed
387387
* with `out`, `ref`, or `params`, where appropriate.
388388
*/
389389
private string parameterTypeToString(int i) {

csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,38 @@ module Public {
127127
SummaryComponentStack return(ReturnKind rk) { result = singleton(SummaryComponent::return(rk)) }
128128
}
129129

130+
private predicate noComponentSpecificCsv(SummaryComponent sc) {
131+
not exists(getComponentSpecificCsv(sc))
132+
}
133+
134+
/** Gets a textual representation of this component used for flow summaries. */
135+
private string getComponentCsv(SummaryComponent sc) {
136+
result = getComponentSpecificCsv(sc)
137+
or
138+
noComponentSpecificCsv(sc) and
139+
(
140+
exists(int i | sc = TParameterSummaryComponent(i) and result = "Parameter[" + i + "]")
141+
or
142+
exists(int i | sc = TArgumentSummaryComponent(i) and result = "Argument[" + i + "]")
143+
or
144+
sc = TReturnSummaryComponent(getReturnValueKind()) and result = "ReturnValue"
145+
)
146+
}
147+
148+
/** Gets a textual representation of this stack used for flow summaries. */
149+
string getComponentStackCsv(SummaryComponentStack stack) {
150+
exists(SummaryComponent head, SummaryComponentStack tail |
151+
head = stack.head() and
152+
tail = stack.tail() and
153+
result = getComponentCsv(head) + " of " + getComponentStackCsv(tail)
154+
)
155+
or
156+
exists(SummaryComponent c |
157+
stack = TSingletonSummaryComponentStack(c) and
158+
result = getComponentCsv(c)
159+
)
160+
}
161+
130162
/**
131163
* A class that exists for QL technical reasons only (the IPA type used
132164
* to represent component stacks needs to be bounded).
@@ -970,18 +1002,31 @@ module Private {
9701002
module TestOutput {
9711003
/** A flow summary to include in the `summary/3` query predicate. */
9721004
abstract class RelevantSummarizedCallable extends SummarizedCallable {
973-
/** Gets the string representation of this callable used by `summary/3`. */
974-
string getFullString() { result = this.toString() }
1005+
/** Gets the string representation of this callable used by `summary/1`. */
1006+
abstract string getCallableCsv();
9751007
}
9761008

977-
/** A query predicate for outputting flow summaries in QL tests. */
978-
query predicate summary(string callable, string flow, boolean preservesValue) {
1009+
/** Render the kind in the format used in flow summaries. */
1010+
private string renderKind(boolean preservesValue) {
1011+
preservesValue = true and result = "value"
1012+
or
1013+
preservesValue = false and result = "taint"
1014+
}
1015+
1016+
/**
1017+
* A query predicate for outputting flow summaries in semi-colon separated format in QL tests.
1018+
* The syntax is: "namespace;type;overrides;name;signature;ext;inputspec;outputspec;kind",
1019+
* ext is hardcoded to empty.
1020+
*/
1021+
query predicate summary(string csv) {
9791022
exists(
980-
RelevantSummarizedCallable c, SummaryComponentStack input, SummaryComponentStack output
1023+
RelevantSummarizedCallable c, SummaryComponentStack input, SummaryComponentStack output,
1024+
boolean preservesValue
9811025
|
982-
callable = c.getFullString() and
9831026
c.propagatesFlow(input, output, preservesValue) and
984-
flow = input + " -> " + output
1027+
csv =
1028+
c.getCallableCsv() + ";;" + getComponentStackCsv(input) + ";" +
1029+
getComponentStackCsv(output) + ";" + renderKind(preservesValue)
9851030
)
9861031
}
9871032
}

csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,26 @@ SummaryComponent interpretComponentSpecific(string c) {
138138
)
139139
}
140140

141+
/** Gets the textual representation of the content in the format used for flow summaries. */
142+
private string getContentSpecificCsv(Content c) {
143+
c = TElementContent() and result = "Element"
144+
or
145+
exists(Field f | c = TFieldContent(f) and result = "Field[" + f.getQualifiedName() + "]")
146+
or
147+
exists(Property p | c = TPropertyContent(p) and result = "Property[" + p.getQualifiedName() + "]")
148+
}
149+
150+
/** Gets the textual representation of a summary component in the format used for flow summaries. */
151+
string getComponentSpecificCsv(SummaryComponent sc) {
152+
exists(Content c | sc = TContentSummaryComponent(c) and result = getContentSpecificCsv(c))
153+
or
154+
exists(ReturnKind rk |
155+
sc = TReturnSummaryComponent(rk) and
156+
result = "ReturnValue[" + rk + "]" and
157+
not rk instanceof NormalReturnKind
158+
)
159+
}
160+
141161
class SourceOrSinkElement = Element;
142162

143163
/** Gets the return kind corresponding to specification `"ReturnValue"`. */

0 commit comments

Comments
 (0)