{"id":29668030,"url":"https://github.com/advanced-security/codeql-qtil","last_synced_at":"2026-02-07T10:31:29.247Z","repository":{"id":305745824,"uuid":"991657637","full_name":"advanced-security/codeql-qtil","owner":"advanced-security","description":"A library with a wide variety of handy CodeQL utilities, from simple to complex.","archived":false,"fork":false,"pushed_at":"2025-09-13T05:09:11.000Z","size":3871,"stargazers_count":4,"open_issues_count":7,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-13T05:40:39.716Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"CodeQL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/advanced-security.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":"SECURITY.md","support":"SUPPORT.md","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-05-28T00:57:33.000Z","updated_at":"2025-09-13T05:09:14.000Z","dependencies_parsed_at":"2025-07-21T20:47:25.753Z","dependency_job_id":"5b15bdea-73e7-444f-a5af-cc3cf2655494","html_url":"https://github.com/advanced-security/codeql-qtil","commit_stats":null,"previous_names":["advanced-security/codeql-qtil"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/advanced-security/codeql-qtil","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/advanced-security%2Fcodeql-qtil","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/advanced-security%2Fcodeql-qtil/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/advanced-security%2Fcodeql-qtil/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/advanced-security%2Fcodeql-qtil/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/advanced-security","download_url":"https://codeload.github.com/advanced-security/codeql-qtil/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/advanced-security%2Fcodeql-qtil/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29192620,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-07T07:37:03.739Z","status":"ssl_error","status_checked_at":"2026-02-07T07:37:03.029Z","response_time":63,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-07-22T17:05:48.774Z","updated_at":"2026-02-07T10:31:29.239Z","avatar_url":"https://github.com/advanced-security.png","language":"CodeQL","readme":"\u003cdiv align=\"center\"\u003e\n\u003cimg src=\"assets/logo.jpg\" style=\"width: 220px;\"\u003e\n\u003c/div\u003e\n\n# qtil, a util library for CodeQL!\n\n`qtil` is a utility library providing a wide array of features and conveniences for CodeQL. `qtil` is developed under the following two guiding principles:\n\n- What would the `underscore.js` of CodeQL look like?\n- No helper utility is too small to belong in `qtil`.\n\nFor examples of the former, `qtil` has conveniences such as string escaping. For examples of the latter, `qtil` has a class does nothing more than remove the need to write the declaration `final FinalType = Type` during parameterized module development.\n\nLet's dive in!\n\n## License \n\nThis project is licensed under the terms of the MIT open source license. Please refer to [MIT](./LICENSE.txt) for the full terms.\n\nCodeQL is subject to the [GitHub CodeQL Terms \u0026 Conditions](https://securitylab.github.com/tools/codeql/license).\n\n## Background\n\nThis pack is just a collection of useful ideas, and no specific new features are currently planned.\nIf you have an idea on how to make writing CodeQL queries easier, please open an issue or a pull\nrequest! And make sure to check back in on occasion to see what new features may have been added.\n\n## Requirements \n\nTo use this library, you should have the CodeQL CLI installed, and a license to use CodeQL on your\nproject (it is free for open source). For writing queries, we recommend using the\n[VsCode CodeQL starter workspace](https://github.com/github/vscode-codeql-starter) and using the\nCodeQL vscode extension.\n\nOnce a query development is up and running, you are ready to install `qtil` with the instructions\nbelow.\n\n### Installing and using qtil\n\nTo install `qtil` for CodeQL development, add the following dependency to the `qlpack.yml` for your project:\n\n```yaml\n...\ndependencies:\n  ...\n  advanced-security/qtil: \"*\"\n```\n\nTo use `qtil`, you can either import everything at once, or pick what you need:\n\n```ql\n// Import everything under the namespace Qtil\nimport qtil.Qtil\nclass MyPair extends Qtil::Pair\u003c...\u003e { ... }\n\n// or import what you need with no namespace\nimport qtil.tuple.Pair\nclass MyPair extends Pair\u003c...\u003e { ... }\n```\n\nMost examples below assume that qtil is imported via the former method. Additionally, some qtilities\nare language specific and should typically be accessed by `import qtil.lang`, e.g., `qtil.cpp`.\n\n## Supported Languages\n\n- C/C++: ✅ available as `import qtil.Cpp` in pack `advanced-security/qtil-cpp`\n- C#: ✅ available as `import qtil.CSharp` in pack `advanced-security/qtil-csharp`\n- Go: ✅ available as `import qtil.Go` in pack `advanced-security/qtil-go`\n- Java: ✅ available as `import qtil.Java` in pack `advanced-security/qtil-java`\n- JavaScript: ✅ available as `import qtil.Javascript` in pack `advanced-security/qtil-javascript`\n- Python: ✅ available as `import qtil.Python` in pack `advanced-security/qtil-python`\n- Ruby: ✅ available as `import qtil.Ruby` in pack `advanced-security/qtil-ruby`\n- Rust: ❌ not yet available\n- Swift: ✅ available as `import qtil.Swift` in pack `advanced-security/qtil-swift`\n- QL: ❌ not yet available\n- other languages: ❌ not supported by CodeQL.\n\n## Features\n\n### Pairs, Tuples, and Products, oh my!\n\n**Pair**: A class to hold some set of paired values of two distinct types.\n\n```ql\npredicate nameAge(string name, int age) {\n  exists(Person p | name = p.getName() and age = p.getAge())\n}\n\n// Selects name, age for all people:\nfrom Qtil::Pair\u003cstring, int, nameAge/2\u003e::Pair pair\nselect pair.getFirst(), pair.getSecond()\n```\n\n**Tuple**: Like a pair, but supports more than two columns.\n\n```ql\npredicate nameAgeCity(string name, int age, City city) {\n  exists(Person p | name = p.getName() and age = p.getAge() and city = p.getCity())\n}\n\n// Selects name, age, city for all people:\nfrom Qtil::Tuple3\u003cstring, int, City, nameAgeCity/3\u003e::Tuple tuple\nselect tuple.getFirst(), tuple.getSecond(), tuple.getThird()\n```\n\n**Product**: A class to hold all combinations of values of two distinct types.\n\n```ql\n// Selects all combinations of people and cities\nfrom Qtil::Product\u003cPerson, City\u003e::Product product\nselect product.getFirst(), product.getSecond()\n```\n\n### Lists\n\n**Ordered**: Takes orderable data, and automatically adds `getPrevious()`, `getNext()` predicate members for ease of traversal.\n\n_Note: the `getOrder()` predicate should not have duplicates._\n\n```ql\nclass AgeOrderedPerson extends Qtil::Ordered\u003cPerson\u003e::Type {\n  override int getOrder() { result = getAge() }\n}\n\n// Selects people, along with the next youngest and next oldest.\nfrom AgeOrderedPerson p\nselect p.getName(), p.getPrevious().getName(), p.getNext().getName()\n```\n\nThis module is also possible to use with groupings, in order to segment the data into different lists.\n\n_Note: the `getOrder()` predicate should not have duplicates for items in the same group._\n\n```ql\nclass AgeOrderedCityPerson extends Qtil::Ordered\u003cPerson\u003e::GroupBy\u003cCity\u003e::Type {\n  override int getOrder() { result = getAge() }\n  override int getGroup() { result = getCity() }\n}\n\n// Selects people, along with the next youngest and next oldest in the same city.\nfrom AgeOrderedCityPerson p\nselect p.getName(), p.getCity(), p.getPrevious().getName(), p.getNext().getName()\n```\n\n**CondensedList**: Like the `Ordered` class, but creates a separate `ListEntry` type rather than\nrequiring you to extend the underlying type.\n\n```ql\nint getAge(Person p) { result = p.getAge() }\nclass GlobalListEntry = Qtil::CondenseList\u003cPerson, getAge/1\u003e::Global::ListEntry\n\n// Selects people, and the next oldest person\nfrom GlobalListEntry listEntry\nselect listEntry.getItem().getName(), listEntry.getNext().getItem().getName()\n\n// Optional grouping to create separate lists per city:\nCity getCity(Person p) { result = p.getCity() }\nclass CityListEntry = Qtil::CondenseList\u003cPerson, getAge/1\u003e::GroupBy\u003cCity, getCity/1\u003e::ListEntry\n\n// Selects people, and the next oldest person, for a given city\nfrom CityListEntry listEntry\nselect listEntry.getItem().getName(), listEntry.getDivision().getName(),\nlistEntry.getNext().getItem().getName()\n```\n\n### Strings\n\n**join(sep, ...)**: The first argument is used as a separator to join the remaining two to eight arguments.\n\nThis is not intended to replace the CodeQL `concat` aggregation, but rather, to be used in cases where aggregation is not desired.\n\n```ql\n// Result is \"a,b,c\"\nselect Qtil::join(\",\", \"a\", \"b\", \"c\")\n```\n\n**Escape**: Provides a set of modules for escaping and unescaping strings.\n\n_CAUTION: Be careful in applying this escaping, which has not yet been thoroughly tested or validated, to a sensitive security context._\n\n```ql\n// Result is \"foo\\\\\\\\bar\\\\nbaz\", \"foo\\\\bar\\nbaz\"\nselect Qtil::Escape\u003cQtil::defaultEscapeMap/2\u003e::escape(\"foo\\\\bar\\nbaz\"),\n    Qtil::Escape\u003cQtil::defaultEscapeMap/2\u003e::unescape(\"foo\\\\\\\\bar\\\\nbaz\")\n\n// Result is \"\\\"foo\\\\\\\"bar\\\\\\\\baz\\\"\", \"foo\\\"bar\\\\baz\"\nselect Qtil::doubleQuoteWrap(\"foo\\\"bar\\\\baz\"), Qtil::unescapeDoubleQuote(\"\\\"foo\\\\\\\"bar\\\\\\\\baz\\\"\")\n\n// CSV-like functionality: result is \"foo\\\\,bar,baz\\\\\\\\qux\", \"foo,bar\"\nselect Qtil::SeparatedEscape\u003cQtil::Chars::comma/0\u003e::EscapeBackslash::of2(\"foo,bar\", \"baz\\\\qux\"),\n    Qtil::SeparatedEscape\u003cQtil::Chars::comma/0\u003e::split(\"foo\\\\,bar,baz\\\\\\\\qux\", Qtil::charOf(\"\\\\\"), 0)\n```\n\nEscaping characters will carefully escape and unescape themselves. See documentation on escape maps\nto handle cases like turning newlines into `\\n`, etc.\n\n**Char**: A subtype of `int` that holds a character code, with members such as `toUppercase()`,\n`isLowercase()`, `isDigit()`, and `repeat(n)`.\n\n```ql\n// Selects \"A\", \"B\", \"0\"\nfrom Qtil::Char c\nwhere c.isStr(\"a\") or c = charOf(\"b\") or c = \"0\".codePointAt(0)\nselect b.toUppercase().toString()\n```\n\nSee also the module `Chars` which defines standard nullary predicates that common characters, for\ninstance, `Qtil::Chars::dollar()` holds for the result `\"$\"`,`Qtil::Chars::a()` holds for `\"a\"`, and `Qtil::Chars::upperA()` holds for `\"A\"`.\n\n### ASTs:\n\nThe following modules are usable by importing `qtil.lang`, for instance, `qtil.cpp`. However, the\nimplementations are shared across languages and are available in a do-it-yourself way as well.\n\n**TwoOperands**: A module to simplify checks that an operator uses two distinct operands in a\ncertain manner.\n\n```ql\nimport qtil.cpp\n\npredicate intPlusConstant(BinaryExpr e) {\n  exists(Qtil::TwoOperands\u003cBinaryExpr\u003e::Set set |\n    set.getOperation() = e and\n    set.someOperand().getType() instanceof IntType and\n    set.otherOperand().isConstant()\n  )\n}\n\n// Roughly equivalent to:\npredicate intPlusConstantOld(BinaryExpr e) {\n  exists(Expr a, Expr b |\n    a = e.getAnOperand() and\n    b = e.getAnOperand() and\n    not a = b and\n    a.getType() instanceof IntType and\n    b.isConstant()\n  )\n}\n```\n\n### Query Formatting\n\n**QlFormat** offers a way of formatting CodeQL query messages in a consistent way, with varying\nnumbers of placeholders, via a template-like syntax. This module is useful for writing more\nuser-friendly messages for certain types of queries, with a cleaner query implementation.\n\nQlFormat can be used as follows:\n\n```ql\nimport qtil.Cpp // or qtil.Java, etc.\n\n// Define a problem predicate for a Locatable and a Qtil::Template:\npredicate problem(Locatable elem, Qtil::Template template) {\n  exists(Variable var, FunctionCall fc |\n    var = elem and\n    fc = var.getInitializer().getAChild*() and\n    template = Qtil::tpl(\"Initializer of variable '{name}' calls {fn}.\")\n      .text(\"name\", var.getName())\n      .link(\"fn\", fc.getFunction())\n  )\n}\n\n// Import the Problem::Query module:\nimport Qtil::Problem\u003cproblem/2\u003e::Query\n```\n\nThe resulting query results will insert the variable name into the alert message, and insert a\nplaceholder link from the function name to the function itself.\n\nThis is particularly useful for when queries have different placeholders, or use placeholders in\ndifferent orders:\n\n```ql\npredicate problem(...) {\n  ... // Previous case which has a placeholder for a function call\n  or\n  // Mixed with alternate case which has no placeholder:\n  exists(Variable var |\n    var = elem and\n    not exists(FunctionCall fc | fc = var.getInitializer().getAChild*()) and\n    template = Qtil::tpl(\"Variable '{name}' has no initializer.\")\n      .text(\"name\", var.getName())\n  )\n}\n```\n\nThis mixture of query results with different numbers of placeholders can be done without the\n`QlFormat` features of qtil, but this approach can allow for much better readability and\nmaintainability of the query code.\n\n**CustomPathProblem**: Allows users to create a query that has a custom trace through the source\ncode. For example, CodeQL data flow `PathGraph` shows dataflow through a program. However, by using\nthis module, query authors can trace any path -- a call graph, inheritance chain, transitive\nfile imports, etc.\n\nTo use the `CustomPathProblem` module, you must define a graph where each `Node` is a `Locatable`,\nand the (directed) edges through that graph. Then by defining start nodes and end nodes, this\nmodule will attempt to efficiently find paths to be reported as problems.\n\n```ql\n/**\n * Find paths through which `main.cpp` may transitively `#include` a banned file \"banned_header.h\".\n * ...\n * @kind path-problem\n * ...\n */\nmodule MyPathProblem implements Qtil::CustomPathProblemConfigSig {\n  class Node = IncludeDirective;\n  predicate start(IncludeDirective n) { node.isInFile(\"main.cpp\") }\n  predicate end(IncludeDirective l) { node.includesFile(\"banned_header.h\") }\n  predicate edge(IncludeDirective a, IncludeDirective b) {\n    b = a.getIncludedFile().getAnIncludeDirective()\n  }\n}\n\nimport CustomPathProblem\u003cMyPathProblem\u003e\nfrom IncludeDirective start, IncludeDirective end\nwhere problem(start, end) // This limits the query to the identified problematic paths.\nselect end, start, end, \"Transitive inclusion of banned_header.h from main.cpp\"\n```\n\nIf you wish to perform a path search such as the above, but without reporting problems, you can\nuse the `Qtil::GraphPathSearch` module instead, which provides an efficient search algorithm\nwithout producing a `@kind path-problem` query.\n\n### Inheritance\n\n**Instance**: A module to make `instanceof` inheritance easier in CodeQL, by writing\n`class Foo extends Qtil::Instanceof\u003cBar\u003e::Type`, which automatically adds `toString()` and a\nmember `Bar inst()` to access the member predicates on the `Bar` parent class.\n\nIn CodeQL, instance inheritance is available as `class Foo instanceof Bar`. In this style of\ninheritance, a `Foo` matches all `Bar`s, but inherits none of the members. This is a useful\nconcept, but in practice often requires a boilerplate `toString()` member and casts:\n\n```ql\nclass Foo extends Qtil::Instance\u003cBar\u003e::Type {\n  predicate qux() { inst().check() }\n}\n\n// is (roughly) equivalent to:\nclass Foo instanceof Bar {\n  predicate qux() { this.(Bar).check() }\n  string toString() { result = this.(Bar).toString() }\n}\n```\n\nThere is also a module `InfInstance` which handles infinite types. Ordinarily, `Instance\u003cT\u003e`\nrequires a finite type (standard CodeQL class type). However, infinite types (such as\nprimitives) require special care, which `InfInstance` handles correctly, allowing\n`bindingset[this] class OpaqueIntType extends Qtil::InfInstance\u003cint\u003e::Type {}`. See also `UnderlyingString`.\n\n**Final**: A module to avoid creating final type alias declarations, which are required in\nsome contexts, such as parameterized modules. Simply extend `Qtil::Final\u003cT\u003e::Type` instead of\ndeclaring a final alias type.\n\n```ql\n// Use CodeQL \"final\" extension:\nclass MyFoo1 extends Qtil::Final\u003cFoo\u003e::Type { ... }\n\n// So that you don't need to create a final alias declaration:\nfinal class FinalFoo = Foo;\nclass MyFoo2 extends FinalFoo { ... }\n```\n\n**UnderlyingString**: A class to support inheriting from string in order to create custom\ninfinite types with a hidden string representation.\n\n```ql\nclass Person extends Qtil::UnderlyingString {\n  string getFirstName() { result = str().split(\" \", 0) }\n  string getLastName() { result = str().split(\" \", 1) }\n}\n```\n\n_Note: this class is effectively the same as `Qtil::InfInstance\u003cstring\u003e::Type`, but uses the member `str()` to get the underlying string instead of the member `inst()`._\n\n**Finitize**: A module to produce a finite type from an infinite type (such as `string`, `int`, or\n`Qtil::InfInstance\u003cstring\u003e::Type`, etc.) by providing predicate that constrains that infinite type.\n\n```ql\nclass Person extends Qtil::UnderlyingString { ... }\npredicate realPerson(Person p) { p in [\"Marie Curie\", \"Albert Einstein\", ...] }\n\nclass RealPerson = Qtil::Finitize\u003cPerson, realPerson/1\u003e::Type;\n```\n\nSince infinite types should generally be avoided, but sometimes are necessary to enable certain\nclean APIs, a common pattern is to have a stage where infinite types are collected, and then use\na constraint such as this one to finitize them at a later stage, to reduce the impact of using\ninfinite types in a query.\n\n### Locations\n\nLocation types in CodeQL are different types across languages. To use these classes, import\n`qtil.lang` (for instance, `qtil.cpp`).\n\n**StringLocation**: A class that supports the codification of any location as a string, which the\nCodeQL engine will use as a location when selected by a query. Also includes support to turn\nexisting locations into strings with `StringToLocation`, and support to finitize them at the point\nwhere a query no longer must deal with an infinite set using the `Finitize` module.\n\n**OptionalLocation**: A class that works much like `Option\u003cLocation\u003e`, but that also implements the\n`hasLocation()` predicate which the CodeQL engine expects of a location. Allows queries to select\nplaceholder locations that may or may not exist.\n\n**NullLocation**: An empty location.\n\n**Locatable**: A signature module that allows cross language support for locatable elements in a\nquery language, for instance C++ or Java.\n\nThis module, and `qtil` modules that depend on it, should already have preexisting\nlanguage-specific implementations in the `qtil` modules for each language, so that you don't have\nto implement it yourself, for instance, in `qtil.Cpp` or `qtil.Java`. However, implementing this\nmodule allows you to add qtil support for new languages.\n\n### Graphs\n\n**GraphPathSearch**: A module for efficiently finding paths in custom directed graphs from a set of\nstarting nodes to a set of ending nodes. For performance, this module uses a pattern called \"forward\nreverse pruning,\" a pattern widely used in the CodeQL dataflow libraries.\n\n```ql\nmodule Config implement Qtil::GraphPathSearchSig\u003cPerson\u003e {\n  predicate start(Person p) { p.checkSomething() }\n  predicate end(Person p) { p.checkSomethingElse() }\n  predicate edge(Person a, Person b) { a.getParent() = b }\n}\n\nfrom Person a, Person b\nwhere Qtil::GraphPathSearch\u003cPerson, Config\u003e::hasPath(a, b)\nselect a, b\n```\n\nThis module takes a set of starting points, ending points, and edges in a graph, and the predicate\n`hasPath` reveals which end nodes are reachable from the given start nodes.\n\nFor displaying the discovered paths to users, see the `CustomPathProblem` module above.\n\n### Testing with Qnit\n\nWhile codeql's `test run` subcommand is a great way to test queries, it can be better in some cases\nto write a more traditional unit test for CodeQL libraries. Rather than selecting a set of outputs\nin a query and then inspecting that the query result (in the `.expectations` file) makes sense, qtil\nprovides a library called \"Qnit\" for writing direct test cases with expectations, so that there's\nbetter cohesion between a test case and its expected output.\n\nTo use Qnit, import the `qtil.testing.Qnit` module, and create a test class that extends\n`Test, Case`. Inside the class override the `run(Qnit test)` member predicate, and conditionally\ncall `test.pass(name)` or `test.fail(description)` as appropriate.\n\n```ql\nimport qtil.testing.Qnit\n\nclass MyTest extends Test, Case {\n  override predicate run(Qnit test) {\n    if 1 = 1\n    then test.pass(\"1 equals 1\")\n    else test.fail(\"1 does not equal 1\")\n  }\n}\n```\n\nYou may define as many test classes as you like, and they will all be run when you run the command\n`codeql test run $TESTDIR`. If all tests pass, the test will output \"{n} tests passed.\" If any test\nfails, the result of each test will be selected (including failing and passing tests).\n\nFor correct use, ensure that each test class passes with a unique name, and that tests always hold\nfor some result, whether its a pass or a fail.\n\n```ql\n  override predicate run(Qnit test) {\n    if 1 = 1\n    then test.pass(\"1 equals 1\") // Ensure this is unique to the test\n    else none() // This would be valid CodeQL, but it would not fail.\n  }\n```\n\nIt is particularly risky, albeit useful, to write `test.fail(\"...\" + somePredicate().toString())`,\nas this test will **not** fail if `somePredicate()` does not hold. This is a risky pattern, and so\nshould only be applied with some caution.\n\nSee the README in the `qtil.testing` directory for more information on how to use Qnit.\n\n### Parameterization\n\n**SignaturePredicates.qll** defines modules for creating signature predicates without separate\nsignature predicate declarations.\n\nRather than writing:\n\n```ql\nsignature predicate binary(int a, int b);\n\nmodule MyModule\u003cbinary/2 binop\u003e { ... }\n```\n\nThis module allows you to write:\n\n```ql\nmodule MyModule\u003cQtil::Binary\u003cint, int\u003e::pred/2 binop\u003e { ... }\n```\n\nThis is particularly useful when you otherwise would have to declare a parameterized module to\ndeclare your signature to your own parameterized module:\n\n```ql\n// Simply write:\nmodule MyModule\u003cFoo A, Bar B, Qtil::Binary\u003cA, B\u003e::pred/2 binop\u003e { ... }\n\n// Instead of:\nmodule SignatureModule\u003cFoo A, Foo B\u003e {\n  signature predicate binary(A, B);\n}\nmodule MyModule\u003cFoo A, Foo B, SignatureModule\u003cA, B\u003e::binary/2 binary\u003e { ... }\n```\n\nThe declared predicate signatures look as follows:\n - `Qtil::Nullary::pred/0`: A predicate with no parameters and no result.\n - `Qtil::Nullary::Ret\u003cint\u003e::pred/0`: A predicate with no parameters and an `int` result.\n - `Qtil::Unary\u003cint\u003e::pred/1`: A predicate with one int parameter and no result.\n - `Qtil::Unary\u003cint\u003e::Ret\u003cstring\u003e::pred/1`: A predicate with one int parameter and a string result.\n - `Qtil::Binary\u003cint, string\u003e::pred/2`: A predicate with two parameters, an int and a string, and no\n      result.\n - `Qtil::Binary\u003cint, string\u003e::Ret\u003cint\u003e::pred/2`: A predicate with two parameters, an int and a\n      string, and an int result.\n - etc., for `Ternary`, `Quaternary`, and up to `Senary` (six parameter) predicates.\n\n**SignatureTypes.qll** contains various baseline signature types to aid in writing correct\nparameterized modules, as well as a utility to create a signature type from any existing type.\n\n```ql\n// A module that accepts any type that is a subclass of `Expr`:\nmodule MyModule\u003cQtil::Signature\u003cExpr\u003e::Type ExprType\u003e { ... }\u003e\n\n// A module that accepts any pair of finite types:\nmodule MyModule\u003cQtil::FiniteType A, Qtil::FiniteType B\u003e { ... }\n```\n\n - `Qtil::Signature\u003cT\u003e::Type`: A module that allows you to create a signature type from any existing\n      type `T`. This is useful for parameterized modules that need to accept a type as a parameter.\n - `Qtil::FiniteType`: Any finite type. Supports `newtype`s. No support for primitive types.\n - `Qtil::FiniteStringableType`: Any finite class (has a `toString()` member). No support for\n      `newtype`s or primitive types.\n - `Qtil::InfSignature\u003cT\u003e::Type`: Like `Qtil::Signature\u003cT\u003e::Type`, but allows you to create a signature\n      type from any existing infinite type `T`.\n - `Qtil::InfiniteType`: Any finite or infinite type, with `bindingset[this]`. Supports\n      `newtype`s and primitives.\n - `Qtil::InfiniteStringableType`: Any finite or infinite class, with `bindingset[this]`,\n      Supports primitives. Does not support `newtype`.\n - `Qtil::StringlikeType`: Any type that extends or is an instanceof `string`.\n\n## Contributing\n\nThis project welcomes contributions and suggestions. See [Contributing](CONTRIBUTING.md) for more\ndetails.\n\n## Support\n\nThis project is intended to be useful and help the CodeQL community. That said, we may not have\ntime and resources to support every feature request or bug report, and when support is offered it\nmay be subject to some delay.\n\nIf you have a feature request or bug report that is of significant importance to you, please do make\nits importance and urgency clear in your issue or pull request, to increase the likelihood of\nreceiving timely support amidst our busy jobs here at GitHub!\n\n## Maintainers\n\nThis project is currently maintained by CodeQL/security/code quality experts. Support on any given\nday is likely to come from @michaelrfairhurst.\n","funding_links":[],"categories":["CodeQL Libraries"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadvanced-security%2Fcodeql-qtil","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadvanced-security%2Fcodeql-qtil","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadvanced-security%2Fcodeql-qtil/lists"}