Skip to content

Commit 0ecab93

Browse files
authored
Merge pull request #23 from github/aibaars/locations-lib
Add Locations.qll and import FileSystem and Locations libraries in generated AST
2 parents 83667ab + f94b5ae commit 0ecab93

File tree

5 files changed

+85
-105
lines changed

5 files changed

+85
-105
lines changed

generator/src/ql.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
use std::fmt;
22

3+
pub enum TopLevel {
4+
Class(Class),
5+
Import(String),
6+
}
7+
8+
impl fmt::Display for TopLevel {
9+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
10+
match self {
11+
TopLevel::Import(x) => write!(f, "import {}", x),
12+
TopLevel::Class(cls) => write!(f, "{}", cls),
13+
}
14+
}
15+
}
16+
317
pub struct Class {
418
pub name: String,
519
pub is_abstract: bool,
@@ -198,7 +212,7 @@ impl fmt::Display for FormalParameter {
198212
pub fn write(
199213
language_name: &str,
200214
file: &mut dyn std::io::Write,
201-
classes: &[Class],
215+
elements: &[TopLevel],
202216
) -> std::io::Result<()> {
203217
write!(file, "/*\n")?;
204218
write!(file, " * CodeQL library for {}\n", language_name)?;
@@ -208,8 +222,8 @@ pub fn write(
208222
)?;
209223
write!(file, " */\n\n")?;
210224

211-
for class in classes {
212-
write!(file, "{}\n\n", &class)?;
225+
for element in elements {
226+
write!(file, "{}\n\n", &element)?;
213227
}
214228

215229
Ok(())

generator/src/ql_gen.rs

Lines changed: 13 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type SupertypeMap = HashMap<String, BTreeSet<String>>;
1212
///
1313
/// `language` - the language for which we're generating a library
1414
/// `classes` - the list of classes to write.
15-
pub fn write(language: &Language, classes: &[ql::Class]) -> std::io::Result<()> {
15+
pub fn write(language: &Language, classes: &[ql::TopLevel]) -> std::io::Result<()> {
1616
println!(
1717
"Writing QL library for {} to '{}'",
1818
&language.name,
@@ -130,89 +130,14 @@ fn create_none_predicate(
130130
}
131131
}
132132

133-
/// Creates the special `Location` class to wrap the location table.
134-
fn create_location_class() -> ql::Class {
135-
let to_string = ql::Predicate {
136-
name: "toString".to_owned(),
137-
overridden: false,
138-
return_type: Some(ql::Type::String),
139-
formal_parameters: vec![],
140-
body: ql::Expression::Equals(
141-
Box::new(ql::Expression::Var("result".to_owned())),
142-
Box::new(ql::Expression::String("Location".to_owned())),
143-
),
144-
};
145-
let has_location_info = ql::Predicate {
146-
name: "hasLocationInfo".to_owned(),
147-
overridden: false,
148-
return_type: None,
149-
formal_parameters: vec![
150-
ql::FormalParameter {
151-
name: "filePath".to_owned(),
152-
param_type: ql::Type::String,
153-
},
154-
ql::FormalParameter {
155-
name: "startLine".to_owned(),
156-
param_type: ql::Type::Int,
157-
},
158-
ql::FormalParameter {
159-
name: "startColumn".to_owned(),
160-
param_type: ql::Type::Int,
161-
},
162-
ql::FormalParameter {
163-
name: "endLine".to_owned(),
164-
param_type: ql::Type::Int,
165-
},
166-
ql::FormalParameter {
167-
name: "endColumn".to_owned(),
168-
param_type: ql::Type::Int,
169-
},
170-
],
171-
body: ql::Expression::Exists(
172-
vec![ql::FormalParameter {
173-
param_type: ql::Type::Normal("File".to_owned()),
174-
name: "f".to_owned(),
175-
}],
176-
Box::new(ql::Expression::And(vec![
177-
ql::Expression::Pred(
178-
"locations_default".to_owned(),
179-
vec![
180-
ql::Expression::Var("this".to_owned()),
181-
ql::Expression::Var("f".to_owned()),
182-
ql::Expression::Var("startLine".to_owned()),
183-
ql::Expression::Var("startColumn".to_owned()),
184-
ql::Expression::Var("endLine".to_owned()),
185-
ql::Expression::Var("endColumn".to_owned()),
186-
],
187-
),
188-
ql::Expression::Equals(
189-
Box::new(ql::Expression::Var("filePath".to_owned())),
190-
Box::new(ql::Expression::Dot(
191-
Box::new(ql::Expression::Var("f".to_owned())),
192-
"getAbsolutePath".to_owned(),
193-
vec![],
194-
)),
195-
),
196-
])),
197-
),
198-
};
199-
ql::Class {
200-
name: "Location".to_owned(),
201-
supertypes: vec![ql::Type::AtType("location".to_owned())],
202-
is_abstract: false,
203-
characteristic_predicate: None,
204-
predicates: vec![to_string, has_location_info],
205-
}
206-
}
207-
208133
/// Given the name of the parent node, and its field information, returns the
209134
/// name of the field's type. This may be an ad-hoc union of all the possible
210135
/// types the field can take, in which case we create a new class and push it to
211136
/// `classes`.
212137
fn create_field_class(
213138
parent_name: &str,
214139
field: &node_types::Field,
215-
classes: &mut Vec<ql::Class>,
140+
classes: &mut Vec<ql::TopLevel>,
216141
supertype_map: &SupertypeMap,
217142
) -> String {
218143
if field.types.len() == 1 {
@@ -225,7 +150,7 @@ fn create_field_class(
225150
let field_union_name = format!("{}_{}_type", parent_name, &field.get_name());
226151
let field_union_name = node_types::escape_name(&field_union_name);
227152
let class_name = dbscheme_name_to_class_name(&field_union_name);
228-
classes.push(ql::Class {
153+
classes.push(ql::TopLevel::Class(ql::Class {
229154
name: class_name.clone(),
230155
is_abstract: false,
231156
supertypes: [
@@ -235,7 +160,7 @@ fn create_field_class(
235160
.concat(),
236161
characteristic_predicate: None,
237162
predicates: vec![],
238-
});
163+
}));
239164
field_union_name
240165
}
241166
}
@@ -455,9 +380,13 @@ fn create_field_getters(
455380
}
456381

457382
/// Converts the given node types into CodeQL classes wrapping the dbscheme.
458-
pub fn convert_nodes(nodes: &Vec<node_types::Entry>) -> Vec<ql::Class> {
383+
pub fn convert_nodes(nodes: &Vec<node_types::Entry>) -> Vec<ql::TopLevel> {
459384
let supertype_map = create_supertype_map(nodes);
460-
let mut classes: Vec<ql::Class> = vec![create_location_class(), create_top_class()];
385+
let mut classes: Vec<ql::TopLevel> = vec![
386+
ql::TopLevel::Import("codeql.files.FileSystem".to_owned()),
387+
ql::TopLevel::Import("codeql.Locations".to_owned()),
388+
ql::TopLevel::Class(create_top_class()),
389+
];
461390

462391
for node in nodes {
463392
match &node {
@@ -472,7 +401,7 @@ pub fn convert_nodes(nodes: &Vec<node_types::Entry>) -> Vec<ql::Class> {
472401
type_name.named,
473402
));
474403
let class_name = dbscheme_name_to_class_name(&union_name);
475-
classes.push(ql::Class {
404+
classes.push(ql::TopLevel::Class(ql::Class {
476405
name: class_name.clone(),
477406
is_abstract: false,
478407
supertypes: [
@@ -482,7 +411,7 @@ pub fn convert_nodes(nodes: &Vec<node_types::Entry>) -> Vec<ql::Class> {
482411
.concat(),
483412
characteristic_predicate: None,
484413
predicates: vec![],
485-
});
414+
}));
486415
}
487416
node_types::Entry::Table { type_name, fields } => {
488417
// Count how many columns there will be in the main table.
@@ -556,7 +485,7 @@ pub fn convert_nodes(nodes: &Vec<node_types::Entry>) -> Vec<ql::Class> {
556485
});
557486
}
558487

559-
classes.push(main_class);
488+
classes.push(ql::TopLevel::Class(main_class));
560489
}
561490
}
562491
}

ql/src/codeql/Locations.qll

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/** Provides classes for working with locations. */
2+
3+
import files.FileSystem
4+
5+
/**
6+
* A location as given by a file, a start line, a start column,
7+
* an end line, and an end column.
8+
*
9+
* For more information about locations see [LGTM locations](https://lgtm.com/help/ql/locations).
10+
*/
11+
class Location extends @location {
12+
/** Gets the file for this location. */
13+
File getFile() { locations_default(this, result, _, _, _, _) }
14+
15+
/** Gets the 1-based line number (inclusive) where this location starts. */
16+
int getStartLine() { locations_default(this, _, result, _, _, _) }
17+
18+
/** Gets the 1-based column number (inclusive) where this location starts. */
19+
int getStartColumn() { locations_default(this, _, _, result, _, _) }
20+
21+
/** Gets the 1-based line number (inclusive) where this location ends. */
22+
int getEndLine() { locations_default(this, _, _, _, result, _) }
23+
24+
/** Gets the 1-based column number (inclusive) where this location ends. */
25+
int getEndColumn() { locations_default(this, _, _, _, _, result) }
26+
27+
/** Gets the number of lines covered by this location. */
28+
int getNumLines() { result = getEndLine() - getStartLine() + 1 }
29+
30+
/** Gets a textual representation of this element. */
31+
string toString() {
32+
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
33+
hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
34+
result = filepath + "@" + startline + ":" + startcolumn + ":" + endline + ":" + endcolumn
35+
)
36+
}
37+
38+
/**
39+
* Holds if this element is at the specified location.
40+
* The location spans column `startcolumn` of line `startline` to
41+
* column `endcolumn` of line `endline` in file `filepath`.
42+
* For more information, see
43+
* [LGTM locations](https://lgtm.com/help/ql/locations).
44+
*/
45+
predicate hasLocationInfo(
46+
string filepath, int startline, int startcolumn, int endline, int endcolumn
47+
) {
48+
exists(File f |
49+
locations_default(this, f, startline, startcolumn, endline, endcolumn) and
50+
filepath = f.getAbsolutePath()
51+
)
52+
}
53+
}

ql/src/codeql_ruby/ast.qll

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,8 @@
33
* Automatically generated from the tree-sitter grammar; do not edit
44
*/
55

6-
class File extends @file {
7-
string getAbsolutePath() { files(this, result, _, _, _) }
8-
9-
string toString() { result = this.getAbsolutePath() }
10-
}
11-
12-
class Location extends @location {
13-
string toString() { result = "Location" }
14-
15-
predicate hasLocationInfo(
16-
string filePath, int startLine, int startColumn, int endLine, int endColumn
17-
) {
18-
exists(File f |
19-
locations_default(this, f, startLine, startColumn, endLine, endColumn) and
20-
filePath = f.getAbsolutePath()
21-
)
22-
}
23-
}
6+
import codeql.files.FileSystem
7+
import codeql.Locations
248

259
class Top extends @top {
2610
string toString() { none() }

0 commit comments

Comments
 (0)