Merge pull request #261 from github/getPrimaryQlClasses

Implement getPrimaryQlClasses
This commit is contained in:
Nick Rolfe
2021-09-07 12:02:15 +01:00
committed by GitHub
6 changed files with 80 additions and 29 deletions

View File

@@ -127,12 +127,13 @@ pub enum Expression<'a> {
Or(Vec<Expression<'a>>),
Equals(Box<Expression<'a>>, Box<Expression<'a>>),
Dot(Box<Expression<'a>>, &'a str, Vec<Expression<'a>>),
Aggregate(
&'a str,
Vec<FormalParameter<'a>>,
Box<Expression<'a>>,
Box<Expression<'a>>,
),
Aggregate {
name: &'a str,
vars: Vec<FormalParameter<'a>>,
range: Option<Box<Expression<'a>>>,
expr: Box<Expression<'a>>,
second_expr: Option<Box<Expression<'a>>>,
},
}
impl<'a> fmt::Display for Expression<'a> {
@@ -188,15 +189,31 @@ impl<'a> fmt::Display for Expression<'a> {
}
write!(f, ")")
}
Expression::Aggregate(n, vars, range, term) => {
write!(f, "{}(", n)?;
for (index, var) in vars.iter().enumerate() {
if index > 0 {
write!(f, ", ")?;
Expression::Aggregate {
name,
vars,
range,
expr,
second_expr,
} => {
write!(f, "{}(", name)?;
if vars.len() > 0 {
for (index, var) in vars.iter().enumerate() {
if index > 0 {
write!(f, ", ")?;
}
write!(f, "{}", var)?;
}
write!(f, "{}", var)?;
write!(f, " | ")?;
}
write!(f, " | {} | {})", range, term)
if let Some(range) = range {
write!(f, "{} | ", range)?;
}
write!(f, "{}", expr)?;
if let Some(second_expr) = second_expr {
write!(f, ", {}", second_expr)?;
}
write!(f, ")")
}
}
}

View File

@@ -79,6 +79,27 @@ pub fn create_ast_node_class<'a>(ast_node: &'a str, ast_node_parent: &'a str) ->
Box::new(ql::Expression::String("???")),
),
};
let get_primary_ql_classes = ql::Predicate {
qldoc: Some(
"Gets a comma-separated list of the names of the primary CodeQL \
classes to which this element belongs."
.to_owned(),
),
name: "getPrimaryQlClasses",
overridden: false,
return_type: Some(ql::Type::String),
formal_parameters: vec![],
body: ql::Expression::Equals(
Box::new(ql::Expression::Var("result")),
Box::new(ql::Expression::Aggregate {
name: "concat",
vars: vec![],
range: None,
expr: Box::new(ql::Expression::Pred("getAPrimaryQlClass", vec![])),
second_expr: Some(Box::new(ql::Expression::String(","))),
}),
),
};
ql::Class {
qldoc: Some(String::from("The base class for all AST nodes")),
name: "AstNode",
@@ -92,6 +113,7 @@ pub fn create_ast_node_class<'a>(ast_node: &'a str, ast_node_parent: &'a str) ->
get_parent_index,
get_a_field_or_child,
get_a_primary_ql_class,
get_primary_ql_classes,
],
}
}
@@ -410,15 +432,16 @@ fn create_field_getters<'a>(
})
.collect();
(
ql::Expression::Aggregate(
"exists",
vec![ql::FormalParameter {
ql::Expression::Aggregate {
name: "exists",
vars: vec![ql::FormalParameter {
name: "value",
param_type: ql::Type::Int,
}],
Box::new(get_value),
Box::new(ql::Expression::Or(disjuncts)),
),
range: Some(Box::new(get_value)),
expr: Box::new(ql::Expression::Or(disjuncts)),
second_expr: None,
},
// Since the getter returns a string and not an AstNode, it won't be part of getAFieldOrChild:
None,
)

View File

@@ -1,17 +1,11 @@
import codeql.ruby.AST
import codeql.ruby.ast.internal.Synthesis
private string getAPrimaryQlClass(AstNode node) {
result = node.getAPrimaryQlClass()
or
not exists(node.getAPrimaryQlClass()) and result = "(none)"
}
query predicate missingParent(AstNode node, string cls) {
not exists(node.getParent()) and
node.getLocation().getFile().getExtension() != "erb" and
not node instanceof Toplevel and
cls = getAPrimaryQlClass(node)
cls = node.getPrimaryQlClasses()
}
pragma[noinline]
@@ -22,7 +16,7 @@ private AstNode parent(AstNode child, int desugarLevel) {
query predicate multipleParents(AstNode node, AstNode parent, string cls) {
parent = node.getParent() and
cls = getAPrimaryQlClass(parent) and
cls = parent.getPrimaryQlClasses() and
exists(AstNode one, AstNode two, int desugarLevel |
one = parent(node, desugarLevel) and
two = parent(node, desugarLevel) and

View File

@@ -32,6 +32,12 @@ class AstNode extends TAstNode {
*/
string getAPrimaryQlClass() { result = "???" }
/**
* Gets a comma-separated list of the names of the primary CodeQL classes to
* which this element belongs.
*/
final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") }
/** Gets the enclosing module, if any. */
ModuleBase getEnclosingModule() {
exists(Scope::Range s |

View File

@@ -26,6 +26,9 @@ module Ruby {
/** Gets the name of the primary QL class for this element. */
string getAPrimaryQlClass() { result = "???" }
/** Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs. */
string getPrimaryQlClasses() { result = concat(getAPrimaryQlClass(), ",") }
}
/** A token. */
@@ -1864,6 +1867,9 @@ module Erb {
/** Gets the name of the primary QL class for this element. */
string getAPrimaryQlClass() { result = "???" }
/** Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs. */
string getPrimaryQlClasses() { result = concat(getAPrimaryQlClass(), ",") }
}
/** A token. */

View File

@@ -18,10 +18,15 @@ class RegExpParent extends TRegExpParent {
/**
* Gets the name of a primary CodeQL class to which this regular
* expression
* term belongs.
* expression term belongs.
*/
string getAPrimaryQlClass() { result = "RegExpParent" }
/**
* Gets a comma-separated list of the names of the primary CodeQL classes to
* which this regular expression term belongs.
*/
final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") }
}
class RegExpLiteral extends TRegExpLiteral, RegExpParent {