make sure the consisntecy-checking library does not mix configurations

This commit is contained in:
Erik Krogh Kristensen
2020-07-08 10:28:41 +02:00
parent ec38df69b3
commit 022cafebd3

View File

@@ -25,6 +25,20 @@ abstract class ConsistencyConfiguration extends string {
File getAFile() { none() }
}
/**
* A string that either equals a `ConsistencyConfiguration`, or the empty string if no such configuration exists.
*
* Is user internally to match a configuration or lack thereof.
*/
final private class Conf extends string {
Conf() {
this instanceof ConsistencyConfiguration
or
not exists(ConsistencyConfiguration c) and
this = ""
}
}
/**
* A line-comment that asserts whether a result exists at that line or not.
* Can optionally include `[INCONSISTENCY]` to indicate that a consistency issue is expected at the location
@@ -54,22 +68,23 @@ private class AssertionComment extends LineComment {
private DataFlow::Node getASink() { exists(DataFlow::Configuration cfg | cfg.hasFlow(_, result)) }
/**
* Gets all the alerts for consistency consistency checking.
* Gets all the alerts for consistency consistency checking from a configuration `conf`.
*/
private DataFlow::Node alerts() {
result = any(ConsistencyConfiguration res).getAnAlert()
private DataFlow::Node alerts(Conf conf) {
result = any(ConsistencyConfiguration res | res = conf).getAnAlert()
or
not exists(ConsistencyConfiguration r) and
result = getASink()
result = getASink() and
conf = ""
}
/**
* Gets an alert in `file` at `line`.
* Gets an alert in `file` at `line` for configuration `conf`.
* The `line` can be either the first or the last line of the alert.
* And if no expression exists at `line`, then an alert on the next line is used.
*/
private DataFlow::Node getAlert(File file, int line) {
result = alerts() and
private DataFlow::Node getAlert(File file, int line, Conf conf) {
result = alerts(conf) and
result.getFile() = file and
(result.hasLocationInfo(_, _, _, line, _) or result.hasLocationInfo(_, line, _, _, _))
or
@@ -77,7 +92,7 @@ private DataFlow::Node getAlert(File file, int line) {
not exists(Expr e |
e.getFile() = file and [e.getLocation().getStartLine(), e.getLocation().getEndLine()] = line
) and
result = alerts() and
result = alerts(conf) and
result.getFile() = file and
result.hasLocationInfo(_, line + 1, _, _, _)
}
@@ -91,66 +106,70 @@ private AssertionComment getComment(File file, int line) {
}
/**
* Holds if there is a false positive in `file` at `line`
* Holds if there is a false positive in `file` at `line` for configuration `conf`.
*/
private predicate falsePositive(File file, int line, AssertionComment comment) {
exists(getAlert(file, line)) and
private predicate falsePositive(File file, int line, AssertionComment comment, Conf conf) {
exists(getAlert(file, line, conf)) and
comment = getComment(file, line) and
not comment.shouldHaveAlert()
}
/**
* Holds if there is a false negative in `file` at `line`
* Holds if there is a false negative in `file` at `line` for configuration `conf`.
*/
private predicate falseNegative(File file, int line, AssertionComment comment) {
not exists(getAlert(file, line)) and
private predicate falseNegative(File file, int line, AssertionComment comment, Conf conf) {
not exists(getAlert(file, line, conf)) and
comment = getComment(file, line) and
comment.shouldHaveAlert()
}
/**
* Gets a file that should be included for consistency checking.
* Gets a file that should be included for consistency checking for configuration `conf`.
*/
private File getATestFile() {
private File getATestFile(string conf) {
not exists(any(ConsistencyConfiguration res).getAFile()) and
result = any(LineComment comment).getFile()
result = any(LineComment comment).getFile() and
conf = ""
or
result = any(ConsistencyConfiguration res).getAFile()
result = any(ConsistencyConfiguration res | res = conf).getAFile()
}
/**
* Gets a description of the configuration that has a sink in `file` at `line`.
* Gets a description of the configuration that has a sink in `file` at `line` for configuration `conf`.
* Or the empty string
*/
bindingset[file, line]
private string getSinkDescription(File file, int line) {
not exists(DataFlow::Configuration c | c.hasFlow(_, getAlert(file, line))) and result = ""
private string getSinkDescription(File file, int line, Conf conf) {
not exists(DataFlow::Configuration c | c.hasFlow(_, getAlert(file, line, conf))) and
result = ""
or
exists(DataFlow::Configuration c | c.hasFlow(_, getAlert(file, line)) | result = " for " + c)
exists(DataFlow::Configuration c | c.hasFlow(_, getAlert(file, line, conf)) |
result = " for " + c
)
}
/**
* Holds if there is a consistency-issue at `location` with description `msg`.
* Holds if there is a consistency-issue at `location` with description `msg` for configuration `conf`.
* The consistency issue an unexpected false positive/negative.
* Or that false positive/negative was expected, and none were found.
*/
query predicate consistencyIssue(string location, string msg, string commentText) {
query predicate consistencyIssue(string location, string msg, string commentText, Conf conf) {
exists(File file, int line |
file = getATestFile() and location = file.getRelativePath() + ":" + line
file = getATestFile(conf) and location = file.getRelativePath() + ":" + line
|
exists(AssertionComment comment |
comment.getText().trim() = commentText and comment = getComment(file, line)
|
falsePositive(file, line, comment) and
falsePositive(file, line, comment, conf) and
not comment.expectConsistencyError() and
msg = "did not expected an alert, but found an alert" + getSinkDescription(file, line)
msg = "did not expect an alert, but found an alert" + getSinkDescription(file, line, conf)
or
falseNegative(file, line, comment) and
falseNegative(file, line, comment, conf) and
not comment.expectConsistencyError() and
msg = "expected an alert, but found none"
or
not falsePositive(file, line, comment) and
not falseNegative(file, line, comment) and
not falsePositive(file, line, comment, conf) and
not falseNegative(file, line, comment, conf) and
comment.expectConsistencyError() and
msg = "expected consistency issue, but found no such issue (" + comment.getText().trim() + ")"
)