mirror of
https://github.com/github/codeql.git
synced 2026-04-28 18:25:24 +02:00
@@ -26,12 +26,12 @@ fn main() -> std::io::Result<()> {
|
||||
|
||||
for line in env::var("LGTM_INDEX_FILTERS")
|
||||
.unwrap_or_default()
|
||||
.split("\n")
|
||||
.split('\n')
|
||||
{
|
||||
if line.starts_with("include:") {
|
||||
cmd.arg("--include").arg(&line[8..]);
|
||||
} else if line.starts_with("exclude:") {
|
||||
cmd.arg("--exclude").arg(&line[8..]);
|
||||
if let Some(stripped) = line.strip_prefix("include:") {
|
||||
cmd.arg("--include").arg(stripped);
|
||||
} else if let Some(stripped) = line.strip_prefix("exclude:") {
|
||||
cmd.arg("--exclude").arg(stripped);
|
||||
}
|
||||
}
|
||||
let exit = &cmd.spawn()?.wait()?;
|
||||
|
||||
@@ -165,7 +165,7 @@ pub fn extract(
|
||||
schema: &NodeTypeMap,
|
||||
trap_writer: &mut TrapWriter,
|
||||
path: &Path,
|
||||
source: &Vec<u8>,
|
||||
source: &[u8],
|
||||
ranges: &[Range],
|
||||
) -> std::io::Result<()> {
|
||||
let span = span!(
|
||||
@@ -180,13 +180,13 @@ pub fn extract(
|
||||
|
||||
let mut parser = Parser::new();
|
||||
parser.set_language(language).unwrap();
|
||||
parser.set_included_ranges(&ranges).unwrap();
|
||||
parser.set_included_ranges(ranges).unwrap();
|
||||
let tree = parser.parse(&source, None).expect("Failed to parse file");
|
||||
trap_writer.comment(format!("Auto-generated TRAP file for {}", path.display()));
|
||||
let file_label = &trap_writer.populate_file(path);
|
||||
let mut visitor = Visitor {
|
||||
source: &source,
|
||||
trap_writer: trap_writer,
|
||||
source,
|
||||
trap_writer,
|
||||
// TODO: should we handle path strings that are not valid UTF8 better?
|
||||
path: format!("{}", path.display()),
|
||||
file_label: *file_label,
|
||||
@@ -205,15 +205,7 @@ pub fn extract(
|
||||
/// HTML entities.
|
||||
fn escape_key<'a, S: Into<Cow<'a, str>>>(key: S) -> Cow<'a, str> {
|
||||
fn needs_escaping(c: char) -> bool {
|
||||
match c {
|
||||
'&' => true,
|
||||
'{' => true,
|
||||
'}' => true,
|
||||
'"' => true,
|
||||
'@' => true,
|
||||
'#' => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(c, '&' | '{' | '}' | '"' | '@' | '#')
|
||||
}
|
||||
|
||||
let key = key.into();
|
||||
@@ -296,7 +288,7 @@ struct Visitor<'a> {
|
||||
/// source file.
|
||||
file_label: Label,
|
||||
/// The source code as a UTF-8 byte array
|
||||
source: &'a Vec<u8>,
|
||||
source: &'a [u8],
|
||||
/// A TrapWriter to accumulate trap entries
|
||||
trap_writer: &'a mut TrapWriter,
|
||||
/// A counter for top-level child nodes
|
||||
@@ -342,7 +334,7 @@ impl Visitor<'_> {
|
||||
full_error_message: String,
|
||||
node: Node,
|
||||
) {
|
||||
let (start_line, start_column, end_line, end_column) = location_for(&self.source, node);
|
||||
let (start_line, start_column, end_line, end_column) = location_for(self.source, node);
|
||||
let loc = self.trap_writer.location(
|
||||
self.file_label,
|
||||
start_line,
|
||||
@@ -373,7 +365,7 @@ impl Visitor<'_> {
|
||||
let id = self.trap_writer.fresh_id();
|
||||
|
||||
self.stack.push((id, 0, Vec::new()));
|
||||
return true;
|
||||
true
|
||||
}
|
||||
|
||||
fn leave_node(&mut self, field_name: Option<&'static str>, node: Node) {
|
||||
@@ -381,7 +373,7 @@ impl Visitor<'_> {
|
||||
return;
|
||||
}
|
||||
let (id, _, child_nodes) = self.stack.pop().expect("Vistor: empty stack");
|
||||
let (start_line, start_column, end_line, end_column) = location_for(&self.source, node);
|
||||
let (start_line, start_column, end_line, end_column) = location_for(self.source, node);
|
||||
let loc = self.trap_writer.location(
|
||||
self.file_label,
|
||||
start_line,
|
||||
@@ -440,11 +432,10 @@ impl Visitor<'_> {
|
||||
Arg::Int(parent_index),
|
||||
],
|
||||
);
|
||||
let mut all_args = Vec::new();
|
||||
all_args.push(Arg::Label(id));
|
||||
let mut all_args = vec![Arg::Label(id)];
|
||||
all_args.extend(args);
|
||||
all_args.push(Arg::Label(loc));
|
||||
self.trap_writer.add_tuple(&table_name, all_args);
|
||||
self.trap_writer.add_tuple(table_name, all_args);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@@ -479,8 +470,8 @@ impl Visitor<'_> {
|
||||
fn complex_node(
|
||||
&mut self,
|
||||
node: &Node,
|
||||
fields: &Vec<Field>,
|
||||
child_nodes: &Vec<ChildNode>,
|
||||
fields: &[Field],
|
||||
child_nodes: &[ChildNode],
|
||||
parent_id: Label,
|
||||
) -> Option<Vec<Arg>> {
|
||||
let mut map: Map<&Option<String>, (&Field, Vec<Arg>)> = Map::new();
|
||||
@@ -517,22 +508,20 @@ impl Visitor<'_> {
|
||||
);
|
||||
self.record_parse_error_for_node(error_message, full_error_message, *node);
|
||||
}
|
||||
} else {
|
||||
if child_node.field_name.is_some() || child_node.type_name.named {
|
||||
let error_message = format!(
|
||||
"value for unknown field: {}::{} and type {:?}",
|
||||
node.kind(),
|
||||
&child_node.field_name.unwrap_or("child"),
|
||||
&child_node.type_name
|
||||
);
|
||||
let full_error_message = format!(
|
||||
"{}:{}: {}",
|
||||
&self.path,
|
||||
node.start_position().row + 1,
|
||||
error_message
|
||||
);
|
||||
self.record_parse_error_for_node(error_message, full_error_message, *node);
|
||||
}
|
||||
} else if child_node.field_name.is_some() || child_node.type_name.named {
|
||||
let error_message = format!(
|
||||
"value for unknown field: {}::{} and type {:?}",
|
||||
node.kind(),
|
||||
&child_node.field_name.unwrap_or("child"),
|
||||
&child_node.type_name
|
||||
);
|
||||
let full_error_message = format!(
|
||||
"{}:{}: {}",
|
||||
&self.path,
|
||||
node.start_position().row + 1,
|
||||
error_message
|
||||
);
|
||||
self.record_parse_error_for_node(error_message, full_error_message, *node);
|
||||
}
|
||||
}
|
||||
let mut args = Vec::new();
|
||||
@@ -580,13 +569,12 @@ impl Visitor<'_> {
|
||||
);
|
||||
break;
|
||||
}
|
||||
let mut args = Vec::new();
|
||||
args.push(Arg::Label(parent_id));
|
||||
let mut args = vec![Arg::Label(parent_id)];
|
||||
if *has_index {
|
||||
args.push(Arg::Int(index))
|
||||
}
|
||||
args.push(child_value.clone());
|
||||
self.trap_writer.add_tuple(&table_name, args);
|
||||
self.trap_writer.add_tuple(table_name, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -604,13 +592,10 @@ impl Visitor<'_> {
|
||||
if tp == single_type {
|
||||
return true;
|
||||
}
|
||||
match &self.schema.get(single_type).unwrap().kind {
|
||||
EntryKind::Union { members } => {
|
||||
if self.type_matches_set(tp, members) {
|
||||
return true;
|
||||
}
|
||||
if let EntryKind::Union { members } = &self.schema.get(single_type).unwrap().kind {
|
||||
if self.type_matches_set(tp, members) {
|
||||
return true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
node_types::FieldTypeInfo::Multiple { types, .. } => {
|
||||
@@ -640,7 +625,7 @@ impl Visitor<'_> {
|
||||
}
|
||||
|
||||
// Emit a slice of a source file as an Arg.
|
||||
fn sliced_source_arg(source: &Vec<u8>, n: Node) -> Arg {
|
||||
fn sliced_source_arg(source: &[u8], n: Node) -> Arg {
|
||||
let range = n.byte_range();
|
||||
Arg::String(String::from_utf8_lossy(&source[range.start..range.end]).into_owned())
|
||||
}
|
||||
@@ -648,7 +633,7 @@ fn sliced_source_arg(source: &Vec<u8>, n: Node) -> Arg {
|
||||
// Emit a pair of `TrapEntry`s for the provided node, appropriately calibrated.
|
||||
// The first is the location and label definition, and the second is the
|
||||
// 'Located' entry.
|
||||
fn location_for<'a>(source: &Vec<u8>, n: Node) -> (usize, usize, usize, usize) {
|
||||
fn location_for(source: &[u8], n: Node) -> (usize, usize, usize, usize) {
|
||||
// Tree-sitter row, column values are 0-based while CodeQL starts
|
||||
// counting at 1. In addition Tree-sitter's row and column for the
|
||||
// end position are exclusive while CodeQL's end positions are inclusive.
|
||||
@@ -806,7 +791,7 @@ impl fmt::Display for Arg {
|
||||
/// the string is sliced at the provided limit. If there is a multi-byte character
|
||||
/// at the limit then the returned slice will be slightly shorter than the limit to
|
||||
/// avoid splitting that multi-byte character.
|
||||
fn limit_string(string: &String, max_size: usize) -> &str {
|
||||
fn limit_string(string: &str, max_size: usize) -> &str {
|
||||
if string.len() <= max_size {
|
||||
return string;
|
||||
}
|
||||
@@ -817,7 +802,7 @@ fn limit_string(string: &String, max_size: usize) -> &str {
|
||||
// encoded data any byte that matches the bit pattern 10XXXXXX is not a start byte.
|
||||
// Therefore we decrement the index as long as there are bytes matching this pattern.
|
||||
// This ensures we cut the string at the border between one character and another.
|
||||
while index > 0 && unsafe { (*p.offset(index as isize) & 0b11000000) == 0b10000000 } {
|
||||
while index > 0 && unsafe { (*p.add(index) & 0b11000000) == 0b10000000 } {
|
||||
index -= 1;
|
||||
}
|
||||
&string[0..index]
|
||||
|
||||
@@ -2,7 +2,6 @@ mod extractor;
|
||||
|
||||
extern crate num_cpus;
|
||||
|
||||
use clap;
|
||||
use flate2::write::GzEncoder;
|
||||
use rayon::prelude::*;
|
||||
use std::fs;
|
||||
@@ -57,7 +56,7 @@ impl TrapCompression {
|
||||
* (minimum of 1). If unspecified, should be considered as set to -1."
|
||||
*/
|
||||
fn num_codeql_threads() -> usize {
|
||||
let threads_str = std::env::var("CODEQL_THREADS").unwrap_or("-1".to_owned());
|
||||
let threads_str = std::env::var("CODEQL_THREADS").unwrap_or_else(|_| "-1".to_owned());
|
||||
match threads_str.parse::<i32>() {
|
||||
Ok(num) if num <= 0 => {
|
||||
let reduction = -num as usize;
|
||||
@@ -191,12 +190,12 @@ fn main() -> std::io::Result<()> {
|
||||
}
|
||||
|
||||
fn write_trap(
|
||||
trap_dir: &PathBuf,
|
||||
trap_dir: &Path,
|
||||
path: PathBuf,
|
||||
trap_writer: extractor::TrapWriter,
|
||||
trap_compression: &TrapCompression,
|
||||
) -> std::io::Result<()> {
|
||||
let trap_file = path_for(&trap_dir, &path, trap_compression.extension());
|
||||
let trap_file = path_for(trap_dir, &path, trap_compression.extension());
|
||||
std::fs::create_dir_all(&trap_file.parent().unwrap())?;
|
||||
let trap_file = std::fs::File::create(&trap_file)?;
|
||||
let mut trap_file = BufWriter::new(trap_file);
|
||||
@@ -211,7 +210,7 @@ fn write_trap(
|
||||
|
||||
fn scan_erb(
|
||||
erb: Language,
|
||||
source: &Vec<u8>,
|
||||
source: &[u8],
|
||||
directive_id: u16,
|
||||
output_directive_id: u16,
|
||||
code_id: u16,
|
||||
@@ -238,7 +237,7 @@ fn scan_erb(
|
||||
}
|
||||
}
|
||||
}
|
||||
if result.len() == 0 {
|
||||
if result.is_empty() {
|
||||
let root = tree.root_node();
|
||||
// Add an empty range at the end of the file
|
||||
result.push(Range {
|
||||
|
||||
@@ -68,10 +68,10 @@ impl<'a> fmt::Display for Table<'a> {
|
||||
}
|
||||
write!(f, "{}", key)?;
|
||||
}
|
||||
write!(f, "]\n")?;
|
||||
writeln!(f, "]")?;
|
||||
}
|
||||
|
||||
write!(f, "{}(\n", self.name)?;
|
||||
writeln!(f, "{}(", self.name)?;
|
||||
for (column_index, column) in self.columns.iter().enumerate() {
|
||||
write!(f, " ")?;
|
||||
if column.unique {
|
||||
@@ -92,7 +92,7 @@ impl<'a> fmt::Display for Table<'a> {
|
||||
if column_index + 1 != self.columns.len() {
|
||||
write!(f, ",")?;
|
||||
}
|
||||
write!(f, "\n")?;
|
||||
writeln!(f)?;
|
||||
}
|
||||
write!(f, ");")?;
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ mod language;
|
||||
mod ql;
|
||||
mod ql_gen;
|
||||
|
||||
use clap;
|
||||
use language::Language;
|
||||
use std::collections::BTreeMap as Map;
|
||||
use std::collections::BTreeSet as Set;
|
||||
@@ -33,7 +32,7 @@ fn make_field_type<'a>(
|
||||
.map(|t| nodes.get(t).unwrap().dbscheme_name.as_str())
|
||||
.collect();
|
||||
(
|
||||
ql::Type::AtType(&dbscheme_union),
|
||||
ql::Type::At(dbscheme_union),
|
||||
Some(dbscheme::Entry::Union(dbscheme::Union {
|
||||
name: dbscheme_union,
|
||||
members,
|
||||
@@ -41,14 +40,14 @@ fn make_field_type<'a>(
|
||||
)
|
||||
}
|
||||
node_types::FieldTypeInfo::Single(t) => {
|
||||
let dbscheme_name = &nodes.get(&t).unwrap().dbscheme_name;
|
||||
(ql::Type::AtType(dbscheme_name), None)
|
||||
let dbscheme_name = &nodes.get(t).unwrap().dbscheme_name;
|
||||
(ql::Type::At(dbscheme_name), None)
|
||||
}
|
||||
node_types::FieldTypeInfo::ReservedWordInt(int_mapping) => {
|
||||
// The field will be an `int` in the db, and we add a case split to
|
||||
// create other db types for each integer value.
|
||||
let mut branches: Vec<(usize, &'a str)> = Vec::new();
|
||||
for (_, (value, name)) in int_mapping {
|
||||
for (value, name) in int_mapping.values() {
|
||||
branches.push((*value, name));
|
||||
}
|
||||
let case = dbscheme::Entry::Case(dbscheme::Case {
|
||||
@@ -74,12 +73,12 @@ fn add_field_for_table_storage<'a>(
|
||||
let parent_name = &nodes.get(&field.parent).unwrap().dbscheme_name;
|
||||
// This field can appear zero or multiple times, so put
|
||||
// it in an auxiliary table.
|
||||
let (field_ql_type, field_type_entry) = make_field_type(parent_name, &field, nodes);
|
||||
let (field_ql_type, field_type_entry) = make_field_type(parent_name, field, nodes);
|
||||
let parent_column = dbscheme::Column {
|
||||
unique: !has_index,
|
||||
db_type: dbscheme::DbColumnType::Int,
|
||||
name: &parent_name,
|
||||
ql_type: ql::Type::AtType(&parent_name),
|
||||
name: parent_name,
|
||||
ql_type: ql::Type::At(parent_name),
|
||||
ql_type_is_ref: true,
|
||||
};
|
||||
let index_column = dbscheme::Column {
|
||||
@@ -97,7 +96,7 @@ fn add_field_for_table_storage<'a>(
|
||||
ql_type_is_ref: true,
|
||||
};
|
||||
let field_table = dbscheme::Table {
|
||||
name: &table_name,
|
||||
name: table_name,
|
||||
columns: if has_index {
|
||||
vec![parent_column, index_column, field_column]
|
||||
} else {
|
||||
@@ -106,7 +105,7 @@ fn add_field_for_table_storage<'a>(
|
||||
// In addition to the field being unique, the combination of
|
||||
// parent+index is unique, so add a keyset for them.
|
||||
keysets: if has_index {
|
||||
Some(vec![&parent_name, "index"])
|
||||
Some(vec![parent_name, "index"])
|
||||
} else {
|
||||
None
|
||||
},
|
||||
@@ -122,7 +121,7 @@ fn add_field_for_column_storage<'a>(
|
||||
) -> (dbscheme::Column<'a>, Option<dbscheme::Entry<'a>>) {
|
||||
// This field must appear exactly once, so we add it as
|
||||
// a column to the main table for the node type.
|
||||
let (field_ql_type, field_type_entry) = make_field_type(parent_name, &field, nodes);
|
||||
let (field_ql_type, field_type_entry) = make_field_type(parent_name, field, nodes);
|
||||
(
|
||||
dbscheme::Column {
|
||||
unique: false,
|
||||
@@ -142,9 +141,9 @@ fn add_field_for_column_storage<'a>(
|
||||
/// 2. A set of names of the members of the `<lang>_ast_node` union.
|
||||
/// 3. A map where the keys are the dbscheme names for token kinds, and the
|
||||
/// values are their integer representations.
|
||||
fn convert_nodes<'a>(
|
||||
nodes: &'a node_types::NodeTypeMap,
|
||||
) -> (Vec<dbscheme::Entry<'a>>, Set<&'a str>, Map<&'a str, usize>) {
|
||||
fn convert_nodes(
|
||||
nodes: &node_types::NodeTypeMap,
|
||||
) -> (Vec<dbscheme::Entry>, Set<&str>, Map<&str, usize>) {
|
||||
let mut entries: Vec<dbscheme::Entry> = Vec::new();
|
||||
let mut ast_node_members: Set<&str> = Set::new();
|
||||
let token_kinds: Map<&str, usize> = nodes
|
||||
@@ -156,7 +155,7 @@ fn convert_nodes<'a>(
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
for (_, node) in nodes {
|
||||
for node in nodes.values() {
|
||||
match &node.kind {
|
||||
node_types::EntryKind::Union { members: n_members } => {
|
||||
// It's a tree-sitter supertype node, for which we create a union
|
||||
@@ -173,12 +172,12 @@ fn convert_nodes<'a>(
|
||||
node_types::EntryKind::Table { name, fields } => {
|
||||
// It's a product type, defined by a table.
|
||||
let mut main_table = dbscheme::Table {
|
||||
name: &name,
|
||||
name,
|
||||
columns: vec![dbscheme::Column {
|
||||
db_type: dbscheme::DbColumnType::Int,
|
||||
name: "id",
|
||||
unique: true,
|
||||
ql_type: ql::Type::AtType(&node.dbscheme_name),
|
||||
ql_type: ql::Type::At(&node.dbscheme_name),
|
||||
ql_type_is_ref: false,
|
||||
}],
|
||||
keysets: None,
|
||||
@@ -238,7 +237,7 @@ fn convert_nodes<'a>(
|
||||
unique: false,
|
||||
db_type: dbscheme::DbColumnType::Int,
|
||||
name: "loc",
|
||||
ql_type: ql::Type::AtType("location"),
|
||||
ql_type: ql::Type::At("location"),
|
||||
ql_type_is_ref: true,
|
||||
});
|
||||
|
||||
@@ -264,14 +263,14 @@ fn create_ast_node_parent_table<'a>(name: &'a str, ast_node_name: &'a str) -> db
|
||||
db_type: dbscheme::DbColumnType::Int,
|
||||
name: "child",
|
||||
unique: false,
|
||||
ql_type: ql::Type::AtType(ast_node_name),
|
||||
ql_type: ql::Type::At(ast_node_name),
|
||||
ql_type_is_ref: true,
|
||||
},
|
||||
dbscheme::Column {
|
||||
db_type: dbscheme::DbColumnType::Int,
|
||||
name: "parent",
|
||||
unique: false,
|
||||
ql_type: ql::Type::AtType(name),
|
||||
ql_type: ql::Type::At(name),
|
||||
ql_type_is_ref: true,
|
||||
},
|
||||
dbscheme::Column {
|
||||
@@ -295,7 +294,7 @@ fn create_tokeninfo<'a>(name: &'a str, type_name: &'a str) -> dbscheme::Table<'a
|
||||
db_type: dbscheme::DbColumnType::Int,
|
||||
name: "id",
|
||||
unique: true,
|
||||
ql_type: ql::Type::AtType(type_name),
|
||||
ql_type: ql::Type::At(type_name),
|
||||
ql_type_is_ref: false,
|
||||
},
|
||||
dbscheme::Column {
|
||||
@@ -316,7 +315,7 @@ fn create_tokeninfo<'a>(name: &'a str, type_name: &'a str) -> dbscheme::Table<'a
|
||||
unique: false,
|
||||
db_type: dbscheme::DbColumnType::Int,
|
||||
name: "loc",
|
||||
ql_type: ql::Type::AtType("location"),
|
||||
ql_type: ql::Type::At("location"),
|
||||
ql_type_is_ref: true,
|
||||
},
|
||||
],
|
||||
@@ -329,9 +328,9 @@ fn create_token_case<'a>(name: &'a str, token_kinds: Map<&'a str, usize>) -> dbs
|
||||
.map(|(&name, kind_id)| (*kind_id, name))
|
||||
.collect();
|
||||
dbscheme::Case {
|
||||
name: name,
|
||||
name,
|
||||
column: "kind",
|
||||
branches: branches,
|
||||
branches,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,7 +350,7 @@ fn create_files_table<'a>() -> dbscheme::Entry<'a> {
|
||||
unique: true,
|
||||
db_type: dbscheme::DbColumnType::Int,
|
||||
name: "id",
|
||||
ql_type: ql::Type::AtType("file"),
|
||||
ql_type: ql::Type::At("file"),
|
||||
ql_type_is_ref: false,
|
||||
},
|
||||
dbscheme::Column {
|
||||
@@ -373,7 +372,7 @@ fn create_folders_table<'a>() -> dbscheme::Entry<'a> {
|
||||
unique: true,
|
||||
db_type: dbscheme::DbColumnType::Int,
|
||||
name: "id",
|
||||
ql_type: ql::Type::AtType("folder"),
|
||||
ql_type: ql::Type::At("folder"),
|
||||
ql_type_is_ref: false,
|
||||
},
|
||||
dbscheme::Column {
|
||||
@@ -396,14 +395,14 @@ fn create_locations_default_table<'a>() -> dbscheme::Entry<'a> {
|
||||
unique: true,
|
||||
db_type: dbscheme::DbColumnType::Int,
|
||||
name: "id",
|
||||
ql_type: ql::Type::AtType("location_default"),
|
||||
ql_type: ql::Type::At("location_default"),
|
||||
ql_type_is_ref: false,
|
||||
},
|
||||
dbscheme::Column {
|
||||
unique: false,
|
||||
db_type: dbscheme::DbColumnType::Int,
|
||||
name: "file",
|
||||
ql_type: ql::Type::AtType("file"),
|
||||
ql_type: ql::Type::At("file"),
|
||||
ql_type_is_ref: true,
|
||||
},
|
||||
dbscheme::Column {
|
||||
@@ -453,14 +452,14 @@ fn create_containerparent_table<'a>() -> dbscheme::Entry<'a> {
|
||||
unique: false,
|
||||
db_type: dbscheme::DbColumnType::Int,
|
||||
name: "parent",
|
||||
ql_type: ql::Type::AtType("container"),
|
||||
ql_type: ql::Type::At("container"),
|
||||
ql_type_is_ref: true,
|
||||
},
|
||||
dbscheme::Column {
|
||||
unique: true,
|
||||
db_type: dbscheme::DbColumnType::Int,
|
||||
name: "child",
|
||||
ql_type: ql::Type::AtType("container"),
|
||||
ql_type: ql::Type::At("container"),
|
||||
ql_type_is_ref: true,
|
||||
},
|
||||
],
|
||||
@@ -491,7 +490,7 @@ fn create_diagnostics<'a>() -> (dbscheme::Case<'a>, dbscheme::Table<'a>) {
|
||||
unique: true,
|
||||
db_type: dbscheme::DbColumnType::Int,
|
||||
name: "id",
|
||||
ql_type: ql::Type::AtType("diagnostic"),
|
||||
ql_type: ql::Type::At("diagnostic"),
|
||||
ql_type_is_ref: false,
|
||||
},
|
||||
dbscheme::Column {
|
||||
@@ -526,7 +525,7 @@ fn create_diagnostics<'a>() -> (dbscheme::Case<'a>, dbscheme::Table<'a>) {
|
||||
unique: false,
|
||||
db_type: dbscheme::DbColumnType::Int,
|
||||
name: "location",
|
||||
ql_type: ql::Type::AtType("location_default"),
|
||||
ql_type: ql::Type::At("location_default"),
|
||||
ql_type_is_ref: true,
|
||||
},
|
||||
],
|
||||
@@ -625,7 +624,7 @@ fn main() -> std::io::Result<()> {
|
||||
let token_name = format!("{}_token", &prefix);
|
||||
let tokeninfo_name = format!("{}_tokeninfo", &prefix);
|
||||
let reserved_word_name = format!("{}_reserved_word", &prefix);
|
||||
let nodes = node_types::read_node_types_str(&prefix, &language.node_types)?;
|
||||
let nodes = node_types::read_node_types_str(&prefix, language.node_types)?;
|
||||
let (dbscheme_entries, mut ast_node_members, token_kinds) = convert_nodes(&nodes);
|
||||
ast_node_members.insert(&token_name);
|
||||
dbscheme::write(&mut dbscheme_writer, &dbscheme_entries)?;
|
||||
|
||||
@@ -43,15 +43,15 @@ impl<'a> fmt::Display for Class<'a> {
|
||||
}
|
||||
write!(f, "{}", supertype)?;
|
||||
}
|
||||
write!(f, " {{ \n")?;
|
||||
writeln!(f, " {{ ")?;
|
||||
|
||||
if let Some(charpred) = &self.characteristic_predicate {
|
||||
write!(
|
||||
writeln!(
|
||||
f,
|
||||
" {}\n",
|
||||
" {}",
|
||||
Predicate {
|
||||
qldoc: None,
|
||||
name: self.name.clone(),
|
||||
name: self.name,
|
||||
overridden: false,
|
||||
return_type: None,
|
||||
formal_parameters: vec![],
|
||||
@@ -61,7 +61,7 @@ impl<'a> fmt::Display for Class<'a> {
|
||||
}
|
||||
|
||||
for predicate in &self.predicates {
|
||||
write!(f, " {}\n", predicate)?;
|
||||
writeln!(f, " {}", predicate)?;
|
||||
}
|
||||
|
||||
write!(f, "}}")?;
|
||||
@@ -82,9 +82,9 @@ impl<'a> fmt::Display for Module<'a> {
|
||||
if let Some(qldoc) = &self.qldoc {
|
||||
write!(f, "/** {} */", qldoc)?;
|
||||
}
|
||||
write!(f, "module {} {{ \n", self.name)?;
|
||||
writeln!(f, "module {} {{ ", self.name)?;
|
||||
for decl in &self.body {
|
||||
write!(f, " {}\n", decl)?;
|
||||
writeln!(f, " {}", decl)?;
|
||||
}
|
||||
write!(f, "}}")?;
|
||||
Ok(())
|
||||
@@ -100,7 +100,7 @@ pub enum Type<'a> {
|
||||
String,
|
||||
|
||||
/// A database type that will need to be referred to with an `@` prefix.
|
||||
AtType(&'a str),
|
||||
At(&'a str),
|
||||
|
||||
/// A user-defined type.
|
||||
Normal(&'a str),
|
||||
@@ -112,7 +112,7 @@ impl<'a> fmt::Display for Type<'a> {
|
||||
Type::Int => write!(f, "int"),
|
||||
Type::String => write!(f, "string"),
|
||||
Type::Normal(name) => write!(f, "{}", name),
|
||||
Type::AtType(name) => write!(f, "@{}", name),
|
||||
Type::At(name) => write!(f, "@{}", name),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -197,7 +197,7 @@ impl<'a> fmt::Display for Expression<'a> {
|
||||
second_expr,
|
||||
} => {
|
||||
write!(f, "{}(", name)?;
|
||||
if vars.len() > 0 {
|
||||
if !vars.is_empty() {
|
||||
for (index, var) in vars.iter().enumerate() {
|
||||
if index > 0 {
|
||||
write!(f, ", ")?;
|
||||
|
||||
@@ -104,7 +104,7 @@ pub fn create_ast_node_class<'a>(ast_node: &'a str, ast_node_parent: &'a str) ->
|
||||
qldoc: Some(String::from("The base class for all AST nodes")),
|
||||
name: "AstNode",
|
||||
is_abstract: false,
|
||||
supertypes: vec![ql::Type::AtType(ast_node)].into_iter().collect(),
|
||||
supertypes: vec![ql::Type::At(ast_node)].into_iter().collect(),
|
||||
characteristic_predicate: None,
|
||||
predicates: vec![
|
||||
to_string,
|
||||
@@ -153,7 +153,7 @@ pub fn create_token_class<'a>(token_type: &'a str, tokeninfo: &'a str) -> ql::Cl
|
||||
qldoc: Some(String::from("A token.")),
|
||||
name: "Token",
|
||||
is_abstract: false,
|
||||
supertypes: vec![ql::Type::AtType(token_type), ql::Type::Normal("AstNode")]
|
||||
supertypes: vec![ql::Type::At(token_type), ql::Type::Normal("AstNode")]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
characteristic_predicate: None,
|
||||
@@ -167,14 +167,14 @@ pub fn create_token_class<'a>(token_type: &'a str, tokeninfo: &'a str) -> ql::Cl
|
||||
}
|
||||
|
||||
// Creates the `ReservedWord` class.
|
||||
pub fn create_reserved_word_class<'a>(db_name: &'a str) -> ql::Class<'a> {
|
||||
pub fn create_reserved_word_class(db_name: &str) -> ql::Class {
|
||||
let class_name = "ReservedWord";
|
||||
let get_a_primary_ql_class = create_get_a_primary_ql_class(&class_name);
|
||||
let get_a_primary_ql_class = create_get_a_primary_ql_class(class_name);
|
||||
ql::Class {
|
||||
qldoc: Some(String::from("A reserved word.")),
|
||||
name: class_name,
|
||||
is_abstract: false,
|
||||
supertypes: vec![ql::Type::AtType(db_name), ql::Type::Normal("Token")]
|
||||
supertypes: vec![ql::Type::At(db_name), ql::Type::Normal("Token")]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
characteristic_predicate: None,
|
||||
@@ -190,8 +190,8 @@ fn create_none_predicate<'a>(
|
||||
return_type: Option<ql::Type<'a>>,
|
||||
) -> ql::Predicate<'a> {
|
||||
ql::Predicate {
|
||||
qldoc: qldoc,
|
||||
name: name,
|
||||
qldoc,
|
||||
name,
|
||||
overridden,
|
||||
return_type,
|
||||
formal_parameters: Vec::new(),
|
||||
@@ -201,7 +201,7 @@ fn create_none_predicate<'a>(
|
||||
|
||||
/// Creates an overridden `getAPrimaryQlClass` predicate that returns the given
|
||||
/// name.
|
||||
fn create_get_a_primary_ql_class<'a>(class_name: &'a str) -> ql::Predicate<'a> {
|
||||
fn create_get_a_primary_ql_class(class_name: &str) -> ql::Predicate {
|
||||
ql::Predicate {
|
||||
qldoc: Some(String::from(
|
||||
"Gets the name of the primary QL class for this element.",
|
||||
@@ -223,7 +223,7 @@ fn create_get_a_primary_ql_class<'a>(class_name: &'a str) -> ql::Predicate<'a> {
|
||||
///
|
||||
/// `def_table` - the name of the table that defines the entity and its location.
|
||||
/// `arity` - the total number of columns in the table
|
||||
fn create_get_location_predicate<'a>(def_table: &'a str, arity: usize) -> ql::Predicate<'a> {
|
||||
fn create_get_location_predicate(def_table: &str, arity: usize) -> ql::Predicate {
|
||||
ql::Predicate {
|
||||
qldoc: Some(String::from("Gets the location of this element.")),
|
||||
name: "getLocation",
|
||||
@@ -248,7 +248,7 @@ fn create_get_location_predicate<'a>(def_table: &'a str, arity: usize) -> ql::Pr
|
||||
/// # Arguments
|
||||
///
|
||||
/// `def_table` - the name of the table that defines the entity and its text.
|
||||
fn create_get_text_predicate<'a>(def_table: &'a str) -> ql::Predicate<'a> {
|
||||
fn create_get_text_predicate(def_table: &str) -> ql::Predicate {
|
||||
ql::Predicate {
|
||||
qldoc: Some(String::from("Gets the text content of this element.")),
|
||||
name: "getText",
|
||||
@@ -339,13 +339,13 @@ fn create_field_getters<'a>(
|
||||
) -> (ql::Predicate<'a>, Option<ql::Expression<'a>>) {
|
||||
let return_type = match &field.type_info {
|
||||
node_types::FieldTypeInfo::Single(t) => {
|
||||
Some(ql::Type::Normal(&nodes.get(&t).unwrap().ql_class_name))
|
||||
Some(ql::Type::Normal(&nodes.get(t).unwrap().ql_class_name))
|
||||
}
|
||||
node_types::FieldTypeInfo::Multiple {
|
||||
types: _,
|
||||
dbscheme_union: _,
|
||||
ql_class,
|
||||
} => Some(ql::Type::Normal(&ql_class)),
|
||||
} => Some(ql::Type::Normal(ql_class)),
|
||||
node_types::FieldTypeInfo::ReservedWordInt(_) => Some(ql::Type::String),
|
||||
};
|
||||
let formal_parameters = match &field.storage {
|
||||
@@ -381,13 +381,13 @@ fn create_field_getters<'a>(
|
||||
(
|
||||
create_get_field_expr_for_column_storage(
|
||||
get_value_result_var_name,
|
||||
&main_table_name,
|
||||
main_table_name,
|
||||
column_index,
|
||||
main_table_arity,
|
||||
),
|
||||
create_get_field_expr_for_column_storage(
|
||||
get_value_result_var_name,
|
||||
&main_table_name,
|
||||
main_table_name,
|
||||
column_index,
|
||||
main_table_arity,
|
||||
),
|
||||
@@ -400,12 +400,12 @@ fn create_field_getters<'a>(
|
||||
} => (
|
||||
create_get_field_expr_for_table_storage(
|
||||
get_value_result_var_name,
|
||||
&field_table_name,
|
||||
field_table_name,
|
||||
if *has_index { Some("i") } else { None },
|
||||
),
|
||||
create_get_field_expr_for_table_storage(
|
||||
get_value_result_var_name,
|
||||
&field_table_name,
|
||||
field_table_name,
|
||||
if *has_index { Some("_") } else { None },
|
||||
),
|
||||
),
|
||||
@@ -453,7 +453,7 @@ fn create_field_getters<'a>(
|
||||
let qldoc = match &field.name {
|
||||
Some(name) => format!("Gets the node corresponding to the field `{}`.", name),
|
||||
None => {
|
||||
if formal_parameters.len() == 0 {
|
||||
if formal_parameters.is_empty() {
|
||||
"Gets the child of this node.".to_owned()
|
||||
} else {
|
||||
"Gets the `i`th child of this node.".to_owned()
|
||||
@@ -474,7 +474,7 @@ fn create_field_getters<'a>(
|
||||
}
|
||||
|
||||
/// Converts the given node types into CodeQL classes wrapping the dbscheme.
|
||||
pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel<'a>> {
|
||||
pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec<ql::TopLevel> {
|
||||
let mut classes: Vec<ql::TopLevel> = Vec::new();
|
||||
let mut token_kinds = BTreeSet::new();
|
||||
for (type_name, node) in nodes {
|
||||
@@ -491,7 +491,7 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel
|
||||
if type_name.named {
|
||||
let get_a_primary_ql_class = create_get_a_primary_ql_class(&node.ql_class_name);
|
||||
let mut supertypes: BTreeSet<ql::Type> = BTreeSet::new();
|
||||
supertypes.insert(ql::Type::AtType(&node.dbscheme_name));
|
||||
supertypes.insert(ql::Type::At(&node.dbscheme_name));
|
||||
supertypes.insert(ql::Type::Normal("Token"));
|
||||
classes.push(ql::TopLevel::Class(ql::Class {
|
||||
qldoc: Some(format!("A class representing `{}` tokens.", type_name.kind)),
|
||||
@@ -511,7 +511,7 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel
|
||||
name: &node.ql_class_name,
|
||||
is_abstract: false,
|
||||
supertypes: vec![
|
||||
ql::Type::AtType(&node.dbscheme_name),
|
||||
ql::Type::At(&node.dbscheme_name),
|
||||
ql::Type::Normal("AstNode"),
|
||||
]
|
||||
.into_iter()
|
||||
@@ -542,25 +542,25 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel
|
||||
let main_class_name = &node.ql_class_name;
|
||||
let mut main_class = ql::Class {
|
||||
qldoc: Some(format!("A class representing `{}` nodes.", type_name.kind)),
|
||||
name: &main_class_name,
|
||||
name: main_class_name,
|
||||
is_abstract: false,
|
||||
supertypes: vec![
|
||||
ql::Type::AtType(&node.dbscheme_name),
|
||||
ql::Type::At(&node.dbscheme_name),
|
||||
ql::Type::Normal("AstNode"),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
characteristic_predicate: None,
|
||||
predicates: vec![
|
||||
create_get_a_primary_ql_class(&main_class_name),
|
||||
create_get_location_predicate(&main_table_name, main_table_arity),
|
||||
create_get_a_primary_ql_class(main_class_name),
|
||||
create_get_location_predicate(main_table_name, main_table_arity),
|
||||
],
|
||||
};
|
||||
|
||||
if fields.is_empty() {
|
||||
main_class
|
||||
.predicates
|
||||
.push(create_get_text_predicate(&main_table_name));
|
||||
.push(create_get_text_predicate(main_table_name));
|
||||
} else {
|
||||
let mut main_table_column_index: usize = 0;
|
||||
let mut get_child_exprs: Vec<ql::Expression> = Vec::new();
|
||||
@@ -571,7 +571,7 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel
|
||||
// - the QL expressions to access the fields that will be part of getAFieldOrChild.
|
||||
for field in fields {
|
||||
let (get_pred, get_child_expr) = create_field_getters(
|
||||
&main_table_name,
|
||||
main_table_name,
|
||||
main_table_arity,
|
||||
&mut main_table_column_index,
|
||||
field,
|
||||
|
||||
@@ -83,13 +83,13 @@ pub enum Storage {
|
||||
|
||||
pub fn read_node_types(prefix: &str, node_types_path: &Path) -> std::io::Result<NodeTypeMap> {
|
||||
let file = fs::File::open(node_types_path)?;
|
||||
let node_types = serde_json::from_reader(file)?;
|
||||
Ok(convert_nodes(&prefix, &node_types))
|
||||
let node_types: Vec<NodeInfo> = serde_json::from_reader(file)?;
|
||||
Ok(convert_nodes(prefix, &node_types))
|
||||
}
|
||||
|
||||
pub fn read_node_types_str(prefix: &str, node_types_json: &str) -> std::io::Result<NodeTypeMap> {
|
||||
let node_types = serde_json::from_str(node_types_json)?;
|
||||
Ok(convert_nodes(&prefix, &node_types))
|
||||
let node_types: Vec<NodeInfo> = serde_json::from_str(node_types_json)?;
|
||||
Ok(convert_nodes(prefix, &node_types))
|
||||
}
|
||||
|
||||
fn convert_type(node_type: &NodeType) -> TypeName {
|
||||
@@ -99,31 +99,31 @@ fn convert_type(node_type: &NodeType) -> TypeName {
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_types(node_types: &Vec<NodeType>) -> Set<TypeName> {
|
||||
let iter = node_types.iter().map(convert_type).collect();
|
||||
std::collections::BTreeSet::from(iter)
|
||||
fn convert_types(node_types: &[NodeType]) -> Set<TypeName> {
|
||||
node_types.iter().map(convert_type).collect()
|
||||
}
|
||||
|
||||
pub fn convert_nodes(prefix: &str, nodes: &Vec<NodeInfo>) -> NodeTypeMap {
|
||||
pub fn convert_nodes(prefix: &str, nodes: &[NodeInfo]) -> NodeTypeMap {
|
||||
let mut entries = NodeTypeMap::new();
|
||||
let mut token_kinds = Set::new();
|
||||
|
||||
// First, find all the token kinds
|
||||
for node in nodes {
|
||||
if node.subtypes.is_none() {
|
||||
if node.fields.as_ref().map_or(0, |x| x.len()) == 0 && node.children.is_none() {
|
||||
let type_name = TypeName {
|
||||
kind: node.kind.clone(),
|
||||
named: node.named,
|
||||
};
|
||||
token_kinds.insert(type_name);
|
||||
}
|
||||
if node.subtypes.is_none()
|
||||
&& node.fields.as_ref().map_or(0, |x| x.len()) == 0
|
||||
&& node.children.is_none()
|
||||
{
|
||||
let type_name = TypeName {
|
||||
kind: node.kind.clone(),
|
||||
named: node.named,
|
||||
};
|
||||
token_kinds.insert(type_name);
|
||||
}
|
||||
}
|
||||
|
||||
for node in nodes {
|
||||
let flattened_name = &node_type_name(&node.kind, node.named);
|
||||
let dbscheme_name = escape_name(&flattened_name);
|
||||
let dbscheme_name = escape_name(flattened_name);
|
||||
let ql_class_name = dbscheme_name_to_class_name(&dbscheme_name);
|
||||
let dbscheme_name = format!("{}_{}", prefix, &dbscheme_name);
|
||||
if let Some(subtypes) = &node.subtypes {
|
||||
@@ -138,7 +138,7 @@ pub fn convert_nodes(prefix: &str, nodes: &Vec<NodeInfo>) -> NodeTypeMap {
|
||||
dbscheme_name,
|
||||
ql_class_name,
|
||||
kind: EntryKind::Union {
|
||||
members: convert_types(&subtypes),
|
||||
members: convert_types(subtypes),
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -160,7 +160,7 @@ pub fn convert_nodes(prefix: &str, nodes: &Vec<NodeInfo>) -> NodeTypeMap {
|
||||
if let Some(node_fields) = &node.fields {
|
||||
for (field_name, field_info) in node_fields {
|
||||
add_field(
|
||||
&prefix,
|
||||
prefix,
|
||||
&type_name,
|
||||
Some(field_name.to_string()),
|
||||
field_info,
|
||||
@@ -172,7 +172,7 @@ pub fn convert_nodes(prefix: &str, nodes: &Vec<NodeInfo>) -> NodeTypeMap {
|
||||
if let Some(children) = &node.children {
|
||||
// Treat children as if they were a field called 'child'.
|
||||
add_field(
|
||||
&prefix,
|
||||
prefix,
|
||||
&type_name,
|
||||
None,
|
||||
children,
|
||||
@@ -253,13 +253,11 @@ fn add_field(
|
||||
// All possible types for this field are reserved words. The db
|
||||
// representation will be an `int` with a `case @foo.field = ...` to
|
||||
// enumerate the possible values.
|
||||
let mut counter = 0;
|
||||
let mut field_token_ints: BTreeMap<String, (usize, String)> = BTreeMap::new();
|
||||
for t in converted_types {
|
||||
for (counter, t) in converted_types.into_iter().enumerate() {
|
||||
let dbscheme_variant_name =
|
||||
escape_name(&format!("{}_{}_{}", &prefix, parent_flattened_name, t.kind));
|
||||
field_token_ints.insert(t.kind.to_owned(), (counter, dbscheme_variant_name));
|
||||
counter += 1;
|
||||
}
|
||||
FieldTypeInfo::ReservedWordInt(field_token_ints)
|
||||
} else if field_info.types.len() == 1 {
|
||||
@@ -330,7 +328,7 @@ fn node_type_name(kind: &str, named: bool) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
const RESERVED_KEYWORDS: [&'static str; 14] = [
|
||||
const RESERVED_KEYWORDS: [&str; 14] = [
|
||||
"boolean", "case", "date", "float", "int", "key", "of", "order", "ref", "string", "subtype",
|
||||
"type", "unique", "varchar",
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user