Files
codeql/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.ql
2019-07-08 13:55:29 +01:00

61 lines
1.7 KiB
Plaintext

import javascript
import semmle.javascript.dataflow.internal.FlowSteps as FlowSteps
/**
* Gets the value of a tag of form `tag:value` in the JSDoc comment for `doc`.
*
* We avoid using JSDoc tags as the call graph construction may depend on them
* in the future.
*/
string getAnnotation(Documentable doc, string tag) {
exists(string text |
text = doc.getDocumentation().getComment().getText().regexpFind("[\\w]+:[\\w\\d.]+", _, _) and
tag = text.regexpCapture("([\\w]+):.*", 1) and
result = text.regexpCapture(".*:([\\w\\d.]+)", 1)
)
}
/** A function annotated with `name:NAME` */
class AnnotatedFunction extends Function {
string name;
AnnotatedFunction() { name = getAnnotation(this, "name") }
string getCalleeName() {
result = name
}
}
/** A function annotated with `calls:NAME` */
class AnnotatedCall extends InvokeExpr {
string calls;
AnnotatedCall() { calls = getAnnotation(this, "calls") }
string getCallTargetName() {
result = calls
}
AnnotatedFunction getAnExpectedCallee() {
result.getCalleeName() = getCallTargetName()
}
}
query predicate spuriousCallee(AnnotatedCall call, AnnotatedFunction target) {
FlowSteps::calls(call.flow(), target) and
not target = call.getAnExpectedCallee()
}
query predicate missingCallee(AnnotatedCall call, AnnotatedFunction target) {
not FlowSteps::calls(call.flow(), target) and
target = call.getAnExpectedCallee()
}
query predicate badAnnotation(string name) {
name = any(AnnotatedCall cl).getCallTargetName() and
not name = any(AnnotatedFunction cl).getCalleeName()
or
not name = any(AnnotatedCall cl).getCallTargetName() and
name = any(AnnotatedFunction cl).getCalleeName()
}