diff --git a/ql/extractor/src/generator.rs b/ql/extractor/src/generator.rs index ea663896e64..1dca6969f34 100644 --- a/ql/extractor/src/generator.rs +++ b/ql/extractor/src/generator.rs @@ -36,5 +36,5 @@ pub fn run(options: Options) -> std::io::Result<()> { }, ]; - generate(languages, options.dbscheme, options.library, false) + generate(languages, options.dbscheme, options.library) } diff --git a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll index 562af993d89..a83095629ab 100644 --- a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll +++ b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll @@ -5,6 +5,10 @@ import codeql.Locations as L +/** Holds if the database is an overlay. */ +overlay[local] +private predicate isOverlay() { databaseMetadata("isOverlay", "true") } + module QL { /** The base class for all AST nodes */ class AstNode extends @ql_ast_node { @@ -48,6 +52,30 @@ module QL { final override string getAPrimaryQlClass() { result = "ReservedWord" } } + /** Gets the file containing the given `node`. */ + overlay[local] + private @file getNodeFile(@ql_ast_node node) { + exists(@location_default loc | ql_ast_node_location(node, loc) | + locations_default(loc, result, _, _, _, _) + ) + } + + /** Holds if `file` was extracted as part of the overlay database. */ + overlay[local] + private predicate discardFile(@file file) { isOverlay() and file = getNodeFile(_) } + + /** Holds if `node` is in the `file` and is part of the overlay base database. */ + overlay[local] + private predicate discardableAstNode(@file file, @ql_ast_node node) { + not isOverlay() and file = getNodeFile(node) + } + + /** Holds if `node` should be discarded, because it is part of the overlay base and is in a file that was also extracted as part of the overlay database. */ + overlay[discard_entity] + private predicate discardAstNode(@ql_ast_node node) { + exists(@file file | discardableAstNode(file, node) and discardFile(file)) + } + /** A class representing `add_expr` nodes. */ class AddExpr extends @ql_add_expr, AstNode { /** Gets the name of the primary QL class for this element. */ @@ -1318,6 +1346,30 @@ module Dbscheme { final override string getAPrimaryQlClass() { result = "ReservedWord" } } + /** Gets the file containing the given `node`. */ + overlay[local] + private @file getNodeFile(@dbscheme_ast_node node) { + exists(@location_default loc | dbscheme_ast_node_location(node, loc) | + locations_default(loc, result, _, _, _, _) + ) + } + + /** Holds if `file` was extracted as part of the overlay database. */ + overlay[local] + private predicate discardFile(@file file) { isOverlay() and file = getNodeFile(_) } + + /** Holds if `node` is in the `file` and is part of the overlay base database. */ + overlay[local] + private predicate discardableAstNode(@file file, @dbscheme_ast_node node) { + not isOverlay() and file = getNodeFile(node) + } + + /** Holds if `node` should be discarded, because it is part of the overlay base and is in a file that was also extracted as part of the overlay database. */ + overlay[discard_entity] + private predicate discardAstNode(@dbscheme_ast_node node) { + exists(@file file | discardableAstNode(file, node) and discardFile(file)) + } + /** A class representing `annotName` tokens. */ class AnnotName extends @dbscheme_token_annot_name, Token { /** Gets the name of the primary QL class for this element. */ @@ -1654,6 +1706,30 @@ module Blame { final override string getAPrimaryQlClass() { result = "ReservedWord" } } + /** Gets the file containing the given `node`. */ + overlay[local] + private @file getNodeFile(@blame_ast_node node) { + exists(@location_default loc | blame_ast_node_location(node, loc) | + locations_default(loc, result, _, _, _, _) + ) + } + + /** Holds if `file` was extracted as part of the overlay database. */ + overlay[local] + private predicate discardFile(@file file) { isOverlay() and file = getNodeFile(_) } + + /** Holds if `node` is in the `file` and is part of the overlay base database. */ + overlay[local] + private predicate discardableAstNode(@file file, @blame_ast_node node) { + not isOverlay() and file = getNodeFile(node) + } + + /** Holds if `node` should be discarded, because it is part of the overlay base and is in a file that was also extracted as part of the overlay database. */ + overlay[discard_entity] + private predicate discardAstNode(@blame_ast_node node) { + exists(@file file | discardableAstNode(file, node) and discardFile(file)) + } + /** A class representing `blame_entry` nodes. */ class BlameEntry extends @blame_blame_entry, AstNode { /** Gets the name of the primary QL class for this element. */ @@ -1767,6 +1843,30 @@ module JSON { final override string getAPrimaryQlClass() { result = "ReservedWord" } } + /** Gets the file containing the given `node`. */ + overlay[local] + private @file getNodeFile(@json_ast_node node) { + exists(@location_default loc | json_ast_node_location(node, loc) | + locations_default(loc, result, _, _, _, _) + ) + } + + /** Holds if `file` was extracted as part of the overlay database. */ + overlay[local] + private predicate discardFile(@file file) { isOverlay() and file = getNodeFile(_) } + + /** Holds if `node` is in the `file` and is part of the overlay base database. */ + overlay[local] + private predicate discardableAstNode(@file file, @json_ast_node node) { + not isOverlay() and file = getNodeFile(node) + } + + /** Holds if `node` should be discarded, because it is part of the overlay base and is in a file that was also extracted as part of the overlay database. */ + overlay[discard_entity] + private predicate discardAstNode(@json_ast_node node) { + exists(@file file | discardableAstNode(file, node) and discardFile(file)) + } + class UnderscoreValue extends @json_underscore_value, AstNode { } /** A class representing `array` nodes. */ diff --git a/ruby/extractor/src/generator.rs b/ruby/extractor/src/generator.rs index 1601d2edda6..00d878243ae 100644 --- a/ruby/extractor/src/generator.rs +++ b/ruby/extractor/src/generator.rs @@ -28,5 +28,5 @@ pub fn run(options: Options) -> std::io::Result<()> { }, ]; - generate(languages, options.dbscheme, options.library, true) + generate(languages, options.dbscheme, options.library) } diff --git a/shared/tree-sitter-extractor/src/generator/mod.rs b/shared/tree-sitter-extractor/src/generator/mod.rs index 6652e8ebefb..e4bd1ac4eb0 100644 --- a/shared/tree-sitter-extractor/src/generator/mod.rs +++ b/shared/tree-sitter-extractor/src/generator/mod.rs @@ -17,7 +17,6 @@ pub fn generate( languages: Vec, dbscheme_path: PathBuf, ql_library_path: PathBuf, - overlay_support: bool, ) -> std::io::Result<()> { let dbscheme_file = File::create(dbscheme_path).map_err(|e| { tracing::error!("Failed to create dbscheme file: {}", e); @@ -50,14 +49,12 @@ pub fn generate( })], )?; - if overlay_support { - ql::write( - &mut ql_writer, - &[ql::TopLevel::Predicate( - ql_gen::create_is_overlay_predicate(), - )], - )?; - } + ql::write( + &mut ql_writer, + &[ql::TopLevel::Predicate( + ql_gen::create_is_overlay_predicate(), + )], + )?; for language in languages { let prefix = node_types::to_snake_case(&language.name); @@ -103,20 +100,19 @@ pub fn generate( ql::TopLevel::Class(ql_gen::create_reserved_word_class(&reserved_word_name)), ]; - if overlay_support { - body.push(ql::TopLevel::Predicate( - ql_gen::create_get_node_file_predicate(&ast_node_name, &node_location_table_name), - )); - body.push(ql::TopLevel::Predicate( - ql_gen::create_discard_file_predicate(), - )); - body.push(ql::TopLevel::Predicate( - ql_gen::create_discardable_ast_node_predicate(&ast_node_name), - )); - body.push(ql::TopLevel::Predicate( - ql_gen::create_discard_ast_node_predicate(&ast_node_name), - )); - } + // Overlay discard predicates + body.push(ql::TopLevel::Predicate( + ql_gen::create_get_node_file_predicate(&ast_node_name, &node_location_table_name), + )); + body.push(ql::TopLevel::Predicate( + ql_gen::create_discard_file_predicate(), + )); + body.push(ql::TopLevel::Predicate( + ql_gen::create_discardable_ast_node_predicate(&ast_node_name), + )); + body.push(ql::TopLevel::Predicate( + ql_gen::create_discard_ast_node_predicate(&ast_node_name), + )); body.append(&mut ql_gen::convert_nodes(&nodes)); ql::write(