diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index ff73bcb4e7b..7fd96b8d941 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -3,6 +3,8 @@ "rust-lang.rust", "bungcip.better-toml", "github.vscode-codeql", + "hbenl.vscode-test-explorer", + "ms-vscode.test-adapter-converter", "slevesque.vscode-zipexplorer" ], "settings": { diff --git a/.github/workflows/swift-codegen.yml b/.github/workflows/swift-codegen.yml index 25485913efd..ded763f8dbb 100644 --- a/.github/workflows/swift-codegen.yml +++ b/.github/workflows/swift-codegen.yml @@ -18,8 +18,16 @@ jobs: - name: Run unit tests run: | bazel test //swift/codegen/test --test_output=errors - - name: Check that code was generated + - name: Check that QL generated code was checked in run: | bazel run //swift/codegen git add swift git diff --exit-code --stat HEAD + - name: Generate C++ files + run: | + bazel run //swift/codegen:trapgen -- --cpp-output=$PWD/swift-generated-headers + bazel run //swift/codegen:cppgen -- --cpp-output=$PWD/swift-generated-headers + - uses: actions/upload-artifact@v3 + with: + name: swift-generated-headers + path: swift-generated-headers/*.h diff --git a/config/identical-files.json b/config/identical-files.json index 4ce332ca7f1..d92c363a36f 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -475,20 +475,23 @@ "python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll", "ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll" ], - "ReDoS Util Python/JS/Ruby": [ + "ReDoS Util Python/JS/Ruby/Java": [ "javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll", "python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll", - "ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll" + "ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll", + "java/ql/lib/semmle/code/java/security/performance/ReDoSUtil.qll" ], - "ReDoS Exponential Python/JS/Ruby": [ + "ReDoS Exponential Python/JS/Ruby/Java": [ "javascript/ql/lib/semmle/javascript/security/performance/ExponentialBackTracking.qll", "python/ql/lib/semmle/python/security/performance/ExponentialBackTracking.qll", - "ruby/ql/lib/codeql/ruby/security/performance/ExponentialBackTracking.qll" + "ruby/ql/lib/codeql/ruby/security/performance/ExponentialBackTracking.qll", + "java/ql/lib/semmle/code/java/security/performance/ExponentialBackTracking.qll" ], - "ReDoS Polynomial Python/JS/Ruby": [ + "ReDoS Polynomial Python/JS/Ruby/Java": [ "javascript/ql/lib/semmle/javascript/security/performance/SuperlinearBackTracking.qll", "python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll", - "ruby/ql/lib/codeql/ruby/security/performance/SuperlinearBackTracking.qll" + "ruby/ql/lib/codeql/ruby/security/performance/SuperlinearBackTracking.qll", + "java/ql/lib/semmle/code/java/security/performance/SuperlinearBackTracking.qll" ], "BadTagFilterQuery Python/JS/Ruby": [ "javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll", @@ -552,5 +555,9 @@ "HttpToFileAccessCustomizations JS/Ruby": [ "javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessCustomizations.qll", "ruby/ql/lib/codeql/ruby/security/HttpToFileAccessCustomizations.qll" + ], + "Typo database": [ + "javascript/ql/src/Expressions/TypoDatabase.qll", + "ql/ql/src/codeql_ql/style/TypoDatabase.qll" ] } diff --git a/cpp/downgrades/cf72c8898d19eb1b3374432cf79d8276cb07ad43/exprparents.ql b/cpp/downgrades/cf72c8898d19eb1b3374432cf79d8276cb07ad43/exprparents.ql new file mode 100644 index 00000000000..baddd72c144 --- /dev/null +++ b/cpp/downgrades/cf72c8898d19eb1b3374432cf79d8276cb07ad43/exprparents.ql @@ -0,0 +1,21 @@ +class Element extends @element { + string toString() { none() } +} + +class Expr extends @expr { + string toString() { none() } +} + +class Stmt extends @stmt { + string toString() { none() } +} + +predicate isStmtWithInitializer(Stmt stmt) { + exists(int kind | stmts(stmt, kind, _) | kind = 2 or kind = 11 or kind = 35) +} + +from Expr child, int index, int index_new, Element parent +where + exprparents(child, index, parent) and + if isStmtWithInitializer(parent) then index_new = index - 1 else index_new = index +select child, index_new, parent diff --git a/cpp/downgrades/cf72c8898d19eb1b3374432cf79d8276cb07ad43/old.dbscheme b/cpp/downgrades/cf72c8898d19eb1b3374432cf79d8276cb07ad43/old.dbscheme new file mode 100644 index 00000000000..cf72c8898d1 --- /dev/null +++ b/cpp/downgrades/cf72c8898d19eb1b3374432cf79d8276cb07ad43/old.dbscheme @@ -0,0 +1,2111 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +/** If `function` is a coroutine, then this gives the + std::experimental::resumable_traits instance associated with it, + and the variables representing the `handle` and `promise` for it. */ +coroutine( + unique int function: @function ref, + int traits: @type ref, + int handle: @variable ref, + int promise: @variable ref +); + +/** The `new` function used for allocating the coroutine state, if any. */ +coroutine_new( + unique int function: @function ref, + int new: @function ref +); + +/** The `delete` function used for deallocating the coroutine state, if any. */ +coroutine_delete( + unique int function: @function ref, + int delete: @function ref +); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + +member_function_this_type(unique int id: @function ref, int this_type: @type ref); + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) +is_structured_binding(unique int id: @variable ref); + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref, + int enclosing : @element ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +/** + * An instance of the C++11 `decltype` operator. For example: + * ``` + * int a; + * decltype(1+a) b; + * ``` + * Here `expr` is `1+a`. + * + * Sometimes an additional pair of parentheses around the expression + * would change the semantics of this decltype, e.g. + * ``` + * struct A { double x; }; + * const A* a = new A(); + * decltype( a->x ); // type is double + * decltype((a->x)); // type is const double& + * ``` + * (Please consult the C++11 standard for more details). + * `parentheses_would_change_meaning` is `true` iff that is the case. + */ +#keyset[id, expr] +decltypes( + int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + | @temp_init + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + | @co_await + | @co_yield + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +| 327 = @co_await +| 328 = @co_yield +| 329 = @temp_init +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +| 37 = @stmt_co_return +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_initialization( + unique int if_stmt: @stmt_if ref, + int init_id: @stmt ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_initialization( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int init_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +switch_initialization( + unique int switch_stmt: @stmt_switch ref, + int init_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/downgrades/cf72c8898d19eb1b3374432cf79d8276cb07ad43/semmlecode.cpp.dbscheme b/cpp/downgrades/cf72c8898d19eb1b3374432cf79d8276cb07ad43/semmlecode.cpp.dbscheme new file mode 100644 index 00000000000..e9a518baf14 --- /dev/null +++ b/cpp/downgrades/cf72c8898d19eb1b3374432cf79d8276cb07ad43/semmlecode.cpp.dbscheme @@ -0,0 +1,2096 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +/** If `function` is a coroutine, then this gives the + std::experimental::resumable_traits instance associated with it, + and the variables representing the `handle` and `promise` for it. */ +coroutine( + unique int function: @function ref, + int traits: @type ref, + int handle: @variable ref, + int promise: @variable ref +); + +/** The `new` function used for allocating the coroutine state, if any. */ +coroutine_new( + unique int function: @function ref, + int new: @function ref +); + +/** The `delete` function used for deallocating the coroutine state, if any. */ +coroutine_delete( + unique int function: @function ref, + int delete: @function ref +); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + +member_function_this_type(unique int id: @function ref, int this_type: @type ref); + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) +is_structured_binding(unique int id: @variable ref); + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref, + int enclosing : @element ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +/** + * An instance of the C++11 `decltype` operator. For example: + * ``` + * int a; + * decltype(1+a) b; + * ``` + * Here `expr` is `1+a`. + * + * Sometimes an additional pair of parentheses around the expression + * would change the semantics of this decltype, e.g. + * ``` + * struct A { double x; }; + * const A* a = new A(); + * decltype( a->x ); // type is double + * decltype((a->x)); // type is const double& + * ``` + * (Please consult the C++11 standard for more details). + * `parentheses_would_change_meaning` is `true` iff that is the case. + */ +#keyset[id, expr] +decltypes( + int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + | @temp_init + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + | @co_await + | @co_yield + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +| 327 = @co_await +| 328 = @co_yield +| 329 = @temp_init +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +| 37 = @stmt_co_return +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/downgrades/cf72c8898d19eb1b3374432cf79d8276cb07ad43/stmtparents.ql b/cpp/downgrades/cf72c8898d19eb1b3374432cf79d8276cb07ad43/stmtparents.ql new file mode 100644 index 00000000000..85465fdf8a3 --- /dev/null +++ b/cpp/downgrades/cf72c8898d19eb1b3374432cf79d8276cb07ad43/stmtparents.ql @@ -0,0 +1,22 @@ +class Element extends @element { + string toString() { none() } +} + +class Stmt extends @stmt { + string toString() { none() } +} + +predicate isStmtWithInitializer(Stmt stmt) { + exists(int kind | stmts(stmt, kind, _) | kind = 2 or kind = 11 or kind = 35) +} + +from Stmt child, int index, int index_new, Element parent +where + stmtparents(child, index, parent) and + ( + not isStmtWithInitializer(parent) + or + index > 0 + ) and + if isStmtWithInitializer(parent) then index_new = index - 1 else index_new = index +select child, index_new, parent diff --git a/cpp/downgrades/cf72c8898d19eb1b3374432cf79d8276cb07ad43/upgrade.properties b/cpp/downgrades/cf72c8898d19eb1b3374432cf79d8276cb07ad43/upgrade.properties new file mode 100644 index 00000000000..784726b09de --- /dev/null +++ b/cpp/downgrades/cf72c8898d19eb1b3374432cf79d8276cb07ad43/upgrade.properties @@ -0,0 +1,6 @@ +description: Support C++17 if and switch initializers +compatibility: partial +if_initialization.rel: delete +switch_initialization.rel: delete +exprparents.rel: run exprparents.qlo +stmtparents.rel: run stmtparents.qlo diff --git a/cpp/ql/lib/CHANGELOG.md b/cpp/ql/lib/CHANGELOG.md index d278929caed..6f030187ef9 100644 --- a/cpp/ql/lib/CHANGELOG.md +++ b/cpp/ql/lib/CHANGELOG.md @@ -1,3 +1,5 @@ +## 0.2.1 + ## 0.2.0 ### Breaking Changes diff --git a/cpp/ql/lib/change-notes/2022-04-12-if-and-switch-initializers.md b/cpp/ql/lib/change-notes/2022-04-12-if-and-switch-initializers.md new file mode 100644 index 00000000000..dcfa69120fa --- /dev/null +++ b/cpp/ql/lib/change-notes/2022-04-12-if-and-switch-initializers.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* A `getInitialization` predicate was added to the `ConstexprIfStmt`, `IfStmt`, and `SwitchStmt` classes that yields the C++17-style initializer of the `if` or `switch` statement when it exists. diff --git a/cpp/ql/lib/change-notes/released/0.2.1.md b/cpp/ql/lib/change-notes/released/0.2.1.md new file mode 100644 index 00000000000..c260de2a9ee --- /dev/null +++ b/cpp/ql/lib/change-notes/released/0.2.1.md @@ -0,0 +1 @@ +## 0.2.1 diff --git a/cpp/ql/lib/codeql-pack.release.yml b/cpp/ql/lib/codeql-pack.release.yml index 5274e27ed52..df29a726bcc 100644 --- a/cpp/ql/lib/codeql-pack.release.yml +++ b/cpp/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.2.0 +lastReleaseVersion: 0.2.1 diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml index 29c32aa15ac..b8488e9ce82 100644 --- a/cpp/ql/lib/qlpack.yml +++ b/cpp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-all -version: 0.2.1-dev +version: 0.2.2-dev groups: cpp dbscheme: semmlecode.cpp.dbscheme extractor: cpp diff --git a/cpp/ql/lib/semmle/code/cpp/Field.qll b/cpp/ql/lib/semmle/code/cpp/Field.qll index 362569708a4..95e55568c4b 100644 --- a/cpp/ql/lib/semmle/code/cpp/Field.qll +++ b/cpp/ql/lib/semmle/code/cpp/Field.qll @@ -31,7 +31,7 @@ class Field extends MemberVariable { int getByteOffset() { fieldoffsets(underlyingElement(this), result, _) } /** - * Gets the byte offset within `mostDerivedClass` of each occurence of this + * Gets the byte offset within `mostDerivedClass` of each occurrence of this * field within `mostDerivedClass` itself or a base class subobject of * `mostDerivedClass`. * Note that for fields of virtual base classes, and non-virtual base classes diff --git a/cpp/ql/lib/semmle/code/cpp/PrintAST.qll b/cpp/ql/lib/semmle/code/cpp/PrintAST.qll index 7658d5cf17a..106e49aff74 100644 --- a/cpp/ql/lib/semmle/code/cpp/PrintAST.qll +++ b/cpp/ql/lib/semmle/code/cpp/PrintAST.qll @@ -663,18 +663,24 @@ private predicate namedStmtChildPredicates(Locatable s, Element e, string pred) or s.(ComputedGotoStmt).getExpr() = e and pred = "getExpr()" or + s.(ConstexprIfStmt).getInitialization() = e and pred = "getInitialization()" + or s.(ConstexprIfStmt).getCondition() = e and pred = "getCondition()" or s.(ConstexprIfStmt).getThen() = e and pred = "getThen()" or s.(ConstexprIfStmt).getElse() = e and pred = "getElse()" or + s.(IfStmt).getInitialization() = e and pred = "getInitialization()" + or s.(IfStmt).getCondition() = e and pred = "getCondition()" or s.(IfStmt).getThen() = e and pred = "getThen()" or s.(IfStmt).getElse() = e and pred = "getElse()" or + s.(SwitchStmt).getInitialization() = e and pred = "getInitialization()" + or s.(SwitchStmt).getExpr() = e and pred = "getExpr()" or s.(SwitchStmt).getStmt() = e and pred = "getStmt()" diff --git a/cpp/ql/lib/semmle/code/cpp/controlflow/internal/CFG.qll b/cpp/ql/lib/semmle/code/cpp/controlflow/internal/CFG.qll index 96f03c931bf..25fdba90d52 100644 --- a/cpp/ql/lib/semmle/code/cpp/controlflow/internal/CFG.qll +++ b/cpp/ql/lib/semmle/code/cpp/controlflow/internal/CFG.qll @@ -708,30 +708,33 @@ private predicate straightLineSparse(Node scope, int i, Node ni, Spec spec) { or scope = any(SwitchStmt s | + // SwitchStmt [-> init] -> expr i = -1 and ni = s and spec.isAt() or - i = 0 and ni = s.getExpr() and spec.isAround() + i = 0 and ni = s.getInitialization() and spec.isAround() + or + i = 1 and ni = s.getExpr() and spec.isAround() or // If the switch body is not a block then this step is skipped, and the // expression jumps directly to the cases. - i = 1 and ni = s.getStmt().(BlockStmt) and spec.isAt() + i = 2 and ni = s.getStmt().(BlockStmt) and spec.isAt() or - i = 2 and ni = s.getASwitchCase() and spec.isBefore() + i = 3 and ni = s.getASwitchCase() and spec.isBefore() or // If there is no default case, we can jump to after the block. Note: `i` // is same value as above. not s.getASwitchCase() instanceof DefaultCase and - i = 2 and + i = 3 and ni = s.getStmt() and spec.isAfter() or - i = 3 and /* BARRIER */ ni = s and spec.isBarrier() + i = 4 and /* BARRIER */ ni = s and spec.isBarrier() or - i = 4 and ni = s.getStmt() and spec.isAfter() + i = 5 and ni = s.getStmt() and spec.isAfter() or - i = 5 and ni = s and spec.isAroundDestructors() + i = 6 and ni = s and spec.isAroundDestructors() or - i = 6 and ni = s and spec.isAfter() + i = 7 and ni = s and spec.isAfter() ) or scope = @@ -836,8 +839,15 @@ private predicate subEdge(Pos p1, Node n1, Node n2, Pos p2) { p2.nodeAt(n2, f) ) or - // IfStmt -> condition ; { then, else } -> + // IfStmt -> [ init -> ] condition ; { then, else } -> exists(IfStmt s | + p1.nodeAt(n1, s) and + p2.nodeBefore(n2, s.getInitialization()) + or + p1.nodeAfter(n1, s.getInitialization()) and + p2.nodeBefore(n2, s.getCondition()) + or + not exists(s.getInitialization()) and p1.nodeAt(n1, s) and p2.nodeBefore(n2, s.getCondition()) or @@ -851,8 +861,15 @@ private predicate subEdge(Pos p1, Node n1, Node n2, Pos p2) { p2.nodeAfter(n2, s) ) or - // ConstexprIfStmt -> condition ; { then, else } -> // same as IfStmt + // ConstexprIfStmt -> [ init -> ] condition ; { then, else } -> // same as IfStmt exists(ConstexprIfStmt s | + p1.nodeAt(n1, s) and + p2.nodeBefore(n2, s.getInitialization()) + or + p1.nodeAfter(n1, s.getInitialization()) and + p2.nodeBefore(n2, s.getCondition()) + or + not exists(s.getInitialization()) and p1.nodeAt(n1, s) and p2.nodeBefore(n2, s.getCondition()) or @@ -953,7 +970,7 @@ private predicate subEdge(Pos p1, Node n1, Node n2, Pos p2) { private predicate subEdgeIncludingDestructors(Pos p1, Node n1, Node n2, Pos p2) { subEdge(p1, n1, n2, p2) or - // If `n1` has sub-nodes to accomodate destructors, but there are none to be + // If `n1` has sub-nodes to accommodate destructors, but there are none to be // called, connect the "before destructors" node directly to the "after // destructors" node. For performance, only do this when the nodes exist. exists(Pos afterDtors | afterDtors.isAfterDestructors() | subEdge(afterDtors, n1, _, _)) and diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 5bd84566df5..fb773ea89f8 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 5bd84566df5..fb773ea89f8 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 5bd84566df5..fb773ea89f8 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 5bd84566df5..fb773ea89f8 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll index e60505d9248..0079b259260 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -305,7 +305,7 @@ cached private module Cached { /** * If needed, call this predicate from `DataFlowImplSpecific.qll` in order to - * force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby + * force a stage-dependency on the `DataFlowImplCommon.qll` stage and thereby * collapsing the two stages. */ cached diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index 5bd84566df5..fb773ea89f8 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 5bd84566df5..fb773ea89f8 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 5bd84566df5..fb773ea89f8 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 5bd84566df5..fb773ea89f8 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 5bd84566df5..fb773ea89f8 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll index e60505d9248..0079b259260 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll @@ -305,7 +305,7 @@ cached private module Cached { /** * If needed, call this predicate from `DataFlowImplSpecific.qll` in order to - * force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby + * force a stage-dependency on the `DataFlowImplCommon.qll` stage and thereby * collapsing the two stages. */ cached diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index ac7466779fe..4171f5a5227 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -37,7 +37,7 @@ private module Cached { * along the chain of addresses computed by `StoreNodeInstr.getInner` to identify field writes * and call `storeStep` accordingly (i.e., for an expression like `a.b.c = x`, we visit `c`, then * `b`, then `a`). - * 2. Flow is transfered from a `WriteSideEffectInstruction` to a `StoreNodeOperand` after flow + * 2. Flow is transferred from a `WriteSideEffectInstruction` to a `StoreNodeOperand` after flow * returns to a caller. Flow will then proceed to the defining instruction of the operand (because * the `StoreNodeInstr` computed by `StoreNodeOperand.getInner()` is the `StoreNode` containing * the defining instruction), and then along the chain computed by `StoreNodeInstr.getInner` like diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/EdgeKind.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/EdgeKind.qll index 32e36bb6787..91e1fe03e23 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/EdgeKind.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/EdgeKind.qll @@ -67,7 +67,7 @@ class DefaultEdge extends EdgeKind, TDefaultEdge { /** * A "case" edge, representing the successor of a `Switch` instruction when the - * the condition value matches a correponding `case` label. + * the condition value matches a corresponding `case` label. */ class CaseEdge extends EdgeKind, TCaseEdge { string minValue; diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll index 796fb792366..ca3c378cd7e 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll @@ -34,7 +34,7 @@ class ValueNumber extends TValueNumber { final Instruction getAnInstruction() { this = valueNumber(result) } /** - * Gets one of the instructions that was assigned this value number. The chosen instuction is + * Gets one of the instructions that was assigned this value number. The chosen instruction is * deterministic but arbitrary. Intended for use only in debugging. */ final Instruction getExampleInstruction() { diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 13ec2ca4ca4..303a9683011 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -1005,7 +1005,7 @@ predicate canReuseSsaForMemoryResult(Instruction instruction) { deprecated predicate canReuseSSAForMemoryResult = canReuseSsaForMemoryResult/1; /** - * Expose some of the internal predicates to PrintSSA.qll. We do this by publically importing those modules in the + * Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the * `DebugSSA` module, which is then imported by PrintSSA. */ module DebugSsa { diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll index 796fb792366..ca3c378cd7e 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll @@ -34,7 +34,7 @@ class ValueNumber extends TValueNumber { final Instruction getAnInstruction() { this = valueNumber(result) } /** - * Gets one of the instructions that was assigned this value number. The chosen instuction is + * Gets one of the instructions that was assigned this value number. The chosen instruction is * deterministic but arbitrary. Intended for use only in debugging. */ final Instruction getExampleInstruction() { diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll index eb195286339..187dbc2f994 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll @@ -421,20 +421,36 @@ class TranslatedCatchAnyHandler extends TranslatedHandler { class TranslatedIfStmt extends TranslatedStmt, ConditionContext { override IfStmt stmt; - override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() } + override Instruction getFirstInstruction() { + if hasInitialization() + then result = getInitialization().getFirstInstruction() + else result = getFirstConditionInstruction() + } override TranslatedElement getChild(int id) { - id = 0 and result = getCondition() + id = 0 and result = getInitialization() or - id = 1 and result = getThen() + id = 1 and result = getCondition() or - id = 2 and result = getElse() + id = 2 and result = getThen() + or + id = 3 and result = getElse() + } + + private predicate hasInitialization() { exists(stmt.getInitialization()) } + + private TranslatedStmt getInitialization() { + result = getTranslatedStmt(stmt.getInitialization()) } private TranslatedCondition getCondition() { result = getTranslatedCondition(stmt.getCondition().getFullyConverted()) } + private Instruction getFirstConditionInstruction() { + result = getCondition().getFirstInstruction() + } + private TranslatedStmt getThen() { result = getTranslatedStmt(stmt.getThen()) } private TranslatedStmt getElse() { result = getTranslatedStmt(stmt.getElse()) } @@ -456,6 +472,9 @@ class TranslatedIfStmt extends TranslatedStmt, ConditionContext { } override Instruction getChildSuccessor(TranslatedElement child) { + child = getInitialization() and + result = getFirstConditionInstruction() + or (child = getThen() or child = getElse()) and result = getParent().getChildSuccessor(this) } @@ -698,14 +717,28 @@ class TranslatedSwitchStmt extends TranslatedStmt { result = getTranslatedExpr(stmt.getExpr().getFullyConverted()) } + private Instruction getFirstExprInstruction() { result = getExpr().getFirstInstruction() } + private TranslatedStmt getBody() { result = getTranslatedStmt(stmt.getStmt()) } - override Instruction getFirstInstruction() { result = getExpr().getFirstInstruction() } + override Instruction getFirstInstruction() { + if hasInitialization() + then result = getInitialization().getFirstInstruction() + else result = getFirstExprInstruction() + } override TranslatedElement getChild(int id) { - id = 0 and result = getExpr() + id = 0 and result = getInitialization() or - id = 1 and result = getBody() + id = 1 and result = getExpr() + or + id = 2 and result = getBody() + } + + private predicate hasInitialization() { exists(stmt.getInitialization()) } + + private TranslatedStmt getInitialization() { + result = getTranslatedStmt(stmt.getInitialization()) } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { @@ -735,6 +768,8 @@ class TranslatedSwitchStmt extends TranslatedStmt { } override Instruction getChildSuccessor(TranslatedElement child) { + child = getInitialization() and result = getFirstExprInstruction() + or child = getExpr() and result = getInstruction(SwitchBranchTag()) or child = getBody() and result = getParent().getChildSuccessor(this) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll index 796fb792366..ca3c378cd7e 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll @@ -34,7 +34,7 @@ class ValueNumber extends TValueNumber { final Instruction getAnInstruction() { this = valueNumber(result) } /** - * Gets one of the instructions that was assigned this value number. The chosen instuction is + * Gets one of the instructions that was assigned this value number. The chosen instruction is * deterministic but arbitrary. Intended for use only in debugging. */ final Instruction getExampleInstruction() { diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 13ec2ca4ca4..303a9683011 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -1005,7 +1005,7 @@ predicate canReuseSsaForMemoryResult(Instruction instruction) { deprecated predicate canReuseSSAForMemoryResult = canReuseSsaForMemoryResult/1; /** - * Expose some of the internal predicates to PrintSSA.qll. We do this by publically importing those modules in the + * Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the * `DebugSSA` module, which is then imported by PrintSSA. */ module DebugSsa { diff --git a/cpp/ql/lib/semmle/code/cpp/security/Encryption.qll b/cpp/ql/lib/semmle/code/cpp/security/Encryption.qll index 120b154b787..00be9a3deb5 100644 --- a/cpp/ql/lib/semmle/code/cpp/security/Encryption.qll +++ b/cpp/ql/lib/semmle/code/cpp/security/Encryption.qll @@ -59,7 +59,7 @@ predicate isInsecureEncryption(string name) { name.regexpMatch(getInsecureAlgori /** * Holds if there is additional evidence that `name` looks like it might be * related to operations with an encyption algorithm, besides the name of a - * specific algorithm. This can be used in conjuction with + * specific algorithm. This can be used in conjunction with * `isInsecureEncryption` to produce a stronger heuristic. */ bindingset[name] diff --git a/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll b/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll index ef311e6fc45..7ccd9f797dd 100644 --- a/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll +++ b/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll @@ -213,6 +213,26 @@ class ConditionalStmt extends ControlStructure, TConditionalStmt { } class IfStmt extends ConditionalStmt, @stmt_if { override string getAPrimaryQlClass() { result = "IfStmt" } + /** + * Gets the initialization statement of this 'if' statement, if any. + * + * For example, for + * ``` + * if (int x = y; b) { f(); } + * ``` + * the result is `int x = y;`. + * + * Does not hold if the initialization statement is missing or an empty statement, as in + * ``` + * if (b) { f(); } + * ``` + * or + * ``` + * if (; b) { f(); } + * ``` + */ + Stmt getInitialization() { if_initialization(underlyingElement(this), unresolveElement(result)) } + /** * Gets the condition expression of this 'if' statement. * @@ -222,7 +242,7 @@ class IfStmt extends ConditionalStmt, @stmt_if { * ``` * the result is `b`. */ - Expr getCondition() { result = this.getChild(0) } + Expr getCondition() { result = this.getChild(1) } override Expr getControllingExpr() { result = this.getCondition() } @@ -299,6 +319,28 @@ class IfStmt extends ConditionalStmt, @stmt_if { class ConstexprIfStmt extends ConditionalStmt, @stmt_constexpr_if { override string getAPrimaryQlClass() { result = "ConstexprIfStmt" } + /** + * Gets the initialization statement of this 'constexpr if' statement, if any. + * + * For example, for + * ``` + * if constexpr (int x = y; b) { f(); } + * ``` + * the result is `int x = y;`. + * + * Does not hold if the initialization statement is missing or an empty statement, as in + * ``` + * if constexpr (b) { f(); } + * ``` + * or + * ``` + * if constexpr (; b) { f(); } + * ``` + */ + Stmt getInitialization() { + constexpr_if_initialization(underlyingElement(this), unresolveElement(result)) + } + /** * Gets the condition expression of this 'constexpr if' statement. * @@ -308,7 +350,7 @@ class ConstexprIfStmt extends ConditionalStmt, @stmt_constexpr_if { * ``` * the result is `b`. */ - Expr getCondition() { result = this.getChild(0) } + Expr getCondition() { result = this.getChild(1) } override Expr getControllingExpr() { result = this.getCondition() } @@ -926,7 +968,7 @@ class ForStmt extends Loop, @stmt_for { * * Does not hold if the initialization statement is an empty statement, as in * ``` - * for (; i < 10; i++) { j++ } + * for (; i < 10; i++) { j++; } * ``` */ Stmt getInitialization() { for_initialization(underlyingElement(this), unresolveElement(result)) } @@ -1470,6 +1512,28 @@ class DefaultCase extends SwitchCase { class SwitchStmt extends ConditionalStmt, @stmt_switch { override string getAPrimaryQlClass() { result = "SwitchStmt" } + /** + * Gets the initialization statement of this 'switch' statement, if any. + * + * For example, for + * ``` + * switch (int x = y; b) { } + * ``` + * the result is `int x = y;`. + * + * Does not hold if the initialization statement is missing or an empty statement, as in + * ``` + * switch (b) { } + * ``` + * or + * ``` + * switch (; b) { } + * ``` + */ + Stmt getInitialization() { + switch_initialization(underlyingElement(this), unresolveElement(result)) + } + /** * Gets the expression that this 'switch' statement switches on. * @@ -1485,7 +1549,7 @@ class SwitchStmt extends ConditionalStmt, @stmt_switch { * ``` * the result is `i`. */ - Expr getExpr() { result = this.getChild(0) } + Expr getExpr() { result = this.getChild(1) } override Expr getControllingExpr() { result = this.getExpr() } diff --git a/cpp/ql/lib/semmlecode.cpp.dbscheme b/cpp/ql/lib/semmlecode.cpp.dbscheme index e9a518baf14..cf72c8898d1 100644 --- a/cpp/ql/lib/semmlecode.cpp.dbscheme +++ b/cpp/ql/lib/semmlecode.cpp.dbscheme @@ -1863,6 +1863,11 @@ variable_vla( int decl: @stmt_vla_decl ref ); +if_initialization( + unique int if_stmt: @stmt_if ref, + int init_id: @stmt ref +); + if_then( unique int if_stmt: @stmt_if ref, int then_id: @stmt ref @@ -1873,6 +1878,11 @@ if_else( int else_id: @stmt ref ); +constexpr_if_initialization( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int init_id: @stmt ref +); + constexpr_if_then( unique int constexpr_if_stmt: @stmt_constexpr_if ref, int then_id: @stmt ref @@ -1893,6 +1903,11 @@ do_body( int body_id: @stmt ref ); +switch_initialization( + unique int switch_stmt: @stmt_switch ref, + int init_id: @stmt ref +); + #keyset[switch_stmt, index] switch_case( int switch_stmt: @stmt_switch ref, diff --git a/cpp/ql/lib/semmlecode.cpp.dbscheme.stats b/cpp/ql/lib/semmlecode.cpp.dbscheme.stats index 472bfd55aaf..52676255dbd 100644 --- a/cpp/ql/lib/semmlecode.cpp.dbscheme.stats +++ b/cpp/ql/lib/semmlecode.cpp.dbscheme.stats @@ -2,7 +2,7 @@ @compilation - 9999 + 9980 @externalDataElement @@ -18,67 +18,67 @@ @location_stmt - 3805195 - - - @location_default - 30199622 - - - @location_expr - 13127189 + 3805462 @diagnostic - 667106 + 632933 @file - 124610 + 124189 @folder - 15576 + 15994 + + + @location_expr + 13128112 + + + @location_default + 30128761 @macroinvocation - 34062185 + 33895024 @function - 4759741 + 4726273 @fun_decl - 5131684 - - - @type_decl - 3292736 - - - @namespace_decl - 307863 - - - @using - 375719 - - - @static_assert - 130790 + 5096962 @var_decl - 8586319 + 8543232 + + + @type_decl + 3283977 + + + @namespace_decl + 306979 + + + @using + 374921 + + + @static_assert + 130414 @parameter - 6696867 + 6660155 @membervariable - 1050009 + 1050083 @globalvariable @@ -86,63 +86,63 @@ @localvariable - 581746 + 581698 @enumconstant - 240596 + 240613 @builtintype - 22184 + 22109 @derivedtype - 4456239 + 4413446 @decltype - 31152 + 31047 @usertype - 5362968 + 5342989 @mangledname - 1733994 + 1730792 @type_mention - 4011226 + 4011508 @routinetype - 543059 + 546982 @ptrtomember - 38232 + 38103 @specifier - 25016 + 24932 @gnuattribute - 663644 + 664228 @stdattribute - 468476 + 469328 @alignas - 8968 + 8937 @declspec - 238528 + 238544 @msattribute @@ -150,15 +150,15 @@ @attribute_arg_token - 25960 + 25402 @attribute_arg_constant - 324742 + 326469 @attribute_arg_type - 1535 + 470 @attribute_arg_empty @@ -166,99 +166,207 @@ @derivation - 397280 + 402388 @frienddecl - 710038 + 715075 @comment - 9024167 + 9004230 @namespace - 12744 + 12701 @specialnamequalifyingelement - 472 + 470 @namequalifier - 1593457 + 1618961 @value - 10645398 + 10646146 @initialiser - 1736804 + 1731850 + + + @lambdacapture + 28224 + + + @stmt_expr + 1480414 + + + @stmt_if + 723174 + + + @stmt_while + 30207 + + + @stmt_label + 53046 + + + @stmt_return + 1306346 + + + @stmt_block + 1446530 + + + @stmt_end_test_while + 148604 + + + @stmt_for + 61324 + + + @stmt_switch_case + 191408 + + + @stmt_switch + 20901 + + + @stmt_try_block + 42701 + + + @stmt_decl + 608508 + + + @stmt_empty + 193487 + + + @stmt_continue + 22507 + + + @stmt_break + 102234 + + + @stmt_range_based_for + 8467 + + + @stmt_handler + 59432 + + + @stmt_constexpr_if + 52508 + + + @stmt_goto + 110490 + + + @stmt_asm + 110589 + + + @stmt_microsoft_try + 163 + + + @stmt_set_vla_size + 26 + + + @stmt_vla_decl + 21 + + + @stmt_assigned_goto + 9059 + + + @stmt_co_return + 2 @delete_array_expr - 1413 + 1410 @new_array_expr - 5113 + 5099 @ctordirectinit - 111984 + 112813 @ctorvirtualinit - 6546 + 6534 @ctorfieldinit - 199374 + 200789 @ctordelegatinginit - 7857 + 3347 @dtordirectdestruct - 41421 + 41715 @dtorvirtualdestruct - 4093 + 4122 @dtorfielddestruct - 41351 + 41644 @static_cast - 212170 + 211822 @reinterpret_cast - 30881 + 30813 @const_cast - 35398 + 35320 + + + @dynamic_cast + 1040 @c_style_cast - 4209375 + 4209393 @lambdaexpr - 21712 + 21639 @param_ref - 403726 + 375289 @errorexpr - 54470 + 46823 @address_of @@ -266,143 +374,139 @@ @reference_to - 1615323 + 1596143 @indirect - 292094 + 292115 @ref_indirect - 1941936 + 1934537 @array_to_pointer - 1424786 + 1424883 @vacuous_destructor_call - 8711 + 8138 @parexpr - 3572304 + 3572547 @arithnegexpr - 650877 - - - @unaryplusexpr - 2903 + 650874 @complementexpr - 27785 + 27787 @notexpr - 277973 + 277992 @postincrexpr - 61769 + 61774 @postdecrexpr - 41857 + 41860 @preincrexpr - 70302 + 70307 @predecrexpr - 26107 + 26108 @conditionalexpr - 654457 + 654502 @addexpr - 400330 + 400358 @subexpr - 339317 + 339340 @mulexpr - 305870 + 305891 @divexpr - 133721 + 133731 @remexpr - 15707 + 15819 @paddexpr - 86499 + 86505 @psubexpr - 49678 + 49681 @pdiffexpr - 35608 + 35529 @lshiftexpr - 562948 + 562988 @rshiftexpr - 141607 + 141617 @andexpr - 491783 + 491818 @orexpr - 146257 + 146267 @xorexpr - 53934 + 53938 @eqexpr - 468840 + 468873 @neexpr - 300391 + 300411 @gtexpr - 101009 + 100669 @ltexpr - 108562 + 106314 @geexpr - 58985 + 58989 @leexpr - 212126 + 212141 @assignexpr - 933354 + 933419 @assignaddexpr @@ -410,19 +514,19 @@ @assignsubexpr - 15624 + 11157 @assignmulexpr - 7586 + 7170 @assigndivexpr - 4971 + 4972 @assignremexpr - 1625 + 419 @assignlshiftexpr @@ -434,123 +538,119 @@ @assignandexpr - 5780 + 4852 @assignorexpr - 23853 + 23851 @assignxorexpr - 21802 + 21804 @assignpaddexpr - 13576 - - - @assignpsubexpr - 1148 + 13577 @andlogicalexpr - 248991 + 249008 @orlogicalexpr - 863957 + 864018 @commaexpr - 181070 + 181539 @subscriptexpr - 367945 + 367915 @callexpr - 310110 + 309063 @vastartexpr - 3713 + 3703 @vaendexpr - 2832 + 2822 + + + @vacopyexpr + 140 @varaccess - 6005942 + 6006364 @thisaccess - 1129204 + 1125933 @new_expr - 55240 + 47598 @delete_expr - 11649 + 11732 @throw_expr - 21806 + 21765 @condition_decl - 38495 + 38595 @braced_init_list - 1005 + 1008 @type_id - 36173 + 36430 @runtime_sizeof - 289248 + 289268 @runtime_alignof - 48208 + 48550 @sizeof_pack - 5664 + 5644 @routineexpr - 3065607 + 3047613 @type_operand - 1125950 - - - @offsetofexpr - 20101 + 1126029 @isemptyexpr - 2310 + 2305 @ispodexpr - 637 + 636 @hastrivialdestructor - 472 + 470 @literal - 4351842 + 4350894 @aggregateliteral @@ -558,31 +658,39 @@ @istrivialexpr - 944 + 940 @istriviallycopyableexpr - 3776 + 3763 + + + @isconstructibleexpr + 2724 @isfinalexpr - 2100 + 2096 @noexceptexpr - 35718 + 23574 @builtinaddressof - 13189 + 13282 @temp_init - 759580 + 760683 @assume - 3209 + 3200 + + + @unaryplusexpr + 2903 @conjugation @@ -628,6 +736,10 @@ @maxexpr 1 + + @assignpsubexpr + 1148 + @virtfunptrexpr 1 @@ -637,12 +749,12 @@ 950 - @vacopyexpr - 139 + @expr_stmt + 94929 - @expr_stmt - 94922 + @offsetofexpr + 20103 @hasassignexpr @@ -686,7 +798,7 @@ @isabstractexpr - 17 + 18 @isbaseofexpr @@ -694,15 +806,15 @@ @isclassexpr - 1841 + 1835 @isconvtoexpr - 1155 + 1152 @isenumexpr - 1260 + 1257 @ispolyexpr @@ -714,7 +826,7 @@ @typescompexpr - 562376 + 562415 @intaddrexpr @@ -722,23 +834,19 @@ @uuidof - 20051 + 19994 @foldexpr 4 - - @dynamic_cast - 1042 - @noopexpr 37 @istriviallyconstructibleexpr - 2836 + 2829 @isdestructibleexpr @@ -754,15 +862,15 @@ @istriviallyassignableexpr - 525 + 524 @isnothrowassignableexpr - 2100 + 2096 @isstandardlayoutexpr - 840 + 838 @isliteraltypeexpr @@ -780,13 +888,9 @@ @hasnothrowmoveassignexpr 4 - - @isconstructibleexpr - 2731 - @isnothrowconstructibleexpr - 4831 + 4821 @hasfinalizerexpr @@ -826,7 +930,7 @@ @builtinchooseexpr - 9135 + 9136 @vec_fill @@ -852,157 +956,53 @@ @co_yield 1 - - @lambdacapture - 28320 - - - @stmt_expr - 1480310 - - - @stmt_if - 723123 - - - @stmt_while - 30265 - - - @stmt_goto - 110482 - - - @stmt_label - 53042 - - - @stmt_return - 1310769 - - - @stmt_block - 1451428 - - - @stmt_end_test_while - 148593 - - - @stmt_for - 61319 - - - @stmt_switch_case - 190914 - - - @stmt_switch - 20900 - - - @stmt_asm - 110581 - - - @stmt_try_block - 42591 - - - @stmt_decl - 609675 - - - @stmt_empty - 193503 - - - @stmt_continue - 22506 - - - @stmt_break - 102528 - - - @stmt_range_based_for - 8496 - - - @stmt_handler - 59279 - - - @stmt_microsoft_try - 163 - - - @stmt_set_vla_size - 26 - - - @stmt_vla_decl - 21 - - - @stmt_assigned_goto - 9058 - - - @stmt_constexpr_if - 52624 - - - @stmt_co_return - 2 - @ppd_if - 671197 + 672225 @ppd_ifdef - 266213 + 265314 @ppd_ifndef - 269517 + 268607 @ppd_elif - 25488 + 25402 @ppd_else - 211460 + 210746 @ppd_endif - 1206927 + 1206147 @ppd_plain_include - 314830 + 313767 @ppd_define - 2443222 + 2437824 @ppd_undef - 264325 + 262021 @ppd_pragma - 313333 + 312641 @ppd_include_next - 1888 + 1881 @ppd_line - 27783 + 27780 @ppd_error @@ -1048,11 +1048,11 @@ compilations - 9999 + 9980 id - 9999 + 9980 cwd @@ -1070,7 +1070,7 @@ 1 2 - 9999 + 9980 @@ -1096,7 +1096,7 @@ compilation_args - 656105 + 656151 id @@ -1104,11 +1104,11 @@ num - 712 + 713 arg - 34648 + 34651 @@ -1346,7 +1346,7 @@ 1 2 - 32573 + 32576 2 @@ -1367,7 +1367,7 @@ 1 2 - 33435 + 33438 2 @@ -1382,7 +1382,7 @@ compilation_compiling_files - 11494 + 11495 id @@ -1394,7 +1394,7 @@ file - 9983 + 9984 @@ -1628,7 +1628,7 @@ compilation_time - 45979 + 45982 id @@ -1644,7 +1644,7 @@ seconds - 13762 + 10779 @@ -1725,48 +1725,48 @@ 3 4 - 278 + 596 4 5 - 715 + 397 6 - 7 - 119 - - - 9 - 11 - 119 - - - 11 - 12 - 238 - - - 13 - 17 - 119 - - - 18 - 20 - 119 - - - 21 - 26 + 9 159 - 44 - 132 + 9 + 10 + 79 + + + 10 + 11 + 159 + + + 11 + 16 + 159 + + + 17 + 19 119 + + 19 + 22 + 159 + + + 26 + 97 + 159 + @@ -1833,32 +1833,32 @@ 3 4 - 1073 + 1153 4 5 - 676 + 596 5 6 - 238 + 119 6 7 - 437 + 556 7 8 - 159 + 79 8 - 10 - 238 + 9 + 318 11 @@ -1866,8 +1866,8 @@ 278 - 29 - 93 + 28 + 98 198 @@ -1916,21 +1916,16 @@ 3 4 + 79 + + + 132 + 133 39 - 5 - 6 - 39 - - - 167 - 168 - 39 - - - 178 - 179 + 141 + 142 39 @@ -1947,22 +1942,27 @@ 1 2 - 8591 + 5887 2 3 - 3420 + 2505 3 4 - 1312 + 1431 4 - 40 - 437 + 7 + 835 + + + 29 + 45 + 119 @@ -1978,22 +1978,32 @@ 1 2 - 8591 + 5369 2 3 - 2744 + 2625 3 4 - 1551 + 875 4 + 5 + 715 + + + 5 + 7 + 914 + + + 7 64 - 875 + 278 @@ -2009,12 +2019,12 @@ 1 2 - 13483 + 10461 2 3 - 278 + 318 @@ -2024,23 +2034,23 @@ diagnostic_for - 917206 + 968526 diagnostic - 667106 + 632828 compilation - 1890 + 1991 file_number - 105 + 104 file_number_diagnostic_number - 105144 + 104912 @@ -2054,17 +2064,22 @@ 1 2 - 465220 + 405919 2 3 - 177937 + 151656 3 - 9 - 23949 + 4 + 42237 + + + 4 + 8 + 33014 @@ -2080,7 +2095,7 @@ 1 2 - 667106 + 632828 @@ -2096,12 +2111,17 @@ 1 2 - 633284 + 561454 2 - 5 - 33822 + 3 + 71164 + + + 3 + 4 + 209 @@ -2117,52 +2137,67 @@ 37 38 - 105 + 104 - 78 - 79 - 210 + 38 + 39 + 104 - 119 - 120 - 105 + 77 + 78 + 104 - 155 - 156 - 105 + 79 + 80 + 104 - 156 - 157 - 210 + 198 + 199 + 104 + + + 222 + 223 + 104 352 353 - 105 + 104 353 354 - 105 + 104 - 710 - 711 - 105 + 359 + 360 + 104 + + + 418 + 419 + 104 + + + 570 + 571 + 104 756 757 - 630 + 628 1001 1002 - 210 + 209 @@ -2178,7 +2213,7 @@ 1 2 - 1890 + 1991 @@ -2194,52 +2229,67 @@ 37 38 - 105 + 104 - 78 - 79 - 210 + 38 + 39 + 104 - 119 - 120 - 105 + 77 + 78 + 104 - 155 - 156 - 105 + 79 + 80 + 104 - 156 - 157 - 210 + 198 + 199 + 104 + + + 222 + 223 + 104 352 353 - 105 + 104 353 354 - 105 + 104 - 710 - 711 - 105 + 359 + 360 + 104 + + + 418 + 419 + 104 + + + 570 + 571 + 104 756 757 - 630 + 628 1001 1002 - 210 + 209 @@ -2253,9 +2303,9 @@ 12 - 6351 - 6352 - 105 + 6038 + 6039 + 104 @@ -2269,9 +2319,9 @@ 12 - 18 - 19 - 105 + 19 + 20 + 104 @@ -2287,7 +2337,7 @@ 1001 1002 - 105 + 104 @@ -2303,42 +2353,42 @@ 2 3 - 25734 + 25677 + + + 5 + 6 + 5974 6 7 - 12814 + 6183 7 8 - 105 + 17083 8 9 - 42015 + 9327 9 10 - 8193 + 22428 10 11 - 525 + 14358 11 - 12 - 9978 - - - 12 - 14 - 5777 + 13 + 3877 @@ -2354,37 +2404,42 @@ 2 3 - 25734 + 25677 8 9 - 4831 + 19494 9 10 - 37499 + 15930 10 - 11 - 105 - - - 11 - 12 - 20587 + 13 + 6917 13 - 16 - 8193 + 14 + 13624 - 17 - 19 - 8193 + 14 + 15 + 2515 + + + 15 + 16 + 12472 + + + 16 + 20 + 8279 @@ -2400,7 +2455,7 @@ 1 2 - 105144 + 104912 @@ -2410,19 +2465,19 @@ compilation_finished - 9999 + 9980 id - 9999 + 9980 cpu_seconds - 8319 + 7181 elapsed_seconds - 139 + 115 @@ -2436,7 +2491,7 @@ 1 2 - 9999 + 9980 @@ -2452,7 +2507,7 @@ 1 2 - 9999 + 9980 @@ -2468,17 +2523,17 @@ 1 2 - 7160 + 5666 2 3 - 915 + 1063 3 - 11 - 243 + 14 + 451 @@ -2494,12 +2549,12 @@ 1 2 - 8064 + 6661 2 3 - 254 + 520 @@ -2527,49 +2582,39 @@ 5 11 - - 6 - 7 - 11 - 7 8 11 - 13 - 14 + 18 + 19 11 - 23 - 24 + 27 + 28 11 - 64 - 65 + 83 + 84 11 - 95 - 96 + 190 + 191 11 - 136 - 137 + 258 + 259 11 - 254 - 255 - 11 - - - 257 - 258 + 272 + 273 11 @@ -2598,49 +2643,39 @@ 5 11 - - 6 - 7 - 11 - 7 8 11 - 13 - 14 + 18 + 19 11 - 22 - 23 + 25 + 26 11 - 63 - 64 + 79 + 80 11 - 91 - 92 + 135 + 136 11 - 94 - 95 + 169 + 170 11 - 203 - 204 - 11 - - - 233 - 234 + 225 + 226 11 @@ -2867,11 +2902,11 @@ sourceLocationPrefix - 472 + 470 prefix - 472 + 470 @@ -4365,31 +4400,31 @@ locations_default - 30199622 + 30128761 id - 30199622 + 30128761 container - 140186 + 140184 startLine - 2121681 + 2114992 startColumn - 37288 + 37162 endLine - 2124985 + 2117814 endColumn - 48616 + 48452 @@ -4403,7 +4438,7 @@ 1 2 - 30199622 + 30128761 @@ -4419,7 +4454,7 @@ 1 2 - 30199622 + 30128761 @@ -4435,7 +4470,7 @@ 1 2 - 30199622 + 30128761 @@ -4451,7 +4486,7 @@ 1 2 - 30199622 + 30128761 @@ -4467,7 +4502,7 @@ 1 2 - 30199622 + 30128761 @@ -4483,67 +4518,67 @@ 1 2 - 16048 + 16464 2 12 - 10856 + 10819 13 20 - 11800 + 11760 21 36 - 11328 + 11289 36 55 - 11328 + 11289 55 77 - 10856 + 10819 77 102 - 10856 + 10819 102 - 146 - 10856 + 149 + 10819 - 148 - 223 - 10856 + 149 + 227 + 11289 - 226 + 228 350 - 11800 + 11289 358 628 - 10856 + 10819 671 1926 - 10856 + 10819 - 2171 + 2168 2380 - 1888 + 1881 @@ -4559,67 +4594,67 @@ 1 2 - 16048 + 16464 2 9 - 10856 + 10819 9 16 - 11800 + 11760 16 25 - 11328 + 11289 25 40 - 10856 + 10819 40 57 - 10856 + 10819 58 72 - 10856 + 10819 73 - 99 - 10856 + 103 + 11289 - 101 + 106 141 - 12272 + 11760 148 226 - 10856 + 11289 226 - 365 - 10856 + 373 + 10819 - 372 - 1253 - 10856 + 381 + 1456 + 10819 - 1452 - 1616 - 1888 + 1464 + 1613 + 1411 @@ -4635,67 +4670,67 @@ 1 2 - 16048 + 16464 2 4 - 8968 + 8937 4 5 - 7552 + 7526 5 6 - 7552 + 7526 6 8 - 12272 + 11760 8 13 - 11800 + 12230 13 17 - 10856 + 10819 17 25 - 11328 + 11289 25 31 - 11800 + 11760 31 38 - 10856 + 10819 38 52 - 10856 + 10819 52 64 - 10856 + 10819 65 77 - 9440 + 9408 @@ -4711,67 +4746,67 @@ 1 2 - 16048 + 16464 2 9 - 10856 + 10819 9 16 - 11800 + 11760 16 25 - 11328 + 11289 25 40 - 10856 + 10819 40 57 - 10856 + 10819 58 71 - 10856 + 10819 72 - 97 - 10856 + 98 + 10819 - 97 + 101 140 - 11800 + 11760 140 - 225 - 11328 + 224 + 10819 - 225 - 365 - 10856 + 224 + 360 + 10819 - 372 - 1253 - 10856 + 364 + 1185 + 10819 - 1449 - 1613 - 1888 + 1254 + 1610 + 2352 @@ -4787,62 +4822,62 @@ 1 2 - 16048 + 16464 2 10 - 11328 + 11289 10 14 - 10856 + 10819 14 21 - 11328 + 11289 22 31 - 11328 + 11289 31 39 - 12744 + 12701 39 48 - 12272 + 12230 48 56 - 11800 + 11760 56 64 - 11800 + 11760 64 72 - 10856 + 10819 72 77 - 11328 + 11289 77 90 - 8496 + 8467 @@ -4858,719 +4893,59 @@ 1 2 - 598507 + 581905 2 3 - 302085 + 318001 3 4 - 190691 + 199456 4 6 - 171339 + 160882 6 10 - 192579 + 190048 10 16 - 161427 + 166057 16 - 24 - 159539 - - - 24 - 42 - 159539 - - - 42 - 142 - 159539 - - - 142 - 298 - 26432 - - - - - - - startLine - container - - - 12 - - - 1 - 2 - 881241 - - - 2 - 3 - 262437 - - - 3 - 4 - 135466 - - - 4 - 7 - 195883 - - - 7 - 11 - 177475 - - - 11 - 16 - 161899 - - - 16 - 29 - 159539 - - - 29 - 298 - 147738 - - - - - - - startLine - startColumn - - - 12 - - - 1 - 2 - 625884 - - - 2 - 3 - 296893 - - - 3 - 4 - 203435 - - - 4 - 6 - 195411 - - - 6 - 9 - 178891 - - - 9 - 13 - 167091 - - - 13 - 19 - 178419 - - - 19 - 29 - 162843 - - - 29 - 52 - 112810 - - - - - - - startLine - endLine - - - 12 - - - 1 - 2 - 1552910 - - - 2 - 3 - 345510 - - - 3 - 5 - 171811 - - - 5 - 16 - 51449 - - - - - - - startLine - endColumn - - - 12 - - - 1 - 2 - 601811 - - - 2 - 3 - 305389 - - - 3 - 4 - 194939 - - - 4 - 6 - 174171 - - - 6 - 9 - 165675 - - - 9 - 14 - 172755 - - - 14 - 20 - 164259 - - - 20 - 31 - 171339 - - - 31 - 58 - 160955 - - - 58 - 67 - 10384 - - - - - - - startColumn - id - - - 12 - - - 1 - 31 - 2832 - - - 42 - 85 - 2832 - - - 86 - 128 - 2832 - - - 129 - 230 - 2832 - - - 247 - 292 - 2832 - - - 292 - 360 - 2832 - - - 377 - 459 - 2832 - - - 476 - 559 - 2832 - - - 565 - 620 - 2832 - - - 625 - 689 - 2832 - - - 700 - 795 - 2832 - - - 820 - 1546 - 2832 - - - 1698 - 5668 - 2832 - - - 15394 - 15395 - 472 - - - - - - - startColumn - container - - - 12 - - - 1 - 18 - 2832 - - - 23 - 35 - 3304 - - - 37 - 43 - 2832 - - - 44 - 61 - 2832 - - - 65 - 73 - 2832 - - - 73 - 83 - 2832 - - - 83 - 96 - 2832 - - - 96 - 100 - 2832 - - - 101 - 103 - 2832 - - - 104 - 108 - 2832 - - - 108 - 115 - 2832 - - - 116 - 150 - 3304 - - - 152 - 298 - 2360 - - - - - - - startColumn - startLine - - - 12 - - - 1 - 19 - 2832 - - - 30 - 72 - 2832 - - - 83 - 122 - 2832 - - - 123 - 204 - 2832 - - - 213 - 262 - 2832 - - - 264 - 324 - 2832 - - - 324 - 380 - 2832 - - - 404 - 439 - 2832 - - - 455 - 475 - 2832 - - - 477 - 510 - 2832 - - - 517 - 579 - 2832 - - - 588 - 836 - 2832 - - - 1112 - 2199 - 2832 - - - 2401 - 2402 - 472 - - - - - - - startColumn - endLine - - - 12 - - - 1 - 19 - 2832 - - - 30 - 72 - 2832 - - - 83 - 122 - 2832 - - - 123 - 204 - 2832 - - - 213 - 262 - 2832 - - - 264 - 324 - 2832 - - - 324 - 380 - 2832 - - - 405 - 439 - 2832 - - - 455 - 475 - 2832 - - - 476 - 509 - 2832 - - - 520 - 578 - 2832 - - - 588 - 835 - 2832 - - - 1115 - 2200 - 2832 - - - 2409 - 2410 - 472 - - - - - - - startColumn - endColumn - - - 12 - - - 1 - 7 - 2832 - - - 7 - 10 - 1888 - - - 10 - 13 - 2832 - - - 13 - 19 - 2832 - - - 19 - 23 - 2832 - - - 23 25 - 3304 + 168879 25 - 31 - 2832 - - - 31 - 36 - 2832 - - - 38 - 41 - 2360 - - - 41 46 - 3304 + 163704 46 - 50 - 3304 + 169 + 159000 - 51 - 62 - 2832 - - - 63 - 81 - 2832 - - - 85 - 86 - 472 + 170 + 299 + 7056 - endLine - id - - - 12 - - - 1 - 2 - 600867 - - - 2 - 3 - 301141 - - - 3 - 4 - 198243 - - - 4 - 6 - 165203 - - - 6 - 10 - 189275 - - - 10 - 16 - 163315 - - - 16 - 24 - 161899 - - - 24 - 43 - 162371 - - - 43 - 145 - 160011 - - - 146 - 298 - 22656 - - - - - - - endLine + startLine container @@ -5579,42 +4954,702 @@ 1 2 - 883129 + 869799 2 3 - 275181 + 280838 3 5 - 194467 + 191459 5 8 - 177947 + 181110 8 12 - 159539 + 162293 12 18 - 171811 + 166527 18 39 - 160011 + 159941 39 - 298 - 102898 + 299 + 103021 + + + + + + + startLine + startColumn + + + 12 + + + 1 + 2 + 612482 + + + 2 + 3 + 313297 + + + 3 + 4 + 202749 + + + 4 + 6 + 184403 + + + 6 + 9 + 180639 + + + 9 + 13 + 166997 + + + 13 + 19 + 173583 + + + 19 + 29 + 167468 + + + 29 + 52 + 113370 + + + + + + + startLine + endLine + + + 12 + + + 1 + 2 + 1545788 + + + 2 + 3 + 351401 + + + 3 + 5 + 164645 + + + 5 + 16 + 53157 + + + + + + + startLine + endColumn + + + 12 + + + 1 + 2 + 586609 + + + 2 + 3 + 318942 + + + 3 + 4 + 201808 + + + 4 + 6 + 167468 + + + 6 + 9 + 160412 + + + 9 + 14 + 178287 + + + 14 + 21 + 176406 + + + 21 + 32 + 163234 + + + 32 + 61 + 159000 + + + 61 + 66 + 2822 + + + + + + + startColumn + id + + + 12 + + + 1 + 31 + 2822 + + + 42 + 85 + 2822 + + + 86 + 128 + 2822 + + + 129 + 229 + 2822 + + + 248 + 292 + 2822 + + + 292 + 360 + 2822 + + + 376 + 459 + 2822 + + + 476 + 558 + 2822 + + + 565 + 620 + 2822 + + + 626 + 699 + 2822 + + + 699 + 796 + 2822 + + + 819 + 1546 + 2822 + + + 1705 + 5645 + 2822 + + + 15306 + 15307 + 470 + + + + + + + startColumn + container + + + 12 + + + 1 + 18 + 2822 + + + 23 + 35 + 3292 + + + 38 + 43 + 2822 + + + 44 + 61 + 2822 + + + 65 + 73 + 2822 + + + 73 + 83 + 2822 + + + 83 + 95 + 2822 + + + 96 + 101 + 3292 + + + 101 + 105 + 3292 + + + 106 + 111 + 2822 + + + 111 + 123 + 2822 + + + 127 + 153 + 2822 + + + 169 + 299 + 1881 + + + + + + + startColumn + startLine + + + 12 + + + 1 + 19 + 2822 + + + 30 + 72 + 2822 + + + 83 + 122 + 2822 + + + 122 + 205 + 2822 + + + 214 + 261 + 2822 + + + 264 + 322 + 2822 + + + 325 + 380 + 2822 + + + 403 + 436 + 2822 + + + 454 + 474 + 2822 + + + 477 + 514 + 2822 + + + 517 + 586 + 2822 + + + 587 + 831 + 2822 + + + 1116 + 2197 + 2822 + + + 2387 + 2388 + 470 + + + + + + + startColumn + endLine + + + 12 + + + 1 + 19 + 2822 + + + 30 + 72 + 2822 + + + 83 + 122 + 2822 + + + 122 + 205 + 2822 + + + 214 + 261 + 2822 + + + 264 + 322 + 2822 + + + 325 + 380 + 2822 + + + 403 + 435 + 2822 + + + 454 + 474 + 2822 + + + 476 + 513 + 2822 + + + 520 + 585 + 2822 + + + 587 + 831 + 2822 + + + 1121 + 2205 + 2822 + + + 2383 + 2384 + 470 + + + + + + + startColumn + endColumn + + + 12 + + + 1 + 7 + 2822 + + + 7 + 11 + 3292 + + + 11 + 16 + 3292 + + + 16 + 22 + 2822 + + + 22 + 24 + 2352 + + + 24 + 27 + 3292 + + + 28 + 33 + 2822 + + + 33 + 40 + 3292 + + + 40 + 43 + 2822 + + + 43 + 49 + 2822 + + + 49 + 54 + 2822 + + + 54 + 74 + 2822 + + + 75 + 86 + 1881 + + + + + + + endLine + id + + + 12 + + + 1 + 2 + 589902 + + + 2 + 3 + 312356 + + + 3 + 4 + 198986 + + + 4 + 6 + 161352 + + + 6 + 10 + 189577 + + + 10 + 16 + 163704 + + + 16 + 25 + 171231 + + + 25 + 45 + 159471 + + + 45 + 160 + 159941 + + + 160 + 299 + 11289 + + + + + + + endLine + container + + + 12 + + + 1 + 2 + 881560 + + + 2 + 3 + 270019 + + + 3 + 4 + 123249 + + + 4 + 6 + 142065 + + + 6 + 10 + 195693 + + + 10 + 15 + 168409 + + + 15 + 26 + 165586 + + + 26 + 120 + 159471 + + + 121 + 299 + 11760 @@ -5630,22 +5665,22 @@ 1 2 - 1542998 + 1538732 2 3 - 354006 + 349048 3 5 - 170395 + 172172 5 10 - 57585 + 57861 @@ -5661,47 +5696,47 @@ 1 2 - 625412 + 621890 2 3 - 301613 + 304359 3 4 - 204852 + 204631 4 6 - 194467 + 186755 6 9 - 175115 + 177817 9 13 - 172755 + 169349 13 19 - 179363 + 174524 19 - 30 - 165203 + 29 + 162764 - 30 + 29 52 - 106202 + 115722 @@ -5717,52 +5752,52 @@ 1 2 - 605115 + 596488 2 3 - 305389 + 311415 3 4 - 200603 + 198986 4 6 - 168507 + 171701 6 9 - 164259 + 157589 9 14 - 174171 + 173583 14 - 20 - 161899 + 21 + 180169 - 20 - 30 - 159539 + 21 + 32 + 165116 - 30 - 54 - 159539 + 32 + 60 + 159000 - 54 - 66 - 25960 + 60 + 65 + 3763 @@ -5778,67 +5813,67 @@ 1 2 - 5192 + 5174 2 8 - 3776 + 3763 9 - 184 - 3776 + 186 + 3763 196 295 - 3776 + 3763 - 297 - 492 - 3776 + 298 + 498 + 3763 - 506 + 503 553 - 3776 + 3763 - 560 - 632 - 3776 + 563 + 634 + 3763 - 638 - 760 - 3776 + 639 + 762 + 3763 763 871 - 3776 + 3763 - 878 - 1082 - 3776 + 879 + 1081 + 3763 - 1085 + 1083 1286 - 3776 + 3763 - 1307 + 1309 1590 - 3776 + 3763 - 1674 - 2430 - 1888 + 1682 + 2419 + 1881 @@ -5854,67 +5889,67 @@ 1 2 - 5664 + 5644 2 6 - 3776 + 3763 6 65 - 3776 + 3763 - 69 - 99 - 3776 + 70 + 100 + 3763 - 99 - 112 - 4248 + 100 + 111 + 3763 - 113 + 112 122 - 3776 + 3763 - 124 - 140 - 3776 + 122 + 134 + 3763 - 143 - 153 - 3776 + 139 + 152 + 3763 - 153 + 152 160 - 3776 + 4233 160 172 - 3776 + 3763 172 176 - 3776 + 3763 176 208 - 3776 + 3763 240 - 298 - 944 + 299 + 940 @@ -5930,67 +5965,67 @@ 1 2 - 5664 + 5644 2 8 - 3776 + 3763 9 106 - 3776 + 3763 - 152 - 242 - 3776 + 155 + 241 + 3763 253 - 333 - 3776 + 335 + 3763 - 339 - 430 - 3776 + 340 + 426 + 3763 - 434 - 490 - 3776 + 437 + 488 + 3763 - 493 - 572 - 3776 + 488 + 574 + 3763 - 572 - 623 - 3776 + 575 + 628 + 3763 - 629 - 696 - 3776 + 630 + 698 + 4233 - 703 - 814 - 3776 + 701 + 817 + 3763 - 822 - 994 - 3776 + 843 + 1107 + 3763 - 1107 - 1175 - 1416 + 1160 + 1174 + 940 @@ -6006,67 +6041,67 @@ 1 2 - 6136 + 6115 2 4 - 3776 + 3763 4 8 - 3776 + 4233 8 - 14 - 3776 + 15 + 3763 - 14 - 22 - 3776 + 15 + 23 + 3763 - 22 + 23 29 - 4248 + 3763 29 35 - 4248 + 4233 35 39 - 3304 + 3292 39 42 - 3304 + 3763 42 44 - 3304 + 2822 44 46 - 3776 + 3763 46 - 50 - 4248 + 49 + 3763 - 51 + 49 53 - 944 + 1411 @@ -6082,67 +6117,67 @@ 1 2 - 5664 + 5644 2 8 - 3776 + 3763 9 - 153 - 3776 + 156 + 3763 - 157 - 243 - 3776 + 159 + 240 + 3763 - 250 - 333 - 3776 + 251 + 334 + 3763 - 341 - 432 - 3776 + 342 + 430 + 3763 - 432 - 488 - 3776 + 435 + 490 + 4233 - 495 - 571 - 3776 + 504 + 576 + 3763 - 573 - 621 - 3776 + 576 + 631 + 3763 - 628 - 700 - 3776 + 635 + 702 + 3763 - 703 - 815 - 3776 + 702 + 813 + 3763 - 819 - 994 - 3776 + 838 + 1109 + 3763 - 1108 - 1177 - 1416 + 1161 + 1181 + 940 @@ -6152,11 +6187,11 @@ locations_stmt - 3805195 + 3805462 id - 3805195 + 3805462 container @@ -6164,7 +6199,7 @@ startLine - 199402 + 199416 startColumn @@ -6172,7 +6207,7 @@ endLine - 193680 + 193694 endColumn @@ -6190,7 +6225,7 @@ 1 2 - 3805195 + 3805462 @@ -6206,7 +6241,7 @@ 1 2 - 3805195 + 3805462 @@ -6222,7 +6257,7 @@ 1 2 - 3805195 + 3805462 @@ -6238,7 +6273,7 @@ 1 2 - 3805195 + 3805462 @@ -6254,7 +6289,7 @@ 1 2 - 3805195 + 3805462 @@ -6655,67 +6690,67 @@ 1 2 - 21492 + 21494 2 3 - 15258 + 15259 3 4 - 12448 + 12449 4 6 - 14417 + 14418 6 8 - 12489 + 12490 8 11 - 16673 + 16674 11 16 - 17226 + 17228 16 22 - 15319 + 15320 22 29 - 16939 + 16941 29 37 - 17329 + 17330 37 45 - 15053 + 15054 45 56 - 16140 + 16141 56 73 - 8613 + 8614 @@ -6731,62 +6766,62 @@ 1 2 - 22251 + 22253 2 3 - 15688 + 15689 3 4 - 12653 + 12654 4 6 - 14355 + 14356 6 8 - 12694 + 12695 8 11 - 17534 + 17535 11 16 - 16324 + 16325 16 22 - 16181 + 16182 22 29 - 16919 + 16920 29 36 - 15955 + 15956 36 44 - 16283 + 16284 44 54 - 15606 + 15607 54 @@ -6807,52 +6842,52 @@ 1 2 - 26763 + 26765 2 3 - 20795 + 20796 3 4 - 16775 + 16776 4 5 - 16037 + 16038 5 6 - 17391 + 17392 6 7 - 19811 + 19812 7 8 - 22702 + 22704 8 9 - 20344 + 20345 9 10 - 14971 + 14972 10 12 - 16611 + 16612 12 @@ -6873,47 +6908,47 @@ 1 2 - 34515 + 34517 2 3 - 25737 + 25739 3 4 - 18395 + 18397 4 5 - 16181 + 16182 5 6 - 12756 + 12757 6 7 - 11997 + 11998 7 8 - 10151 + 10152 8 9 - 10951 + 10952 9 10 - 10705 + 10706 10 @@ -6923,17 +6958,17 @@ 11 12 - 10151 + 10152 12 14 - 15750 + 15751 14 24 - 11607 + 11608 @@ -6949,62 +6984,62 @@ 1 2 - 22087 + 22089 2 3 - 16160 + 16161 3 4 - 12920 + 12921 4 6 - 16037 + 16038 6 8 - 14663 + 14664 8 10 - 13166 + 13167 10 14 - 18252 + 18253 14 18 - 16980 + 16982 18 22 - 17534 + 17535 22 26 - 18457 + 18458 26 30 - 16345 + 16346 30 36 - 15196 + 15197 36 @@ -7395,12 +7430,12 @@ 1 2 - 17370 + 17371 2 3 - 14376 + 14377 3 @@ -7410,7 +7445,7 @@ 4 6 - 15565 + 15566 6 @@ -7420,42 +7455,42 @@ 8 11 - 15422 + 15423 11 15 - 14601 + 14602 15 21 - 16058 + 16059 21 27 - 15381 + 15382 27 34 - 14909 + 14910 34 42 - 15709 + 15710 42 52 - 15975 + 15977 52 130 - 14376 + 14377 @@ -7471,62 +7506,62 @@ 1 2 - 24897 + 24898 2 3 - 16099 + 16100 3 4 - 12735 + 12736 4 6 - 15627 + 15628 6 8 - 14971 + 14972 8 11 - 15852 + 15854 11 16 - 17411 + 17412 16 20 - 14560 + 14561 20 26 - 17124 + 17125 26 32 - 16222 + 16223 32 39 - 14827 + 14828 39 59 - 13350 + 13351 @@ -7542,62 +7577,62 @@ 1 2 - 32403 + 32405 2 3 - 23707 + 23709 3 4 - 18416 + 18417 4 5 - 15114 + 15115 5 6 - 13843 + 13844 6 7 - 11648 + 11649 7 8 - 11710 + 11711 8 9 - 10889 + 10890 9 10 - 10151 + 10152 10 12 - 17924 + 17925 12 15 - 17678 + 17679 15 100 - 10192 + 10193 @@ -7613,52 +7648,52 @@ 1 2 - 24897 + 24898 2 3 - 20344 + 20345 3 4 - 16796 + 16797 4 5 - 17760 + 17761 5 6 - 18539 + 18540 6 7 - 20385 + 20386 7 8 - 22374 + 22376 8 9 - 18703 + 18704 9 10 - 12899 + 12900 10 12 - 14991 + 14992 12 @@ -7679,12 +7714,12 @@ 1 2 - 24650 + 24652 2 3 - 16591 + 16592 3 @@ -7694,52 +7729,52 @@ 4 6 - 17780 + 17781 6 8 - 15299 + 15300 8 10 - 12797 + 12798 10 13 - 14376 + 14377 13 16 - 14991 + 14992 16 19 - 14622 + 14623 19 22 - 14007 + 14008 22 26 - 17083 + 17084 26 31 - 15299 + 15300 31 39 - 3670 + 3671 @@ -8134,27 +8169,27 @@ locations_expr - 13127189 + 13128112 id - 13127189 + 13128112 container - 4347 + 4348 startLine - 191486 + 191499 startColumn - 2460 + 2461 endLine - 191465 + 191479 endColumn @@ -8172,7 +8207,7 @@ 1 2 - 13127189 + 13128112 @@ -8188,7 +8223,7 @@ 1 2 - 13127189 + 13128112 @@ -8204,7 +8239,7 @@ 1 2 - 13127189 + 13128112 @@ -8220,7 +8255,7 @@ 1 2 - 13127189 + 13128112 @@ -8236,7 +8271,7 @@ 1 2 - 13127189 + 13128112 @@ -8642,67 +8677,67 @@ 1 5 - 16078 + 16079 5 9 - 16447 + 16448 9 15 - 15996 + 15997 15 23 - 15073 + 15074 23 32 - 15114 + 15115 32 44 - 14971 + 14972 44 60 - 14724 + 14726 60 80 - 14807 + 14808 80 103 - 14581 + 14582 103 130 - 14786 + 14787 130 159 - 14560 + 14561 159 194 - 14560 + 14561 194 302 - 9782 + 9783 @@ -8718,22 +8753,22 @@ 1 2 - 23461 + 23463 2 3 - 15586 + 15587 3 4 - 11320 + 11321 4 6 - 16324 + 16325 6 @@ -8743,32 +8778,32 @@ 8 11 - 16406 + 16407 11 16 - 17329 + 17330 16 21 - 16406 + 16407 21 28 - 16611 + 16612 28 35 - 15955 + 15956 35 43 - 15934 + 15936 43 @@ -8789,62 +8824,62 @@ 1 4 - 15934 + 15936 4 7 - 17493 + 17494 7 11 - 16652 + 16653 11 16 - 17370 + 17371 16 21 - 17473 + 17474 21 26 - 15032 + 15033 26 31 - 16140 + 16141 31 36 - 17698 + 17699 36 40 - 15791 + 15792 40 44 - 16529 + 16530 44 49 - 16591 + 16592 49 63 - 8777 + 8778 @@ -8860,22 +8895,22 @@ 1 2 - 101762 + 101769 2 3 - 44564 + 44567 3 4 - 27501 + 27503 4 6 - 14540 + 14541 6 @@ -8896,62 +8931,62 @@ 1 4 - 16919 + 16920 4 7 - 16611 + 16612 7 11 - 16386 + 16387 11 16 - 16181 + 16182 16 21 - 16406 + 16407 21 27 - 16734 + 16735 27 33 - 16406 + 16407 33 38 - 14458 + 14459 38 43 - 15504 + 15505 43 47 - 14745 + 14746 47 52 - 16714 + 16715 52 65 - 14376 + 14377 66 @@ -9352,67 +9387,67 @@ 1 5 - 16099 + 16100 5 9 - 16447 + 16448 9 15 - 15770 + 15772 15 23 - 15053 + 15054 23 32 - 15606 + 15607 32 44 - 14704 + 14705 44 60 - 14458 + 14459 60 80 - 15237 + 15238 80 103 - 14478 + 14479 103 130 - 14786 + 14787 130 159 - 14458 + 14459 159 193 - 14376 + 14377 193 299 - 9987 + 9988 @@ -9428,67 +9463,67 @@ 1 2 - 23461 + 23463 2 3 - 15524 + 15525 3 4 - 11320 + 11321 4 6 - 16016 + 16018 6 8 - 13453 + 13454 8 11 - 16468 + 16469 11 15 - 14458 + 14459 15 20 - 16673 + 16674 20 26 - 14971 + 14972 26 33 - 16119 + 16120 33 40 - 14724 + 14726 40 49 - 14724 + 14726 49 60 - 3547 + 3548 @@ -9504,22 +9539,22 @@ 1 2 - 95343 + 95349 2 3 - 49835 + 49838 3 4 - 29306 + 29308 4 6 - 15565 + 15566 6 @@ -9540,62 +9575,62 @@ 1 4 - 15791 + 15792 4 7 - 17411 + 17412 7 11 - 16447 + 16448 11 16 - 17309 + 17310 16 21 - 17268 + 17269 21 26 - 15114 + 15115 26 31 - 16263 + 16264 31 36 - 17678 + 17679 36 40 - 15340 + 15341 40 44 - 16591 + 16592 44 49 - 16734 + 16735 49 63 - 9515 + 9516 @@ -9611,62 +9646,62 @@ 1 4 - 17144 + 17146 4 7 - 16755 + 16756 7 11 - 16386 + 16387 11 16 - 16837 + 16838 16 21 - 15975 + 15977 21 26 - 14478 + 14479 26 32 - 16119 + 16120 32 37 - 14376 + 14377 37 42 - 15832 + 15833 42 46 - 14232 + 14233 46 51 - 17247 + 17248 51 59 - 14458 + 14459 59 @@ -9726,7 +9761,7 @@ 4177 - 7133 + 7135 225 @@ -9803,22 +9838,22 @@ 135 139 - 225 + 246 139 146 - 225 + 205 146 148 - 225 + 205 148 152 - 225 + 246 152 @@ -10056,23 +10091,23 @@ numlines - 1411307 + 1406545 element_id - 1404227 + 1399488 num_lines - 103842 + 102550 num_code - 85433 + 85615 num_comment - 59945 + 60213 @@ -10086,12 +10121,12 @@ 1 2 - 1397147 + 1392432 2 3 - 7080 + 7056 @@ -10107,12 +10142,12 @@ 1 2 - 1398091 + 1393373 2 3 - 6136 + 6115 @@ -10128,7 +10163,7 @@ 1 2 - 1404227 + 1399488 @@ -10144,27 +10179,27 @@ 1 2 - 69385 + 68680 2 3 - 14160 + 12230 3 - 5 - 8496 + 4 + 7526 - 5 - 63 - 8024 + 4 + 21 + 7997 - 79 + 29 926 - 3776 + 6115 @@ -10180,27 +10215,27 @@ 1 2 - 71745 + 71032 2 3 - 14160 + 12230 3 4 - 7552 + 8467 4 6 - 8968 + 9408 6 7 - 1416 + 1411 @@ -10216,22 +10251,22 @@ 1 2 - 70801 + 70092 2 3 - 16992 + 15053 3 4 - 9912 + 10819 4 7 - 6136 + 6585 @@ -10247,27 +10282,27 @@ 1 2 - 52393 + 53157 2 3 - 15104 + 14582 3 5 - 6608 + 6585 5 42 - 6608 + 6585 - 45 + 44 927 - 4720 + 4704 @@ -10283,27 +10318,27 @@ 1 2 - 52393 + 53157 2 3 - 17464 + 16934 3 5 - 6136 + 6115 5 8 - 7080 + 6585 8 12 - 2360 + 2822 @@ -10319,27 +10354,27 @@ 1 2 - 52865 + 53627 2 3 - 16520 + 15994 3 5 - 7552 + 7526 5 7 - 5192 + 5174 7 10 - 3304 + 3292 @@ -10355,32 +10390,32 @@ 1 2 - 34928 + 34810 2 3 - 8496 + 9408 3 4 - 4720 + 4233 4 6 - 4720 + 4704 6 11 - 5192 + 5174 17 2622 - 1888 + 1881 @@ -10396,32 +10431,32 @@ 1 2 - 34928 + 34810 2 3 - 8496 + 9408 3 4 - 4720 + 4233 4 6 - 4720 + 4704 6 8 - 4720 + 4704 10 - 37 - 2360 + 38 + 2352 @@ -10437,32 +10472,32 @@ 1 2 - 34928 + 34810 2 3 - 8496 + 9408 3 4 - 4720 + 4233 4 6 - 4720 + 4704 6 10 - 4720 + 4704 10 37 - 2360 + 2352 @@ -10472,31 +10507,31 @@ diagnostics - 667106 + 632933 id - 667106 + 632933 severity - 210 + 209 error_tag - 7142 + 7441 error_message - 50629 + 50202 full_error_message - 666371 + 632199 location - 366903 + 354878 @@ -10510,7 +10545,7 @@ 1 2 - 667106 + 632933 @@ -10526,7 +10561,7 @@ 1 2 - 667106 + 632933 @@ -10542,7 +10577,7 @@ 1 2 - 667106 + 632933 @@ -10558,7 +10593,7 @@ 1 2 - 667106 + 632933 @@ -10574,7 +10609,7 @@ 1 2 - 667106 + 632933 @@ -10588,14 +10623,14 @@ 12 - 375 - 376 - 105 + 354 + 355 + 104 - 5976 - 5977 - 105 + 5685 + 5686 + 104 @@ -10611,12 +10646,12 @@ 4 5 - 105 + 104 - 64 - 65 - 105 + 67 + 68 + 104 @@ -10632,12 +10667,12 @@ 6 7 - 105 + 104 - 476 - 477 - 105 + 473 + 474 + 104 @@ -10651,14 +10686,14 @@ 12 - 375 - 376 - 105 + 354 + 355 + 104 - 5969 - 5970 - 105 + 5678 + 5679 + 104 @@ -10672,14 +10707,14 @@ 12 - 211 - 212 - 105 + 198 + 199 + 104 - 3378 - 3379 - 105 + 3278 + 3279 + 104 @@ -10695,256 +10730,246 @@ 1 2 - 735 + 1048 2 3 - 735 + 1048 3 - 4 - 525 - - - 4 - 6 - 630 - - - 6 - 8 - 630 - - - 8 - 14 - 630 - - - 14 - 17 - 525 - - - 18 - 30 - 630 - - - 33 - 51 - 630 - - - 52 - 149 - 630 - - - 200 - 808 - 630 - - - 845 - 1335 - 210 - - - - - - - error_tag - severity - - - 12 - - - 1 - 2 - 7142 - - - - - - - error_tag - error_message - - - 12 - - - 1 - 2 - 4726 - - - 2 - 3 - 630 - - - 3 - 4 - 420 - - - 4 - 6 - 630 - - - 6 - 53 - 630 - - - 249 - 250 - 105 - - - - - - - error_tag - full_error_message - - - 12 - - - 1 - 2 - 840 - - - 2 - 3 - 735 - - - 3 - 4 - 525 - - - 4 - 6 - 630 - - - 6 - 8 - 630 - - - 8 - 14 - 525 - - - 14 - 17 - 525 - - - 18 - 30 - 630 - - - 33 - 51 - 630 - - - 52 - 149 - 630 - - - 200 - 808 - 630 - - - 845 - 1335 - 210 - - - - - - - error_tag - location - - - 12 - - - 1 - 2 - 1155 - - - 2 - 3 - 840 - - - 3 - 4 - 735 - - - 4 5 - 420 + 628 5 - 6 - 420 + 7 + 628 - 6 - 8 - 525 + 7 + 11 + 628 - 8 - 13 - 630 + 12 + 16 + 524 - 14 + 16 25 - 630 + 628 25 + 38 + 628 + + + 41 + 72 + 628 + + + 95 + 610 + 628 + + + 624 + 1277 + 419 + + + + + + + error_tag + severity + + + 12 + + + 1 + 2 + 7441 + + + + + + + error_tag + error_message + + + 12 + + + 1 + 2 + 5240 + + + 2 + 3 + 419 + + + 3 + 4 + 419 + + + 4 + 6 + 628 + + + 6 51 - 630 + 628 - 57 - 219 - 630 + 251 + 252 + 104 + + + + + + + error_tag + full_error_message + + + 12 + + + 1 + 2 + 1152 - 382 - 733 - 525 + 2 + 3 + 1048 + + + 3 + 5 + 628 + + + 5 + 7 + 628 + + + 7 + 13 + 628 + + + 13 + 16 + 419 + + + 16 + 25 + 628 + + + 25 + 38 + 628 + + + 41 + 72 + 628 + + + 95 + 610 + 628 + + + 624 + 1277 + 419 + + + + + + + error_tag + location + + + 12 + + + 1 + 2 + 1781 + + + 2 + 3 + 733 + + + 3 + 4 + 524 + + + 4 + 6 + 628 + + + 6 + 7 + 524 + + + 7 + 12 + 628 + + + 12 + 17 + 628 + + + 24 + 44 + 628 + + + 44 + 110 + 628 + + + 167 + 542 + 628 + + + 704 + 705 + 104 @@ -10960,42 +10985,42 @@ 1 2 - 20377 + 20437 2 3 - 10503 + 10899 3 4 - 2415 + 2829 4 5 - 4411 + 2515 5 - 7 - 3991 + 6 + 2829 - 7 - 14 - 4096 + 6 + 9 + 3773 - 14 - 67 - 3886 + 9 + 21 + 3773 - 75 - 1335 - 945 + 21 + 1277 + 3144 @@ -11011,7 +11036,7 @@ 1 2 - 50629 + 50202 @@ -11027,7 +11052,7 @@ 1 2 - 50629 + 50202 @@ -11043,42 +11068,42 @@ 1 2 - 20482 + 20542 2 3 - 10503 + 10899 3 4 - 2415 + 2829 4 5 - 4411 + 2515 5 - 7 - 3991 + 6 + 2829 - 7 - 14 - 3991 + 6 + 10 + 4087 - 14 - 67 - 3886 + 10 + 24 + 3877 - 75 - 1335 - 945 + 25 + 1277 + 2620 @@ -11094,32 +11119,32 @@ 1 2 - 32352 + 32280 2 3 - 5987 + 5345 3 5 - 3886 + 3563 5 - 9 - 3886 + 8 + 3877 - 9 - 86 - 3886 + 8 + 34 + 3773 - 130 - 733 - 630 + 34 + 705 + 1362 @@ -11135,12 +11160,12 @@ 1 2 - 666266 + 632094 8 9 - 105 + 104 @@ -11156,7 +11181,7 @@ 1 2 - 666371 + 632199 @@ -11172,7 +11197,7 @@ 1 2 - 666371 + 632199 @@ -11188,7 +11213,7 @@ 1 2 - 666371 + 632199 @@ -11204,7 +11229,7 @@ 1 2 - 666371 + 632199 @@ -11220,22 +11245,22 @@ 1 2 - 184554 + 180059 2 3 - 134345 + 135621 3 - 5 - 31721 + 6 + 31023 - 5 + 6 17 - 16281 + 8174 @@ -11251,12 +11276,12 @@ 1 2 - 356819 + 345445 2 3 - 10083 + 9432 @@ -11272,12 +11297,12 @@ 1 2 - 349361 + 338947 2 - 5 - 17541 + 6 + 15930 @@ -11293,12 +11318,12 @@ 1 2 - 348836 + 338423 2 - 5 - 18066 + 6 + 16454 @@ -11314,22 +11339,22 @@ 1 2 - 184659 + 180164 2 3 - 134345 + 135621 3 - 5 - 31721 + 6 + 31023 - 5 + 6 17 - 16176 + 8070 @@ -11339,15 +11364,15 @@ files - 124610 + 124189 id - 124610 + 124189 name - 124610 + 124189 @@ -11361,7 +11386,7 @@ 1 2 - 124610 + 124189 @@ -11377,7 +11402,7 @@ 1 2 - 124610 + 124189 @@ -11387,15 +11412,15 @@ folders - 15576 + 15994 id - 15576 + 15994 name - 15576 + 15994 @@ -11409,7 +11434,7 @@ 1 2 - 15576 + 15994 @@ -11425,7 +11450,7 @@ 1 2 - 15576 + 15994 @@ -11435,15 +11460,15 @@ containerparent - 139242 + 139243 parent - 15576 + 15994 child - 139242 + 139243 @@ -11457,32 +11482,32 @@ 1 2 - 6608 + 7056 2 3 - 3304 + 3292 3 5 - 1416 + 1411 5 12 - 1416 + 1411 23 28 - 1416 + 1411 40 67 - 1416 + 1411 @@ -11498,7 +11523,7 @@ 1 2 - 139242 + 139243 @@ -11508,11 +11533,11 @@ fileannotations - 5264964 + 5254893 id - 5028 + 5019 kind @@ -11520,11 +11545,11 @@ name - 56220 + 56112 value - 47263 + 47173 @@ -11543,7 +11568,7 @@ 2 3 - 4854 + 4845 @@ -11564,52 +11589,52 @@ 102 225 - 382 + 381 227 299 - 382 + 381 301 452 - 405 + 404 452 555 - 382 + 381 559 626 - 382 + 381 626 716 - 382 + 381 729 904 - 382 + 381 904 934 - 81 + 80 936 937 - 1459 + 1457 1083 2036 - 382 + 381 2293 @@ -11635,32 +11660,32 @@ 114 275 - 382 + 381 275 363 - 382 + 381 393 638 - 382 + 381 643 744 - 382 + 381 751 955 - 382 + 381 955 1087 - 382 + 381 1088 @@ -11670,17 +11695,17 @@ 1501 1502 - 1459 + 1457 1504 1874 - 382 + 381 1972 4080 - 243 + 242 @@ -11759,62 +11784,62 @@ 1 2 - 9095 + 9078 2 3 - 6384 + 6372 3 5 - 4287 + 4279 5 9 - 4379 + 4371 9 14 - 4090 + 4082 14 18 - 4287 + 4279 18 20 - 4843 + 4834 20 34 - 4333 + 4325 34 128 - 4623 + 4614 128 229 - 4229 + 4221 229 387 - 4356 + 4348 387 434 - 1309 + 1306 @@ -11830,7 +11855,7 @@ 1 2 - 56220 + 56112 @@ -11846,62 +11871,62 @@ 1 2 - 9107 + 9089 2 3 - 8273 + 8257 3 4 - 2630 + 2625 4 6 - 4634 + 4625 6 9 - 4240 + 4232 9 14 - 4321 + 4313 14 17 - 4240 + 4232 17 22 - 4715 + 4706 22 41 - 4321 + 4313 41 82 - 4275 + 4267 82 157 - 4217 + 4209 158 1895 - 1239 + 1237 @@ -11917,67 +11942,67 @@ 1 2 - 7346 + 7332 2 5 - 2294 + 2289 5 8 - 3418 + 3411 8 15 - 3626 + 3619 15 17 - 2607 + 2602 17 19 - 4252 + 4244 19 34 - 3418 + 3411 34 189 - 3719 + 3712 189 201 - 3707 + 3700 201 266 - 3649 + 3642 266 321 - 3777 + 3770 322 399 - 4055 + 4047 399 435 - 1390 + 1387 @@ -11993,7 +12018,7 @@ 1 2 - 47251 + 47161 2 @@ -12014,67 +12039,67 @@ 1 2 - 7369 + 7355 2 5 - 2653 + 2648 5 8 - 3603 + 3596 8 15 - 3649 + 3642 15 17 - 2908 + 2902 17 19 - 3684 + 3677 19 29 - 3603 + 3596 29 39 - 3765 + 3758 39 48 - 3707 + 3700 48 74 - 3661 + 3654 74 102 - 3545 + 3538 102 119 - 3696 + 3689 119 146 - 1413 + 1410 @@ -12084,15 +12109,15 @@ inmacroexpansion - 109305879 + 109313317 id - 17940692 + 17941916 inv - 2681885 + 2682068 @@ -12106,37 +12131,37 @@ 1 3 - 1565908 + 1566018 3 5 - 1071272 + 1071344 5 6 - 1179734 + 1179814 6 7 - 4799673 + 4800000 7 8 - 6358947 + 6359380 8 9 - 2595071 + 2595248 9 150 - 370084 + 370109 @@ -12152,32 +12177,32 @@ 1 2 - 371830 + 371855 2 3 - 540079 + 540113 3 4 - 349893 + 349917 4 7 - 199801 + 199815 7 8 - 206276 + 206290 8 9 - 240865 + 240882 9 @@ -12187,22 +12212,22 @@ 10 11 - 324110 + 324132 11 337 - 223895 + 223913 339 422 - 201369 + 201383 422 7616 - 21561 + 21563 @@ -12212,15 +12237,15 @@ affectedbymacroexpansion - 35538114 + 35540532 id - 5134928 + 5135277 inv - 2772993 + 2773181 @@ -12234,37 +12259,37 @@ 1 2 - 2804021 + 2804212 2 3 - 557759 + 557797 3 4 - 263786 + 263804 4 5 - 563401 + 563439 5 12 - 390245 + 390272 12 50 - 405678 + 405705 50 9900 - 150035 + 150045 @@ -12280,67 +12305,67 @@ 1 4 - 228146 + 228162 4 7 - 230808 + 230823 7 9 - 219545 + 219560 9 12 - 250025 + 250042 12 13 - 332565 + 332588 13 14 - 164888 + 164899 14 15 - 297580 + 297600 15 16 - 121327 + 121336 16 17 - 275438 + 275457 17 18 - 146319 + 146328 18 20 - 251068 + 251085 20 25 - 208095 + 208109 25 109 - 47183 + 47186 @@ -12350,19 +12375,19 @@ macroinvocations - 34062185 + 33895024 id - 34062185 + 33895024 macro_id - 81572 + 81382 location - 779877 + 778558 kind @@ -12380,7 +12405,7 @@ 1 2 - 34062185 + 33895024 @@ -12396,7 +12421,7 @@ 1 2 - 34062185 + 33895024 @@ -12412,7 +12437,7 @@ 1 2 - 34062185 + 33895024 @@ -12428,52 +12453,57 @@ 1 2 - 16835 + 17578 2 3 - 17322 + 16977 3 4 - 3846 + 3700 4 - 6 - 7323 + 5 + 4880 - 6 - 11 - 7265 + 5 + 8 + 6048 - 11 - 21 - 6546 + 8 + 14 + 6406 - 21 - 47 - 6257 + 14 + 29 + 6291 - 47 - 143 - 6117 + 29 + 72 + 6106 - 143 - 934 - 6152 + 72 + 247 + 6129 - 934 - 168391 - 3904 + 248 + 4166 + 6106 + + + 4220 + 168296 + 1156 @@ -12489,37 +12519,37 @@ 1 2 - 43648 + 43507 2 3 - 10648 + 10651 3 4 - 5295 + 5285 4 6 - 7010 + 6985 6 13 - 6627 + 6626 13 66 - 6152 + 6140 66 3614 - 2189 + 2185 @@ -12535,12 +12565,12 @@ 1 2 - 75732 + 75553 2 3 - 5839 + 5828 @@ -12556,42 +12586,37 @@ 1 2 - 297219 + 320983 2 3 - 195287 + 177752 3 4 - 48978 + 47300 4 5 - 57610 + 59605 5 - 8 - 59059 + 9 + 68533 - 8 - 17 - 59267 + 9 + 23 + 58425 - 17 - 934 - 58572 - - - 942 - 244474 - 3881 + 23 + 244365 + 45958 @@ -12607,12 +12632,12 @@ 1 2 - 732509 + 731281 2 350 - 47367 + 47277 @@ -12628,7 +12653,7 @@ 1 2 - 779877 + 778558 @@ -12642,13 +12667,13 @@ 12 - 21085 - 21086 + 20414 + 20415 11 - 2918595 - 2918596 + 2910446 + 2910447 11 @@ -12668,8 +12693,8 @@ 11 - 5421 - 5422 + 5418 + 5419 11 @@ -12684,13 +12709,13 @@ 12 - 6289 - 6290 + 6291 + 6292 11 - 61017 - 61018 + 61030 + 61031 11 @@ -12701,15 +12726,15 @@ macroparent - 30544569 + 30455631 id - 30544569 + 30455631 parent_id - 23768631 + 23698229 @@ -12723,7 +12748,7 @@ 1 2 - 30544569 + 30455631 @@ -12739,17 +12764,17 @@ 1 2 - 18363231 + 18307194 2 3 - 4552338 + 4540068 3 88 - 853060 + 850966 @@ -12759,15 +12784,15 @@ macrolocationbind - 3984360 + 3984640 id - 2778691 + 2778886 location - 1988314 + 1988454 @@ -12781,22 +12806,22 @@ 1 2 - 2182951 + 2183104 2 3 - 336419 + 336443 3 7 - 229799 + 229815 7 57 - 29521 + 29523 @@ -12812,22 +12837,22 @@ 1 2 - 1589477 + 1589588 2 3 - 169635 + 169647 3 8 - 154222 + 154233 8 723 - 74979 + 74984 @@ -12837,19 +12862,19 @@ macro_argument_unexpanded - 86422356 + 86176891 invocation - 26658798 + 26568376 argument_index - 764 + 763 text - 326615 + 326094 @@ -12863,22 +12888,22 @@ 1 2 - 7473686 + 7436803 2 3 - 10892801 + 10861705 3 4 - 6274590 + 6256816 4 67 - 2017720 + 2013051 @@ -12894,22 +12919,22 @@ 1 2 - 7545213 + 7508019 2 3 - 11043502 + 11011575 3 4 - 6104017 + 6087240 4 67 - 1966065 + 1961541 @@ -12923,18 +12948,18 @@ 12 - 41253 - 41254 - 672 + 41230 + 41231 + 670 - 41455 - 174137 + 41432 + 174067 57 - 715654 - 2300744 + 715085 + 2297335 34 @@ -12951,7 +12976,7 @@ 2 3 - 672 + 670 13 @@ -12960,7 +12985,7 @@ 6559 - 19569 + 19579 34 @@ -12977,57 +13002,57 @@ 1 2 - 39998 + 40858 2 3 - 66161 + 65607 3 4 - 14947 + 15184 4 5 - 44065 + 45103 5 - 7 - 24761 + 8 + 25569 - 7 + 8 12 - 18643 + 16075 12 16 - 22281 + 22297 16 23 - 26673 + 26518 23 43 - 24784 + 24748 43 164 - 24506 + 24459 164 - 521728 - 19790 + 521384 + 19671 @@ -13043,17 +13068,17 @@ 1 2 - 236190 + 235830 2 3 - 79869 + 79728 3 9 - 10555 + 10535 @@ -13063,19 +13088,19 @@ macro_argument_expanded - 86422356 + 86176891 invocation - 26658798 + 26568376 argument_index - 764 + 763 text - 197906 + 197597 @@ -13089,22 +13114,22 @@ 1 2 - 7473686 + 7436803 2 3 - 10892801 + 10861705 3 4 - 6274590 + 6256816 4 67 - 2017720 + 2013051 @@ -13120,22 +13145,22 @@ 1 2 - 10794971 + 10747757 2 3 - 9400379 + 9374150 3 4 - 5321625 + 5307004 4 9 - 1141821 + 1139463 @@ -13149,18 +13174,18 @@ 12 - 41253 - 41254 - 672 + 41230 + 41231 + 670 - 41455 - 174137 + 41432 + 174067 57 - 715654 - 2300744 + 715085 + 2297335 34 @@ -13177,7 +13202,7 @@ 1 2 - 660 + 659 2 @@ -13186,7 +13211,7 @@ 870 - 13871 + 13877 46 @@ -13203,62 +13228,62 @@ 1 2 - 24008 + 24552 2 3 - 41238 + 41147 3 4 - 6940 + 6927 4 5 - 15874 + 16364 5 6 - 3835 + 2995 6 7 - 23324 + 23291 7 9 - 15457 + 15982 9 15 - 17345 + 16699 15 - 30 - 14842 + 31 + 15589 - 30 - 89 - 14947 + 31 + 97 + 15080 - 90 - 505 - 14854 + 97 + 775 + 15485 - 510 - 1054483 - 5237 + 775 + 1052916 + 3481 @@ -13274,17 +13299,17 @@ 1 2 - 100112 + 99989 2 3 - 83009 + 82850 3 66 - 14785 + 14756 @@ -13294,19 +13319,19 @@ functions - 4759741 + 4726273 id - 4759741 + 4726273 name - 1941845 + 1934352 kind - 3304 + 3292 @@ -13320,7 +13345,7 @@ 1 2 - 4759741 + 4726273 @@ -13336,7 +13361,7 @@ 1 2 - 4759741 + 4726273 @@ -13352,22 +13377,22 @@ 1 2 - 1523173 + 1516622 2 3 - 153875 + 154296 3 5 - 151986 + 151003 5 - 1754 - 112810 + 1724 + 112429 @@ -13383,12 +13408,12 @@ 1 2 - 1941373 + 1933881 2 3 - 472 + 470 @@ -13404,37 +13429,37 @@ 6 7 - 472 + 470 64 65 - 472 + 470 173 174 - 472 + 470 195 196 - 472 + 470 - 1365 - 1366 - 472 + 1358 + 1359 + 470 - 2462 - 2463 - 472 + 2432 + 2433 + 470 5819 5820 - 472 + 470 @@ -13450,37 +13475,37 @@ 3 4 - 472 + 470 33 34 - 472 + 470 39 40 - 472 + 470 94 95 - 472 + 470 195 196 - 472 + 470 - 246 - 247 - 472 + 244 + 245 + 470 3505 3506 - 472 + 470 @@ -13490,15 +13515,15 @@ function_entry_point - 1180967 + 1176981 id - 1171054 + 1167103 entry_point - 1180967 + 1176981 @@ -13512,12 +13537,12 @@ 1 2 - 1161142 + 1157224 2 3 - 9912 + 9878 @@ -13533,7 +13558,7 @@ 1 2 - 1180967 + 1176981 @@ -13543,15 +13568,15 @@ function_return_type - 4768237 + 4734741 id - 4759741 + 4726273 return_type - 1027092 + 1016569 @@ -13565,12 +13590,12 @@ 1 2 - 4752660 + 4719217 2 5 - 7080 + 7056 @@ -13586,22 +13611,22 @@ 1 2 - 524874 + 523103 2 3 - 398847 + 390445 3 11 - 78825 + 78559 11 - 2523 - 24544 + 2516 + 24461 @@ -13923,48 +13948,48 @@ purefunctions - 99735 + 99448 id - 99735 + 99448 function_deleted - 141130 + 140654 id - 141130 + 140654 function_defaulted - 74577 + 74325 id - 74577 + 74325 member_function_this_type - 549916 + 553641 id - 549916 + 553641 this_type - 188354 + 189690 @@ -13978,7 +14003,7 @@ 1 2 - 549916 + 553641 @@ -13994,32 +14019,32 @@ 1 2 - 68044 + 68526 2 3 - 45024 + 45414 3 4 - 30331 + 30475 4 5 - 15428 + 15537 5 7 - 15497 + 15607 7 66 - 14028 + 14128 @@ -14029,27 +14054,27 @@ fun_decls - 5136876 + 5102136 id - 5131684 + 5096962 function - 4611530 + 4578563 type_id - 1023788 + 1013276 name - 1843196 + 1836035 location - 3473987 + 3461324 @@ -14063,7 +14088,7 @@ 1 2 - 5131684 + 5096962 @@ -14079,12 +14104,12 @@ 1 2 - 5126492 + 5091787 2 3 - 5192 + 5174 @@ -14100,7 +14125,7 @@ 1 2 - 5131684 + 5096962 @@ -14116,7 +14141,7 @@ 1 2 - 5131684 + 5096962 @@ -14132,17 +14157,17 @@ 1 2 - 4172561 + 4141075 2 3 - 364391 + 363161 3 7 - 74577 + 74325 @@ -14158,12 +14183,12 @@ 1 2 - 4569521 + 4536696 2 5 - 42008 + 41867 @@ -14179,7 +14204,7 @@ 1 2 - 4611530 + 4578563 @@ -14195,17 +14220,17 @@ 1 2 - 4229674 + 4197996 2 4 - 380439 + 379155 4 6 - 1416 + 1411 @@ -14221,22 +14246,22 @@ 1 2 - 447464 + 445954 2 3 - 462097 + 453481 3 9 - 79769 + 79500 9 - 2775 - 34456 + 2768 + 34340 @@ -14252,22 +14277,22 @@ 1 2 - 532426 + 530629 2 3 - 390351 + 381978 3 11 - 77409 + 77148 11 - 2484 - 23600 + 2477 + 23520 @@ -14283,17 +14308,17 @@ 1 2 - 893985 + 883912 2 5 - 90625 + 90319 5 - 824 - 39176 + 822 + 39044 @@ -14309,22 +14334,22 @@ 1 2 - 789199 + 779480 2 3 - 133578 + 133127 3 11 - 78353 + 78089 11 - 2032 - 22656 + 2030 + 22579 @@ -14340,27 +14365,27 @@ 1 2 - 1250824 + 1245192 2 3 - 269517 + 269548 3 4 - 80713 + 80441 4 6 - 139714 + 138772 6 - 1788 - 102426 + 1758 + 102080 @@ -14376,22 +14401,22 @@ 1 2 - 1432076 + 1425832 2 3 - 152930 + 153355 3 5 - 146322 + 145358 5 - 1738 - 111866 + 1708 + 111488 @@ -14407,17 +14432,17 @@ 1 2 - 1622295 + 1615880 2 4 - 135466 + 135009 4 - 969 - 85433 + 954 + 85145 @@ -14433,27 +14458,27 @@ 1 2 - 1272064 + 1266831 2 3 - 297365 + 296362 3 4 - 79769 + 79500 4 8 - 139714 + 139243 8 - 666 - 54281 + 664 + 54097 @@ -14469,17 +14494,17 @@ 1 2 - 3005754 + 2995611 2 4 - 304445 + 302007 4 55 - 163787 + 163704 @@ -14495,17 +14520,17 @@ 1 2 - 3073724 + 3063351 2 6 - 270933 + 268607 6 55 - 129330 + 129364 @@ -14521,12 +14546,12 @@ 1 2 - 3256863 + 3245873 2 27 - 217124 + 215450 @@ -14542,12 +14567,12 @@ 1 2 - 3296512 + 3285388 2 13 - 177475 + 175935 @@ -14557,22 +14582,22 @@ fun_def - 1970638 + 1963988 id - 1970638 + 1963988 fun_specialized - 26432 + 26343 id - 26432 + 26343 @@ -14590,15 +14615,15 @@ fun_decl_specifiers - 2947225 + 2937280 id - 1716697 + 1710904 name - 2832 + 2822 @@ -14612,17 +14637,17 @@ 1 2 - 505049 + 503345 2 3 - 1192767 + 1188742 3 4 - 18880 + 18816 @@ -14638,32 +14663,32 @@ 50 51 - 472 + 470 203 204 - 472 + 470 209 210 - 472 + 470 657 658 - 472 + 470 2561 2562 - 472 + 470 2564 2565 - 472 + 470 @@ -14794,26 +14819,26 @@ fun_decl_empty_throws - 2002263 + 1978101 fun_decl - 2002263 + 1978101 fun_decl_noexcept - 61343 + 61207 fun_decl - 61343 + 61207 constant - 61238 + 61102 @@ -14827,7 +14852,7 @@ 1 2 - 61343 + 61207 @@ -14843,12 +14868,12 @@ 1 2 - 61133 + 60998 2 3 - 105 + 104 @@ -14858,11 +14883,11 @@ fun_decl_empty_noexcept - 890209 + 888146 fun_decl - 890209 + 888146 @@ -14967,19 +14992,19 @@ param_decl_bind - 7511554 + 7472094 id - 7511554 + 7472094 index - 8024 + 7997 fun_decl - 4315108 + 4286434 @@ -14993,7 +15018,7 @@ 1 2 - 7511554 + 7472094 @@ -15009,7 +15034,7 @@ 1 2 - 7511554 + 7472094 @@ -15025,72 +15050,72 @@ 2 3 - 944 + 940 5 6 - 472 + 470 7 8 - 472 + 470 10 11 - 944 + 940 11 12 - 472 + 470 12 13 - 944 + 940 13 14 - 472 + 470 25 26 - 472 + 470 78 79 - 472 + 470 245 246 - 472 + 470 636 637 - 472 + 470 1713 1714 - 472 + 470 3991 3992 - 472 + 470 - 9142 - 9143 - 472 + 9112 + 9113 + 470 @@ -15106,72 +15131,72 @@ 2 3 - 944 + 940 5 6 - 472 + 470 7 8 - 472 + 470 10 11 - 944 + 940 11 12 - 472 + 470 12 13 - 944 + 940 13 14 - 472 + 470 25 26 - 472 + 470 78 79 - 472 + 470 245 246 - 472 + 470 636 637 - 472 + 470 1713 1714 - 472 + 470 3991 3992 - 472 + 470 - 9142 - 9143 - 472 + 9112 + 9113 + 470 @@ -15187,22 +15212,22 @@ 1 2 - 2431319 + 2409002 2 3 - 1075237 + 1071608 3 4 - 508353 + 506638 4 18 - 300197 + 299184 @@ -15218,22 +15243,22 @@ 1 2 - 2431319 + 2409002 2 3 - 1075237 + 1071608 3 4 - 508353 + 506638 4 18 - 300197 + 299184 @@ -15243,27 +15268,27 @@ var_decls - 8655233 + 8611913 id - 8586319 + 8543232 variable - 7559699 + 7520077 type_id - 2453031 + 2430641 name - 674973 + 672695 location - 5383265 + 5365099 @@ -15277,7 +15302,7 @@ 1 2 - 8586319 + 8543232 @@ -15293,12 +15318,12 @@ 1 2 - 8517406 + 8474552 2 3 - 68913 + 68680 @@ -15314,7 +15339,7 @@ 1 2 - 8586319 + 8543232 @@ -15330,7 +15355,7 @@ 1 2 - 8586319 + 8543232 @@ -15346,17 +15371,17 @@ 1 2 - 6694978 + 6658274 2 3 - 709429 + 707035 3 7 - 155291 + 154767 @@ -15372,12 +15397,12 @@ 1 2 - 7386000 + 7346963 2 4 - 173699 + 173113 @@ -15393,12 +15418,12 @@ 1 2 - 7442169 + 7402943 2 3 - 117530 + 117133 @@ -15414,12 +15439,12 @@ 1 2 - 7005089 + 6967337 2 4 - 554610 + 552739 @@ -15435,27 +15460,27 @@ 1 2 - 1525061 + 1505802 2 3 - 517794 + 516046 3 4 - 99121 + 98787 4 7 - 189275 + 188636 7 780 - 121778 + 121367 @@ -15471,22 +15496,22 @@ 1 2 - 1660056 + 1640342 2 3 - 492777 + 491114 3 7 - 188803 + 188166 7 742 - 111394 + 111018 @@ -15502,17 +15527,17 @@ 1 2 - 1939485 + 1918828 2 3 - 389879 + 388563 3 128 - 123666 + 123249 @@ -15528,22 +15553,22 @@ 1 2 - 1763898 + 1743833 2 3 - 408287 + 406910 3 8 - 190691 + 190048 8 595 - 90153 + 89849 @@ -15559,37 +15584,37 @@ 1 2 - 345038 + 343874 2 3 - 87793 + 87497 3 4 - 49088 + 48923 4 6 - 52393 + 52216 6 12 - 52865 + 52686 12 33 - 50976 + 50804 34 - 3311 - 36816 + 3281 + 36692 @@ -15605,37 +15630,37 @@ 1 2 - 372887 + 371628 2 3 - 78825 + 78559 3 4 - 45784 + 45630 4 6 - 50032 + 49864 6 14 - 53809 + 53627 14 56 - 51449 + 51275 56 - 3228 - 22184 + 3198 + 22109 @@ -15651,27 +15676,27 @@ 1 2 - 462097 + 460537 2 3 - 94873 + 94553 3 5 - 47200 + 47041 5 19 - 51449 + 51275 19 - 2009 - 19352 + 1979 + 19287 @@ -15687,32 +15712,32 @@ 1 2 - 383271 + 381978 2 3 - 91569 + 91260 3 5 - 60417 + 60213 5 9 - 51921 + 51745 9 21 - 50976 + 50804 21 1020 - 36816 + 36692 @@ -15728,17 +15753,17 @@ 1 2 - 4551113 + 4535755 2 3 - 552250 + 550387 3 - 1813 - 279901 + 1783 + 278956 @@ -15754,17 +15779,17 @@ 1 2 - 4956568 + 4939842 2 17 - 415840 + 414436 17 - 1809 - 10856 + 1779 + 10819 @@ -15780,12 +15805,12 @@ 1 2 - 5033506 + 5016520 2 - 1591 - 349758 + 1561 + 348578 @@ -15801,12 +15826,12 @@ 1 2 - 5379017 + 5360865 2 24 - 4248 + 4233 @@ -15816,26 +15841,26 @@ var_def - 4097512 + 4083685 id - 4097512 + 4083685 var_decl_specifiers - 336070 + 334936 id - 336070 + 334936 name - 1416 + 1411 @@ -15849,7 +15874,7 @@ 1 2 - 336070 + 334936 @@ -15865,17 +15890,17 @@ 15 16 - 472 + 470 66 67 - 472 + 470 631 632 - 472 + 470 @@ -15885,30 +15910,30 @@ is_structured_binding - 10 + 18 id - 10 + 18 type_decls - 3292736 + 3283977 id - 3292736 + 3283977 type_id - 3241759 + 3233172 location - 3212494 + 3204006 @@ -15922,7 +15947,7 @@ 1 2 - 3292736 + 3283977 @@ -15938,7 +15963,7 @@ 1 2 - 3292736 + 3283977 @@ -15954,12 +15979,12 @@ 1 2 - 3199750 + 3191305 2 5 - 42008 + 41867 @@ -15975,12 +16000,12 @@ 1 2 - 3199750 + 3191305 2 5 - 42008 + 41867 @@ -15996,12 +16021,12 @@ 1 2 - 3171430 + 3163080 2 20 - 41064 + 40926 @@ -16017,12 +16042,12 @@ 1 2 - 3171430 + 3163080 2 20 - 41064 + 40926 @@ -16032,45 +16057,45 @@ type_def - 2666852 + 2660675 id - 2666852 + 2660675 type_decl_top - 758990 + 755959 type_decl - 758990 + 755959 namespace_decls - 307863 + 306979 id - 307863 + 306979 namespace_id - 1418 + 1414 location - 307863 + 306979 bodylocation - 307863 + 306979 @@ -16084,7 +16109,7 @@ 1 2 - 307863 + 306979 @@ -16100,7 +16125,7 @@ 1 2 - 307863 + 306979 @@ -16116,7 +16141,7 @@ 1 2 - 307863 + 306979 @@ -16132,7 +16157,7 @@ 1 2 - 296 + 295 2 @@ -16142,17 +16167,17 @@ 3 6 - 126 + 125 6 14 - 107 + 106 14 30 - 107 + 106 30 @@ -16167,17 +16192,17 @@ 80 127 - 107 + 106 129 199 - 107 + 106 201 504 - 107 + 106 512 @@ -16198,7 +16223,7 @@ 1 2 - 296 + 295 2 @@ -16208,17 +16233,17 @@ 3 6 - 126 + 125 6 14 - 107 + 106 14 30 - 107 + 106 30 @@ -16233,17 +16258,17 @@ 80 127 - 107 + 106 129 199 - 107 + 106 201 504 - 107 + 106 512 @@ -16264,7 +16289,7 @@ 1 2 - 296 + 295 2 @@ -16274,17 +16299,17 @@ 3 6 - 126 + 125 6 14 - 107 + 106 14 30 - 107 + 106 30 @@ -16299,17 +16324,17 @@ 80 127 - 107 + 106 129 199 - 107 + 106 201 504 - 107 + 106 512 @@ -16330,7 +16355,7 @@ 1 2 - 307863 + 306979 @@ -16346,7 +16371,7 @@ 1 2 - 307863 + 306979 @@ -16362,7 +16387,7 @@ 1 2 - 307863 + 306979 @@ -16378,7 +16403,7 @@ 1 2 - 307863 + 306979 @@ -16394,7 +16419,7 @@ 1 2 - 307863 + 306979 @@ -16410,7 +16435,7 @@ 1 2 - 307863 + 306979 @@ -16420,19 +16445,19 @@ usings - 375719 + 374921 id - 375719 + 374921 element_id - 319078 + 318471 location - 250164 + 249791 @@ -16446,7 +16471,7 @@ 1 2 - 375719 + 374921 @@ -16462,7 +16487,7 @@ 1 2 - 375719 + 374921 @@ -16478,17 +16503,17 @@ 1 2 - 264325 + 263903 2 3 - 53337 + 53157 3 5 - 1416 + 1411 @@ -16504,17 +16529,17 @@ 1 2 - 264325 + 263903 2 3 - 53337 + 53157 3 5 - 1416 + 1411 @@ -16530,22 +16555,22 @@ 1 2 - 203907 + 203690 2 4 - 11328 + 11289 4 5 - 31624 + 31517 5 11 - 3304 + 3292 @@ -16561,22 +16586,22 @@ 1 2 - 203907 + 203690 2 4 - 11328 + 11289 4 5 - 31624 + 31517 5 11 - 3304 + 3292 @@ -16586,15 +16611,15 @@ using_container - 479100 + 478195 parent - 11308 + 11298 child - 303777 + 303207 @@ -16608,47 +16633,47 @@ 1 2 - 3348 + 3353 2 4 - 961 + 959 4 6 - 428 + 427 6 7 - 2560 + 2555 7 17 - 926 + 925 19 143 - 787 + 786 178 179 - 1332 + 1329 179 183 - 880 + 878 201 488 - 81 + 80 @@ -16664,22 +16689,22 @@ 1 2 - 224046 + 223629 2 3 - 53091 + 52990 3 11 - 24448 + 24401 13 41 - 2189 + 2185 @@ -16689,27 +16714,27 @@ static_asserts - 130790 + 130414 id - 130790 + 130414 condition - 130790 + 130414 message - 29535 + 29450 location - 16816 + 16768 enclosing - 1948 + 1942 @@ -16723,7 +16748,7 @@ 1 2 - 130790 + 130414 @@ -16739,7 +16764,7 @@ 1 2 - 130790 + 130414 @@ -16755,7 +16780,7 @@ 1 2 - 130790 + 130414 @@ -16771,7 +16796,7 @@ 1 2 - 130790 + 130414 @@ -16787,7 +16812,7 @@ 1 2 - 130790 + 130414 @@ -16803,7 +16828,7 @@ 1 2 - 130790 + 130414 @@ -16819,7 +16844,7 @@ 1 2 - 130790 + 130414 @@ -16835,7 +16860,7 @@ 1 2 - 130790 + 130414 @@ -16851,32 +16876,32 @@ 1 2 - 22006 + 21943 2 3 - 403 + 402 3 4 - 2774 + 2766 4 11 - 1425 + 1420 12 17 - 2383 + 2376 17 513 - 542 + 540 @@ -16892,32 +16917,32 @@ 1 2 - 22006 + 21943 2 3 - 403 + 402 3 4 - 2774 + 2766 4 11 - 1425 + 1420 12 17 - 2383 + 2376 17 513 - 542 + 540 @@ -16933,12 +16958,12 @@ 1 2 - 27416 + 27337 2 33 - 2118 + 2112 @@ -16954,27 +16979,27 @@ 1 2 - 23425 + 23357 2 3 - 189 + 188 3 4 - 2572 + 2565 4 11 - 1267 + 1263 12 21 - 2080 + 2074 @@ -16990,22 +17015,22 @@ 1 2 - 3133 + 3124 2 3 - 2705 + 2697 3 4 - 1311 + 1307 5 6 - 3632 + 3621 6 @@ -17015,7 +17040,7 @@ 14 15 - 2055 + 2049 16 @@ -17025,12 +17050,12 @@ 17 18 - 3411 + 3401 19 52 - 346 + 345 @@ -17046,22 +17071,22 @@ 1 2 - 3133 + 3124 2 3 - 2705 + 2697 3 4 - 1311 + 1307 5 6 - 3632 + 3621 6 @@ -17071,7 +17096,7 @@ 14 15 - 2055 + 2049 16 @@ -17081,12 +17106,12 @@ 17 18 - 3411 + 3401 19 52 - 346 + 345 @@ -17102,17 +17127,17 @@ 1 2 - 4634 + 4621 2 3 - 5958 + 5941 3 4 - 6040 + 6023 4 @@ -17133,32 +17158,32 @@ 1 2 - 3739 + 3728 2 3 - 6129 + 6111 3 4 - 1084 + 1081 4 5 - 3600 + 3590 5 6 - 189 + 188 13 14 - 2055 + 2049 16 @@ -17179,7 +17204,7 @@ 1 2 - 1380 + 1376 2 @@ -17199,7 +17224,7 @@ 209 11052 - 126 + 125 @@ -17215,7 +17240,7 @@ 1 2 - 1380 + 1376 2 @@ -17235,7 +17260,7 @@ 209 11052 - 126 + 125 @@ -17251,17 +17276,17 @@ 1 2 - 1551 + 1546 2 6 - 151 + 150 9 210 - 170 + 169 223 @@ -17282,7 +17307,7 @@ 1 2 - 1538 + 1534 2 @@ -17307,23 +17332,23 @@ params - 6863014 + 6825742 id - 6696867 + 6660155 function - 3967709 + 3940208 index - 8024 + 7997 type_id - 2256204 + 2234478 @@ -17337,7 +17362,7 @@ 1 2 - 6696867 + 6660155 @@ -17353,7 +17378,7 @@ 1 2 - 6696867 + 6660155 @@ -17369,12 +17394,12 @@ 1 2 - 6571312 + 6535025 2 4 - 125554 + 125130 @@ -17390,22 +17415,22 @@ 1 2 - 2325117 + 2303158 2 3 - 963842 + 960590 3 4 - 434720 + 433253 4 18 - 244028 + 243205 @@ -17421,22 +17446,22 @@ 1 2 - 2325117 + 2303158 2 3 - 963842 + 960590 3 4 - 434720 + 433253 4 18 - 244028 + 243205 @@ -17452,22 +17477,22 @@ 1 2 - 2628619 + 2605636 2 3 - 834040 + 831225 3 4 - 350702 + 349519 4 12 - 154347 + 153826 @@ -17483,72 +17508,72 @@ 2 3 - 944 + 940 4 5 - 472 + 470 6 7 - 472 + 470 8 9 - 944 + 940 9 10 - 472 + 470 10 11 - 944 + 940 11 12 - 472 + 470 19 20 - 472 + 470 64 65 - 472 + 470 194 195 - 472 + 470 517 518 - 472 + 470 1438 1439 - 472 + 470 3480 3481 - 472 + 470 - 8406 - 8407 - 472 + 8376 + 8377 + 470 @@ -17564,72 +17589,72 @@ 2 3 - 944 + 940 4 5 - 472 + 470 6 7 - 472 + 470 8 9 - 944 + 940 9 10 - 472 + 470 10 11 - 944 + 940 11 12 - 472 + 470 19 20 - 472 + 470 64 65 - 472 + 470 194 195 - 472 + 470 517 518 - 472 + 470 1438 1439 - 472 + 470 3480 3481 - 472 + 470 - 8406 - 8407 - 472 + 8376 + 8377 + 470 @@ -17645,67 +17670,67 @@ 1 2 - 944 + 940 3 4 - 472 + 470 4 5 - 472 + 470 5 6 - 472 + 470 6 7 - 1416 + 1411 7 8 - 944 + 940 11 12 - 472 + 470 42 43 - 472 + 470 106 107 - 472 + 470 228 229 - 472 + 470 582 583 - 472 + 470 1275 1276 - 472 + 470 - 3696 - 3697 - 472 + 3666 + 3667 + 470 @@ -17721,22 +17746,22 @@ 1 2 - 1544886 + 1525560 2 3 - 447936 + 446425 3 8 - 172283 + 171701 8 522 - 91097 + 90790 @@ -17752,22 +17777,22 @@ 1 2 - 1769090 + 1749008 2 3 - 251580 + 250731 3 9 - 170395 + 169820 9 506 - 65137 + 64917 @@ -17783,17 +17808,17 @@ 1 2 - 1821955 + 1801694 2 3 - 354478 + 353282 3 13 - 79769 + 79500 @@ -17803,15 +17828,15 @@ overrides - 160287 + 159827 new - 125386 + 125026 old - 15139 + 15096 @@ -17825,12 +17850,12 @@ 1 2 - 90491 + 90231 2 3 - 34888 + 34788 3 @@ -17851,37 +17876,37 @@ 1 2 - 7945 + 7922 2 3 - 1910 + 1905 3 4 - 989 + 987 4 5 - 1324 + 1320 5 11 - 1216 + 1213 11 60 - 1166 + 1163 61 231 - 586 + 584 @@ -17891,19 +17916,19 @@ membervariables - 1051799 + 1051873 id - 1050009 + 1050083 type_id - 326270 + 326293 name - 449611 + 449643 @@ -17917,7 +17942,7 @@ 1 2 - 1048298 + 1048372 2 @@ -17938,7 +17963,7 @@ 1 2 - 1050009 + 1050083 @@ -17954,22 +17979,22 @@ 1 2 - 241948 + 241965 2 3 - 51667 + 51670 3 10 - 25415 + 25417 10 4152 - 7238 + 7239 @@ -17985,17 +18010,17 @@ 1 2 - 254119 + 254137 2 3 - 46257 + 46261 3 40 - 24501 + 24502 41 @@ -18016,22 +18041,22 @@ 1 2 - 294013 + 294034 2 3 - 86151 + 86157 3 5 - 41007 + 41010 5 646 - 28438 + 28440 @@ -18047,17 +18072,17 @@ 1 2 - 366204 + 366230 2 3 - 51508 + 51511 3 650 - 31899 + 31901 @@ -18238,19 +18263,19 @@ localvariables - 581746 + 581698 id - 581746 + 581698 type_id - 37913 + 37905 name - 91411 + 91404 @@ -18264,7 +18289,7 @@ 1 2 - 581746 + 581698 @@ -18280,7 +18305,7 @@ 1 2 - 581746 + 581698 @@ -18296,12 +18321,12 @@ 1 2 - 21213 + 21207 2 3 - 5413 + 5417 3 @@ -18311,12 +18336,12 @@ 4 7 - 3413 + 3408 7 18 - 2879 + 2878 18 @@ -18337,7 +18362,7 @@ 1 2 - 27001 + 26999 2 @@ -18347,7 +18372,7 @@ 3 5 - 2946 + 2942 5 @@ -18373,17 +18398,17 @@ 1 2 - 57575 + 57570 2 3 - 14421 + 14420 3 5 - 8389 + 8388 5 @@ -18393,7 +18418,7 @@ 15 5176 - 3976 + 3975 @@ -18409,7 +18434,7 @@ 1 2 - 77221 + 77215 2 @@ -18419,7 +18444,7 @@ 3 1486 - 6708 + 6707 @@ -18429,15 +18454,15 @@ autoderivation - 149996 + 149665 var - 149996 + 149665 derivation_type - 525 + 524 @@ -18451,7 +18476,7 @@ 1 2 - 149996 + 149665 @@ -18467,27 +18492,27 @@ 33 34 - 105 + 104 90 91 - 105 + 104 353 354 - 105 + 104 392 393 - 105 + 104 560 561 - 105 + 104 @@ -18497,19 +18522,19 @@ enumconstants - 240596 + 240613 id - 240596 + 240613 parent - 28399 + 28401 index - 10182 + 10183 type_id @@ -18517,11 +18542,11 @@ name - 240318 + 240334 location - 220589 + 220605 @@ -18535,7 +18560,7 @@ 1 2 - 240596 + 240613 @@ -18551,7 +18576,7 @@ 1 2 - 240596 + 240613 @@ -18567,7 +18592,7 @@ 1 2 - 240596 + 240613 @@ -18583,7 +18608,7 @@ 1 2 - 240596 + 240613 @@ -18599,7 +18624,7 @@ 1 2 - 240596 + 240613 @@ -18630,7 +18655,7 @@ 4 5 - 3897 + 3898 5 @@ -18696,7 +18721,7 @@ 4 5 - 3897 + 3898 5 @@ -18747,7 +18772,7 @@ 1 2 - 28399 + 28401 @@ -18778,7 +18803,7 @@ 4 5 - 3897 + 3898 5 @@ -19002,7 +19027,7 @@ 1 2 - 10182 + 10183 @@ -19210,7 +19235,7 @@ 1 2 - 240039 + 240056 2 @@ -19231,7 +19256,7 @@ 1 2 - 240039 + 240056 2 @@ -19252,7 +19277,7 @@ 1 2 - 240318 + 240334 @@ -19268,7 +19293,7 @@ 1 2 - 240318 + 240334 @@ -19284,7 +19309,7 @@ 1 2 - 240039 + 240056 2 @@ -19305,7 +19330,7 @@ 1 2 - 219834 + 219849 2 @@ -19326,7 +19351,7 @@ 1 2 - 220589 + 220605 @@ -19342,7 +19367,7 @@ 1 2 - 219834 + 219849 2 @@ -19363,7 +19388,7 @@ 1 2 - 220589 + 220605 @@ -19379,7 +19404,7 @@ 1 2 - 219834 + 219849 2 @@ -19394,31 +19419,31 @@ builtintypes - 22184 + 22109 id - 22184 + 22109 name - 22184 + 22109 kind - 22184 + 22109 size - 3304 + 3292 sign - 1416 + 1411 alignment - 2360 + 2352 @@ -19432,7 +19457,7 @@ 1 2 - 22184 + 22109 @@ -19448,7 +19473,7 @@ 1 2 - 22184 + 22109 @@ -19464,7 +19489,7 @@ 1 2 - 22184 + 22109 @@ -19480,7 +19505,7 @@ 1 2 - 22184 + 22109 @@ -19496,7 +19521,7 @@ 1 2 - 22184 + 22109 @@ -19512,7 +19537,7 @@ 1 2 - 22184 + 22109 @@ -19528,7 +19553,7 @@ 1 2 - 22184 + 22109 @@ -19544,7 +19569,7 @@ 1 2 - 22184 + 22109 @@ -19560,7 +19585,7 @@ 1 2 - 22184 + 22109 @@ -19576,7 +19601,7 @@ 1 2 - 22184 + 22109 @@ -19592,7 +19617,7 @@ 1 2 - 22184 + 22109 @@ -19608,7 +19633,7 @@ 1 2 - 22184 + 22109 @@ -19624,7 +19649,7 @@ 1 2 - 22184 + 22109 @@ -19640,7 +19665,7 @@ 1 2 - 22184 + 22109 @@ -19656,7 +19681,7 @@ 1 2 - 22184 + 22109 @@ -19672,37 +19697,37 @@ 1 2 - 472 + 470 2 3 - 472 + 470 4 5 - 472 + 470 7 8 - 472 + 470 9 10 - 472 + 470 11 12 - 472 + 470 13 14 - 472 + 470 @@ -19718,37 +19743,37 @@ 1 2 - 472 + 470 2 3 - 472 + 470 4 5 - 472 + 470 7 8 - 472 + 470 9 10 - 472 + 470 11 12 - 472 + 470 13 14 - 472 + 470 @@ -19764,37 +19789,37 @@ 1 2 - 472 + 470 2 3 - 472 + 470 4 5 - 472 + 470 7 8 - 472 + 470 9 10 - 472 + 470 11 12 - 472 + 470 13 14 - 472 + 470 @@ -19810,12 +19835,12 @@ 1 2 - 944 + 940 3 4 - 2360 + 2352 @@ -19831,12 +19856,12 @@ 1 2 - 2360 + 2352 2 3 - 944 + 940 @@ -19852,17 +19877,17 @@ 6 7 - 472 + 470 12 13 - 472 + 470 29 30 - 472 + 470 @@ -19878,17 +19903,17 @@ 6 7 - 472 + 470 12 13 - 472 + 470 29 30 - 472 + 470 @@ -19904,17 +19929,17 @@ 6 7 - 472 + 470 12 13 - 472 + 470 29 30 - 472 + 470 @@ -19930,12 +19955,12 @@ 5 6 - 944 + 940 7 8 - 472 + 470 @@ -19951,7 +19976,7 @@ 5 6 - 1416 + 1411 @@ -19967,27 +19992,27 @@ 4 5 - 472 + 470 8 9 - 472 + 470 10 11 - 472 + 470 12 13 - 472 + 470 13 14 - 472 + 470 @@ -20003,27 +20028,27 @@ 4 5 - 472 + 470 8 9 - 472 + 470 10 11 - 472 + 470 12 13 - 472 + 470 13 14 - 472 + 470 @@ -20039,27 +20064,27 @@ 4 5 - 472 + 470 8 9 - 472 + 470 10 11 - 472 + 470 12 13 - 472 + 470 13 14 - 472 + 470 @@ -20075,12 +20100,12 @@ 1 2 - 472 + 470 2 3 - 1888 + 1881 @@ -20096,7 +20121,7 @@ 3 4 - 2360 + 2352 @@ -20106,23 +20131,23 @@ derivedtypes - 4456239 + 4413446 id - 4456239 + 4413446 name - 2235907 + 2205312 kind - 2832 + 2822 type_id - 2752285 + 2729356 @@ -20136,7 +20161,7 @@ 1 2 - 4456239 + 4413446 @@ -20152,7 +20177,7 @@ 1 2 - 4456239 + 4413446 @@ -20168,7 +20193,7 @@ 1 2 - 4456239 + 4413446 @@ -20184,17 +20209,17 @@ 1 2 - 1961670 + 1935763 2 5 - 175587 + 171231 5 1173 - 98649 + 98317 @@ -20210,12 +20235,12 @@ 1 2 - 2234963 + 2204371 2 3 - 944 + 940 @@ -20231,17 +20256,17 @@ 1 2 - 1961670 + 1935763 2 5 - 175587 + 171231 5 1155 - 98649 + 98317 @@ -20255,34 +20280,34 @@ 12 - 198 - 199 - 472 + 199 + 200 + 470 - 1118 - 1119 - 472 + 1103 + 1104 + 470 1154 1155 - 472 + 470 1223 1224 - 472 + 470 - 2208 - 2209 - 472 + 2193 + 2194 + 470 - 3540 - 3541 - 472 + 3510 + 3511 + 470 @@ -20298,32 +20323,32 @@ 1 2 - 472 + 470 164 165 - 472 + 470 611 612 - 472 + 470 - 796 - 797 - 472 + 783 + 784 + 470 - 1161 - 1162 - 472 + 1149 + 1150 + 470 - 2006 - 2007 - 472 + 1982 + 1983 + 470 @@ -20337,34 +20362,34 @@ 12 - 83 - 84 - 472 + 84 + 85 + 470 - 1118 - 1119 - 472 + 1103 + 1104 + 470 1154 1155 - 472 + 470 1223 1224 - 472 + 470 - 2163 - 2164 - 472 + 2148 + 2149 + 470 - 3540 - 3541 - 472 + 3510 + 3511 + 470 @@ -20380,22 +20405,22 @@ 1 2 - 1698289 + 1685972 2 3 - 570659 + 568733 3 4 - 375719 + 367395 4 54 - 107618 + 107254 @@ -20411,22 +20436,22 @@ 1 2 - 1709617 + 1697262 2 3 - 563107 + 561206 3 4 - 372887 + 364572 4 54 - 106674 + 106314 @@ -20442,22 +20467,22 @@ 1 2 - 1702537 + 1690206 2 3 - 574435 + 572496 3 4 - 374775 + 366454 4 6 - 100537 + 100198 @@ -20467,19 +20492,19 @@ pointerishsize - 3320584 + 3314342 id - 3320584 + 3314342 size - 472 + 35 alignment - 472 + 35 @@ -20493,7 +20518,7 @@ 1 2 - 3320584 + 3314342 @@ -20509,7 +20534,7 @@ 1 2 - 3320584 + 3314342 @@ -20523,9 +20548,9 @@ 12 - 7035 - 7036 - 472 + 94071 + 94072 + 35 @@ -20541,7 +20566,7 @@ 1 2 - 472 + 35 @@ -20555,9 +20580,9 @@ 12 - 7035 - 7036 - 472 + 94071 + 94072 + 35 @@ -20573,7 +20598,7 @@ 1 2 - 472 + 35 @@ -20583,23 +20608,23 @@ arraysizes - 71745 + 71503 id - 71745 + 71503 num_elements - 23600 + 23520 bytesize - 26432 + 26343 alignment - 1888 + 1881 @@ -20613,7 +20638,7 @@ 1 2 - 71745 + 71503 @@ -20629,7 +20654,7 @@ 1 2 - 71745 + 71503 @@ -20645,7 +20670,7 @@ 1 2 - 71745 + 71503 @@ -20661,32 +20686,32 @@ 1 2 - 2360 + 2352 2 3 - 15104 + 15053 3 4 - 1416 + 1411 4 6 - 1888 + 1881 6 11 - 1888 + 1881 12 14 - 944 + 940 @@ -20702,22 +20727,22 @@ 1 2 - 18408 + 18346 2 3 - 2360 + 2352 3 4 - 1888 + 1881 4 7 - 944 + 940 @@ -20733,22 +20758,22 @@ 1 2 - 18408 + 18346 2 3 - 2832 + 2822 3 4 - 1416 + 1411 4 5 - 944 + 940 @@ -20764,27 +20789,27 @@ 1 2 - 2832 + 2822 2 3 - 16992 + 16934 3 4 - 3304 + 3292 4 8 - 2360 + 2352 11 16 - 944 + 940 @@ -20800,17 +20825,17 @@ 1 2 - 21712 + 21639 2 3 - 3304 + 3292 3 5 - 1416 + 1411 @@ -20826,17 +20851,17 @@ 1 2 - 22184 + 22109 2 3 - 3304 + 3292 4 5 - 944 + 940 @@ -20852,22 +20877,22 @@ 5 6 - 472 + 470 16 17 - 472 + 470 31 32 - 472 + 470 100 101 - 472 + 470 @@ -20883,17 +20908,17 @@ 4 5 - 472 + 470 7 8 - 944 + 940 50 51 - 472 + 470 @@ -20909,22 +20934,22 @@ 4 5 - 472 + 470 7 8 - 472 + 470 8 9 - 472 + 470 50 51 - 472 + 470 @@ -20934,15 +20959,15 @@ typedefbase - 1731312 + 1724183 id - 1731312 + 1724183 type_id - 809076 + 803747 @@ -20956,7 +20981,7 @@ 1 2 - 1731312 + 1724183 @@ -20972,22 +20997,22 @@ 1 2 - 628341 + 623381 2 3 - 84469 + 84307 3 6 - 64632 + 64497 6 5443 - 31632 + 31560 @@ -20997,23 +21022,23 @@ decltypes - 354722 + 355640 id - 23891 + 23953 expr - 354722 + 355640 base_type - 17137 + 17181 parentheses_would_change_meaning - 17 + 18 @@ -21027,37 +21052,37 @@ 1 2 - 5945 + 5961 2 3 - 7472 + 7492 3 4 - 3251 + 3259 4 7 - 1993 + 1999 7 18 - 1993 + 1999 18 42 - 2011 + 2017 42 1767 - 1221 + 1224 @@ -21073,7 +21098,7 @@ 1 2 - 23891 + 23953 @@ -21089,7 +21114,7 @@ 1 2 - 23891 + 23953 @@ -21105,7 +21130,7 @@ 1 2 - 354722 + 355640 @@ -21121,7 +21146,7 @@ 1 2 - 354722 + 355640 @@ -21137,7 +21162,7 @@ 1 2 - 354722 + 355640 @@ -21153,17 +21178,17 @@ 1 2 - 14442 + 14479 2 3 - 2209 + 2215 3 149 - 485 + 486 @@ -21179,37 +21204,37 @@ 1 2 - 1796 + 1800 2 3 - 7329 + 7348 3 4 - 3071 + 3079 4 5 - 1419 + 1422 5 11 - 1365 + 1368 11 43 - 1562 + 1566 43 6569 - 592 + 594 @@ -21225,7 +21250,7 @@ 1 2 - 17137 + 17181 @@ -21241,7 +21266,7 @@ 1330 1331 - 17 + 18 @@ -21257,7 +21282,7 @@ 19747 19748 - 17 + 18 @@ -21273,7 +21298,7 @@ 954 955 - 17 + 18 @@ -21283,19 +21308,19 @@ usertypes - 5362968 + 5342989 id - 5362968 + 5342989 name - 1392427 + 1383024 kind - 5192 + 5174 @@ -21309,7 +21334,7 @@ 1 2 - 5362968 + 5342989 @@ -21325,7 +21350,7 @@ 1 2 - 5362968 + 5342989 @@ -21341,27 +21366,27 @@ 1 2 - 1009627 + 1001986 2 3 - 162371 + 161352 3 7 - 108562 + 107725 7 - 81 - 104786 + 80 + 104432 - 92 + 80 885 - 7080 + 7526 @@ -21377,17 +21402,17 @@ 1 2 - 1247992 + 1240488 2 3 - 128858 + 127012 3 7 - 15576 + 15523 @@ -21403,57 +21428,57 @@ 6 7 - 472 + 470 10 11 - 472 + 470 26 27 - 472 + 470 - 121 - 122 - 472 + 124 + 125 + 470 - 138 - 139 - 472 + 139 + 140 + 470 - 690 - 691 - 472 + 700 + 701 + 470 - 862 - 863 - 472 + 861 + 862 + 470 963 964 - 472 + 470 - 1770 - 1771 - 472 + 1762 + 1763 + 470 - 1913 - 1914 - 472 + 1899 + 1900 + 470 - 4863 - 4864 - 472 + 4868 + 4869 + 470 @@ -21469,57 +21494,57 @@ 5 6 - 472 + 470 6 7 - 472 + 470 14 15 - 472 + 470 30 31 - 472 + 470 44 45 - 472 + 470 - 124 - 125 - 472 + 126 + 127 + 470 269 270 - 472 + 470 373 374 - 472 + 470 433 434 - 472 + 470 - 749 - 750 - 472 + 748 + 749 + 470 - 1250 - 1251 - 472 + 1236 + 1237 + 470 @@ -21529,19 +21554,19 @@ usertypesize - 1766258 + 1755594 id - 1766258 + 1755594 size - 13688 + 13642 alignment - 2360 + 2352 @@ -21555,7 +21580,7 @@ 1 2 - 1766258 + 1755594 @@ -21571,7 +21596,7 @@ 1 2 - 1766258 + 1755594 @@ -21587,47 +21612,47 @@ 1 2 - 3304 + 3292 2 3 - 4248 + 4233 3 4 - 472 + 470 4 5 - 944 + 940 6 8 - 944 + 940 9 15 - 944 + 940 37 84 - 944 + 940 92 - 160 - 944 + 163 + 940 748 - 2552 - 944 + 2539 + 940 @@ -21643,17 +21668,17 @@ 1 2 - 10384 + 10349 2 3 - 2832 + 2822 3 4 - 472 + 470 @@ -21669,27 +21694,27 @@ 2 3 - 472 + 470 6 7 - 472 + 470 - 181 - 182 - 472 + 184 + 185 + 470 254 255 - 472 + 470 - 3299 - 3300 - 472 + 3286 + 3287 + 470 @@ -21705,27 +21730,27 @@ 1 2 - 472 + 470 2 3 - 472 + 470 3 4 - 472 + 470 9 10 - 472 + 470 22 23 - 472 + 470 @@ -21735,26 +21760,26 @@ usertype_final - 9558 + 9537 id - 9558 + 9537 usertype_uuid - 36206 + 36102 id - 36206 + 36102 uuid - 36206 + 35737 @@ -21768,7 +21793,7 @@ 1 2 - 36206 + 36102 @@ -21784,7 +21809,12 @@ 1 2 - 36206 + 35373 + + + 2 + 3 + 364 @@ -21794,15 +21824,15 @@ mangled_name - 5283199 + 5264430 id - 5283199 + 5264430 mangled_name - 1236664 + 1235313 @@ -21816,7 +21846,7 @@ 1 2 - 5283199 + 5264430 @@ -21832,32 +21862,32 @@ 1 2 - 733502 + 731027 2 3 - 178419 + 178287 3 4 - 82601 + 84674 4 6 - 85905 + 86086 6 - 14 - 99121 + 13 + 93142 - 14 + 13 885 - 57113 + 62094 @@ -21867,59 +21897,59 @@ is_pod_class - 559630 + 554327 id - 559630 + 554327 is_standard_layout_class - 1306521 + 1295997 id - 1306521 + 1295997 is_complete - 1706313 + 1694439 id - 1706313 + 1694439 is_class_template - 406871 + 405028 id - 406871 + 405028 class_instantiation - 1132350 + 1121943 to - 1132350 + 1121943 from - 171811 + 170761 @@ -21933,7 +21963,7 @@ 1 2 - 1132350 + 1121943 @@ -21949,42 +21979,42 @@ 1 2 - 60417 + 58802 2 3 - 29736 + 30106 3 4 - 16048 + 16464 4 5 - 14160 + 14582 5 7 - 15576 + 15523 7 - 14 - 15576 + 13 + 13171 - 14 - 34 - 13216 + 13 + 29 + 13171 - 34 + 30 84 - 7080 + 8937 @@ -21994,19 +22024,19 @@ class_template_argument - 2984763 + 2978116 type_id - 1362392 + 1355715 index - 1297 + 1295 arg_type - 873917 + 863387 @@ -22020,27 +22050,27 @@ 1 2 - 553906 + 551563 2 3 - 419705 + 411593 3 4 - 242829 + 246019 4 7 - 121721 + 122356 7 113 - 24228 + 24182 @@ -22056,22 +22086,22 @@ 1 2 - 578853 + 577422 2 3 - 432393 + 424939 3 4 - 256363 + 257885 4 113 - 94781 + 95468 @@ -22092,7 +22122,7 @@ 2 3 - 822 + 821 3 @@ -22111,12 +22141,12 @@ 592 - 8760 + 8835 104 - 12939 - 114739 + 13776 + 114840 46 @@ -22138,7 +22168,7 @@ 2 3 - 822 + 821 3 @@ -22157,12 +22187,12 @@ 195 - 3458 + 4197 104 - 11165 - 39733 + 10467 + 39739 34 @@ -22179,27 +22209,27 @@ 1 2 - 536062 + 535650 2 3 - 191313 + 181071 3 4 - 53972 + 52573 4 - 11 - 67088 + 10 + 65688 - 11 - 10817 - 25479 + 10 + 11334 + 28403 @@ -22215,17 +22245,17 @@ 1 2 - 762763 + 755683 2 3 - 94156 + 85741 3 22 - 16998 + 21961 @@ -22235,19 +22265,19 @@ class_template_argument_value - 506465 + 508520 type_id - 314830 + 316590 index - 1888 + 1881 arg_value - 506465 + 508520 @@ -22261,17 +22291,17 @@ 1 2 - 259133 + 261081 2 3 - 53809 + 53627 3 4 - 1888 + 1881 @@ -22287,22 +22317,22 @@ 1 2 - 199187 + 200397 2 3 - 81185 + 81852 3 - 4 - 12272 + 5 + 29165 - 4 + 5 9 - 22184 + 5174 @@ -22318,22 +22348,22 @@ 18 19 - 472 + 470 92 93 - 472 + 470 - 299 - 300 - 472 + 309 + 310 + 470 - 380 - 381 - 472 + 376 + 377 + 470 @@ -22349,22 +22379,22 @@ 19 20 - 472 + 470 124 125 - 472 + 470 - 410 - 411 - 472 + 425 + 426 + 470 - 520 - 521 - 472 + 513 + 514 + 470 @@ -22380,7 +22410,7 @@ 1 2 - 506465 + 508520 @@ -22396,7 +22426,7 @@ 1 2 - 506465 + 508520 @@ -22406,15 +22436,15 @@ is_proxy_class_for - 65137 + 65387 id - 65137 + 65387 templ_param_id - 65137 + 65387 @@ -22428,7 +22458,7 @@ 1 2 - 65137 + 65387 @@ -22444,7 +22474,7 @@ 1 2 - 65137 + 65387 @@ -22454,19 +22484,19 @@ type_mentions - 4011226 + 4011508 id - 4011226 + 4011508 type_id - 197321 + 197335 location - 3977856 + 3978135 kind @@ -22484,7 +22514,7 @@ 1 2 - 4011226 + 4011508 @@ -22500,7 +22530,7 @@ 1 2 - 4011226 + 4011508 @@ -22516,7 +22546,7 @@ 1 2 - 4011226 + 4011508 @@ -22532,17 +22562,17 @@ 1 2 - 97169 + 97176 2 3 - 21637 + 21638 3 4 - 8193 + 8194 4 @@ -22552,22 +22582,22 @@ 5 7 - 14318 + 14319 7 12 - 15790 + 15791 12 27 - 15114 + 15115 27 8555 - 14358 + 14359 @@ -22583,17 +22613,17 @@ 1 2 - 97169 + 97176 2 3 - 21637 + 21638 3 4 - 8193 + 8194 4 @@ -22603,22 +22633,22 @@ 5 7 - 14318 + 14319 7 12 - 15790 + 15791 12 27 - 15114 + 15115 27 8555 - 14358 + 14359 @@ -22634,7 +22664,7 @@ 1 2 - 197321 + 197335 @@ -22650,12 +22680,12 @@ 1 2 - 3944485 + 3944762 2 3 - 33370 + 33373 @@ -22671,12 +22701,12 @@ 1 2 - 3944485 + 3944762 2 3 - 33370 + 33373 @@ -22692,7 +22722,7 @@ 1 2 - 3977856 + 3978135 @@ -22750,26 +22780,26 @@ is_function_template - 1418387 + 1413601 id - 1418387 + 1413601 function_instantiation - 895034 + 906422 to - 895034 + 906422 from - 144729 + 146002 @@ -22783,7 +22813,7 @@ 1 2 - 895034 + 906422 @@ -22799,27 +22829,27 @@ 1 2 - 100124 + 101152 2 3 - 14448 + 14480 3 6 - 11964 + 12014 6 21 - 11964 + 12049 22 - 864 - 6227 + 869 + 6306 @@ -22829,19 +22859,19 @@ function_template_argument - 2313992 + 2339815 function_id - 1303055 + 1318394 index - 559 + 563 arg_type - 302683 + 305041 @@ -22855,22 +22885,22 @@ 1 2 - 668792 + 679667 2 3 - 388709 + 388084 3 4 - 175375 + 179966 4 15 - 70178 + 70676 @@ -22886,22 +22916,22 @@ 1 2 - 683870 + 694852 2 3 - 393991 + 393404 3 4 - 146583 + 150970 4 9 - 78609 + 79167 @@ -22917,57 +22947,57 @@ 1 2 - 209 + 211 7 8 - 34 + 35 35 36 - 34 + 35 108 109 - 34 + 35 164 165 - 34 + 35 294 295 - 34 + 35 849 850 - 34 + 35 - 3198 - 3199 - 34 + 3293 + 3294 + 35 - 8582 - 8583 - 34 + 8487 + 8488 + 35 - 17395 - 17396 - 34 + 17489 + 17490 + 35 - 34286 - 34287 - 34 + 34459 + 34460 + 35 @@ -22983,57 +23013,57 @@ 1 2 - 209 + 211 3 4 - 34 + 35 11 12 - 34 + 35 22 23 - 34 + 35 30 31 - 34 + 35 61 62 - 34 + 35 134 135 - 34 + 35 - 452 - 453 - 34 + 453 + 454 + 35 - 1127 - 1128 - 34 + 1126 + 1127 + 35 2404 2405 - 34 + 35 - 5836 - 5837 - 34 + 5842 + 5843 + 35 @@ -23049,32 +23079,32 @@ 1 2 - 185521 + 186978 2 3 - 44534 + 44850 3 5 - 23334 + 23218 5 16 - 23369 + 23535 16 - 113 - 25118 + 107 + 23006 - 126 + 108 955 - 804 + 3452 @@ -23090,17 +23120,17 @@ 1 2 - 272771 + 274918 2 4 - 25818 + 26001 4 17 - 4093 + 4122 @@ -23110,19 +23140,19 @@ function_template_argument_value - 358342 + 362998 function_id - 179083 + 181340 index - 559 + 563 arg_value - 355719 + 360356 @@ -23136,12 +23166,12 @@ 1 2 - 169778 + 171969 2 8 - 9305 + 9371 @@ -23157,17 +23187,17 @@ 1 2 - 149417 + 151428 2 3 - 20535 + 20681 3 97 - 9130 + 9230 @@ -23183,52 +23213,52 @@ 1 2 - 209 + 211 2 3 - 69 + 70 11 12 - 34 + 35 26 27 - 34 + 35 94 95 - 34 + 35 314 315 - 34 + 35 709 710 - 34 + 35 - 964 - 965 - 34 + 992 + 993 + 35 1187 1188 - 34 + 35 2148 2149 - 34 + 35 @@ -23244,52 +23274,52 @@ 1 2 - 209 + 211 2 3 - 69 + 70 60 61 - 34 + 35 80 81 - 34 + 35 141 142 - 34 + 35 533 534 - 34 + 35 - 1550 - 1551 - 34 + 1610 + 1611 + 35 1821 1822 - 34 + 35 2202 2203 - 34 + 35 3771 3772 - 34 + 35 @@ -23305,12 +23335,12 @@ 1 2 - 353095 + 357714 2 3 - 2623 + 2642 @@ -23326,7 +23356,7 @@ 1 2 - 355719 + 360356 @@ -23336,26 +23366,26 @@ is_variable_template - 42225 + 42132 id - 42225 + 42132 variable_instantiation - 48633 + 49154 to - 48633 + 49154 from - 24894 + 25049 @@ -23369,7 +23399,7 @@ 1 2 - 48633 + 49154 @@ -23385,22 +23415,22 @@ 1 2 - 14390 + 14358 2 3 - 7667 + 7650 3 8 - 1785 + 1991 8 14 - 1050 + 1048 @@ -23410,19 +23440,19 @@ variable_template_argument - 328248 + 327628 variable_id - 26469 + 26411 index - 1785 + 1781 arg_type - 217116 + 216742 @@ -23436,22 +23466,22 @@ 1 2 - 16176 + 16140 2 3 - 5672 + 5659 3 4 - 3886 + 3877 4 17 - 735 + 733 @@ -23467,52 +23497,52 @@ 1 2 - 5987 + 5974 2 3 - 5251 + 5240 3 4 - 1995 + 1991 4 5 - 1155 + 1152 5 6 - 2415 + 2410 6 8 - 2310 + 2305 8 11 - 2205 + 2200 11 18 - 2415 + 2410 18 67 - 1995 + 1991 80 - 515 - 735 + 516 + 733 @@ -23528,42 +23558,42 @@ 1 2 - 105 + 104 2 3 - 630 + 628 3 4 - 420 + 419 5 6 - 210 + 209 27 28 - 105 + 104 42 43 - 105 + 104 79 80 - 105 + 104 248 249 - 105 + 104 @@ -23579,52 +23609,52 @@ 1 2 - 105 + 104 12 13 - 630 + 628 13 14 - 105 + 104 14 15 - 315 + 314 24 25 - 105 + 104 32 33 - 105 + 104 128 129 - 105 + 104 - 436 - 437 - 105 + 437 + 438 + 104 636 637 - 105 + 104 890 891 - 105 + 104 @@ -23640,17 +23670,17 @@ 1 2 - 181088 + 180793 2 3 - 20902 + 20856 3 37 - 15125 + 15092 @@ -23666,17 +23696,17 @@ 1 2 - 199890 + 199553 2 5 - 16806 + 16769 5 6 - 420 + 419 @@ -23686,19 +23716,19 @@ variable_template_argument_value - 15650 + 15616 variable_id - 2836 + 2829 index - 420 + 419 arg_value - 12079 + 12052 @@ -23712,12 +23742,12 @@ 1 2 - 2625 + 2620 2 3 - 210 + 209 @@ -23733,42 +23763,42 @@ 2 3 - 420 + 419 3 4 - 105 + 104 4 5 - 1365 + 1362 5 6 - 210 + 209 6 7 - 210 + 209 8 9 - 210 + 209 12 17 - 210 + 209 20 21 - 105 + 104 @@ -23784,22 +23814,22 @@ 2 3 - 105 + 104 6 7 - 105 + 104 8 9 - 105 + 104 13 14 - 105 + 104 @@ -23815,22 +23845,22 @@ 12 13 - 105 + 104 30 31 - 105 + 104 33 34 - 105 + 104 40 41 - 105 + 104 @@ -23846,12 +23876,12 @@ 1 2 - 8508 + 8489 2 3 - 3571 + 3563 @@ -23867,7 +23897,7 @@ 1 2 - 12079 + 12052 @@ -23877,15 +23907,15 @@ routinetypes - 543059 + 546982 id - 543059 + 546982 return_type - 283826 + 285945 @@ -23899,7 +23929,7 @@ 1 2 - 543059 + 546982 @@ -23915,17 +23945,17 @@ 1 2 - 247373 + 249233 2 3 - 21165 + 21315 3 3594 - 15288 + 15396 @@ -23935,19 +23965,19 @@ routinetypeargs - 996883 + 993519 routine - 430472 + 429019 index - 8024 + 7997 type_id - 230340 + 229563 @@ -23961,27 +23991,27 @@ 1 2 - 156235 + 155707 2 3 - 135938 + 135479 3 4 - 64193 + 63976 4 5 - 46256 + 46100 5 18 - 27848 + 27754 @@ -23997,27 +24027,27 @@ 1 2 - 186443 + 185814 2 3 - 135466 + 135009 3 4 - 59473 + 59272 4 5 - 33984 + 33869 5 11 - 15104 + 15053 @@ -24033,67 +24063,67 @@ 2 3 - 944 + 940 4 5 - 472 + 470 6 7 - 472 + 470 8 9 - 944 + 940 9 10 - 472 + 470 10 11 - 1416 + 1411 13 14 - 472 + 470 28 29 - 472 + 470 59 60 - 472 + 470 157 158 - 472 + 470 293 294 - 472 + 470 581 582 - 472 + 470 912 913 - 472 + 470 @@ -24109,57 +24139,57 @@ 1 2 - 944 + 940 3 4 - 944 + 940 4 5 - 1416 + 1411 5 6 - 944 + 940 6 7 - 944 + 940 10 11 - 472 + 470 14 15 - 472 + 470 47 48 - 472 + 470 90 91 - 472 + 470 176 177 - 472 + 470 349 350 - 472 + 470 @@ -24175,27 +24205,27 @@ 1 2 - 149154 + 148651 2 3 - 31152 + 31047 3 5 - 16992 + 16934 5 12 - 18408 + 18346 12 113 - 14632 + 14582 @@ -24211,22 +24241,22 @@ 1 2 - 175587 + 174994 2 3 - 31152 + 31047 3 6 - 18880 + 18816 6 14 - 4720 + 4704 @@ -24236,19 +24266,19 @@ ptrtomembers - 38232 + 38103 id - 38232 + 38103 type_id - 38232 + 38103 class_id - 15576 + 15523 @@ -24262,7 +24292,7 @@ 1 2 - 38232 + 38103 @@ -24278,7 +24308,7 @@ 1 2 - 38232 + 38103 @@ -24294,7 +24324,7 @@ 1 2 - 38232 + 38103 @@ -24310,7 +24340,7 @@ 1 2 - 38232 + 38103 @@ -24326,17 +24356,17 @@ 1 2 - 13688 + 13642 8 9 - 1416 + 1411 28 29 - 472 + 470 @@ -24352,17 +24382,17 @@ 1 2 - 13688 + 13642 8 9 - 1416 + 1411 28 29 - 472 + 470 @@ -24372,15 +24402,15 @@ specifiers - 25016 + 24932 id - 25016 + 24932 str - 25016 + 24932 @@ -24394,7 +24424,7 @@ 1 2 - 25016 + 24932 @@ -24410,7 +24440,7 @@ 1 2 - 25016 + 24932 @@ -24420,15 +24450,15 @@ typespecifiers - 1326345 + 1317166 type_id - 1307937 + 1298819 spec_id - 3776 + 3763 @@ -24442,12 +24472,12 @@ 1 2 - 1289529 + 1280473 2 3 - 18408 + 18346 @@ -24463,42 +24493,42 @@ 8 9 - 472 + 470 36 37 - 472 + 470 51 52 - 472 + 470 86 87 - 472 + 470 105 106 - 472 + 470 219 220 - 472 + 470 - 221 - 222 - 472 + 226 + 227 + 470 - 2084 - 2085 - 472 + 2069 + 2070 + 470 @@ -24508,15 +24538,15 @@ funspecifiers - 12993924 + 13049498 func_id - 3955310 + 3975160 spec_id - 699 + 704 @@ -24530,27 +24560,27 @@ 1 2 - 312758 + 314977 2 3 - 540295 + 544551 3 4 - 1132682 + 1145438 4 5 - 1734095 + 1732127 5 8 - 235478 + 238064 @@ -24566,97 +24596,97 @@ 13 14 - 69 + 70 98 99 - 34 + 35 200 201 - 34 + 35 296 297 - 34 + 35 304 305 - 34 + 35 572 573 - 34 + 35 716 717 - 34 + 35 1599 1600 - 34 + 35 1646 1647 - 34 + 35 3782 3783 - 34 + 35 - 3872 - 3873 - 34 + 3902 + 3903 + 35 5095 5096 - 34 + 35 6814 6815 - 34 + 35 - 9270 - 9271 - 34 + 9303 + 9304 + 35 - 12058 - 12059 - 34 + 12218 + 12219 + 35 - 53280 - 53281 - 34 + 52896 + 52897 + 35 - 80172 - 80173 - 34 + 79931 + 79932 + 35 - 91598 - 91599 - 34 + 91328 + 91329 + 35 - 100025 - 100026 - 34 + 99658 + 99659 + 35 @@ -24666,15 +24696,15 @@ varspecifiers - 2352966 + 2347848 var_id - 1257904 + 1255071 spec_id - 3776 + 3763 @@ -24688,22 +24718,22 @@ 1 2 - 738222 + 735731 2 3 - 202491 + 203219 3 4 - 59001 + 58802 4 5 - 258189 + 257317 @@ -24719,42 +24749,42 @@ 112 113 - 472 + 470 315 316 - 472 + 470 - 411 - 412 - 472 + 414 + 415 + 470 560 561 - 472 + 470 692 693 - 472 + 470 700 701 - 472 + 470 732 733 - 472 + 470 - 1463 - 1464 - 472 + 1466 + 1467 + 470 @@ -24764,27 +24794,27 @@ attributes - 696623 + 696970 id - 696623 + 696970 kind - 315 + 314 name - 1575 + 1676 name_space - 210 + 209 location - 484652 + 484420 @@ -24798,7 +24828,7 @@ 1 2 - 696623 + 696970 @@ -24814,7 +24844,7 @@ 1 2 - 696623 + 696970 @@ -24830,7 +24860,7 @@ 1 2 - 696623 + 696970 @@ -24846,7 +24876,7 @@ 1 2 - 696623 + 696970 @@ -24862,17 +24892,17 @@ 4 5 - 105 + 104 2168 2169 - 105 + 104 - 4460 - 4461 - 105 + 4478 + 4479 + 104 @@ -24888,248 +24918,258 @@ 1 2 - 105 - - - 5 - 6 - 105 - - - 11 - 12 - 105 - - - - - - - kind - name_space - - - 12 - - - 1 - 2 - 210 - - - 2 - 3 - 105 - - - - - - - kind - location - - - 12 - - - 2 - 3 - 105 - - - 2055 - 2056 - 105 - - - 2557 - 2558 - 105 - - - - - - - name - id - - - 12 - - - 1 - 2 - 210 - - - 2 - 3 - 105 - - - 4 - 5 - 210 - - - 5 - 6 - 105 - - - 9 - 10 - 105 - - - 14 - 15 - 105 - - - 16 - 17 - 105 - - - 24 - 25 - 105 - - - 86 - 87 - 105 - - - 115 - 116 - 105 - - - 659 - 660 - 105 - - - 1760 - 1761 - 105 - - - 3932 - 3933 - 105 - - - - - - - name - kind - - - 12 - - - 1 - 2 - 1365 - - - 2 - 3 - 210 - - - - - - - name - name_space - - - 12 - - - 1 - 2 - 1575 - - - - - - - name - location - - - 12 - - - 1 - 2 - 315 - - - 2 - 3 - 210 - - - 4 - 5 - 105 + 104 6 7 - 105 + 104 + + + 11 + 12 + 104 + + + + + + + kind + name_space + + + 12 + + + 1 + 2 + 209 + + + 2 + 3 + 104 + + + + + + + kind + location + + + 12 + + + 2 + 3 + 104 + + + 2055 + 2056 + 104 + + + 2565 + 2566 + 104 + + + + + + + name + id + + + 12 + + + 1 + 2 + 209 + + + 2 + 3 + 104 + + + 4 + 5 + 209 + + + 5 + 6 + 104 9 10 - 105 + 104 14 15 - 105 + 104 + + + 16 + 17 + 104 18 19 - 105 + 104 + + + 24 + 25 + 104 + + + 86 + 87 + 104 + + + 115 + 116 + 104 + + + 659 + 660 + 104 + + + 1760 + 1761 + 104 + + + 3932 + 3933 + 104 + + + + + + + name + kind + + + 12 + + + 1 + 2 + 1467 + + + 2 + 3 + 209 + + + + + + + name + name_space + + + 12 + + + 1 + 2 + 1676 + + + + + + + name + location + + + 12 + + + 1 + 2 + 314 + + + 2 + 3 + 209 + + + 4 + 5 + 104 + + + 6 + 7 + 104 + + + 8 + 9 + 104 + + + 9 + 10 + 104 + + + 14 + 15 + 104 + + + 18 + 19 + 104 59 60 - 105 + 104 72 73 - 105 + 104 331 332 - 105 + 104 1756 1757 - 105 + 104 2379 2380 - 105 + 104 @@ -25143,14 +25183,14 @@ 12 - 5 - 6 - 105 + 23 + 24 + 104 6627 6628 - 105 + 104 @@ -25166,12 +25206,12 @@ 1 2 - 105 + 104 3 4 - 105 + 104 @@ -25185,14 +25225,14 @@ 12 - 1 - 2 - 105 + 2 + 3 + 104 14 15 - 105 + 104 @@ -25206,14 +25246,14 @@ 12 - 1 - 2 - 105 + 9 + 10 + 104 4613 4614 - 105 + 104 @@ -25229,17 +25269,17 @@ 1 2 - 443372 + 443126 2 9 - 36868 + 36787 9 201 - 4411 + 4506 @@ -25255,7 +25295,7 @@ 1 2 - 484652 + 484420 @@ -25271,12 +25311,12 @@ 1 2 - 480346 + 480123 2 3 - 4306 + 4297 @@ -25292,7 +25332,7 @@ 1 2 - 484652 + 484420 @@ -25302,27 +25342,27 @@ attribute_args - 351174 + 352341 id - 351174 + 352341 kind - 1416 + 1411 attribute - 269045 + 270489 index - 1416 + 1411 location - 328046 + 329291 @@ -25336,7 +25376,7 @@ 1 2 - 351174 + 352341 @@ -25352,7 +25392,7 @@ 1 2 - 351174 + 352341 @@ -25368,7 +25408,7 @@ 1 2 - 351174 + 352341 @@ -25384,7 +25424,7 @@ 1 2 - 351174 + 352341 @@ -25400,17 +25440,17 @@ 1 2 - 472 + 470 - 55 - 56 - 472 + 54 + 55 + 470 - 688 - 689 - 472 + 694 + 695 + 470 @@ -25426,17 +25466,17 @@ 1 2 - 472 + 470 - 55 - 56 - 472 + 54 + 55 + 470 - 536 - 537 - 472 + 542 + 543 + 470 @@ -25452,12 +25492,12 @@ 1 2 - 944 + 940 3 4 - 472 + 470 @@ -25473,17 +25513,17 @@ 1 2 - 472 + 470 - 55 - 56 - 472 + 54 + 55 + 470 - 666 - 667 - 472 + 672 + 673 + 470 @@ -25499,17 +25539,17 @@ 1 2 - 202963 + 204631 2 3 - 50032 + 49864 3 4 - 16048 + 15994 @@ -25525,12 +25565,12 @@ 1 2 - 258661 + 260140 2 3 - 10384 + 10349 @@ -25546,17 +25586,17 @@ 1 2 - 202963 + 204631 2 3 - 50032 + 49864 3 4 - 16048 + 15994 @@ -25572,17 +25612,17 @@ 1 2 - 202963 + 204631 2 3 - 50032 + 49864 3 4 - 16048 + 15994 @@ -25598,17 +25638,17 @@ 34 35 - 472 + 470 140 141 - 472 + 470 - 570 - 571 - 472 + 575 + 576 + 470 @@ -25624,12 +25664,12 @@ 1 2 - 944 + 940 3 4 - 472 + 470 @@ -25645,17 +25685,17 @@ 34 35 - 472 + 470 140 141 - 472 + 470 - 570 - 571 - 472 + 575 + 576 + 470 @@ -25671,17 +25711,17 @@ 34 35 - 472 + 470 140 141 - 472 + 470 - 521 - 522 - 472 + 526 + 527 + 470 @@ -25697,12 +25737,12 @@ 1 2 - 313886 + 315179 2 16 - 14160 + 14112 @@ -25718,12 +25758,12 @@ 1 2 - 315302 + 316590 2 3 - 12744 + 12701 @@ -25739,12 +25779,12 @@ 1 2 - 313886 + 315179 2 16 - 14160 + 14112 @@ -25760,7 +25800,7 @@ 1 2 - 328046 + 329291 @@ -25770,15 +25810,15 @@ attribute_arg_value - 350702 + 351871 arg - 350702 + 351871 value - 32568 + 34810 @@ -25792,7 +25832,7 @@ 1 2 - 350702 + 351871 @@ -25808,22 +25848,22 @@ 1 2 - 14632 + 16934 2 3 - 12272 + 12230 3 14 - 2832 + 2822 15 247 - 2832 + 2822 @@ -25833,15 +25873,15 @@ attribute_arg_type - 1535 + 470 arg - 1535 + 470 type_id - 1354 + 470 @@ -25855,7 +25895,7 @@ 1 2 - 1535 + 470 @@ -25871,12 +25911,7 @@ 1 2 - 1264 - - - 3 - 4 - 90 + 470 @@ -25939,15 +25974,15 @@ typeattributes - 60817 + 62570 type_id - 60397 + 62150 spec_id - 60817 + 62570 @@ -25961,12 +25996,12 @@ 1 2 - 59977 + 61731 2 3 - 420 + 419 @@ -25982,7 +26017,7 @@ 1 2 - 60817 + 62570 @@ -25992,15 +26027,15 @@ funcattributes - 637684 + 635532 func_id - 448880 + 447366 spec_id - 637684 + 635532 @@ -26014,22 +26049,22 @@ 1 2 - 342678 + 341522 2 3 - 65137 + 64917 3 6 - 40120 + 39985 6 7 - 944 + 940 @@ -26045,7 +26080,7 @@ 1 2 - 637684 + 635532 @@ -26113,15 +26148,15 @@ stmtattributes - 1008 + 1006 stmt_id - 1008 + 1006 spec_id - 1008 + 1006 @@ -26135,7 +26170,7 @@ 1 2 - 1008 + 1006 @@ -26151,7 +26186,7 @@ 1 2 - 1008 + 1006 @@ -26161,15 +26196,15 @@ unspecifiedtype - 10417715 + 10352924 type_id - 10417715 + 10352924 unspecified_type_id - 6996120 + 6956047 @@ -26183,7 +26218,7 @@ 1 2 - 10417715 + 10352924 @@ -26199,17 +26234,17 @@ 1 2 - 4696963 + 4675939 2 3 - 2054184 + 2037843 3 147 - 244972 + 242264 @@ -26219,19 +26254,19 @@ member - 5120282 + 5134480 parent - 692861 + 689567 index - 8746 + 8808 child - 5057871 + 5070710 @@ -26245,42 +26280,42 @@ 1 3 - 18716 + 18884 3 4 - 396265 + 390691 4 5 - 38727 + 39072 5 7 - 52616 + 53059 7 10 - 52476 + 52848 10 16 - 57164 + 57569 16 30 - 52581 + 52954 30 251 - 24313 + 24486 @@ -26296,42 +26331,42 @@ 1 3 - 18716 + 18884 3 4 - 396230 + 390656 4 5 - 38692 + 39107 5 7 - 52791 + 53165 7 10 - 52791 + 53165 10 16 - 56919 + 57323 16 29 - 52371 + 52742 29 253 - 24348 + 24521 @@ -26347,62 +26382,62 @@ 1 2 - 1399 + 1409 2 3 - 804 + 810 3 4 - 944 + 951 5 22 - 769 + 669 22 - 43 - 664 + 42 + 669 - 43 - 61 - 699 + 42 + 56 + 669 - 62 - 113 - 664 + 56 + 100 + 669 - 114 - 185 - 664 + 104 + 164 + 669 - 186 - 331 - 664 + 181 + 299 + 669 - 367 - 1282 - 664 + 300 + 727 + 669 - 1418 - 5994 - 664 + 845 + 4002 + 669 - 7270 - 19474 - 139 + 4606 + 19241 + 281 @@ -26418,62 +26453,62 @@ 1 2 - 804 + 810 2 3 - 874 + 880 3 4 - 1154 + 1162 4 - 16 - 734 + 15 + 669 16 - 33 - 664 + 35 + 739 - 34 - 58 - 664 + 36 + 55 + 669 - 58 + 57 93 - 699 + 739 97 135 - 664 + 669 140 - 253 - 664 + 256 + 669 - 253 - 601 - 664 + 268 + 612 + 669 - 611 - 2463 - 664 + 619 + 2611 + 669 - 2610 - 19486 - 489 + 2770 + 19253 + 458 @@ -26489,7 +26524,7 @@ 1 2 - 5057871 + 5070710 @@ -26505,12 +26540,12 @@ 1 2 - 4996578 + 5008419 2 - 5 - 61292 + 8 + 62290 @@ -26520,15 +26555,15 @@ enclosingfunction - 121976 + 121743 child - 121976 + 121743 parent - 69638 + 69504 @@ -26542,7 +26577,7 @@ 1 2 - 121976 + 121743 @@ -26558,22 +26593,22 @@ 1 2 - 36765 + 36695 2 3 - 21633 + 21591 3 4 - 6117 + 6106 4 45 - 5121 + 5111 @@ -26583,27 +26618,27 @@ derivations - 397280 + 402388 derivation - 397280 + 402388 sub - 376919 + 381883 index - 209 + 211 super - 228236 + 206461 location - 37887 + 38156 @@ -26617,7 +26652,7 @@ 1 2 - 397280 + 402388 @@ -26633,7 +26668,7 @@ 1 2 - 397280 + 402388 @@ -26649,7 +26684,7 @@ 1 2 - 397280 + 402388 @@ -26665,7 +26700,7 @@ 1 2 - 397280 + 402388 @@ -26681,12 +26716,12 @@ 1 2 - 361876 + 366733 2 7 - 15043 + 15149 @@ -26702,12 +26737,12 @@ 1 2 - 361876 + 366733 2 7 - 15043 + 15149 @@ -26723,12 +26758,12 @@ 1 2 - 361876 + 366733 2 7 - 15043 + 15149 @@ -26744,12 +26779,12 @@ 1 2 - 361876 + 366733 2 7 - 15043 + 15149 @@ -26765,22 +26800,22 @@ 25 26 - 104 + 105 77 78 - 34 + 35 430 431 - 34 + 35 - 10774 - 10775 - 34 + 10839 + 10840 + 35 @@ -26796,22 +26831,22 @@ 25 26 - 104 + 105 77 78 - 34 + 35 430 431 - 34 + 35 - 10774 - 10775 - 34 + 10839 + 10840 + 35 @@ -26827,27 +26862,27 @@ 23 24 - 34 + 35 25 26 - 69 + 70 35 36 - 34 + 35 261 262 - 34 + 35 - 6169 - 6170 - 34 + 5505 + 5506 + 35 @@ -26863,22 +26898,22 @@ 1 2 - 104 + 105 9 10 - 34 + 35 66 67 - 34 + 35 1005 1006 - 34 + 35 @@ -26894,12 +26929,12 @@ 1 2 - 220960 + 199133 2 - 1076 - 7276 + 1225 + 7328 @@ -26915,12 +26950,12 @@ 1 2 - 220960 + 199133 2 - 1076 - 7276 + 1225 + 7328 @@ -26936,12 +26971,12 @@ 1 2 - 227781 + 206003 2 4 - 454 + 458 @@ -26957,12 +26992,12 @@ 1 2 - 224668 + 202867 2 108 - 3568 + 3593 @@ -26978,27 +27013,27 @@ 1 2 - 28197 + 28326 2 5 - 3043 + 3135 5 16 - 2973 + 2994 17 133 - 2973 + 2994 - 154 - 656 - 699 + 142 + 474 + 704 @@ -27014,27 +27049,27 @@ 1 2 - 28197 + 28326 2 5 - 3043 + 3135 5 16 - 2973 + 2994 17 133 - 2973 + 2994 - 154 - 656 - 699 + 142 + 474 + 704 @@ -27050,7 +27085,7 @@ 1 2 - 37887 + 38156 @@ -27066,22 +27101,22 @@ 1 2 - 30611 + 30757 2 5 - 3218 + 3417 5 55 - 2868 + 2889 60 - 656 - 1189 + 420 + 1092 @@ -27091,15 +27126,15 @@ derspecifiers - 399169 + 404291 der_id - 396895 + 402001 spec_id - 139 + 140 @@ -27113,12 +27148,12 @@ 1 2 - 394621 + 399710 2 3 - 2273 + 2290 @@ -27134,22 +27169,22 @@ 65 66 - 34 + 35 93 94 - 34 + 35 1132 1133 - 34 + 35 - 10120 - 10121 - 34 + 10185 + 10186 + 35 @@ -27159,15 +27194,15 @@ direct_base_offsets - 368208 + 373110 der_id - 368208 + 373110 offset - 349 + 352 @@ -27181,7 +27216,7 @@ 1 2 - 368208 + 373110 @@ -27197,32 +27232,32 @@ 1 2 - 34 + 35 2 3 - 104 + 105 3 4 - 69 + 70 4 5 - 69 + 70 85 86 - 34 + 35 - 10419 - 10420 - 34 + 10484 + 10485 + 35 @@ -27232,15 +27267,15 @@ virtual_base_offsets - 6674 + 6661 sub - 3684 + 3677 super - 509 + 508 offset @@ -27258,17 +27293,17 @@ 1 2 - 2896 + 2891 2 4 - 324 + 323 4 7 - 266 + 265 7 @@ -27289,7 +27324,7 @@ 1 2 - 3105 + 3099 2 @@ -27299,7 +27334,7 @@ 4 8 - 266 + 265 @@ -27315,7 +27350,7 @@ 1 2 - 81 + 80 2 @@ -27381,7 +27416,7 @@ 2 3 - 81 + 80 4 @@ -27483,7 +27518,7 @@ 1 2 - 81 + 80 2 @@ -27523,23 +27558,23 @@ frienddecls - 710038 + 715075 id - 710038 + 715075 type_id - 42085 + 42384 decl_id - 69688 + 70182 location - 6297 + 6341 @@ -27553,7 +27588,7 @@ 1 2 - 710038 + 715075 @@ -27569,7 +27604,7 @@ 1 2 - 710038 + 715075 @@ -27585,7 +27620,7 @@ 1 2 - 710038 + 715075 @@ -27601,47 +27636,47 @@ 1 2 - 6157 + 6200 2 3 - 13119 + 13212 3 6 - 2938 + 2959 6 10 - 3183 + 3206 10 17 - 3253 + 3276 17 24 - 3323 + 3347 25 36 - 3288 + 3311 37 55 - 3218 + 3241 55 103 - 3603 + 3628 @@ -27657,47 +27692,47 @@ 1 2 - 6157 + 6200 2 3 - 13119 + 13212 3 6 - 2938 + 2959 6 10 - 3183 + 3206 10 17 - 3253 + 3276 17 24 - 3323 + 3347 25 36 - 3288 + 3311 37 55 - 3218 + 3241 55 103 - 3603 + 3628 @@ -27713,12 +27748,12 @@ 1 2 - 40651 + 40939 2 13 - 1434 + 1444 @@ -27734,37 +27769,37 @@ 1 2 - 40196 + 40481 2 3 - 5842 + 5883 3 8 - 5982 + 6024 8 15 - 5387 + 5425 15 32 - 5247 + 5284 32 71 - 5247 + 5284 72 160 - 1784 + 1796 @@ -27780,37 +27815,37 @@ 1 2 - 40196 + 40481 2 3 - 5842 + 5883 3 8 - 5982 + 6024 8 15 - 5387 + 5425 15 32 - 5247 + 5284 32 71 - 5247 + 5284 72 160 - 1784 + 1796 @@ -27826,12 +27861,12 @@ 1 2 - 69023 + 69513 2 5 - 664 + 669 @@ -27847,12 +27882,12 @@ 1 2 - 5912 + 5954 2 20106 - 384 + 387 @@ -27868,12 +27903,12 @@ 1 2 - 6157 + 6200 2 1105 - 139 + 140 @@ -27889,12 +27924,12 @@ 1 2 - 5947 + 5989 2 1837 - 349 + 352 @@ -27904,19 +27939,19 @@ comments - 9024167 + 9004230 id - 9024167 + 9004230 contents - 3546138 + 3538304 location - 9024167 + 9004230 @@ -27930,7 +27965,7 @@ 1 2 - 9024167 + 9004230 @@ -27946,7 +27981,7 @@ 1 2 - 9024167 + 9004230 @@ -27962,17 +27997,17 @@ 1 2 - 3255074 + 3247882 2 10 - 268901 + 268307 10 32841 - 22163 + 22114 @@ -27988,17 +28023,17 @@ 1 2 - 3255074 + 3247882 2 10 - 268901 + 268307 10 32841 - 22163 + 22114 @@ -28014,7 +28049,7 @@ 1 2 - 9024167 + 9004230 @@ -28030,7 +28065,7 @@ 1 2 - 9024167 + 9004230 @@ -28040,15 +28075,15 @@ commentbinding - 3153021 + 3145674 id - 2495512 + 2490384 element - 3075612 + 3068526 @@ -28062,12 +28097,12 @@ 1 2 - 2412911 + 2408061 2 97 - 82601 + 82322 @@ -28083,12 +28118,12 @@ 1 2 - 2998202 + 2991378 2 3 - 77409 + 77148 @@ -28098,15 +28133,15 @@ exprconv - 7003263 + 7003750 converted - 7003263 + 7003750 conversion - 7003263 + 7003750 @@ -28120,7 +28155,7 @@ 1 2 - 7003263 + 7003750 @@ -28136,7 +28171,7 @@ 1 2 - 7003263 + 7003750 @@ -28146,30 +28181,30 @@ compgenerated - 8432513 + 8494343 id - 8432513 + 8494343 synthetic_destructor_call - 132767 + 133110 element - 103217 + 103484 i - 305 + 306 destructor_call - 117462 + 117766 @@ -28183,17 +28218,17 @@ 1 2 - 85325 + 85546 2 3 - 11801 + 11832 3 18 - 6089 + 6105 @@ -28209,17 +28244,17 @@ 1 2 - 85325 + 85546 2 3 - 11801 + 11832 3 18 - 6089 + 6105 @@ -28235,67 +28270,67 @@ 1 2 - 17 + 18 2 3 - 53 + 54 3 4 - 17 + 18 4 5 - 53 + 54 6 7 - 17 + 18 11 12 - 17 + 18 20 21 - 17 + 18 34 35 - 17 + 18 65 66 - 17 + 18 152 153 - 17 + 18 339 340 - 17 + 18 996 997 - 17 + 18 5746 5747 - 17 + 18 @@ -28311,67 +28346,67 @@ 1 2 - 17 + 18 2 3 - 53 + 54 3 4 - 17 + 18 4 5 - 53 + 54 6 7 - 17 + 18 11 12 - 17 + 18 20 21 - 17 + 18 34 35 - 17 + 18 65 66 - 17 + 18 151 152 - 17 + 18 338 339 - 17 + 18 995 996 - 17 + 18 4897 4898 - 17 + 18 @@ -28387,12 +28422,12 @@ 1 2 - 115450 + 115749 2 26 - 2011 + 2017 @@ -28408,7 +28443,7 @@ 1 2 - 117462 + 117766 @@ -28418,15 +28453,15 @@ namespaces - 12744 + 12701 id - 12744 + 12701 name - 10384 + 10349 @@ -28440,7 +28475,7 @@ 1 2 - 12744 + 12701 @@ -28456,17 +28491,17 @@ 1 2 - 8968 + 8937 2 3 - 472 + 470 3 4 - 944 + 940 @@ -28476,26 +28511,26 @@ namespace_inline - 1416 + 1411 id - 1416 + 1411 namespacembrs - 2473800 + 2463100 parentid - 10856 + 10819 memberid - 2473800 + 2463100 @@ -28509,57 +28544,57 @@ 1 2 - 1888 + 1881 2 3 - 944 + 940 3 4 - 472 + 470 4 5 - 944 + 940 5 7 - 944 + 940 7 8 - 944 + 940 8 12 - 944 + 940 17 30 - 944 + 940 43 47 - 944 + 940 52 143 - 944 + 940 - 247 - 4603 - 944 + 253 + 4592 + 940 @@ -28575,7 +28610,7 @@ 1 2 - 2473800 + 2463100 @@ -28585,19 +28620,19 @@ exprparents - 14151887 + 14152882 expr_id - 14151887 + 14152882 child_index - 14601 + 14602 parent_id - 9417337 + 9417999 @@ -28611,7 +28646,7 @@ 1 2 - 14151887 + 14152882 @@ -28627,7 +28662,7 @@ 1 2 - 14151887 + 14152882 @@ -28663,7 +28698,7 @@ 5 8 - 1209 + 1210 8 @@ -28677,7 +28712,7 @@ 56 - 389706 + 354077 369 @@ -28714,7 +28749,7 @@ 5 8 - 1209 + 1210 8 @@ -28728,7 +28763,7 @@ 56 - 389706 + 354077 369 @@ -28745,17 +28780,17 @@ 1 2 - 5388560 + 5388939 2 3 - 3692338 + 3692597 3 712 - 336438 + 336462 @@ -28771,17 +28806,17 @@ 1 2 - 5388560 + 5388939 2 3 - 3692338 + 3692597 3 712 - 336438 + 336462 @@ -28791,22 +28826,22 @@ expr_isload - 4944556 + 4981789 expr_id - 4944556 + 4981789 conversionkinds - 4220603 + 4220621 expr_id - 4220603 + 4220621 kind @@ -28824,7 +28859,7 @@ 1 2 - 4220603 + 4220621 @@ -28848,23 +28883,23 @@ 1 - 13430 - 13431 + 13442 + 13443 1 - 26288 - 26289 + 26289 + 26290 1 - 44458 - 44459 + 44470 + 44471 1 - 4131036 - 4131037 + 4131029 + 4131030 1 @@ -28875,15 +28910,15 @@ iscall - 3095893 + 3078157 caller - 3095893 + 3078157 kind - 53 + 54 @@ -28897,7 +28932,7 @@ 1 2 - 3095893 + 3078157 @@ -28911,19 +28946,19 @@ 12 - 1389 - 1390 - 17 + 1378 + 1379 + 18 2512 2513 - 17 + 18 - 168444 - 168445 - 17 + 167025 + 167026 + 18 @@ -28933,15 +28968,15 @@ numtemplatearguments - 553810 + 543303 expr_id - 553810 + 543303 num - 71 + 72 @@ -28955,7 +28990,7 @@ 1 2 - 553810 + 543303 @@ -28971,22 +29006,22 @@ 26 27 - 17 + 18 28 29 - 17 + 18 220 221 - 17 + 18 - 30556 - 30557 - 17 + 29893 + 29894 + 18 @@ -28996,15 +29031,15 @@ specialnamequalifyingelements - 472 + 470 id - 472 + 470 name - 472 + 470 @@ -29018,7 +29053,7 @@ 1 2 - 472 + 470 @@ -29034,7 +29069,7 @@ 1 2 - 472 + 470 @@ -29044,23 +29079,23 @@ namequalifiers - 1593457 + 1618961 id - 1593457 + 1618961 qualifiableelement - 1593457 + 1618961 qualifyingelement - 74044 + 79675 location - 273366 + 282719 @@ -29074,7 +29109,7 @@ 1 2 - 1593457 + 1618961 @@ -29090,7 +29125,7 @@ 1 2 - 1593457 + 1618961 @@ -29106,7 +29141,7 @@ 1 2 - 1593457 + 1618961 @@ -29122,7 +29157,7 @@ 1 2 - 1593457 + 1618961 @@ -29138,7 +29173,7 @@ 1 2 - 1593457 + 1618961 @@ -29154,7 +29189,7 @@ 1 2 - 1593457 + 1618961 @@ -29170,27 +29205,27 @@ 1 2 - 46848 + 45546 2 3 - 12322 + 17163 3 4 - 5802 + 6195 4 - 11 - 5622 + 8 + 6087 - 11 - 31104 - 3448 + 8 + 31227 + 4682 @@ -29206,27 +29241,27 @@ 1 2 - 46848 + 45546 2 3 - 12322 + 17163 3 4 - 5802 + 6195 4 - 11 - 5622 + 8 + 6087 - 11 - 31104 - 3448 + 8 + 31227 + 4682 @@ -29242,27 +29277,27 @@ 1 2 - 50477 + 49725 2 3 - 10885 + 15992 3 4 - 6089 + 6411 4 - 15 - 5604 + 9 + 6123 - 15 + 9 7095 - 987 + 1422 @@ -29278,32 +29313,32 @@ 1 2 - 85792 + 91742 2 3 - 24160 + 25646 3 4 - 41621 + 42179 4 6 - 12736 + 12895 6 7 - 89547 + 89869 7 2135 - 19508 + 20387 @@ -29319,32 +29354,32 @@ 1 2 - 85792 + 91742 2 3 - 24160 + 25646 3 4 - 41621 + 42179 4 6 - 12736 + 12895 6 7 - 89547 + 89869 7 2135 - 19508 + 20387 @@ -29360,22 +29395,22 @@ 1 2 - 118270 + 125168 2 3 - 50782 + 52354 3 4 - 95942 + 96622 4 152 - 8370 + 8572 @@ -29385,15 +29420,15 @@ varbind - 6005942 + 6006364 expr - 6005942 + 6006364 var - 765575 + 765629 @@ -29407,7 +29442,7 @@ 1 2 - 6005942 + 6006364 @@ -29423,52 +29458,52 @@ 1 2 - 125736 + 125745 2 3 - 137344 + 137353 3 4 - 105884 + 105891 4 5 - 84883 + 84889 5 6 - 61053 + 61057 6 7 - 47927 + 47931 7 9 - 59392 + 59396 9 13 - 59043 + 59047 13 28 - 58653 + 58657 28 5137 - 25655 + 25657 @@ -29478,15 +29513,15 @@ funbind - 3098283 + 3080553 expr - 3094672 + 3076933 fun - 512404 + 514037 @@ -29500,12 +29535,12 @@ 1 2 - 3091061 + 3073313 2 3 - 3610 + 3619 @@ -29521,32 +29556,32 @@ 1 2 - 298514 + 306546 2 3 - 85810 + 78793 3 4 - 36160 + 37226 4 7 - 42968 + 43475 7 - 35 - 38603 + 38 + 38703 - 35 + 38 4943 - 10346 + 9293 @@ -29556,19 +29591,19 @@ expr_allocator - 54190 + 46541 expr - 54190 + 46541 func - 104 + 105 form - 34 + 35 @@ -29582,7 +29617,7 @@ 1 2 - 54190 + 46541 @@ -29598,7 +29633,7 @@ 1 2 - 54190 + 46541 @@ -29614,17 +29649,17 @@ 1 2 - 34 + 35 585 586 - 34 + 35 - 963 - 964 - 34 + 735 + 736 + 35 @@ -29640,7 +29675,7 @@ 1 2 - 104 + 105 @@ -29654,9 +29689,9 @@ 12 - 1549 - 1550 - 34 + 1321 + 1322 + 35 @@ -29672,7 +29707,7 @@ 3 4 - 34 + 35 @@ -29682,19 +29717,19 @@ expr_deallocator - 62901 + 55314 expr - 62901 + 55314 func - 104 + 105 form - 69 + 70 @@ -29708,7 +29743,7 @@ 1 2 - 62901 + 55314 @@ -29724,7 +29759,7 @@ 1 2 - 62901 + 55314 @@ -29740,17 +29775,17 @@ 1 2 - 34 + 35 + + + 722 + 723 + 35 847 848 - 34 - - - 950 - 951 - 34 + 35 @@ -29766,7 +29801,7 @@ 1 2 - 104 + 105 @@ -29780,14 +29815,14 @@ 12 - 848 - 849 - 34 + 722 + 723 + 35 - 950 - 951 - 34 + 848 + 849 + 35 @@ -29803,12 +29838,12 @@ 1 2 - 34 + 35 2 3 - 34 + 35 @@ -29829,15 +29864,15 @@ expr_cond_guard - 654457 + 654502 cond - 654457 + 654502 guard - 654457 + 654502 @@ -29851,7 +29886,7 @@ 1 2 - 654457 + 654502 @@ -29867,7 +29902,7 @@ 1 2 - 654457 + 654502 @@ -29877,15 +29912,15 @@ expr_cond_true - 654455 + 654499 cond - 654455 + 654499 true - 654455 + 654499 @@ -29899,7 +29934,7 @@ 1 2 - 654455 + 654499 @@ -29915,7 +29950,7 @@ 1 2 - 654455 + 654499 @@ -29925,15 +29960,15 @@ expr_cond_false - 654457 + 654502 cond - 654457 + 654502 false - 654457 + 654502 @@ -29947,7 +29982,7 @@ 1 2 - 654457 + 654502 @@ -29963,7 +29998,7 @@ 1 2 - 654457 + 654502 @@ -29973,15 +30008,15 @@ values - 10645398 + 10646146 id - 10645398 + 10646146 str - 86632 + 86639 @@ -29995,7 +30030,7 @@ 1 2 - 10645398 + 10646146 @@ -30011,7 +30046,7 @@ 1 2 - 58704 + 58708 2 @@ -30021,12 +30056,12 @@ 3 6 - 6746 + 6747 6 62 - 6512 + 6513 62 @@ -30041,15 +30076,15 @@ valuetext - 4756700 + 4756729 id - 4756700 + 4756729 text - 703927 + 703924 @@ -30063,7 +30098,7 @@ 1 2 - 4756700 + 4756729 @@ -30079,7 +30114,7 @@ 1 2 - 527530 + 527529 2 @@ -30089,7 +30124,7 @@ 3 7 - 56761 + 56759 7 @@ -30104,15 +30139,15 @@ valuebind - 11082271 + 11083050 val - 10645398 + 10646146 expr - 11082271 + 11083050 @@ -30126,12 +30161,12 @@ 1 2 - 10231303 + 10232022 2 7 - 414094 + 414124 @@ -30147,7 +30182,7 @@ 1 2 - 11082271 + 11083050 @@ -30157,15 +30192,15 @@ fieldoffsets - 1050009 + 1050083 id - 1050009 + 1050083 byteoffset - 22591 + 22593 bitoffset @@ -30183,7 +30218,7 @@ 1 2 - 1050009 + 1050083 @@ -30199,7 +30234,7 @@ 1 2 - 1050009 + 1050083 @@ -30215,7 +30250,7 @@ 1 2 - 12966 + 12967 2 @@ -30261,7 +30296,7 @@ 1 2 - 21915 + 21917 2 @@ -30358,19 +30393,19 @@ bitfield - 21007 + 20961 id - 21007 + 20961 bits - 2625 + 2620 declared_bits - 2625 + 2620 @@ -30384,7 +30419,7 @@ 1 2 - 21007 + 20961 @@ -30400,7 +30435,7 @@ 1 2 - 21007 + 20961 @@ -30416,42 +30451,42 @@ 1 2 - 735 + 733 2 3 - 630 + 628 3 4 - 210 + 209 4 5 - 210 + 209 5 6 - 210 + 209 6 8 - 210 + 209 8 11 - 210 + 209 12 115 - 210 + 209 @@ -30467,7 +30502,7 @@ 1 2 - 2625 + 2620 @@ -30483,42 +30518,42 @@ 1 2 - 735 + 733 2 3 - 630 + 628 3 4 - 210 + 209 4 5 - 210 + 209 5 6 - 210 + 209 6 8 - 210 + 209 8 11 - 210 + 209 12 115 - 210 + 209 @@ -30534,7 +30569,7 @@ 1 2 - 2625 + 2620 @@ -30544,23 +30579,23 @@ initialisers - 1736804 + 1731850 init - 1736804 + 1731850 var - 719782 + 717751 expr - 1736804 + 1731850 location - 391526 + 390432 @@ -30574,7 +30609,7 @@ 1 2 - 1736804 + 1731850 @@ -30590,7 +30625,7 @@ 1 2 - 1736804 + 1731850 @@ -30606,7 +30641,7 @@ 1 2 - 1736804 + 1731850 @@ -30622,17 +30657,17 @@ 1 2 - 631170 + 629393 2 16 - 31717 + 31625 16 25 - 56851 + 56687 25 @@ -30653,17 +30688,17 @@ 1 2 - 631170 + 629393 2 16 - 31717 + 31625 16 25 - 56851 + 56687 25 @@ -30684,7 +30719,7 @@ 1 2 - 719700 + 717669 2 @@ -30705,7 +30740,7 @@ 1 2 - 1736804 + 1731850 @@ -30721,7 +30756,7 @@ 1 2 - 1736804 + 1731850 @@ -30737,7 +30772,7 @@ 1 2 - 1736804 + 1731850 @@ -30753,22 +30788,22 @@ 1 2 - 318848 + 317950 2 3 - 23904 + 23835 3 15 - 30865 + 30789 15 - 111462 - 17907 + 111459 + 17856 @@ -30784,17 +30819,17 @@ 1 2 - 341914 + 340950 2 4 - 35670 + 35580 4 - 12741 - 13941 + 12738 + 13901 @@ -30810,22 +30845,22 @@ 1 2 - 318848 + 317950 2 3 - 23904 + 23835 3 15 - 30865 + 30789 15 - 111462 - 17907 + 111459 + 17856 @@ -30835,15 +30870,15 @@ expr_ancestor - 121360 + 121674 exp - 121360 + 121674 ancestor - 84661 + 84880 @@ -30857,7 +30892,7 @@ 1 2 - 121360 + 121674 @@ -30873,22 +30908,22 @@ 1 2 - 61219 + 61377 2 3 - 16741 + 16785 3 8 - 6466 + 6483 8 18 - 233 + 234 @@ -30898,19 +30933,19 @@ exprs - 18298854 + 18300140 id - 18298854 + 18300140 kind - 8670 + 3382 location - 7747846 + 3561673 @@ -30924,7 +30959,7 @@ 1 2 - 18298854 + 18300140 @@ -30940,7 +30975,7 @@ 1 2 - 18298854 + 18300140 @@ -30955,68 +30990,68 @@ 1 - 6 - 632 + 5 + 281 - 6 - 12 - 632 + 5 + 14 + 211 - 18 - 28 - 541 + 14 + 38 + 281 - 29 - 45 - 722 + 42 + 66 + 281 - 45 - 88 - 722 + 82 + 135 + 281 - 89 - 122 - 722 + 141 + 334 + 281 - 152 - 234 - 722 + 338 + 509 + 281 - 241 - 441 - 722 + 563 + 830 + 281 - 504 - 778 - 722 + 831 + 1183 + 281 - 802 - 1049 - 722 + 1184 + 2071 + 281 - 1117 - 2286 - 722 + 2627 + 5700 + 281 - 2424 - 9743 - 722 + 6591 + 63491 + 281 - 22722 - 53144 - 361 + 78915 + 109590 + 70 @@ -31031,68 +31066,68 @@ 1 + 2 + 281 + + + 2 3 - 722 + 176 3 - 4 - 541 + 6 + 281 - 4 + 6 13 - 722 + 281 - 13 - 24 - 722 + 14 + 26 + 281 - 24 - 37 - 722 + 28 + 62 + 246 - 41 - 101 - 722 + 63 + 83 + 281 - 102 - 175 - 722 + 91 + 183 + 281 - 180 - 279 - 722 + 206 + 342 + 281 - 281 - 499 - 722 + 353 + 448 + 281 - 565 - 774 - 722 + 468 + 1018 + 281 - 813 - 1643 - 722 + 1051 + 14609 + 281 - 1728 - 13946 - 722 - - - 15037 - 33170 - 180 + 16974 + 32757 + 140 @@ -31108,22 +31143,32 @@ 1 2 - 5161708 + 1936933 2 3 - 1378731 + 816932 3 - 5 - 662723 + 4 + 247260 - 5 - 14777 - 544682 + 4 + 8 + 280872 + + + 8 + 136 + 267131 + + + 136 + 54140 + 12542 @@ -31139,17 +31184,22 @@ 1 2 - 5999730 + 2363808 2 3 - 1427591 + 873691 3 - 26 - 320523 + 6 + 307261 + + + 6 + 25 + 16911 @@ -31159,19 +31209,19 @@ expr_types - 18356354 + 18357789 id - 18298854 + 18300140 typeid - 806338 + 829282 value_category - 53 + 54 @@ -31185,12 +31235,12 @@ 1 2 - 18241425 + 18242562 2 5 - 57428 + 57577 @@ -31206,7 +31256,7 @@ 1 2 - 18298854 + 18300140 @@ -31222,42 +31272,42 @@ 1 2 - 278288 + 293470 2 3 - 160556 + 160720 3 4 - 69787 + 69824 4 5 - 57051 + 60801 5 7 - 62027 + 66996 7 12 - 67236 + 65321 12 35 - 61758 + 62638 35 - 78725 - 49632 + 78674 + 49509 @@ -31273,17 +31323,17 @@ 1 2 - 695684 + 716180 2 3 - 100271 + 102314 3 4 - 10382 + 10787 @@ -31297,19 +31347,19 @@ 12 - 11948 - 11949 - 17 + 11828 + 11829 + 18 - 253514 - 253515 - 17 + 253738 + 253739 + 18 - 753215 - 753216 - 17 + 750551 + 750552 + 18 @@ -31323,19 +31373,19 @@ 12 - 1415 - 1416 - 17 + 1446 + 1447 + 18 - 11760 - 11761 - 17 + 11978 + 11979 + 18 - 38451 - 38452 - 17 + 39501 + 39502 + 18 @@ -31345,15 +31395,15 @@ new_allocated_type - 55240 + 47598 expr - 55240 + 47598 type_id - 27952 + 28150 @@ -31367,7 +31417,7 @@ 1 2 - 55240 + 47598 @@ -31383,22 +31433,17 @@ 1 2 - 9095 + 11767 2 3 - 15987 + 14903 3 - 6 - 2134 - - - 6 - 28 - 734 + 19 + 1479 @@ -31408,15 +31453,15 @@ new_array_allocated_type - 5113 + 5099 expr - 5113 + 5099 type_id - 2200 + 2194 @@ -31430,7 +31475,7 @@ 1 2 - 5113 + 5099 @@ -31451,12 +31496,12 @@ 2 3 - 1948 + 1942 3 7 - 170 + 169 8 @@ -32018,15 +32063,15 @@ condition_decl_bind - 38495 + 38595 expr - 38495 + 38595 decl - 38495 + 38595 @@ -32040,7 +32085,7 @@ 1 2 - 38495 + 38595 @@ -32056,7 +32101,7 @@ 1 2 - 38495 + 38595 @@ -32066,15 +32111,15 @@ typeid_bind - 36173 + 36430 expr - 36173 + 36430 type_id - 16267 + 16383 @@ -32088,7 +32133,7 @@ 1 2 - 36173 + 36430 @@ -32104,12 +32149,12 @@ 1 2 - 15847 + 15960 3 328 - 419 + 422 @@ -32119,15 +32164,15 @@ uuidof_bind - 20051 + 19994 expr - 20051 + 19994 type_id - 19856 + 19799 @@ -32141,7 +32186,7 @@ 1 2 - 20051 + 19994 @@ -32157,7 +32202,7 @@ 1 2 - 19692 + 19635 2 @@ -32172,15 +32217,15 @@ sizeof_bind - 191840 + 191854 expr - 191840 + 191854 type_id - 8193 + 8194 @@ -32194,7 +32239,7 @@ 1 2 - 191840 + 191854 @@ -32303,19 +32348,19 @@ lambdas - 21712 + 21639 expr - 21712 + 21639 default_capture - 472 + 470 has_explicit_return_type - 472 + 470 @@ -32329,7 +32374,7 @@ 1 2 - 21712 + 21639 @@ -32345,7 +32390,7 @@ 1 2 - 21712 + 21639 @@ -32361,7 +32406,7 @@ 46 47 - 472 + 470 @@ -32377,7 +32422,7 @@ 1 2 - 472 + 470 @@ -32393,7 +32438,7 @@ 46 47 - 472 + 470 @@ -32409,7 +32454,7 @@ 1 2 - 472 + 470 @@ -32419,35 +32464,35 @@ lambda_capture - 28320 + 28224 id - 28320 + 28224 lambda - 20768 + 20698 index - 944 + 940 field - 28320 + 28224 captured_by_reference - 472 + 470 is_implicit - 472 + 470 location - 2832 + 2822 @@ -32461,7 +32506,7 @@ 1 2 - 28320 + 28224 @@ -32477,7 +32522,7 @@ 1 2 - 28320 + 28224 @@ -32493,7 +32538,7 @@ 1 2 - 28320 + 28224 @@ -32509,7 +32554,7 @@ 1 2 - 28320 + 28224 @@ -32525,7 +32570,7 @@ 1 2 - 28320 + 28224 @@ -32541,7 +32586,7 @@ 1 2 - 28320 + 28224 @@ -32557,12 +32602,12 @@ 1 2 - 13216 + 13171 2 3 - 7552 + 7526 @@ -32578,12 +32623,12 @@ 1 2 - 13216 + 13171 2 3 - 7552 + 7526 @@ -32599,12 +32644,12 @@ 1 2 - 13216 + 13171 2 3 - 7552 + 7526 @@ -32620,7 +32665,7 @@ 1 2 - 20768 + 20698 @@ -32636,7 +32681,7 @@ 1 2 - 20768 + 20698 @@ -32652,12 +32697,12 @@ 1 2 - 13216 + 13171 2 3 - 7552 + 7526 @@ -32673,12 +32718,12 @@ 16 17 - 472 + 470 44 45 - 472 + 470 @@ -32694,12 +32739,12 @@ 16 17 - 472 + 470 44 45 - 472 + 470 @@ -32715,12 +32760,12 @@ 16 17 - 472 + 470 44 45 - 472 + 470 @@ -32736,7 +32781,7 @@ 1 2 - 944 + 940 @@ -32752,7 +32797,7 @@ 1 2 - 944 + 940 @@ -32768,12 +32813,12 @@ 2 3 - 472 + 470 4 5 - 472 + 470 @@ -32789,7 +32834,7 @@ 1 2 - 28320 + 28224 @@ -32805,7 +32850,7 @@ 1 2 - 28320 + 28224 @@ -32821,7 +32866,7 @@ 1 2 - 28320 + 28224 @@ -32837,7 +32882,7 @@ 1 2 - 28320 + 28224 @@ -32853,7 +32898,7 @@ 1 2 - 28320 + 28224 @@ -32869,7 +32914,7 @@ 1 2 - 28320 + 28224 @@ -32885,7 +32930,7 @@ 60 61 - 472 + 470 @@ -32901,7 +32946,7 @@ 44 45 - 472 + 470 @@ -32917,7 +32962,7 @@ 2 3 - 472 + 470 @@ -32933,7 +32978,7 @@ 60 61 - 472 + 470 @@ -32949,7 +32994,7 @@ 1 2 - 472 + 470 @@ -32965,7 +33010,7 @@ 6 7 - 472 + 470 @@ -32981,7 +33026,7 @@ 60 61 - 472 + 470 @@ -32997,7 +33042,7 @@ 44 45 - 472 + 470 @@ -33013,7 +33058,7 @@ 2 3 - 472 + 470 @@ -33029,7 +33074,7 @@ 60 61 - 472 + 470 @@ -33045,7 +33090,7 @@ 1 2 - 472 + 470 @@ -33061,7 +33106,7 @@ 6 7 - 472 + 470 @@ -33077,12 +33122,12 @@ 8 9 - 1888 + 1881 14 15 - 944 + 940 @@ -33098,12 +33143,12 @@ 8 9 - 1888 + 1881 14 15 - 944 + 940 @@ -33119,7 +33164,7 @@ 1 2 - 2832 + 2822 @@ -33135,12 +33180,12 @@ 8 9 - 1888 + 1881 14 15 - 944 + 940 @@ -33156,7 +33201,7 @@ 1 2 - 2832 + 2822 @@ -33172,7 +33217,7 @@ 1 2 - 2832 + 2822 @@ -33298,19 +33343,19 @@ stmts - 4689495 + 4659955 id - 4689495 + 4659955 kind - 1995 + 1991 location - 2293751 + 2288683 @@ -33324,7 +33369,7 @@ 1 2 - 4689495 + 4659955 @@ -33340,7 +33385,7 @@ 1 2 - 4689495 + 4659955 @@ -33356,97 +33401,97 @@ 1 2 - 105 + 104 18 19 - 105 + 104 22 23 - 105 + 104 46 47 - 105 + 104 75 76 - 105 + 104 83 84 - 105 + 104 102 103 - 105 + 104 154 155 - 105 + 104 242 243 - 105 + 104 284 285 - 105 + 104 383 384 - 105 + 104 418 419 - 105 + 104 501 502 - 105 + 104 1324 1325 - 105 + 104 2629 2630 - 105 + 104 - 4606 - 4607 - 105 + 4609 + 4610 + 104 - 8935 - 8936 - 105 + 8749 + 8750 + 104 11547 11548 - 105 + 104 13275 13276 - 105 + 104 @@ -33462,97 +33507,97 @@ 1 2 - 105 + 104 8 9 - 105 + 104 18 19 - 105 + 104 45 46 - 105 + 104 50 51 - 105 + 104 56 57 - 105 + 104 74 75 - 105 + 104 88 89 - 105 + 104 101 102 - 105 + 104 128 129 - 105 + 104 209 210 - 105 + 104 252 253 - 105 + 104 368 369 - 105 + 104 641 642 - 105 + 104 1742 1743 - 105 + 104 - 2183 - 2184 - 105 + 2186 + 2187 + 104 - 4210 - 4211 - 105 + 4191 + 4192 + 104 6065 6066 - 105 + 104 6529 6530 - 105 + 104 @@ -33568,22 +33613,22 @@ 1 2 - 1897016 + 1893663 2 4 - 177201 + 176600 4 12 - 176466 + 175762 12 684 - 43066 + 42656 @@ -33599,12 +33644,12 @@ 1 2 - 2234613 + 2231353 2 8 - 59137 + 57329 @@ -33709,16 +33754,64 @@ - if_then - 723123 + if_initialization + 314 if_stmt - 723123 + 314 + + + init_id + 314 + + + + + if_stmt + init_id + + + 12 + + + 1 + 2 + 314 + + + + + + + init_id + if_stmt + + + 12 + + + 1 + 2 + 314 + + + + + + + + + if_then + 723174 + + + if_stmt + 723174 then_id - 723123 + 723174 @@ -33732,7 +33825,7 @@ 1 2 - 723123 + 723174 @@ -33748,7 +33841,7 @@ 1 2 - 723123 + 723174 @@ -33758,15 +33851,15 @@ if_else - 183959 + 183972 if_stmt - 183959 + 183972 else_id - 183959 + 183972 @@ -33780,7 +33873,7 @@ 1 2 - 183959 + 183972 @@ -33796,7 +33889,55 @@ 1 2 - 183959 + 183972 + + + + + + + + + constexpr_if_initialization + 1 + + + constexpr_if_stmt + 1 + + + init_id + 1 + + + + + constexpr_if_stmt + init_id + + + 12 + + + 1 + 2 + 1 + + + + + + + init_id + constexpr_if_stmt + + + 12 + + + 1 + 2 + 1 @@ -33806,15 +33947,15 @@ constexpr_if_then - 52624 + 52508 constexpr_if_stmt - 52624 + 52508 then_id - 52624 + 52508 @@ -33828,7 +33969,7 @@ 1 2 - 52624 + 52508 @@ -33844,7 +33985,7 @@ 1 2 - 52624 + 52508 @@ -33854,15 +33995,15 @@ constexpr_if_else - 30986 + 30918 constexpr_if_stmt - 30986 + 30918 else_id - 30986 + 30918 @@ -33876,7 +34017,7 @@ 1 2 - 30986 + 30918 @@ -33892,7 +34033,7 @@ 1 2 - 30986 + 30918 @@ -33902,15 +34043,15 @@ while_body - 30265 + 30207 while_stmt - 30265 + 30207 body_id - 30265 + 30207 @@ -33924,7 +34065,7 @@ 1 2 - 30265 + 30207 @@ -33940,7 +34081,7 @@ 1 2 - 30265 + 30207 @@ -33950,15 +34091,15 @@ do_body - 148593 + 148604 do_stmt - 148593 + 148604 body_id - 148593 + 148604 @@ -33972,7 +34113,7 @@ 1 2 - 148593 + 148604 @@ -33988,7 +34129,55 @@ 1 2 - 148593 + 148604 + + + + + + + + + switch_initialization + 4 + + + switch_stmt + 4 + + + init_id + 4 + + + + + switch_stmt + init_id + + + 12 + + + 1 + 2 + 4 + + + + + + + init_id + switch_stmt + + + 12 + + + 1 + 2 + 4 @@ -33998,19 +34187,19 @@ switch_case - 190914 + 191408 switch_stmt - 10275 + 10301 index - 4418 + 4430 case_id - 190914 + 191408 @@ -34024,57 +34213,57 @@ 2 3 - 53 + 54 3 4 - 2263 + 2269 4 5 - 1652 + 1656 5 6 - 1005 + 1008 6 7 - 754 + 756 7 9 - 718 + 720 9 10 - 970 + 972 10 11 - 323 + 324 11 14 - 862 + 864 14 31 - 826 + 828 36 247 - 844 + 846 @@ -34090,57 +34279,57 @@ 2 3 - 53 + 54 3 4 - 2263 + 2269 4 5 - 1652 + 1656 5 6 - 1005 + 1008 6 7 - 754 + 756 7 9 - 718 + 720 9 10 - 970 + 972 10 11 - 323 + 324 11 14 - 862 + 864 14 31 - 826 + 828 36 247 - 844 + 846 @@ -34156,32 +34345,32 @@ 14 15 - 1167 + 1170 18 19 - 538 + 540 32 33 - 1904 + 1909 33 62 - 377 + 378 66 296 - 341 + 342 351 573 - 89 + 90 @@ -34197,32 +34386,32 @@ 14 15 - 1167 + 1170 18 19 - 538 + 540 32 33 - 1904 + 1909 33 62 - 377 + 378 66 296 - 341 + 342 351 573 - 89 + 90 @@ -34238,7 +34427,7 @@ 1 2 - 190914 + 191408 @@ -34254,7 +34443,7 @@ 1 2 - 190914 + 191408 @@ -34264,15 +34453,15 @@ switch_body - 20900 + 20901 switch_stmt - 20900 + 20901 body_id - 20900 + 20901 @@ -34286,7 +34475,7 @@ 1 2 - 20900 + 20901 @@ -34302,7 +34491,7 @@ 1 2 - 20900 + 20901 @@ -34312,15 +34501,15 @@ for_initialization - 53198 + 53202 for_stmt - 53198 + 53202 init_id - 53198 + 53202 @@ -34334,7 +34523,7 @@ 1 2 - 53198 + 53202 @@ -34350,7 +34539,7 @@ 1 2 - 53198 + 53202 @@ -34360,15 +34549,15 @@ for_condition - 55454 + 55458 for_stmt - 55454 + 55458 condition_id - 55454 + 55458 @@ -34382,7 +34571,7 @@ 1 2 - 55454 + 55458 @@ -34398,7 +34587,7 @@ 1 2 - 55454 + 55458 @@ -34408,15 +34597,15 @@ for_update - 53301 + 53304 for_stmt - 53301 + 53304 update_id - 53301 + 53304 @@ -34430,7 +34619,7 @@ 1 2 - 53301 + 53304 @@ -34446,7 +34635,7 @@ 1 2 - 53301 + 53304 @@ -34456,15 +34645,15 @@ for_body - 61319 + 61324 for_stmt - 61319 + 61324 body_id - 61319 + 61324 @@ -34478,7 +34667,7 @@ 1 2 - 61319 + 61324 @@ -34494,7 +34683,7 @@ 1 2 - 61319 + 61324 @@ -34504,19 +34693,19 @@ stmtparents - 4064694 + 4052307 id - 4064694 + 4052307 index - 12245 + 12210 parent - 1724432 + 1719451 @@ -34530,7 +34719,7 @@ 1 2 - 4064694 + 4052307 @@ -34546,7 +34735,7 @@ 1 2 - 4064694 + 4052307 @@ -34562,12 +34751,12 @@ 1 2 - 4022 + 4011 2 3 - 1002 + 999 3 @@ -34577,37 +34766,37 @@ 4 5 - 1557 + 1553 7 8 - 1021 + 1018 8 12 - 794 + 792 12 29 - 1078 + 1075 29 38 - 920 + 917 41 77 - 926 + 924 77 - 196938 - 699 + 196934 + 697 @@ -34623,12 +34812,12 @@ 1 2 - 4022 + 4011 2 3 - 1002 + 999 3 @@ -34638,37 +34827,37 @@ 4 5 - 1557 + 1553 7 8 - 1021 + 1018 8 12 - 794 + 792 12 29 - 1078 + 1075 29 38 - 920 + 917 41 77 - 926 + 924 77 - 196938 - 699 + 196934 + 697 @@ -34684,32 +34873,32 @@ 1 2 - 989567 + 987314 2 3 - 374640 + 372959 3 4 - 106047 + 105742 4 6 - 111564 + 111231 6 17 - 130216 + 129842 17 1943 - 12396 + 12361 @@ -34725,32 +34914,32 @@ 1 2 - 989567 + 987314 2 3 - 374640 + 372959 3 4 - 106047 + 105742 4 6 - 111564 + 111231 6 17 - 130216 + 129842 17 1943 - 12396 + 12361 @@ -34760,22 +34949,22 @@ ishandler - 59279 + 59432 block - 59279 + 59432 stmt_decl_bind - 585681 + 585632 stmt - 545527 + 545482 num @@ -34783,7 +34972,7 @@ decl - 585576 + 585527 @@ -34797,12 +34986,12 @@ 1 2 - 524646 + 524602 2 19 - 20881 + 20879 @@ -34818,12 +35007,12 @@ 1 2 - 524646 + 524602 2 19 - 20881 + 20879 @@ -35021,7 +35210,7 @@ 1 2 - 585538 + 585489 2 @@ -35042,7 +35231,7 @@ 1 2 - 585576 + 585527 @@ -35052,11 +35241,11 @@ stmt_decl_entry_bind - 528084 + 528040 stmt - 488233 + 488193 num @@ -35064,7 +35253,7 @@ decl_entry - 528025 + 527981 @@ -35078,12 +35267,12 @@ 1 2 - 467616 + 467578 2 19 - 20616 + 20615 @@ -35099,12 +35288,12 @@ 1 2 - 467616 + 467578 2 19 - 20616 + 20615 @@ -35302,7 +35491,7 @@ 1 2 - 528004 + 527960 3 @@ -35323,7 +35512,7 @@ 1 2 - 528025 + 527981 @@ -35333,15 +35522,15 @@ blockscope - 1442932 + 1438063 block - 1442932 + 1438063 enclosing - 1326345 + 1321870 @@ -35355,7 +35544,7 @@ 1 2 - 1442932 + 1438063 @@ -35371,12 +35560,12 @@ 1 2 - 1260264 + 1256011 2 13 - 66081 + 65858 @@ -35386,19 +35575,19 @@ jumpinfo - 253977 + 253995 id - 253977 + 253995 str - 21151 + 21152 target - 53042 + 53046 @@ -35412,7 +35601,7 @@ 1 2 - 253977 + 253995 @@ -35428,7 +35617,7 @@ 1 2 - 253977 + 253995 @@ -35444,7 +35633,7 @@ 2 3 - 9874 + 9875 3 @@ -35490,7 +35679,7 @@ 1 2 - 16716 + 16717 2 @@ -35526,12 +35715,12 @@ 2 3 - 26426 + 26428 3 4 - 12896 + 12897 4 @@ -35541,7 +35730,7 @@ 5 8 - 4690 + 4691 8 @@ -35562,7 +35751,7 @@ 1 2 - 53042 + 53046 @@ -35572,19 +35761,19 @@ preprocdirects - 4447274 + 4437448 id - 4447274 + 4437448 kind - 1050 + 1048 location - 4444753 + 4434933 @@ -35598,7 +35787,7 @@ 1 2 - 4447274 + 4437448 @@ -35614,7 +35803,7 @@ 1 2 - 4447274 + 4437448 @@ -35630,52 +35819,52 @@ 121 122 - 105 + 104 693 694 - 105 + 104 794 795 - 105 + 104 917 918 - 105 + 104 1697 1698 - 105 + 104 1785 1786 - 105 + 104 2983 2984 - 105 + 104 3799 3800 - 105 + 104 6290 6291 - 105 + 104 23260 23261 - 105 + 104 @@ -35691,52 +35880,52 @@ 121 122 - 105 + 104 693 694 - 105 + 104 794 795 - 105 + 104 917 918 - 105 + 104 1697 1698 - 105 + 104 1785 1786 - 105 + 104 2983 2984 - 105 + 104 3799 3800 - 105 + 104 6290 6291 - 105 + 104 23236 23237 - 105 + 104 @@ -35752,12 +35941,12 @@ 1 2 - 4444648 + 4434828 25 26 - 105 + 104 @@ -35773,7 +35962,7 @@ 1 2 - 4444753 + 4434933 @@ -35783,15 +35972,15 @@ preprocpair - 1443876 + 1442296 begin - 1206927 + 1206147 elseelifend - 1443876 + 1442296 @@ -35805,17 +35994,17 @@ 1 2 - 986027 + 985992 2 3 - 210516 + 209805 3 11 - 10384 + 10349 @@ -35831,7 +36020,7 @@ 1 2 - 1443876 + 1442296 @@ -35841,41 +36030,41 @@ preproctrue - 784479 + 782302 branch - 784479 + 782302 preprocfalse - 325686 + 327409 branch - 325686 + 327409 preproctext - 3585423 + 3577502 id - 3585423 + 3577502 head - 2599941 + 2594197 body - 1520449 + 1517194 @@ -35889,7 +36078,7 @@ 1 2 - 3585423 + 3577502 @@ -35905,7 +36094,7 @@ 1 2 - 3585423 + 3577502 @@ -35921,12 +36110,12 @@ 1 2 - 2452360 + 2446942 2 740 - 147580 + 147254 @@ -35942,12 +36131,12 @@ 1 2 - 2537548 + 2531941 2 5 - 62393 + 62255 @@ -35963,17 +36152,17 @@ 1 2 - 1376334 + 1373398 2 6 - 114073 + 113821 6 - 11582 - 30041 + 11581 + 29974 @@ -35989,17 +36178,17 @@ 1 2 - 1379380 + 1376438 2 7 - 114388 + 114135 7 - 2959 - 26680 + 2958 + 26621 @@ -36009,15 +36198,15 @@ includes - 316718 + 315649 id - 316718 + 315649 included - 118474 + 118074 @@ -36031,7 +36220,7 @@ 1 2 - 316718 + 315649 @@ -36047,32 +36236,32 @@ 1 2 - 61833 + 61624 2 3 - 22184 + 22109 3 4 - 12744 + 12701 4 6 - 10384 + 10349 6 14 - 8968 + 8937 14 47 - 2360 + 2352 @@ -36130,15 +36319,15 @@ link_parent - 40018704 + 40143068 element - 5094359 + 5115983 link_target - 349 + 352 @@ -36152,17 +36341,17 @@ 1 2 - 694015 + 701934 2 9 - 43135 + 44146 9 10 - 4357208 + 4369903 @@ -36178,52 +36367,52 @@ 3 4 - 34 + 35 - 124724 - 124725 - 34 + 124207 + 124208 + 35 - 124828 - 124829 - 34 + 124311 + 124312 + 35 - 124926 - 124927 - 34 + 124409 + 124410 + 35 - 124964 - 124965 - 34 + 124447 + 124448 + 35 - 124978 - 124979 - 34 + 124454 + 124455 + 35 - 124980 - 124981 - 34 + 124463 + 124464 + 35 - 126863 - 126864 - 34 + 126339 + 126340 + 35 - 132946 - 132947 - 34 + 132460 + 132461 + 35 - 134697 - 134698 - 34 + 134288 + 134289 + 35 diff --git a/cpp/ql/lib/upgrades/e9a518baf14f4322ac243578a8e1391386ff030f/exprparents.ql b/cpp/ql/lib/upgrades/e9a518baf14f4322ac243578a8e1391386ff030f/exprparents.ql new file mode 100644 index 00000000000..ca800c8e311 --- /dev/null +++ b/cpp/ql/lib/upgrades/e9a518baf14f4322ac243578a8e1391386ff030f/exprparents.ql @@ -0,0 +1,21 @@ +class Element extends @element { + string toString() { none() } +} + +class Expr extends @expr { + string toString() { none() } +} + +class Stmt extends @stmt { + string toString() { none() } +} + +predicate isStmtWithInitializer(Stmt stmt) { + exists(int kind | stmts(stmt, kind, _) | kind = 2 or kind = 11 or kind = 35) +} + +from Expr child, int index, int index_new, Element parent +where + exprparents(child, index, parent) and + if isStmtWithInitializer(parent) then index_new = index + 1 else index_new = index +select child, index_new, parent diff --git a/cpp/ql/lib/upgrades/e9a518baf14f4322ac243578a8e1391386ff030f/old.dbscheme b/cpp/ql/lib/upgrades/e9a518baf14f4322ac243578a8e1391386ff030f/old.dbscheme new file mode 100644 index 00000000000..e9a518baf14 --- /dev/null +++ b/cpp/ql/lib/upgrades/e9a518baf14f4322ac243578a8e1391386ff030f/old.dbscheme @@ -0,0 +1,2096 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +/** If `function` is a coroutine, then this gives the + std::experimental::resumable_traits instance associated with it, + and the variables representing the `handle` and `promise` for it. */ +coroutine( + unique int function: @function ref, + int traits: @type ref, + int handle: @variable ref, + int promise: @variable ref +); + +/** The `new` function used for allocating the coroutine state, if any. */ +coroutine_new( + unique int function: @function ref, + int new: @function ref +); + +/** The `delete` function used for deallocating the coroutine state, if any. */ +coroutine_delete( + unique int function: @function ref, + int delete: @function ref +); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + +member_function_this_type(unique int id: @function ref, int this_type: @type ref); + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) +is_structured_binding(unique int id: @variable ref); + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref, + int enclosing : @element ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +/** + * An instance of the C++11 `decltype` operator. For example: + * ``` + * int a; + * decltype(1+a) b; + * ``` + * Here `expr` is `1+a`. + * + * Sometimes an additional pair of parentheses around the expression + * would change the semantics of this decltype, e.g. + * ``` + * struct A { double x; }; + * const A* a = new A(); + * decltype( a->x ); // type is double + * decltype((a->x)); // type is const double& + * ``` + * (Please consult the C++11 standard for more details). + * `parentheses_would_change_meaning` is `true` iff that is the case. + */ +#keyset[id, expr] +decltypes( + int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + | @temp_init + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + | @co_await + | @co_yield + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +| 327 = @co_await +| 328 = @co_yield +| 329 = @temp_init +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +| 37 = @stmt_co_return +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/ql/lib/upgrades/e9a518baf14f4322ac243578a8e1391386ff030f/semmlecode.cpp.dbscheme b/cpp/ql/lib/upgrades/e9a518baf14f4322ac243578a8e1391386ff030f/semmlecode.cpp.dbscheme new file mode 100644 index 00000000000..cf72c8898d1 --- /dev/null +++ b/cpp/ql/lib/upgrades/e9a518baf14f4322ac243578a8e1391386ff030f/semmlecode.cpp.dbscheme @@ -0,0 +1,2111 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +/** If `function` is a coroutine, then this gives the + std::experimental::resumable_traits instance associated with it, + and the variables representing the `handle` and `promise` for it. */ +coroutine( + unique int function: @function ref, + int traits: @type ref, + int handle: @variable ref, + int promise: @variable ref +); + +/** The `new` function used for allocating the coroutine state, if any. */ +coroutine_new( + unique int function: @function ref, + int new: @function ref +); + +/** The `delete` function used for deallocating the coroutine state, if any. */ +coroutine_delete( + unique int function: @function ref, + int delete: @function ref +); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + +member_function_this_type(unique int id: @function ref, int this_type: @type ref); + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) +is_structured_binding(unique int id: @variable ref); + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref, + int enclosing : @element ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +/** + * An instance of the C++11 `decltype` operator. For example: + * ``` + * int a; + * decltype(1+a) b; + * ``` + * Here `expr` is `1+a`. + * + * Sometimes an additional pair of parentheses around the expression + * would change the semantics of this decltype, e.g. + * ``` + * struct A { double x; }; + * const A* a = new A(); + * decltype( a->x ); // type is double + * decltype((a->x)); // type is const double& + * ``` + * (Please consult the C++11 standard for more details). + * `parentheses_would_change_meaning` is `true` iff that is the case. + */ +#keyset[id, expr] +decltypes( + int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + | @temp_init + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + | @co_await + | @co_yield + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +| 327 = @co_await +| 328 = @co_yield +| 329 = @temp_init +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +| 37 = @stmt_co_return +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_initialization( + unique int if_stmt: @stmt_if ref, + int init_id: @stmt ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_initialization( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int init_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +switch_initialization( + unique int switch_stmt: @stmt_switch ref, + int init_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/ql/lib/upgrades/e9a518baf14f4322ac243578a8e1391386ff030f/stmtparents.ql b/cpp/ql/lib/upgrades/e9a518baf14f4322ac243578a8e1391386ff030f/stmtparents.ql new file mode 100644 index 00000000000..e4865284f9c --- /dev/null +++ b/cpp/ql/lib/upgrades/e9a518baf14f4322ac243578a8e1391386ff030f/stmtparents.ql @@ -0,0 +1,17 @@ +class Element extends @element { + string toString() { none() } +} + +class Stmt extends @stmt { + string toString() { none() } +} + +predicate isStmtWithInitializer(Stmt stmt) { + exists(int kind | stmts(stmt, kind, _) | kind = 2 or kind = 11 or kind = 35) +} + +from Stmt child, int index, int index_new, Element parent +where + stmtparents(child, index, parent) and + if isStmtWithInitializer(parent) then index_new = index + 1 else index_new = index +select child, index_new, parent diff --git a/cpp/ql/lib/upgrades/e9a518baf14f4322ac243578a8e1391386ff030f/upgrade.properties b/cpp/ql/lib/upgrades/e9a518baf14f4322ac243578a8e1391386ff030f/upgrade.properties new file mode 100644 index 00000000000..46b0525f473 --- /dev/null +++ b/cpp/ql/lib/upgrades/e9a518baf14f4322ac243578a8e1391386ff030f/upgrade.properties @@ -0,0 +1,4 @@ +description: Support C++17 if and switch initializers +compatibility: partial +exprparents.rel: run exprparents.qlo +stmtparents.rel: run stmtparents.qlo diff --git a/cpp/ql/src/Best Practices/Unused Entities/UnusedLocals.ql b/cpp/ql/src/Best Practices/Unused Entities/UnusedLocals.ql index 851d59f680f..cbb143dcebc 100644 --- a/cpp/ql/src/Best Practices/Unused Entities/UnusedLocals.ql +++ b/cpp/ql/src/Best Practices/Unused Entities/UnusedLocals.ql @@ -57,6 +57,5 @@ where not declarationHasSideEffects(v) and not exists(AsmStmt s | f = s.getEnclosingFunction()) and not v.getAnAttribute().getName() = "unused" and - not any(ErrorExpr e).getEnclosingFunction() = f and // unextracted expr may use `v` - not any(ConditionDeclExpr cde).getEnclosingFunction() = f // this case can be removed when the `if (a = b; a)` and `switch (a = b; a)` test cases don't depend on this exclusion + not any(ErrorExpr e).getEnclosingFunction() = f // unextracted expr may use `v` select v, "Variable " + v.getName() + " is not used" diff --git a/cpp/ql/src/CHANGELOG.md b/cpp/ql/src/CHANGELOG.md index fa04b672083..50408aea104 100644 --- a/cpp/ql/src/CHANGELOG.md +++ b/cpp/ql/src/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.1.2 + +### Minor Analysis Improvements + +* The "XML external entity expansion" (`cpp/external-entity-expansion`) query has been extended to support a broader selection of XML libraries and interfaces. + ## 0.1.1 ### New Queries diff --git a/cpp/ql/src/Diagnostics/ExtractionProblems.qll b/cpp/ql/src/Diagnostics/ExtractionProblems.qll index c96e2e926e8..b6dd835261d 100644 --- a/cpp/ql/src/Diagnostics/ExtractionProblems.qll +++ b/cpp/ql/src/Diagnostics/ExtractionProblems.qll @@ -57,10 +57,10 @@ class ExtractionProblem extends TExtractionProblem { /** Gets the problem message for this problem. */ string getProblemMessage() { none() } - /** Gets the file this problem occured in. */ + /** Gets the file this problem occurred in. */ File getFile() { none() } - /** Gets the location this problem occured in. */ + /** Gets the location this problem occurred in. */ Location getLocation() { none() } /** Gets the SARIF severity of this problem. */ diff --git a/cpp/ql/src/Diagnostics/Internal/ExtractionErrors.qll b/cpp/ql/src/Diagnostics/Internal/ExtractionErrors.qll index 4cf6f8145f8..1ac69186a93 100644 --- a/cpp/ql/src/Diagnostics/Internal/ExtractionErrors.qll +++ b/cpp/ql/src/Diagnostics/Internal/ExtractionErrors.qll @@ -57,10 +57,10 @@ class ExtractionError extends TExtractionError { /** Gets the error message for this error. */ string getErrorMessage() { none() } - /** Gets the file this error occured in. */ + /** Gets the file this error occurred in. */ File getFile() { none() } - /** Gets the location this error occured in. */ + /** Gets the location this error occurred in. */ Location getLocation() { none() } /** Gets the SARIF severity of this error. */ diff --git a/cpp/ql/src/Security/CWE/CWE-611/XXE.ql b/cpp/ql/src/Security/CWE/CWE-611/XXE.ql index c8b638ddecd..6791bbe69da 100644 --- a/cpp/ql/src/Security/CWE/CWE-611/XXE.ql +++ b/cpp/ql/src/Security/CWE/CWE-611/XXE.ql @@ -7,7 +7,7 @@ * @id cpp/external-entity-expansion * @problem.severity warning * @security-severity 9.1 - * @precision medium + * @precision high * @tags security * external/cwe/cwe-611 */ @@ -30,14 +30,14 @@ abstract class XXEFlowState extends DataFlow::FlowState { * An `Expr` that changes the configuration of an XML object, transforming the * `XXEFlowState` that flows through it. */ -abstract class XXEFlowStateTranformer extends Expr { +abstract class XXEFlowStateTransformer extends Expr { /** * Gets the flow state that `flowstate` is transformed into. * * Due to limitations of the implementation the transformation defined by this * predicate must be idempotent, that is, for any input `x` it must be that: * ``` - * transform(tranform(x)) = tranform(x) + * transform(transform(x)) = transform(x) * ``` */ abstract XXEFlowState transform(XXEFlowState flowstate); @@ -57,6 +57,13 @@ class XercesDOMParserClass extends Class { XercesDOMParserClass() { this.hasName("XercesDOMParser") } } +/** + * The `DOMLSParser` class. + */ +class DomLSParserClass extends Class { + DomLSParserClass() { this.hasName("DOMLSParser") } +} + /** * The `SAXParser` class. */ @@ -112,10 +119,10 @@ class XercesFlowState extends XXEFlowState { * `SAXParser.setDisableDefaultEntityResolution`. Transforms the flow * state through the qualifier according to the setting in the parameter. */ -class DisableDefaultEntityResolutionTranformer extends XXEFlowStateTranformer { +class DisableDefaultEntityResolutionTransformer extends XXEFlowStateTransformer { Expr newValue; - DisableDefaultEntityResolutionTranformer() { + DisableDefaultEntityResolutionTransformer() { exists(Call call, Function f | call.getTarget() = f and ( @@ -147,10 +154,10 @@ class DisableDefaultEntityResolutionTranformer extends XXEFlowStateTranformer { * `AbstractDOMParser.setCreateEntityReferenceNodes`. Transforms the flow * state through the qualifier according to the setting in the parameter. */ -class CreateEntityReferenceNodesTranformer extends XXEFlowStateTranformer { +class CreateEntityReferenceNodesTransformer extends XXEFlowStateTransformer { Expr newValue; - CreateEntityReferenceNodesTranformer() { + CreateEntityReferenceNodesTransformer() { exists(Call call, Function f | call.getTarget() = f and f.getClassAndName("setCreateEntityReferenceNodes") instanceof AbstractDOMParserClass and @@ -188,10 +195,10 @@ class FeatureDisableDefaultEntityResolution extends Variable { * specifying the feature `XMLUni::fgXercesDisableDefaultEntityResolution`. * Transforms the flow state through the qualifier according to this setting. */ -class SetFeatureTranformer extends XXEFlowStateTranformer { +class SetFeatureTransformer extends XXEFlowStateTransformer { Expr newValue; - SetFeatureTranformer() { + SetFeatureTransformer() { exists(Call call, Function f | call.getTarget() = f and f.getClassAndName("setFeature") instanceof Sax2XmlReader and @@ -217,12 +224,71 @@ class SetFeatureTranformer extends XXEFlowStateTranformer { } /** - * The `AbstractDOMParser.parse`, `SAXParser.parse` or `SAX2XMLReader.parse` - * method. + * The `DOMLSParser.getDomConfig` function. + */ +class GetDomConfig extends Function { + GetDomConfig() { this.getClassAndName("getDomConfig") instanceof DomLSParserClass } +} + +/** + * The `DOMConfiguration.setParameter` function. + */ +class DomConfigurationSetParameter extends Function { + DomConfigurationSetParameter() { + this.getClassAndName("setParameter").getName() = "DOMConfiguration" + } +} + +/** + * A flow state transformer for a call to `DOMConfiguration.setParameter` + * specifying the feature `XMLUni::fgXercesDisableDefaultEntityResolution`. + * This is a slightly more complex transformer because the qualifier is a + * `DOMConfiguration` pointer returned by `DOMLSParser.getDomConfig` - and it + * is *that* qualifier we want to transform the flow state of. + */ +class DomConfigurationSetParameterTransformer extends XXEFlowStateTransformer { + Expr newValue; + + DomConfigurationSetParameterTransformer() { + exists(FunctionCall getDomConfigCall, FunctionCall setParameterCall | + // this is the qualifier of a call to `DOMLSParser.getDomConfig`. + getDomConfigCall.getTarget() instanceof GetDomConfig and + this = getDomConfigCall.getQualifier() and + // `setParameterCall` is a call to `setParameter` on the return value of + // the same call to `DOMLSParser.getDomConfig`. + setParameterCall.getTarget() instanceof DomConfigurationSetParameter and + globalValueNumber(setParameterCall.getQualifier()).getAnExpr() = getDomConfigCall and + // the parameter being set is + // `XMLUni::fgXercesDisableDefaultEntityResolution`. + globalValueNumber(setParameterCall.getArgument(0)).getAnExpr().(VariableAccess).getTarget() + instanceof FeatureDisableDefaultEntityResolution and + // the value being set is `newValue`. + newValue = setParameterCall.getArgument(1) + ) + } + + final override XXEFlowState transform(XXEFlowState flowstate) { + exists(int createEntityReferenceNodes | + encodeXercesFlowState(flowstate, _, createEntityReferenceNodes) and + ( + globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true + encodeXercesFlowState(result, 1, createEntityReferenceNodes) + or + not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown + encodeXercesFlowState(result, 0, createEntityReferenceNodes) + ) + ) + } +} + +/** + * The `AbstractDOMParser.parse`, `DOMLSParserClass.parse`, `SAXParser.parse` + * or `SAX2XMLReader.parse` method. */ class ParseFunction extends Function { ParseFunction() { this.getClassAndName("parse") instanceof AbstractDOMParserClass or + this.getClassAndName("parse") instanceof DomLSParserClass or this.getClassAndName("parse") instanceof SaxParserClass or this.getClassAndName("parse") instanceof Sax2XmlReader } @@ -235,7 +301,7 @@ class ParseFunction extends Function { class CreateLSParser extends Function { CreateLSParser() { this.hasName("createLSParser") and - this.getUnspecifiedType().(PointerType).getBaseType().getName() = "DOMLSParser" // returns a `DOMLSParser *`. + this.getUnspecifiedType().(PointerType).getBaseType() instanceof DomLSParserClass // returns a `DOMLSParser *`. } } @@ -363,15 +429,15 @@ class XXEConfiguration extends DataFlow::Configuration { override predicate isAdditionalFlowStep( DataFlow::Node node1, string state1, DataFlow::Node node2, string state2 ) { - // create additional flow steps for `XXEFlowStateTranformer`s - state2 = node2.asConvertedExpr().(XXEFlowStateTranformer).transform(state1) and + // create additional flow steps for `XXEFlowStateTransformer`s + state2 = node2.asConvertedExpr().(XXEFlowStateTransformer).transform(state1) and DataFlow::simpleLocalFlowStep(node1, node2) } override predicate isBarrier(DataFlow::Node node, string flowstate) { // when the flowstate is transformed at a call node, block the original // flowstate value. - node.asConvertedExpr().(XXEFlowStateTranformer).transform(flowstate) != flowstate + node.asConvertedExpr().(XXEFlowStateTransformer).transform(flowstate) != flowstate } } diff --git a/cpp/ql/src/change-notes/2022-04-12-unused-local-variable.md b/cpp/ql/src/change-notes/2022-04-12-unused-local-variable.md new file mode 100644 index 00000000000..d4120401e1a --- /dev/null +++ b/cpp/ql/src/change-notes/2022-04-12-unused-local-variable.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The `cpp/unused-local-variable` no longer ignores functions that include `if` and `switch` statements with C++17-style initializers. diff --git a/cpp/ql/src/change-notes/2022-05-12-external-entity-expansion.md b/cpp/ql/src/change-notes/2022-05-12-external-entity-expansion.md new file mode 100644 index 00000000000..7d2f38c5040 --- /dev/null +++ b/cpp/ql/src/change-notes/2022-05-12-external-entity-expansion.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The "XML external entity expansion" (`cpp/external-entity-expansion`) query precision has been increased to `high`. diff --git a/cpp/ql/src/change-notes/2022-04-28-external-entity-expansion.md b/cpp/ql/src/change-notes/released/0.1.2.md similarity index 78% rename from cpp/ql/src/change-notes/2022-04-28-external-entity-expansion.md rename to cpp/ql/src/change-notes/released/0.1.2.md index 911cbd7e54c..ca3236f5950 100644 --- a/cpp/ql/src/change-notes/2022-04-28-external-entity-expansion.md +++ b/cpp/ql/src/change-notes/released/0.1.2.md @@ -1,4 +1,5 @@ ---- -category: minorAnalysis ---- +## 0.1.2 + +### Minor Analysis Improvements + * The "XML external entity expansion" (`cpp/external-entity-expansion`) query has been extended to support a broader selection of XML libraries and interfaces. diff --git a/cpp/ql/src/codeql-pack.release.yml b/cpp/ql/src/codeql-pack.release.yml index 92d1505475f..6abd14b1ef8 100644 --- a/cpp/ql/src/codeql-pack.release.yml +++ b/cpp/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.1.1 +lastReleaseVersion: 0.1.2 diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml index d4df6bb5e07..b31a20cb12a 100644 --- a/cpp/ql/src/qlpack.yml +++ b/cpp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-queries -version: 0.1.2-dev +version: 0.1.3-dev groups: - cpp - queries diff --git a/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll b/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll index a4d264b2703..3891fcf13a1 100644 --- a/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -181,7 +181,7 @@ private string expectationCommentPattern() { result = "\\s*\\$((?:[^/]|/[^/])*)( /** * The possible columns in an expectation comment. The `TDefaultColumn` branch represents the first * column in a comment. This column is not precedeeded by a name. `TNamedColumn(name)` represents a - * column containing expected results preceeded by the string `name:`. + * column containing expected results preceded by the string `name:`. */ private newtype TColumn = TDefaultColumn() or diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index af029bf3748..9aedef96249 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -13559,6 +13559,422 @@ ir.cpp: # 1754| Type = [SpecifiedType] const CopyConstructorTestVirtualClass # 1754| ValueCategory = lvalue # 1755| getStmt(2): [ReturnStmt] return ... +# 1757| [TopLevelFunction] void if_initialization(int) +# 1757| : +# 1757| getParameter(0): [Parameter] x +# 1757| Type = [IntType] int +# 1757| getEntryPoint(): [BlockStmt] { ... } +# 1758| getStmt(0): [IfStmt] if (...) ... +# 1758| getInitialization(): [DeclStmt] declaration +# 1758| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y +# 1758| Type = [IntType] int +# 1758| getVariable().getInitializer(): [Initializer] initializer for y +# 1758| getExpr(): [VariableAccess] x +# 1758| Type = [IntType] int +# 1758| ValueCategory = prvalue(load) +# 1758| getCondition(): [AddExpr] ... + ... +# 1758| Type = [IntType] int +# 1758| ValueCategory = prvalue +# 1758| getLeftOperand(): [VariableAccess] x +# 1758| Type = [IntType] int +# 1758| ValueCategory = prvalue(load) +# 1758| getRightOperand(): [Literal] 1 +# 1758| Type = [IntType] int +# 1758| Value = [Literal] 1 +# 1758| ValueCategory = prvalue +# 1758| getThen(): [BlockStmt] { ... } +# 1759| getStmt(0): [ExprStmt] ExprStmt +# 1759| getExpr(): [AssignExpr] ... = ... +# 1759| Type = [IntType] int +# 1759| ValueCategory = lvalue +# 1759| getLValue(): [VariableAccess] x +# 1759| Type = [IntType] int +# 1759| ValueCategory = lvalue +# 1759| getRValue(): [AddExpr] ... + ... +# 1759| Type = [IntType] int +# 1759| ValueCategory = prvalue +# 1759| getLeftOperand(): [VariableAccess] x +# 1759| Type = [IntType] int +# 1759| ValueCategory = prvalue(load) +# 1759| getRightOperand(): [VariableAccess] y +# 1759| Type = [IntType] int +# 1759| ValueCategory = prvalue(load) +# 1758| getCondition().getFullyConverted(): [CStyleCast] (bool)... +# 1758| Conversion = [BoolConversion] conversion to bool +# 1758| Type = [BoolType] bool +# 1758| ValueCategory = prvalue +# 1762| getStmt(1): [DeclStmt] declaration +# 1762| getDeclarationEntry(0): [VariableDeclarationEntry] definition of w +# 1762| Type = [IntType] int +# 1763| getStmt(2): [IfStmt] if (...) ... +# 1763| getInitialization(): [ExprStmt] ExprStmt +# 1763| getExpr(): [AssignExpr] ... = ... +# 1763| Type = [IntType] int +# 1763| ValueCategory = lvalue +# 1763| getLValue(): [VariableAccess] w +# 1763| Type = [IntType] int +# 1763| ValueCategory = lvalue +# 1763| getRValue(): [VariableAccess] x +# 1763| Type = [IntType] int +# 1763| ValueCategory = prvalue(load) +# 1763| getCondition(): [AddExpr] ... + ... +# 1763| Type = [IntType] int +# 1763| ValueCategory = prvalue +# 1763| getLeftOperand(): [VariableAccess] x +# 1763| Type = [IntType] int +# 1763| ValueCategory = prvalue(load) +# 1763| getRightOperand(): [Literal] 1 +# 1763| Type = [IntType] int +# 1763| Value = [Literal] 1 +# 1763| ValueCategory = prvalue +# 1763| getThen(): [BlockStmt] { ... } +# 1764| getStmt(0): [ExprStmt] ExprStmt +# 1764| getExpr(): [AssignExpr] ... = ... +# 1764| Type = [IntType] int +# 1764| ValueCategory = lvalue +# 1764| getLValue(): [VariableAccess] x +# 1764| Type = [IntType] int +# 1764| ValueCategory = lvalue +# 1764| getRValue(): [AddExpr] ... + ... +# 1764| Type = [IntType] int +# 1764| ValueCategory = prvalue +# 1764| getLeftOperand(): [VariableAccess] x +# 1764| Type = [IntType] int +# 1764| ValueCategory = prvalue(load) +# 1764| getRightOperand(): [VariableAccess] w +# 1764| Type = [IntType] int +# 1764| ValueCategory = prvalue(load) +# 1763| getCondition().getFullyConverted(): [CStyleCast] (bool)... +# 1763| Conversion = [BoolConversion] conversion to bool +# 1763| Type = [BoolType] bool +# 1763| ValueCategory = prvalue +# 1767| getStmt(3): [IfStmt] if (...) ... +# 1767| getInitialization(): [ExprStmt] ExprStmt +# 1767| getExpr(): [AssignExpr] ... = ... +# 1767| Type = [IntType] int +# 1767| ValueCategory = lvalue +# 1767| getLValue(): [VariableAccess] w +# 1767| Type = [IntType] int +# 1767| ValueCategory = lvalue +# 1767| getRValue(): [VariableAccess] x +# 1767| Type = [IntType] int +# 1767| ValueCategory = prvalue(load) +# 1767| getCondition(): [ConditionDeclExpr] (condition decl) +# 1767| Type = [BoolType] bool +# 1767| ValueCategory = prvalue +# 1767| getVariableAccess(): [VariableAccess] w2 +# 1767| Type = [IntType] int +# 1767| ValueCategory = prvalue(load) +# 1767| getVariableAccess().getFullyConverted(): [CStyleCast] (bool)... +# 1767| Conversion = [BoolConversion] conversion to bool +# 1767| Type = [BoolType] bool +# 1767| ValueCategory = prvalue +# 1767| getThen(): [BlockStmt] { ... } +# 1768| getStmt(0): [ExprStmt] ExprStmt +# 1768| getExpr(): [AssignExpr] ... = ... +# 1768| Type = [IntType] int +# 1768| ValueCategory = lvalue +# 1768| getLValue(): [VariableAccess] x +# 1768| Type = [IntType] int +# 1768| ValueCategory = lvalue +# 1768| getRValue(): [AddExpr] ... + ... +# 1768| Type = [IntType] int +# 1768| ValueCategory = prvalue +# 1768| getLeftOperand(): [VariableAccess] x +# 1768| Type = [IntType] int +# 1768| ValueCategory = prvalue(load) +# 1768| getRightOperand(): [VariableAccess] w +# 1768| Type = [IntType] int +# 1768| ValueCategory = prvalue(load) +# 1771| getStmt(4): [IfStmt] if (...) ... +# 1771| getInitialization(): [DeclStmt] declaration +# 1771| getDeclarationEntry(0): [VariableDeclarationEntry] definition of v +# 1771| Type = [IntType] int +# 1771| getVariable().getInitializer(): [Initializer] initializer for v +# 1771| getExpr(): [VariableAccess] x +# 1771| Type = [IntType] int +# 1771| ValueCategory = prvalue(load) +# 1771| getCondition(): [ConditionDeclExpr] (condition decl) +# 1771| Type = [BoolType] bool +# 1771| ValueCategory = prvalue +# 1771| getVariableAccess(): [VariableAccess] v2 +# 1771| Type = [IntType] int +# 1771| ValueCategory = prvalue(load) +# 1771| getVariableAccess().getFullyConverted(): [CStyleCast] (bool)... +# 1771| Conversion = [BoolConversion] conversion to bool +# 1771| Type = [BoolType] bool +# 1771| ValueCategory = prvalue +# 1771| getThen(): [BlockStmt] { ... } +# 1772| getStmt(0): [ExprStmt] ExprStmt +# 1772| getExpr(): [AssignExpr] ... = ... +# 1772| Type = [IntType] int +# 1772| ValueCategory = lvalue +# 1772| getLValue(): [VariableAccess] x +# 1772| Type = [IntType] int +# 1772| ValueCategory = lvalue +# 1772| getRValue(): [AddExpr] ... + ... +# 1772| Type = [IntType] int +# 1772| ValueCategory = prvalue +# 1772| getLeftOperand(): [VariableAccess] x +# 1772| Type = [IntType] int +# 1772| ValueCategory = prvalue(load) +# 1772| getRightOperand(): [VariableAccess] v +# 1772| Type = [IntType] int +# 1772| ValueCategory = prvalue(load) +# 1775| getStmt(5): [DeclStmt] declaration +# 1775| getDeclarationEntry(0): [VariableDeclarationEntry] definition of z +# 1775| Type = [IntType] int +# 1775| getVariable().getInitializer(): [Initializer] initializer for z +# 1775| getExpr(): [VariableAccess] x +# 1775| Type = [IntType] int +# 1775| ValueCategory = prvalue(load) +# 1776| getStmt(6): [IfStmt] if (...) ... +# 1776| getCondition(): [VariableAccess] z +# 1776| Type = [IntType] int +# 1776| ValueCategory = prvalue(load) +# 1776| getThen(): [BlockStmt] { ... } +# 1777| getStmt(0): [ExprStmt] ExprStmt +# 1777| getExpr(): [AssignExpr] ... = ... +# 1777| Type = [IntType] int +# 1777| ValueCategory = lvalue +# 1777| getLValue(): [VariableAccess] x +# 1777| Type = [IntType] int +# 1777| ValueCategory = lvalue +# 1777| getRValue(): [AddExpr] ... + ... +# 1777| Type = [IntType] int +# 1777| ValueCategory = prvalue +# 1777| getLeftOperand(): [VariableAccess] x +# 1777| Type = [IntType] int +# 1777| ValueCategory = prvalue(load) +# 1777| getRightOperand(): [VariableAccess] z +# 1777| Type = [IntType] int +# 1777| ValueCategory = prvalue(load) +# 1776| getCondition().getFullyConverted(): [CStyleCast] (bool)... +# 1776| Conversion = [BoolConversion] conversion to bool +# 1776| Type = [BoolType] bool +# 1776| ValueCategory = prvalue +# 1780| getStmt(7): [IfStmt] if (...) ... +# 1780| getCondition(): [ConditionDeclExpr] (condition decl) +# 1780| Type = [BoolType] bool +# 1780| ValueCategory = prvalue +# 1780| getVariableAccess(): [VariableAccess] z2 +# 1780| Type = [IntType] int +# 1780| ValueCategory = prvalue(load) +# 1780| getVariableAccess().getFullyConverted(): [CStyleCast] (bool)... +# 1780| Conversion = [BoolConversion] conversion to bool +# 1780| Type = [BoolType] bool +# 1780| ValueCategory = prvalue +# 1780| getThen(): [BlockStmt] { ... } +# 1781| getStmt(0): [ExprStmt] ExprStmt +# 1781| getExpr(): [AssignAddExpr] ... += ... +# 1781| Type = [IntType] int +# 1781| ValueCategory = lvalue +# 1781| getLValue(): [VariableAccess] x +# 1781| Type = [IntType] int +# 1781| ValueCategory = lvalue +# 1781| getRValue(): [VariableAccess] z2 +# 1781| Type = [IntType] int +# 1781| ValueCategory = prvalue(load) +# 1783| getStmt(8): [ReturnStmt] return ... +# 1785| [TopLevelFunction] void switch_initialization(int) +# 1785| : +# 1785| getParameter(0): [Parameter] x +# 1785| Type = [IntType] int +# 1785| getEntryPoint(): [BlockStmt] { ... } +# 1786| getStmt(0): [SwitchStmt] switch (...) ... +# 1786| getInitialization(): [DeclStmt] declaration +# 1786| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y +# 1786| Type = [IntType] int +# 1786| getVariable().getInitializer(): [Initializer] initializer for y +# 1786| getExpr(): [VariableAccess] x +# 1786| Type = [IntType] int +# 1786| ValueCategory = prvalue(load) +# 1786| getExpr(): [AddExpr] ... + ... +# 1786| Type = [IntType] int +# 1786| ValueCategory = prvalue +# 1786| getLeftOperand(): [VariableAccess] x +# 1786| Type = [IntType] int +# 1786| ValueCategory = prvalue(load) +# 1786| getRightOperand(): [Literal] 1 +# 1786| Type = [IntType] int +# 1786| Value = [Literal] 1 +# 1786| ValueCategory = prvalue +# 1786| getStmt(): [BlockStmt] { ... } +# 1787| getStmt(0): [SwitchCase] default: +# 1788| getStmt(1): [ExprStmt] ExprStmt +# 1788| getExpr(): [AssignExpr] ... = ... +# 1788| Type = [IntType] int +# 1788| ValueCategory = lvalue +# 1788| getLValue(): [VariableAccess] x +# 1788| Type = [IntType] int +# 1788| ValueCategory = lvalue +# 1788| getRValue(): [AddExpr] ... + ... +# 1788| Type = [IntType] int +# 1788| ValueCategory = prvalue +# 1788| getLeftOperand(): [VariableAccess] x +# 1788| Type = [IntType] int +# 1788| ValueCategory = prvalue(load) +# 1788| getRightOperand(): [VariableAccess] y +# 1788| Type = [IntType] int +# 1788| ValueCategory = prvalue(load) +# 1791| getStmt(1): [DeclStmt] declaration +# 1791| getDeclarationEntry(0): [VariableDeclarationEntry] definition of w +# 1791| Type = [IntType] int +# 1792| getStmt(2): [SwitchStmt] switch (...) ... +# 1792| getInitialization(): [ExprStmt] ExprStmt +# 1792| getExpr(): [AssignExpr] ... = ... +# 1792| Type = [IntType] int +# 1792| ValueCategory = lvalue +# 1792| getLValue(): [VariableAccess] w +# 1792| Type = [IntType] int +# 1792| ValueCategory = lvalue +# 1792| getRValue(): [VariableAccess] x +# 1792| Type = [IntType] int +# 1792| ValueCategory = prvalue(load) +# 1792| getExpr(): [AddExpr] ... + ... +# 1792| Type = [IntType] int +# 1792| ValueCategory = prvalue +# 1792| getLeftOperand(): [VariableAccess] x +# 1792| Type = [IntType] int +# 1792| ValueCategory = prvalue(load) +# 1792| getRightOperand(): [Literal] 1 +# 1792| Type = [IntType] int +# 1792| Value = [Literal] 1 +# 1792| ValueCategory = prvalue +# 1792| getStmt(): [BlockStmt] { ... } +# 1793| getStmt(0): [SwitchCase] default: +# 1794| getStmt(1): [ExprStmt] ExprStmt +# 1794| getExpr(): [AssignExpr] ... = ... +# 1794| Type = [IntType] int +# 1794| ValueCategory = lvalue +# 1794| getLValue(): [VariableAccess] x +# 1794| Type = [IntType] int +# 1794| ValueCategory = lvalue +# 1794| getRValue(): [AddExpr] ... + ... +# 1794| Type = [IntType] int +# 1794| ValueCategory = prvalue +# 1794| getLeftOperand(): [VariableAccess] x +# 1794| Type = [IntType] int +# 1794| ValueCategory = prvalue(load) +# 1794| getRightOperand(): [VariableAccess] w +# 1794| Type = [IntType] int +# 1794| ValueCategory = prvalue(load) +# 1797| getStmt(3): [SwitchStmt] switch (...) ... +# 1797| getInitialization(): [ExprStmt] ExprStmt +# 1797| getExpr(): [AssignExpr] ... = ... +# 1797| Type = [IntType] int +# 1797| ValueCategory = lvalue +# 1797| getLValue(): [VariableAccess] w +# 1797| Type = [IntType] int +# 1797| ValueCategory = lvalue +# 1797| getRValue(): [VariableAccess] x +# 1797| Type = [IntType] int +# 1797| ValueCategory = prvalue(load) +# 1797| getExpr(): [ConditionDeclExpr] (condition decl) +# 1797| Type = [IntType] int +# 1797| ValueCategory = prvalue +# 1797| getVariableAccess(): [VariableAccess] w2 +# 1797| Type = [IntType] int +# 1797| ValueCategory = prvalue(load) +# 1797| getStmt(): [BlockStmt] { ... } +# 1798| getStmt(0): [SwitchCase] default: +# 1799| getStmt(1): [ExprStmt] ExprStmt +# 1799| getExpr(): [AssignExpr] ... = ... +# 1799| Type = [IntType] int +# 1799| ValueCategory = lvalue +# 1799| getLValue(): [VariableAccess] x +# 1799| Type = [IntType] int +# 1799| ValueCategory = lvalue +# 1799| getRValue(): [AddExpr] ... + ... +# 1799| Type = [IntType] int +# 1799| ValueCategory = prvalue +# 1799| getLeftOperand(): [VariableAccess] x +# 1799| Type = [IntType] int +# 1799| ValueCategory = prvalue(load) +# 1799| getRightOperand(): [VariableAccess] w +# 1799| Type = [IntType] int +# 1799| ValueCategory = prvalue(load) +# 1802| getStmt(4): [SwitchStmt] switch (...) ... +# 1802| getInitialization(): [DeclStmt] declaration +# 1802| getDeclarationEntry(0): [VariableDeclarationEntry] definition of v +# 1802| Type = [IntType] int +# 1802| getVariable().getInitializer(): [Initializer] initializer for v +# 1802| getExpr(): [VariableAccess] x +# 1802| Type = [IntType] int +# 1802| ValueCategory = prvalue(load) +# 1802| getExpr(): [ConditionDeclExpr] (condition decl) +# 1802| Type = [IntType] int +# 1802| ValueCategory = prvalue +# 1802| getVariableAccess(): [VariableAccess] v2 +# 1802| Type = [IntType] int +# 1802| ValueCategory = prvalue(load) +# 1802| getStmt(): [BlockStmt] { ... } +# 1803| getStmt(0): [SwitchCase] default: +# 1804| getStmt(1): [ExprStmt] ExprStmt +# 1804| getExpr(): [AssignExpr] ... = ... +# 1804| Type = [IntType] int +# 1804| ValueCategory = lvalue +# 1804| getLValue(): [VariableAccess] x +# 1804| Type = [IntType] int +# 1804| ValueCategory = lvalue +# 1804| getRValue(): [AddExpr] ... + ... +# 1804| Type = [IntType] int +# 1804| ValueCategory = prvalue +# 1804| getLeftOperand(): [VariableAccess] x +# 1804| Type = [IntType] int +# 1804| ValueCategory = prvalue(load) +# 1804| getRightOperand(): [VariableAccess] v +# 1804| Type = [IntType] int +# 1804| ValueCategory = prvalue(load) +# 1807| getStmt(5): [DeclStmt] declaration +# 1807| getDeclarationEntry(0): [VariableDeclarationEntry] definition of z +# 1807| Type = [IntType] int +# 1807| getVariable().getInitializer(): [Initializer] initializer for z +# 1807| getExpr(): [VariableAccess] x +# 1807| Type = [IntType] int +# 1807| ValueCategory = prvalue(load) +# 1808| getStmt(6): [SwitchStmt] switch (...) ... +# 1808| getExpr(): [VariableAccess] z +# 1808| Type = [IntType] int +# 1808| ValueCategory = prvalue(load) +# 1808| getStmt(): [BlockStmt] { ... } +# 1809| getStmt(0): [SwitchCase] default: +# 1810| getStmt(1): [ExprStmt] ExprStmt +# 1810| getExpr(): [AssignExpr] ... = ... +# 1810| Type = [IntType] int +# 1810| ValueCategory = lvalue +# 1810| getLValue(): [VariableAccess] x +# 1810| Type = [IntType] int +# 1810| ValueCategory = lvalue +# 1810| getRValue(): [AddExpr] ... + ... +# 1810| Type = [IntType] int +# 1810| ValueCategory = prvalue +# 1810| getLeftOperand(): [VariableAccess] x +# 1810| Type = [IntType] int +# 1810| ValueCategory = prvalue(load) +# 1810| getRightOperand(): [VariableAccess] z +# 1810| Type = [IntType] int +# 1810| ValueCategory = prvalue(load) +# 1813| getStmt(7): [SwitchStmt] switch (...) ... +# 1813| getExpr(): [ConditionDeclExpr] (condition decl) +# 1813| Type = [IntType] int +# 1813| ValueCategory = prvalue +# 1813| getVariableAccess(): [VariableAccess] z2 +# 1813| Type = [IntType] int +# 1813| ValueCategory = prvalue(load) +# 1813| getStmt(): [BlockStmt] { ... } +# 1814| getStmt(0): [SwitchCase] default: +# 1815| getStmt(1): [ExprStmt] ExprStmt +# 1815| getExpr(): [AssignAddExpr] ... += ... +# 1815| Type = [IntType] int +# 1815| ValueCategory = lvalue +# 1815| getLValue(): [VariableAccess] x +# 1815| Type = [IntType] int +# 1815| ValueCategory = lvalue +# 1815| getRValue(): [VariableAccess] z2 +# 1815| Type = [IntType] int +# 1815| ValueCategory = prvalue(load) +# 1817| getStmt(8): [ReturnStmt] return ... perf-regression.cpp: # 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&) # 4| : diff --git a/cpp/ql/test/library-tests/ir/ir/ir.cpp b/cpp/ql/test/library-tests/ir/ir/ir.cpp index 4e3006c8901..e85c5f1b505 100644 --- a/cpp/ql/test/library-tests/ir/ir/ir.cpp +++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp @@ -1754,4 +1754,66 @@ int implicit_copy_constructor_test( CopyConstructorTestVirtualClass cy = y; } +void if_initialization(int x) { + if (int y = x; x + 1) { + x = x + y; + } + + int w; + if (w = x; x + 1) { + x = x + w; + } + + if (w = x; int w2 = w) { + x = x + w; + } + + if (int v = x; int v2 = v) { + x = x + v; + } + + int z = x; + if (z) { + x = x + z; + } + + if (int z2 = z) { + x += z2; + } +} + +void switch_initialization(int x) { + switch (int y = x; x + 1) { + default: + x = x + y; + } + + int w; + switch (w = x; x + 1) { + default: + x = x + w; + } + + switch (w = x; int w2 = w) { + default: + x = x + w; + } + + switch (int v = x; int v2 = v) { + default: + x = x + v; + } + + int z = x; + switch (z) { + default: + x = x + z; + } + + switch (int z2 = z) { + default: + x += z2; + } +} + // semmle-extractor-options: -std=c++17 --clang diff --git a/cpp/ql/test/library-tests/ir/ir/operand_locations.expected b/cpp/ql/test/library-tests/ir/ir/operand_locations.expected index 259cc553dbb..1581085efc6 100644 --- a/cpp/ql/test/library-tests/ir/ir/operand_locations.expected +++ b/cpp/ql/test/library-tests/ir/ir/operand_locations.expected @@ -8215,6 +8215,248 @@ | ir.cpp:1754:42:1754:42 | SideEffect | ~m1752_4 | | ir.cpp:1754:42:1754:42 | Unary | r1754_5 | | ir.cpp:1754:42:1754:42 | Unary | r1754_6 | +| ir.cpp:1757:6:1757:22 | ChiPartial | partial:m1757_3 | +| ir.cpp:1757:6:1757:22 | ChiTotal | total:m1757_2 | +| ir.cpp:1757:6:1757:22 | SideEffect | m1757_3 | +| ir.cpp:1757:28:1757:28 | Address | &:r1757_5 | +| ir.cpp:1758:13:1758:13 | Address | &:r1758_1 | +| ir.cpp:1758:17:1758:17 | Address | &:r1758_2 | +| ir.cpp:1758:17:1758:17 | Load | m1757_6 | +| ir.cpp:1758:17:1758:17 | StoreValue | r1758_3 | +| ir.cpp:1758:20:1758:20 | Address | &:r1758_5 | +| ir.cpp:1758:20:1758:20 | Left | r1758_6 | +| ir.cpp:1758:20:1758:20 | Load | m1757_6 | +| ir.cpp:1758:20:1758:24 | Condition | r1758_10 | +| ir.cpp:1758:20:1758:24 | Left | r1758_8 | +| ir.cpp:1758:20:1758:24 | Right | r1758_9 | +| ir.cpp:1758:24:1758:24 | Right | r1758_7 | +| ir.cpp:1759:9:1759:9 | Address | &:r1759_6 | +| ir.cpp:1759:13:1759:13 | Address | &:r1759_1 | +| ir.cpp:1759:13:1759:13 | Left | r1759_2 | +| ir.cpp:1759:13:1759:13 | Load | m1757_6 | +| ir.cpp:1759:13:1759:17 | StoreValue | r1759_5 | +| ir.cpp:1759:17:1759:17 | Address | &:r1759_3 | +| ir.cpp:1759:17:1759:17 | Load | m1758_4 | +| ir.cpp:1759:17:1759:17 | Right | r1759_4 | +| ir.cpp:1762:9:1762:9 | Address | &:r1762_2 | +| ir.cpp:1762:9:1762:9 | Phi | from 0:m1757_6 | +| ir.cpp:1762:9:1762:9 | Phi | from 1:m1759_7 | +| ir.cpp:1763:9:1763:9 | Address | &:r1763_3 | +| ir.cpp:1763:13:1763:13 | Address | &:r1763_1 | +| ir.cpp:1763:13:1763:13 | Load | m1762_1 | +| ir.cpp:1763:13:1763:13 | StoreValue | r1763_2 | +| ir.cpp:1763:16:1763:16 | Address | &:r1763_5 | +| ir.cpp:1763:16:1763:16 | Left | r1763_6 | +| ir.cpp:1763:16:1763:16 | Load | m1762_1 | +| ir.cpp:1763:16:1763:20 | Condition | r1763_10 | +| ir.cpp:1763:16:1763:20 | Left | r1763_8 | +| ir.cpp:1763:16:1763:20 | Right | r1763_9 | +| ir.cpp:1763:20:1763:20 | Right | r1763_7 | +| ir.cpp:1764:9:1764:9 | Address | &:r1764_6 | +| ir.cpp:1764:13:1764:13 | Address | &:r1764_1 | +| ir.cpp:1764:13:1764:13 | Left | r1764_2 | +| ir.cpp:1764:13:1764:13 | Load | m1762_1 | +| ir.cpp:1764:13:1764:17 | StoreValue | r1764_5 | +| ir.cpp:1764:17:1764:17 | Address | &:r1764_3 | +| ir.cpp:1764:17:1764:17 | Load | m1763_4 | +| ir.cpp:1764:17:1764:17 | Right | r1764_4 | +| ir.cpp:1767:9:1767:9 | Address | &:r1767_4 | +| ir.cpp:1767:13:1767:13 | Address | &:r1767_2 | +| ir.cpp:1767:13:1767:13 | Load | m1767_1 | +| ir.cpp:1767:13:1767:13 | Phi | from 2:m1762_1 | +| ir.cpp:1767:13:1767:13 | Phi | from 3:m1764_7 | +| ir.cpp:1767:13:1767:13 | StoreValue | r1767_3 | +| ir.cpp:1767:14:1767:25 | Address | &:r1767_6 | +| ir.cpp:1767:14:1767:25 | Condition | r1767_14 | +| ir.cpp:1767:20:1767:21 | Address | &:r1767_10 | +| ir.cpp:1767:20:1767:21 | Left | r1767_11 | +| ir.cpp:1767:20:1767:21 | Load | m1767_9 | +| ir.cpp:1767:20:1767:21 | Right | r1767_12 | +| ir.cpp:1767:20:1767:21 | Unary | r1767_13 | +| ir.cpp:1767:25:1767:25 | Address | &:r1767_7 | +| ir.cpp:1767:25:1767:25 | Load | m1767_5 | +| ir.cpp:1767:25:1767:25 | StoreValue | r1767_8 | +| ir.cpp:1768:9:1768:9 | Address | &:r1768_6 | +| ir.cpp:1768:13:1768:13 | Address | &:r1768_1 | +| ir.cpp:1768:13:1768:13 | Left | r1768_2 | +| ir.cpp:1768:13:1768:13 | Load | m1767_1 | +| ir.cpp:1768:13:1768:17 | StoreValue | r1768_5 | +| ir.cpp:1768:17:1768:17 | Address | &:r1768_3 | +| ir.cpp:1768:17:1768:17 | Load | m1767_5 | +| ir.cpp:1768:17:1768:17 | Right | r1768_4 | +| ir.cpp:1771:9:1771:29 | Address | &:r1771_6 | +| ir.cpp:1771:9:1771:29 | Condition | r1771_14 | +| ir.cpp:1771:13:1771:13 | Address | &:r1771_2 | +| ir.cpp:1771:13:1771:13 | Phi | from 4:m1767_1 | +| ir.cpp:1771:13:1771:13 | Phi | from 5:m1768_7 | +| ir.cpp:1771:17:1771:17 | Address | &:r1771_3 | +| ir.cpp:1771:17:1771:17 | Load | m1771_1 | +| ir.cpp:1771:17:1771:17 | StoreValue | r1771_4 | +| ir.cpp:1771:24:1771:25 | Address | &:r1771_10 | +| ir.cpp:1771:24:1771:25 | Left | r1771_11 | +| ir.cpp:1771:24:1771:25 | Load | m1771_9 | +| ir.cpp:1771:24:1771:25 | Right | r1771_12 | +| ir.cpp:1771:24:1771:25 | Unary | r1771_13 | +| ir.cpp:1771:29:1771:29 | Address | &:r1771_7 | +| ir.cpp:1771:29:1771:29 | Load | m1771_5 | +| ir.cpp:1771:29:1771:29 | StoreValue | r1771_8 | +| ir.cpp:1772:9:1772:9 | Address | &:r1772_6 | +| ir.cpp:1772:13:1772:13 | Address | &:r1772_1 | +| ir.cpp:1772:13:1772:13 | Left | r1772_2 | +| ir.cpp:1772:13:1772:13 | Load | m1771_1 | +| ir.cpp:1772:13:1772:17 | StoreValue | r1772_5 | +| ir.cpp:1772:17:1772:17 | Address | &:r1772_3 | +| ir.cpp:1772:17:1772:17 | Load | m1771_5 | +| ir.cpp:1772:17:1772:17 | Right | r1772_4 | +| ir.cpp:1775:9:1775:9 | Address | &:r1775_2 | +| ir.cpp:1775:9:1775:9 | Phi | from 6:m1771_1 | +| ir.cpp:1775:9:1775:9 | Phi | from 7:m1772_7 | +| ir.cpp:1775:13:1775:13 | Address | &:r1775_3 | +| ir.cpp:1775:13:1775:13 | Load | m1775_1 | +| ir.cpp:1775:13:1775:13 | StoreValue | r1775_4 | +| ir.cpp:1776:9:1776:9 | Address | &:r1776_1 | +| ir.cpp:1776:9:1776:9 | Condition | r1776_4 | +| ir.cpp:1776:9:1776:9 | Left | r1776_2 | +| ir.cpp:1776:9:1776:9 | Load | m1775_5 | +| ir.cpp:1776:9:1776:9 | Right | r1776_3 | +| ir.cpp:1777:9:1777:9 | Address | &:r1777_6 | +| ir.cpp:1777:13:1777:13 | Address | &:r1777_1 | +| ir.cpp:1777:13:1777:13 | Left | r1777_2 | +| ir.cpp:1777:13:1777:13 | Load | m1775_1 | +| ir.cpp:1777:13:1777:17 | StoreValue | r1777_5 | +| ir.cpp:1777:17:1777:17 | Address | &:r1777_3 | +| ir.cpp:1777:17:1777:17 | Load | m1775_5 | +| ir.cpp:1777:17:1777:17 | Right | r1777_4 | +| ir.cpp:1780:9:1780:18 | Address | &:r1780_2 | +| ir.cpp:1780:9:1780:18 | Condition | r1780_10 | +| ir.cpp:1780:9:1780:18 | Phi | from 8:m1775_1 | +| ir.cpp:1780:9:1780:18 | Phi | from 9:m1777_7 | +| ir.cpp:1780:13:1780:14 | Address | &:r1780_6 | +| ir.cpp:1780:13:1780:14 | Left | r1780_7 | +| ir.cpp:1780:13:1780:14 | Load | m1780_5 | +| ir.cpp:1780:13:1780:14 | Right | r1780_8 | +| ir.cpp:1780:13:1780:14 | Unary | r1780_9 | +| ir.cpp:1780:18:1780:18 | Address | &:r1780_3 | +| ir.cpp:1780:18:1780:18 | Load | m1775_5 | +| ir.cpp:1780:18:1780:18 | StoreValue | r1780_4 | +| ir.cpp:1781:9:1781:9 | Address | &:r1781_3 | +| ir.cpp:1781:9:1781:9 | Address | &:r1781_3 | +| ir.cpp:1781:9:1781:9 | Left | r1781_4 | +| ir.cpp:1781:9:1781:9 | Load | m1780_1 | +| ir.cpp:1781:9:1781:15 | StoreValue | r1781_5 | +| ir.cpp:1781:14:1781:15 | Address | &:r1781_1 | +| ir.cpp:1781:14:1781:15 | Load | m1780_5 | +| ir.cpp:1781:14:1781:15 | Right | r1781_2 | +| ir.cpp:1785:6:1785:26 | ChiPartial | partial:m1785_3 | +| ir.cpp:1785:6:1785:26 | ChiTotal | total:m1785_2 | +| ir.cpp:1785:6:1785:26 | SideEffect | m1785_3 | +| ir.cpp:1785:32:1785:32 | Address | &:r1785_5 | +| ir.cpp:1786:17:1786:17 | Address | &:r1786_1 | +| ir.cpp:1786:21:1786:21 | Address | &:r1786_2 | +| ir.cpp:1786:21:1786:21 | Load | m1785_6 | +| ir.cpp:1786:21:1786:21 | StoreValue | r1786_3 | +| ir.cpp:1786:24:1786:24 | Address | &:r1786_5 | +| ir.cpp:1786:24:1786:24 | Left | r1786_6 | +| ir.cpp:1786:24:1786:24 | Load | m1785_6 | +| ir.cpp:1786:24:1786:28 | Condition | r1786_8 | +| ir.cpp:1786:28:1786:28 | Right | r1786_7 | +| ir.cpp:1788:9:1788:9 | Address | &:r1788_6 | +| ir.cpp:1788:13:1788:13 | Address | &:r1788_1 | +| ir.cpp:1788:13:1788:13 | Left | r1788_2 | +| ir.cpp:1788:13:1788:13 | Load | m1785_6 | +| ir.cpp:1788:13:1788:17 | StoreValue | r1788_5 | +| ir.cpp:1788:17:1788:17 | Address | &:r1788_3 | +| ir.cpp:1788:17:1788:17 | Load | m1786_4 | +| ir.cpp:1788:17:1788:17 | Right | r1788_4 | +| ir.cpp:1791:9:1791:9 | Address | &:r1791_1 | +| ir.cpp:1792:13:1792:13 | Address | &:r1792_3 | +| ir.cpp:1792:17:1792:17 | Address | &:r1792_1 | +| ir.cpp:1792:17:1792:17 | Load | m1788_7 | +| ir.cpp:1792:17:1792:17 | StoreValue | r1792_2 | +| ir.cpp:1792:20:1792:20 | Address | &:r1792_5 | +| ir.cpp:1792:20:1792:20 | Left | r1792_6 | +| ir.cpp:1792:20:1792:20 | Load | m1788_7 | +| ir.cpp:1792:20:1792:24 | Condition | r1792_8 | +| ir.cpp:1792:24:1792:24 | Right | r1792_7 | +| ir.cpp:1794:9:1794:9 | Address | &:r1794_6 | +| ir.cpp:1794:13:1794:13 | Address | &:r1794_1 | +| ir.cpp:1794:13:1794:13 | Left | r1794_2 | +| ir.cpp:1794:13:1794:13 | Load | m1788_7 | +| ir.cpp:1794:13:1794:17 | StoreValue | r1794_5 | +| ir.cpp:1794:17:1794:17 | Address | &:r1794_3 | +| ir.cpp:1794:17:1794:17 | Load | m1792_4 | +| ir.cpp:1794:17:1794:17 | Right | r1794_4 | +| ir.cpp:1797:13:1797:13 | Address | &:r1797_3 | +| ir.cpp:1797:17:1797:17 | Address | &:r1797_1 | +| ir.cpp:1797:17:1797:17 | Load | m1794_7 | +| ir.cpp:1797:17:1797:17 | StoreValue | r1797_2 | +| ir.cpp:1797:18:1797:29 | Address | &:r1797_5 | +| ir.cpp:1797:18:1797:29 | Condition | r1797_11 | +| ir.cpp:1797:24:1797:25 | Address | &:r1797_9 | +| ir.cpp:1797:24:1797:25 | Load | m1797_8 | +| ir.cpp:1797:24:1797:25 | Unary | r1797_10 | +| ir.cpp:1797:29:1797:29 | Address | &:r1797_6 | +| ir.cpp:1797:29:1797:29 | Load | m1797_4 | +| ir.cpp:1797:29:1797:29 | StoreValue | r1797_7 | +| ir.cpp:1799:9:1799:9 | Address | &:r1799_6 | +| ir.cpp:1799:13:1799:13 | Address | &:r1799_1 | +| ir.cpp:1799:13:1799:13 | Left | r1799_2 | +| ir.cpp:1799:13:1799:13 | Load | m1794_7 | +| ir.cpp:1799:13:1799:17 | StoreValue | r1799_5 | +| ir.cpp:1799:17:1799:17 | Address | &:r1799_3 | +| ir.cpp:1799:17:1799:17 | Load | m1797_4 | +| ir.cpp:1799:17:1799:17 | Right | r1799_4 | +| ir.cpp:1802:13:1802:33 | Address | &:r1802_5 | +| ir.cpp:1802:13:1802:33 | Condition | r1802_11 | +| ir.cpp:1802:17:1802:17 | Address | &:r1802_1 | +| ir.cpp:1802:21:1802:21 | Address | &:r1802_2 | +| ir.cpp:1802:21:1802:21 | Load | m1799_7 | +| ir.cpp:1802:21:1802:21 | StoreValue | r1802_3 | +| ir.cpp:1802:28:1802:29 | Address | &:r1802_9 | +| ir.cpp:1802:28:1802:29 | Load | m1802_8 | +| ir.cpp:1802:28:1802:29 | Unary | r1802_10 | +| ir.cpp:1802:33:1802:33 | Address | &:r1802_6 | +| ir.cpp:1802:33:1802:33 | Load | m1802_4 | +| ir.cpp:1802:33:1802:33 | StoreValue | r1802_7 | +| ir.cpp:1804:9:1804:9 | Address | &:r1804_6 | +| ir.cpp:1804:13:1804:13 | Address | &:r1804_1 | +| ir.cpp:1804:13:1804:13 | Left | r1804_2 | +| ir.cpp:1804:13:1804:13 | Load | m1799_7 | +| ir.cpp:1804:13:1804:17 | StoreValue | r1804_5 | +| ir.cpp:1804:17:1804:17 | Address | &:r1804_3 | +| ir.cpp:1804:17:1804:17 | Load | m1802_4 | +| ir.cpp:1804:17:1804:17 | Right | r1804_4 | +| ir.cpp:1807:9:1807:9 | Address | &:r1807_1 | +| ir.cpp:1807:13:1807:13 | Address | &:r1807_2 | +| ir.cpp:1807:13:1807:13 | Load | m1804_7 | +| ir.cpp:1807:13:1807:13 | StoreValue | r1807_3 | +| ir.cpp:1808:13:1808:13 | Address | &:r1808_1 | +| ir.cpp:1808:13:1808:13 | Condition | r1808_2 | +| ir.cpp:1808:13:1808:13 | Load | m1807_4 | +| ir.cpp:1810:9:1810:9 | Address | &:r1810_6 | +| ir.cpp:1810:13:1810:13 | Address | &:r1810_1 | +| ir.cpp:1810:13:1810:13 | Left | r1810_2 | +| ir.cpp:1810:13:1810:13 | Load | m1804_7 | +| ir.cpp:1810:13:1810:17 | StoreValue | r1810_5 | +| ir.cpp:1810:17:1810:17 | Address | &:r1810_3 | +| ir.cpp:1810:17:1810:17 | Load | m1807_4 | +| ir.cpp:1810:17:1810:17 | Right | r1810_4 | +| ir.cpp:1813:13:1813:22 | Address | &:r1813_1 | +| ir.cpp:1813:13:1813:22 | Condition | r1813_7 | +| ir.cpp:1813:17:1813:18 | Address | &:r1813_5 | +| ir.cpp:1813:17:1813:18 | Load | m1813_4 | +| ir.cpp:1813:17:1813:18 | Unary | r1813_6 | +| ir.cpp:1813:22:1813:22 | Address | &:r1813_2 | +| ir.cpp:1813:22:1813:22 | Load | m1807_4 | +| ir.cpp:1813:22:1813:22 | StoreValue | r1813_3 | +| ir.cpp:1815:9:1815:9 | Address | &:r1815_3 | +| ir.cpp:1815:9:1815:9 | Address | &:r1815_3 | +| ir.cpp:1815:9:1815:9 | Left | r1815_4 | +| ir.cpp:1815:9:1815:9 | Load | m1810_7 | +| ir.cpp:1815:9:1815:15 | StoreValue | r1815_5 | +| ir.cpp:1815:14:1815:15 | Address | &:r1815_1 | +| ir.cpp:1815:14:1815:15 | Load | m1813_4 | +| ir.cpp:1815:14:1815:15 | Right | r1815_2 | | perf-regression.cpp:6:3:6:5 | Address | &:r6_5 | | perf-regression.cpp:6:3:6:5 | Address | &:r6_5 | | perf-regression.cpp:6:3:6:5 | Address | &:r6_7 | diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 3f49642c4fb..17c59485eb9 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -9418,6 +9418,308 @@ ir.cpp: # 1750| v1750_6(void) = AliasedUse : ~m? # 1750| v1750_7(void) = ExitFunction : +# 1757| void if_initialization(int) +# 1757| Block 0 +# 1757| v1757_1(void) = EnterFunction : +# 1757| mu1757_2(unknown) = AliasedDefinition : +# 1757| mu1757_3(unknown) = InitializeNonLocal : +# 1757| r1757_4(glval) = VariableAddress[x] : +# 1757| mu1757_5(int) = InitializeParameter[x] : &:r1757_4 +# 1758| r1758_1(glval) = VariableAddress[y] : +# 1758| r1758_2(glval) = VariableAddress[x] : +# 1758| r1758_3(int) = Load[x] : &:r1758_2, ~m? +# 1758| mu1758_4(int) = Store[y] : &:r1758_1, r1758_3 +# 1758| r1758_5(glval) = VariableAddress[x] : +# 1758| r1758_6(int) = Load[x] : &:r1758_5, ~m? +# 1758| r1758_7(int) = Constant[1] : +# 1758| r1758_8(int) = Add : r1758_6, r1758_7 +# 1758| r1758_9(int) = Constant[0] : +# 1758| r1758_10(bool) = CompareNE : r1758_8, r1758_9 +# 1758| v1758_11(void) = ConditionalBranch : r1758_10 +#-----| False -> Block 2 +#-----| True -> Block 1 + +# 1759| Block 1 +# 1759| r1759_1(glval) = VariableAddress[x] : +# 1759| r1759_2(int) = Load[x] : &:r1759_1, ~m? +# 1759| r1759_3(glval) = VariableAddress[y] : +# 1759| r1759_4(int) = Load[y] : &:r1759_3, ~m? +# 1759| r1759_5(int) = Add : r1759_2, r1759_4 +# 1759| r1759_6(glval) = VariableAddress[x] : +# 1759| mu1759_7(int) = Store[x] : &:r1759_6, r1759_5 +#-----| Goto -> Block 2 + +# 1762| Block 2 +# 1762| r1762_1(glval) = VariableAddress[w] : +# 1762| mu1762_2(int) = Uninitialized[w] : &:r1762_1 +# 1763| r1763_1(glval) = VariableAddress[x] : +# 1763| r1763_2(int) = Load[x] : &:r1763_1, ~m? +# 1763| r1763_3(glval) = VariableAddress[w] : +# 1763| mu1763_4(int) = Store[w] : &:r1763_3, r1763_2 +# 1763| r1763_5(glval) = VariableAddress[x] : +# 1763| r1763_6(int) = Load[x] : &:r1763_5, ~m? +# 1763| r1763_7(int) = Constant[1] : +# 1763| r1763_8(int) = Add : r1763_6, r1763_7 +# 1763| r1763_9(int) = Constant[0] : +# 1763| r1763_10(bool) = CompareNE : r1763_8, r1763_9 +# 1763| v1763_11(void) = ConditionalBranch : r1763_10 +#-----| False -> Block 4 +#-----| True -> Block 3 + +# 1764| Block 3 +# 1764| r1764_1(glval) = VariableAddress[x] : +# 1764| r1764_2(int) = Load[x] : &:r1764_1, ~m? +# 1764| r1764_3(glval) = VariableAddress[w] : +# 1764| r1764_4(int) = Load[w] : &:r1764_3, ~m? +# 1764| r1764_5(int) = Add : r1764_2, r1764_4 +# 1764| r1764_6(glval) = VariableAddress[x] : +# 1764| mu1764_7(int) = Store[x] : &:r1764_6, r1764_5 +#-----| Goto -> Block 4 + +# 1767| Block 4 +# 1767| r1767_1(glval) = VariableAddress[x] : +# 1767| r1767_2(int) = Load[x] : &:r1767_1, ~m? +# 1767| r1767_3(glval) = VariableAddress[w] : +# 1767| mu1767_4(int) = Store[w] : &:r1767_3, r1767_2 +# 1767| r1767_5(glval) = VariableAddress[w2] : +# 1767| r1767_6(glval) = VariableAddress[w] : +# 1767| r1767_7(int) = Load[w] : &:r1767_6, ~m? +# 1767| mu1767_8(int) = Store[w2] : &:r1767_5, r1767_7 +# 1767| r1767_9(glval) = VariableAddress[w2] : +# 1767| r1767_10(int) = Load[w2] : &:r1767_9, ~m? +# 1767| r1767_11(int) = Constant[0] : +# 1767| r1767_12(bool) = CompareNE : r1767_10, r1767_11 +# 1767| r1767_13(bool) = CopyValue : r1767_12 +# 1767| v1767_14(void) = ConditionalBranch : r1767_13 +#-----| False -> Block 6 +#-----| True -> Block 5 + +# 1768| Block 5 +# 1768| r1768_1(glval) = VariableAddress[x] : +# 1768| r1768_2(int) = Load[x] : &:r1768_1, ~m? +# 1768| r1768_3(glval) = VariableAddress[w] : +# 1768| r1768_4(int) = Load[w] : &:r1768_3, ~m? +# 1768| r1768_5(int) = Add : r1768_2, r1768_4 +# 1768| r1768_6(glval) = VariableAddress[x] : +# 1768| mu1768_7(int) = Store[x] : &:r1768_6, r1768_5 +#-----| Goto -> Block 6 + +# 1771| Block 6 +# 1771| r1771_1(glval) = VariableAddress[v] : +# 1771| r1771_2(glval) = VariableAddress[x] : +# 1771| r1771_3(int) = Load[x] : &:r1771_2, ~m? +# 1771| mu1771_4(int) = Store[v] : &:r1771_1, r1771_3 +# 1771| r1771_5(glval) = VariableAddress[v2] : +# 1771| r1771_6(glval) = VariableAddress[v] : +# 1771| r1771_7(int) = Load[v] : &:r1771_6, ~m? +# 1771| mu1771_8(int) = Store[v2] : &:r1771_5, r1771_7 +# 1771| r1771_9(glval) = VariableAddress[v2] : +# 1771| r1771_10(int) = Load[v2] : &:r1771_9, ~m? +# 1771| r1771_11(int) = Constant[0] : +# 1771| r1771_12(bool) = CompareNE : r1771_10, r1771_11 +# 1771| r1771_13(bool) = CopyValue : r1771_12 +# 1771| v1771_14(void) = ConditionalBranch : r1771_13 +#-----| False -> Block 8 +#-----| True -> Block 7 + +# 1772| Block 7 +# 1772| r1772_1(glval) = VariableAddress[x] : +# 1772| r1772_2(int) = Load[x] : &:r1772_1, ~m? +# 1772| r1772_3(glval) = VariableAddress[v] : +# 1772| r1772_4(int) = Load[v] : &:r1772_3, ~m? +# 1772| r1772_5(int) = Add : r1772_2, r1772_4 +# 1772| r1772_6(glval) = VariableAddress[x] : +# 1772| mu1772_7(int) = Store[x] : &:r1772_6, r1772_5 +#-----| Goto -> Block 8 + +# 1775| Block 8 +# 1775| r1775_1(glval) = VariableAddress[z] : +# 1775| r1775_2(glval) = VariableAddress[x] : +# 1775| r1775_3(int) = Load[x] : &:r1775_2, ~m? +# 1775| mu1775_4(int) = Store[z] : &:r1775_1, r1775_3 +# 1776| r1776_1(glval) = VariableAddress[z] : +# 1776| r1776_2(int) = Load[z] : &:r1776_1, ~m? +# 1776| r1776_3(int) = Constant[0] : +# 1776| r1776_4(bool) = CompareNE : r1776_2, r1776_3 +# 1776| v1776_5(void) = ConditionalBranch : r1776_4 +#-----| False -> Block 10 +#-----| True -> Block 9 + +# 1777| Block 9 +# 1777| r1777_1(glval) = VariableAddress[x] : +# 1777| r1777_2(int) = Load[x] : &:r1777_1, ~m? +# 1777| r1777_3(glval) = VariableAddress[z] : +# 1777| r1777_4(int) = Load[z] : &:r1777_3, ~m? +# 1777| r1777_5(int) = Add : r1777_2, r1777_4 +# 1777| r1777_6(glval) = VariableAddress[x] : +# 1777| mu1777_7(int) = Store[x] : &:r1777_6, r1777_5 +#-----| Goto -> Block 10 + +# 1780| Block 10 +# 1780| r1780_1(glval) = VariableAddress[z2] : +# 1780| r1780_2(glval) = VariableAddress[z] : +# 1780| r1780_3(int) = Load[z] : &:r1780_2, ~m? +# 1780| mu1780_4(int) = Store[z2] : &:r1780_1, r1780_3 +# 1780| r1780_5(glval) = VariableAddress[z2] : +# 1780| r1780_6(int) = Load[z2] : &:r1780_5, ~m? +# 1780| r1780_7(int) = Constant[0] : +# 1780| r1780_8(bool) = CompareNE : r1780_6, r1780_7 +# 1780| r1780_9(bool) = CopyValue : r1780_8 +# 1780| v1780_10(void) = ConditionalBranch : r1780_9 +#-----| False -> Block 12 +#-----| True -> Block 11 + +# 1781| Block 11 +# 1781| r1781_1(glval) = VariableAddress[z2] : +# 1781| r1781_2(int) = Load[z2] : &:r1781_1, ~m? +# 1781| r1781_3(glval) = VariableAddress[x] : +# 1781| r1781_4(int) = Load[x] : &:r1781_3, ~m? +# 1781| r1781_5(int) = Add : r1781_4, r1781_2 +# 1781| mu1781_6(int) = Store[x] : &:r1781_3, r1781_5 +#-----| Goto -> Block 12 + +# 1783| Block 12 +# 1783| v1783_1(void) = NoOp : +# 1757| v1757_6(void) = ReturnVoid : +# 1757| v1757_7(void) = AliasedUse : ~m? +# 1757| v1757_8(void) = ExitFunction : + +# 1785| void switch_initialization(int) +# 1785| Block 0 +# 1785| v1785_1(void) = EnterFunction : +# 1785| mu1785_2(unknown) = AliasedDefinition : +# 1785| mu1785_3(unknown) = InitializeNonLocal : +# 1785| r1785_4(glval) = VariableAddress[x] : +# 1785| mu1785_5(int) = InitializeParameter[x] : &:r1785_4 +# 1786| r1786_1(glval) = VariableAddress[y] : +# 1786| r1786_2(glval) = VariableAddress[x] : +# 1786| r1786_3(int) = Load[x] : &:r1786_2, ~m? +# 1786| mu1786_4(int) = Store[y] : &:r1786_1, r1786_3 +# 1786| r1786_5(glval) = VariableAddress[x] : +# 1786| r1786_6(int) = Load[x] : &:r1786_5, ~m? +# 1786| r1786_7(int) = Constant[1] : +# 1786| r1786_8(int) = Add : r1786_6, r1786_7 +# 1786| v1786_9(void) = Switch : r1786_8 +#-----| Default -> Block 1 + +# 1787| Block 1 +# 1787| v1787_1(void) = NoOp : +# 1788| r1788_1(glval) = VariableAddress[x] : +# 1788| r1788_2(int) = Load[x] : &:r1788_1, ~m? +# 1788| r1788_3(glval) = VariableAddress[y] : +# 1788| r1788_4(int) = Load[y] : &:r1788_3, ~m? +# 1788| r1788_5(int) = Add : r1788_2, r1788_4 +# 1788| r1788_6(glval) = VariableAddress[x] : +# 1788| mu1788_7(int) = Store[x] : &:r1788_6, r1788_5 +# 1791| r1791_1(glval) = VariableAddress[w] : +# 1791| mu1791_2(int) = Uninitialized[w] : &:r1791_1 +# 1792| r1792_1(glval) = VariableAddress[x] : +# 1792| r1792_2(int) = Load[x] : &:r1792_1, ~m? +# 1792| r1792_3(glval) = VariableAddress[w] : +# 1792| mu1792_4(int) = Store[w] : &:r1792_3, r1792_2 +# 1792| r1792_5(glval) = VariableAddress[x] : +# 1792| r1792_6(int) = Load[x] : &:r1792_5, ~m? +# 1792| r1792_7(int) = Constant[1] : +# 1792| r1792_8(int) = Add : r1792_6, r1792_7 +# 1792| v1792_9(void) = Switch : r1792_8 +#-----| Default -> Block 2 + +# 1793| Block 2 +# 1793| v1793_1(void) = NoOp : +# 1794| r1794_1(glval) = VariableAddress[x] : +# 1794| r1794_2(int) = Load[x] : &:r1794_1, ~m? +# 1794| r1794_3(glval) = VariableAddress[w] : +# 1794| r1794_4(int) = Load[w] : &:r1794_3, ~m? +# 1794| r1794_5(int) = Add : r1794_2, r1794_4 +# 1794| r1794_6(glval) = VariableAddress[x] : +# 1794| mu1794_7(int) = Store[x] : &:r1794_6, r1794_5 +# 1797| r1797_1(glval) = VariableAddress[x] : +# 1797| r1797_2(int) = Load[x] : &:r1797_1, ~m? +# 1797| r1797_3(glval) = VariableAddress[w] : +# 1797| mu1797_4(int) = Store[w] : &:r1797_3, r1797_2 +# 1797| r1797_5(glval) = VariableAddress[w2] : +# 1797| r1797_6(glval) = VariableAddress[w] : +# 1797| r1797_7(int) = Load[w] : &:r1797_6, ~m? +# 1797| mu1797_8(int) = Store[w2] : &:r1797_5, r1797_7 +# 1797| r1797_9(glval) = VariableAddress[w2] : +# 1797| r1797_10(int) = Load[w2] : &:r1797_9, ~m? +# 1797| r1797_11(int) = CopyValue : r1797_10 +# 1797| v1797_12(void) = Switch : r1797_11 +#-----| Default -> Block 3 + +# 1798| Block 3 +# 1798| v1798_1(void) = NoOp : +# 1799| r1799_1(glval) = VariableAddress[x] : +# 1799| r1799_2(int) = Load[x] : &:r1799_1, ~m? +# 1799| r1799_3(glval) = VariableAddress[w] : +# 1799| r1799_4(int) = Load[w] : &:r1799_3, ~m? +# 1799| r1799_5(int) = Add : r1799_2, r1799_4 +# 1799| r1799_6(glval) = VariableAddress[x] : +# 1799| mu1799_7(int) = Store[x] : &:r1799_6, r1799_5 +# 1802| r1802_1(glval) = VariableAddress[v] : +# 1802| r1802_2(glval) = VariableAddress[x] : +# 1802| r1802_3(int) = Load[x] : &:r1802_2, ~m? +# 1802| mu1802_4(int) = Store[v] : &:r1802_1, r1802_3 +# 1802| r1802_5(glval) = VariableAddress[v2] : +# 1802| r1802_6(glval) = VariableAddress[v] : +# 1802| r1802_7(int) = Load[v] : &:r1802_6, ~m? +# 1802| mu1802_8(int) = Store[v2] : &:r1802_5, r1802_7 +# 1802| r1802_9(glval) = VariableAddress[v2] : +# 1802| r1802_10(int) = Load[v2] : &:r1802_9, ~m? +# 1802| r1802_11(int) = CopyValue : r1802_10 +# 1802| v1802_12(void) = Switch : r1802_11 +#-----| Default -> Block 4 + +# 1803| Block 4 +# 1803| v1803_1(void) = NoOp : +# 1804| r1804_1(glval) = VariableAddress[x] : +# 1804| r1804_2(int) = Load[x] : &:r1804_1, ~m? +# 1804| r1804_3(glval) = VariableAddress[v] : +# 1804| r1804_4(int) = Load[v] : &:r1804_3, ~m? +# 1804| r1804_5(int) = Add : r1804_2, r1804_4 +# 1804| r1804_6(glval) = VariableAddress[x] : +# 1804| mu1804_7(int) = Store[x] : &:r1804_6, r1804_5 +# 1807| r1807_1(glval) = VariableAddress[z] : +# 1807| r1807_2(glval) = VariableAddress[x] : +# 1807| r1807_3(int) = Load[x] : &:r1807_2, ~m? +# 1807| mu1807_4(int) = Store[z] : &:r1807_1, r1807_3 +# 1808| r1808_1(glval) = VariableAddress[z] : +# 1808| r1808_2(int) = Load[z] : &:r1808_1, ~m? +# 1808| v1808_3(void) = Switch : r1808_2 +#-----| Default -> Block 5 + +# 1809| Block 5 +# 1809| v1809_1(void) = NoOp : +# 1810| r1810_1(glval) = VariableAddress[x] : +# 1810| r1810_2(int) = Load[x] : &:r1810_1, ~m? +# 1810| r1810_3(glval) = VariableAddress[z] : +# 1810| r1810_4(int) = Load[z] : &:r1810_3, ~m? +# 1810| r1810_5(int) = Add : r1810_2, r1810_4 +# 1810| r1810_6(glval) = VariableAddress[x] : +# 1810| mu1810_7(int) = Store[x] : &:r1810_6, r1810_5 +# 1813| r1813_1(glval) = VariableAddress[z2] : +# 1813| r1813_2(glval) = VariableAddress[z] : +# 1813| r1813_3(int) = Load[z] : &:r1813_2, ~m? +# 1813| mu1813_4(int) = Store[z2] : &:r1813_1, r1813_3 +# 1813| r1813_5(glval) = VariableAddress[z2] : +# 1813| r1813_6(int) = Load[z2] : &:r1813_5, ~m? +# 1813| r1813_7(int) = CopyValue : r1813_6 +# 1813| v1813_8(void) = Switch : r1813_7 +#-----| Default -> Block 6 + +# 1814| Block 6 +# 1814| v1814_1(void) = NoOp : +# 1815| r1815_1(glval) = VariableAddress[z2] : +# 1815| r1815_2(int) = Load[z2] : &:r1815_1, ~m? +# 1815| r1815_3(glval) = VariableAddress[x] : +# 1815| r1815_4(int) = Load[x] : &:r1815_3, ~m? +# 1815| r1815_5(int) = Add : r1815_4, r1815_2 +# 1815| mu1815_6(int) = Store[x] : &:r1815_3, r1815_5 +# 1817| v1817_1(void) = NoOp : +# 1785| v1785_6(void) = ReturnVoid : +# 1785| v1785_7(void) = AliasedUse : ~m? +# 1785| v1785_8(void) = ExitFunction : + perf-regression.cpp: # 6| void Big::Big() # 6| Block 0 diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-611/XXE.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-611/XXE.expected index 24371939674..a4db6155e31 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-611/XXE.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-611/XXE.expected @@ -4,6 +4,15 @@ edges | tests3.cpp:23:21:23:53 | call to createXMLReader | tests3.cpp:25:2:25:2 | p | | tests3.cpp:60:21:60:53 | call to createXMLReader | tests3.cpp:63:2:63:2 | p | | tests3.cpp:67:21:67:53 | call to createXMLReader | tests3.cpp:70:2:70:2 | p | +| tests5.cpp:27:25:27:38 | call to createLSParser | tests5.cpp:29:2:29:2 | p | +| tests5.cpp:40:25:40:38 | call to createLSParser | tests5.cpp:43:2:43:2 | p | +| tests5.cpp:55:25:55:38 | call to createLSParser | tests5.cpp:59:2:59:2 | p | +| tests5.cpp:81:25:81:38 | call to createLSParser | tests5.cpp:83:2:83:2 | p | +| tests5.cpp:81:25:81:38 | call to createLSParser | tests5.cpp:83:2:83:2 | p | +| tests5.cpp:83:2:83:2 | p | tests5.cpp:85:2:85:2 | p | +| tests5.cpp:85:2:85:2 | p | tests5.cpp:86:2:86:2 | p | +| tests5.cpp:86:2:86:2 | p | tests5.cpp:88:2:88:2 | p | +| tests5.cpp:88:2:88:2 | p | tests5.cpp:89:2:89:2 | p | | tests.cpp:15:23:15:43 | XercesDOMParser output argument | tests.cpp:17:2:17:2 | p | | tests.cpp:28:23:28:43 | XercesDOMParser output argument | tests.cpp:31:2:31:2 | p | | tests.cpp:35:19:35:19 | VariableAddress [post update] | tests.cpp:37:2:37:2 | p | @@ -46,6 +55,19 @@ nodes | tests4.cpp:46:34:46:68 | ... \| ... | semmle.label | ... \| ... | | tests4.cpp:77:34:77:38 | flags | semmle.label | flags | | tests4.cpp:130:39:130:55 | (int)... | semmle.label | (int)... | +| tests5.cpp:27:25:27:38 | call to createLSParser | semmle.label | call to createLSParser | +| tests5.cpp:29:2:29:2 | p | semmle.label | p | +| tests5.cpp:40:25:40:38 | call to createLSParser | semmle.label | call to createLSParser | +| tests5.cpp:43:2:43:2 | p | semmle.label | p | +| tests5.cpp:55:25:55:38 | call to createLSParser | semmle.label | call to createLSParser | +| tests5.cpp:59:2:59:2 | p | semmle.label | p | +| tests5.cpp:81:25:81:38 | call to createLSParser | semmle.label | call to createLSParser | +| tests5.cpp:83:2:83:2 | p | semmle.label | p | +| tests5.cpp:83:2:83:2 | p | semmle.label | p | +| tests5.cpp:85:2:85:2 | p | semmle.label | p | +| tests5.cpp:86:2:86:2 | p | semmle.label | p | +| tests5.cpp:88:2:88:2 | p | semmle.label | p | +| tests5.cpp:89:2:89:2 | p | semmle.label | p | | tests.cpp:15:23:15:43 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument | | tests.cpp:17:2:17:2 | p | semmle.label | p | | tests.cpp:28:23:28:43 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument | @@ -93,6 +115,11 @@ subpaths | tests4.cpp:46:34:46:68 | ... \| ... | tests4.cpp:46:34:46:68 | ... \| ... | tests4.cpp:46:34:46:68 | ... \| ... | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests4.cpp:46:34:46:68 | ... \| ... | XML parser | | tests4.cpp:77:34:77:38 | flags | tests4.cpp:77:34:77:38 | flags | tests4.cpp:77:34:77:38 | flags | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests4.cpp:77:34:77:38 | flags | XML parser | | tests4.cpp:130:39:130:55 | (int)... | tests4.cpp:130:39:130:55 | (int)... | tests4.cpp:130:39:130:55 | (int)... | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests4.cpp:130:39:130:55 | (int)... | XML parser | +| tests5.cpp:29:2:29:2 | p | tests5.cpp:27:25:27:38 | call to createLSParser | tests5.cpp:29:2:29:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests5.cpp:27:25:27:38 | call to createLSParser | XML parser | +| tests5.cpp:43:2:43:2 | p | tests5.cpp:40:25:40:38 | call to createLSParser | tests5.cpp:43:2:43:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests5.cpp:40:25:40:38 | call to createLSParser | XML parser | +| tests5.cpp:59:2:59:2 | p | tests5.cpp:55:25:55:38 | call to createLSParser | tests5.cpp:59:2:59:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests5.cpp:55:25:55:38 | call to createLSParser | XML parser | +| tests5.cpp:83:2:83:2 | p | tests5.cpp:81:25:81:38 | call to createLSParser | tests5.cpp:83:2:83:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests5.cpp:81:25:81:38 | call to createLSParser | XML parser | +| tests5.cpp:89:2:89:2 | p | tests5.cpp:81:25:81:38 | call to createLSParser | tests5.cpp:89:2:89:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests5.cpp:81:25:81:38 | call to createLSParser | XML parser | | tests.cpp:17:2:17:2 | p | tests.cpp:15:23:15:43 | XercesDOMParser output argument | tests.cpp:17:2:17:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:15:23:15:43 | XercesDOMParser output argument | XML parser | | tests.cpp:31:2:31:2 | p | tests.cpp:28:23:28:43 | XercesDOMParser output argument | tests.cpp:31:2:31:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:28:23:28:43 | XercesDOMParser output argument | XML parser | | tests.cpp:39:2:39:2 | p | tests.cpp:35:23:35:43 | XercesDOMParser output argument | tests.cpp:39:2:39:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:35:23:35:43 | XercesDOMParser output argument | XML parser | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-611/tests5.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-611/tests5.cpp index e98d5a99e60..99027c9bd93 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-611/tests5.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-611/tests5.cpp @@ -26,7 +26,7 @@ public: void test5_1(DOMImplementationLS *impl, InputSource &data) { DOMLSParser *p = impl->createLSParser(); - p->parse(data); // BAD (parser not correctly configured) [NOT DETECTED] + p->parse(data); // BAD (parser not correctly configured) } void test5_2(DOMImplementationLS *impl, InputSource &data) { @@ -40,7 +40,7 @@ void test5_3(DOMImplementationLS *impl, InputSource &data) { DOMLSParser *p = impl->createLSParser(); p->getDomConfig()->setParameter(XMLUni::fgXercesDisableDefaultEntityResolution, false); - p->parse(data); // BAD (parser not correctly configured) [NOT DETECTED] + p->parse(data); // BAD (parser not correctly configured) } void test5_4(DOMImplementationLS *impl, InputSource &data) { @@ -56,7 +56,7 @@ void test5_5(DOMImplementationLS *impl, InputSource &data) { DOMConfiguration *cfg = p->getDomConfig(); cfg->setParameter(XMLUni::fgXercesDisableDefaultEntityResolution, false); - p->parse(data); // BAD (parser not correctly configured) [NOT DETECTED] + p->parse(data); // BAD (parser not correctly configured) } DOMImplementationLS *g_impl; @@ -76,3 +76,28 @@ void test5_6() { g_p1->parse(*g_data); // GOOD g_p2->parse(*g_data); // BAD (parser not correctly configured) [NOT DETECTED] } + +void test5_7(DOMImplementationLS *impl, InputSource &data) { + DOMLSParser *p = impl->createLSParser(); + + p->parse(data); // BAD (parser not correctly configured) + + p->getDomConfig()->setParameter(XMLUni::fgXercesDisableDefaultEntityResolution, true); + p->parse(data); // GOOD + + p->getDomConfig()->setParameter(XMLUni::fgXercesDisableDefaultEntityResolution, false); + p->parse(data); // BAD (parser not correctly configured) +} + +void test5_8(DOMImplementationLS *impl, InputSource &data) { + DOMLSParser *p = impl->createLSParser(); + DOMConfiguration *cfg = p->getDomConfig(); + + p->parse(data); // BAD (parser not correctly configured) [NOT DETECTED] + + cfg->setParameter(XMLUni::fgXercesDisableDefaultEntityResolution, true); + p->parse(data); // GOOD + + cfg->setParameter(XMLUni::fgXercesDisableDefaultEntityResolution, false); + p->parse(data); // BAD (parser not correctly configured) [NOT DETECTED] +} diff --git a/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt.cpp b/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt.cpp new file mode 100644 index 00000000000..b8d09edffca --- /dev/null +++ b/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt.cpp @@ -0,0 +1,8 @@ +void normal(int x, int y) { + if(int z = y; x == z) { + l1:; + } + l2:; +} + +// semmle-extractor-options: -std=c++17 diff --git a/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt01.expected b/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt01.expected index 9ed533ab840..73752ac3834 100644 --- a/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt01.expected +++ b/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt01.expected @@ -1 +1,2 @@ | ifstmt.c:28:6:28:11 | ... == ... | l2 | +| ifstmt.cpp:2:17:2:22 | ... == ... | l2 | diff --git a/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt02.expected b/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt02.expected index 1dfd5b6042e..fcc99833adc 100644 --- a/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt02.expected +++ b/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt02.expected @@ -1 +1,2 @@ | ifstmt.c:28:6:28:11 | ... == ... | l1 | +| ifstmt.cpp:2:17:2:22 | ... == ... | l1 | diff --git a/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt04.expected b/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt04.expected index a3eb12cc2c2..6de3a7b13f0 100644 --- a/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt04.expected +++ b/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt04.expected @@ -1 +1,2 @@ | ifstmt.c:29:8:29:8 | ; | l2 | +| ifstmt.cpp:3:8:3:8 | ; | l2 | diff --git a/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt05.ql b/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt05.ql index 46d6d103b8a..e59a59a01f4 100644 --- a/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt05.ql +++ b/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt05.ql @@ -1,6 +1,9 @@ /** * @name ifstmt05 - * @description Every if statement has its condition or one of the condition's descendants as its unique successor. + * @description Every if statement with an initialization has the initialization or one of the + * initialization's descendants as its unique successor. Every if statement without + * and initialization has its condition or one of the condition's descendants as + * its unique successor. */ import cpp @@ -8,7 +11,11 @@ import cpp from IfStmt is where not ( - is.getASuccessor() = is.getCondition().getAChild*() and + ( + if exists(is.getInitialization()) + then is.getASuccessor() = is.getInitialization().getAChild*() + else is.getASuccessor() = is.getCondition().getAChild*() + ) and count(is.getASuccessor()) = 1 ) select is diff --git a/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt10.expected b/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt10.expected index 8ffff11ac6e..a031d5f7d66 100644 --- a/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt10.expected +++ b/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt10.expected @@ -1,12 +1,27 @@ | 0 | ifstmt.c:27:27:32:1 | { ... } | 1 | ifstmt.c:28:3:30:3 | if (...) ... | +| 0 | ifstmt.cpp:1:27:6:1 | { ... } | 1 | ifstmt.cpp:2:3:4:3 | if (...) ... | | 1 | ifstmt.c:28:3:30:3 | if (...) ... | 1 | ifstmt.c:28:6:28:6 | x | | 1 | ifstmt.c:28:6:28:6 | x | 1 | ifstmt.c:28:11:28:11 | y | | 1 | ifstmt.c:28:6:28:11 | ... == ... | 1 | ifstmt.c:28:14:30:3 | { ... } | | 1 | ifstmt.c:28:6:28:11 | ... == ... | 4 | ifstmt.c:31:3:31:5 | label ...: | | 1 | ifstmt.c:28:11:28:11 | y | 1 | ifstmt.c:28:6:28:11 | ... == ... | | 1 | ifstmt.c:28:14:30:3 | { ... } | 2 | ifstmt.c:29:5:29:7 | label ...: | +| 1 | ifstmt.cpp:2:3:4:3 | if (...) ... | 1 | ifstmt.cpp:2:6:2:6 | declaration | +| 1 | ifstmt.cpp:2:6:2:6 | declaration | 1 | ifstmt.cpp:2:13:2:14 | initializer for z | +| 1 | ifstmt.cpp:2:13:2:14 | initializer for z | 1 | ifstmt.cpp:2:14:2:14 | y | +| 1 | ifstmt.cpp:2:14:2:14 | y | 1 | ifstmt.cpp:2:17:2:17 | x | +| 1 | ifstmt.cpp:2:17:2:17 | x | 1 | ifstmt.cpp:2:22:2:22 | z | +| 1 | ifstmt.cpp:2:17:2:22 | ... == ... | 1 | ifstmt.cpp:2:25:4:3 | { ... } | +| 1 | ifstmt.cpp:2:17:2:22 | ... == ... | 4 | ifstmt.cpp:5:3:5:5 | label ...: | +| 1 | ifstmt.cpp:2:22:2:22 | z | 1 | ifstmt.cpp:2:17:2:22 | ... == ... | +| 1 | ifstmt.cpp:2:25:4:3 | { ... } | 2 | ifstmt.cpp:3:5:3:7 | label ...: | | 2 | ifstmt.c:29:5:29:7 | label ...: | 2 | ifstmt.c:29:8:29:8 | ; | | 2 | ifstmt.c:29:8:29:8 | ; | 4 | ifstmt.c:31:3:31:5 | label ...: | +| 2 | ifstmt.cpp:3:5:3:7 | label ...: | 2 | ifstmt.cpp:3:8:3:8 | ; | +| 2 | ifstmt.cpp:3:8:3:8 | ; | 4 | ifstmt.cpp:5:3:5:5 | label ...: | | 4 | ifstmt.c:31:3:31:5 | label ...: | 4 | ifstmt.c:31:6:31:6 | ; | | 4 | ifstmt.c:31:6:31:6 | ; | 5 | ifstmt.c:32:1:32:1 | return ... | +| 4 | ifstmt.cpp:5:3:5:5 | label ...: | 4 | ifstmt.cpp:5:6:5:6 | ; | +| 4 | ifstmt.cpp:5:6:5:6 | ; | 5 | ifstmt.cpp:6:1:6:1 | return ... | | 5 | ifstmt.c:32:1:32:1 | return ... | 0 | ifstmt.c:27:6:27:11 | normal | +| 5 | ifstmt.cpp:6:1:6:1 | return ... | 0 | ifstmt.cpp:1:6:1:11 | normal | diff --git a/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt11.expected b/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt11.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt11.ql b/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt11.ql new file mode 100644 index 00000000000..ad729b076e6 --- /dev/null +++ b/cpp/ql/test/successor-tests/ifstmt/ifstmt/ifstmt11.ql @@ -0,0 +1,15 @@ +/** + * @name ifstmt11 + * @description If an initialization exists, then the condition is a successor of the initialization. + */ + +import cpp + +from IfStmt is, Expr e, Stmt s, ControlFlowNode n +where + s = is.getInitialization() and + e = is.getCondition() and + n = s.getASuccessor*() and + not exists(ControlFlowNode m | m = e.getASuccessor*() | m = n) and + not exists(ControlFlowNode m | m = e.getAPredecessor*() | m = n) +select is diff --git a/cpp/ql/test/successor-tests/switchstmt/switchstmt/cfg.expected b/cpp/ql/test/successor-tests/switchstmt/switchstmt/cfg.expected index ca3de0ffaff..607995cefd3 100644 --- a/cpp/ql/test/successor-tests/switchstmt/switchstmt/cfg.expected +++ b/cpp/ql/test/successor-tests/switchstmt/switchstmt/cfg.expected @@ -12,3 +12,20 @@ | switchstmt | switchstmt.c:1:6:1:6 | f | 7 | 8 | switchstmt.c:7:5:7:5 | switchstmt.c:7:5:7:5 | switchstmt.c:7:5:7:5 | ; | 8: return ... | | switchstmt | switchstmt.c:1:6:1:6 | f | 8 | 9 | switchstmt.c:8:1:8:1 | switchstmt.c:8:1:8:1 | switchstmt.c:8:1:8:1 | return ... | 8: f | | switchstmt | switchstmt.c:1:6:1:6 | f | 8 | 10 | switchstmt.c:1:6:1:6 | switchstmt.c:1:6:1:6 | switchstmt.c:1:6:1:6 | f | | +| switchstmt | switchstmt.cpp:3:6:3:6 | g | 3 | 1 | switchstmt.cpp:3:15:12:1 | switchstmt.cpp:3:15:12:1 | switchstmt.cpp:3:15:12:1 | { ... } | 4: switch (...) ... | +| switchstmt | switchstmt.cpp:3:6:3:6 | g | 4 | 2 | switchstmt.cpp:4:6:10:5 | switchstmt.cpp:4:6:10:5 | switchstmt.cpp:4:6:10:5 | switch (...) ... | 5: declaration | +| switchstmt | switchstmt.cpp:3:6:3:6 | g | 5 | 3 | switchstmt.cpp:5:10:5:10 | switchstmt.cpp:5:10:5:10 | switchstmt.cpp:5:10:5:10 | declaration | 5: initializer for y | +| switchstmt | switchstmt.cpp:3:6:3:6 | g | 5 | 4 | switchstmt.cpp:5:17:5:18 | switchstmt.cpp:5:17:5:18 | switchstmt.cpp:5:17:5:18 | initializer for y | 5: x | +| switchstmt | switchstmt.cpp:3:6:3:6 | g | 5 | 5 | switchstmt.cpp:5:18:5:18 | switchstmt.cpp:5:18:5:18 | switchstmt.cpp:5:18:5:18 | x | 6: y | +| switchstmt | switchstmt.cpp:3:6:3:6 | g | 6 | 6 | switchstmt.cpp:6:10:6:10 | switchstmt.cpp:6:10:6:10 | switchstmt.cpp:6:10:6:10 | y | 6: { ... } | +| switchstmt | switchstmt.cpp:3:6:3:6 | g | 6 | 7 | switchstmt.cpp:6:13:10:5 | switchstmt.cpp:6:13:10:5 | switchstmt.cpp:6:13:10:5 | { ... } | 7: case ...: | +| switchstmt | switchstmt.cpp:3:6:3:6 | g | 6 | 7 | switchstmt.cpp:6:13:10:5 | switchstmt.cpp:6:13:10:5 | switchstmt.cpp:6:13:10:5 | { ... } | 8: case ...: | +| switchstmt | switchstmt.cpp:3:6:3:6 | g | 6 | 7 | switchstmt.cpp:6:13:10:5 | switchstmt.cpp:6:13:10:5 | switchstmt.cpp:6:13:10:5 | { ... } | 9: default: | +| switchstmt | switchstmt.cpp:3:6:3:6 | g | 7 | 1 | switchstmt.cpp:7:14:7:14 | switchstmt.cpp:7:14:7:14 | switchstmt.cpp:7:14:7:14 | 1 | | +| switchstmt | switchstmt.cpp:3:6:3:6 | g | 7 | 8 | switchstmt.cpp:7:9:7:15 | switchstmt.cpp:7:9:7:15 | switchstmt.cpp:7:9:7:15 | case ...: | 8: case ...: | +| switchstmt | switchstmt.cpp:3:6:3:6 | g | 8 | 1 | switchstmt.cpp:8:14:8:14 | switchstmt.cpp:8:14:8:14 | switchstmt.cpp:8:14:8:14 | 2 | | +| switchstmt | switchstmt.cpp:3:6:3:6 | g | 8 | 9 | switchstmt.cpp:8:9:8:15 | switchstmt.cpp:8:9:8:15 | switchstmt.cpp:8:9:8:15 | case ...: | 9: default: | +| switchstmt | switchstmt.cpp:3:6:3:6 | g | 9 | 10 | switchstmt.cpp:9:9:9:16 | switchstmt.cpp:9:9:9:16 | switchstmt.cpp:9:9:9:16 | default: | 11: ; | +| switchstmt | switchstmt.cpp:3:6:3:6 | g | 11 | 11 | switchstmt.cpp:11:5:11:5 | switchstmt.cpp:11:5:11:5 | switchstmt.cpp:11:5:11:5 | ; | 12: return ... | +| switchstmt | switchstmt.cpp:3:6:3:6 | g | 12 | 12 | switchstmt.cpp:12:1:12:1 | switchstmt.cpp:12:1:12:1 | switchstmt.cpp:12:1:12:1 | return ... | 12: g | +| switchstmt | switchstmt.cpp:3:6:3:6 | g | 12 | 13 | switchstmt.cpp:3:6:3:6 | switchstmt.cpp:3:6:3:6 | switchstmt.cpp:3:6:3:6 | g | | diff --git a/cpp/ql/test/successor-tests/switchstmt/switchstmt/switchstmt.cpp b/cpp/ql/test/successor-tests/switchstmt/switchstmt/switchstmt.cpp new file mode 100644 index 00000000000..a88ad7e710c --- /dev/null +++ b/cpp/ql/test/successor-tests/switchstmt/switchstmt/switchstmt.cpp @@ -0,0 +1,12 @@ +// semmle-extractor-options: -std=c++17 + +void g(int x) { + switch ( + int y = x; + y) { + case 1: + case 2: + default: + } + ; +} diff --git a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md index 2791add0d9c..a3b06b075db 100644 --- a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md +++ b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md @@ -1,3 +1,5 @@ +## 1.1.2 + ## 1.1.1 ## 1.1.0 diff --git a/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.1.2.md b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.1.2.md new file mode 100644 index 00000000000..a948ef6c11d --- /dev/null +++ b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.1.2.md @@ -0,0 +1 @@ +## 1.1.2 diff --git a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml index 1a19084be3f..53ab127707f 100644 --- a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml +++ b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.1.1 +lastReleaseVersion: 1.1.2 diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml index 6007262cb29..ef0192e094a 100644 --- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-all -version: 1.1.2-dev +version: 1.1.3-dev groups: - csharp - solorigate diff --git a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md index 2791add0d9c..a3b06b075db 100644 --- a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md +++ b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md @@ -1,3 +1,5 @@ +## 1.1.2 + ## 1.1.1 ## 1.1.0 diff --git a/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.1.2.md b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.1.2.md new file mode 100644 index 00000000000..a948ef6c11d --- /dev/null +++ b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.1.2.md @@ -0,0 +1 @@ +## 1.1.2 diff --git a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml index 1a19084be3f..53ab127707f 100644 --- a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml +++ b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.1.1 +lastReleaseVersion: 1.1.2 diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml index fd0349bb9f9..d3d0baabf19 100644 --- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-queries -version: 1.1.2-dev +version: 1.1.3-dev groups: - csharp - solorigate diff --git a/csharp/ql/lib/CHANGELOG.md b/csharp/ql/lib/CHANGELOG.md index 67bb243493e..17252098beb 100644 --- a/csharp/ql/lib/CHANGELOG.md +++ b/csharp/ql/lib/CHANGELOG.md @@ -1,3 +1,5 @@ +## 0.2.1 + ## 0.2.0 ### Breaking Changes diff --git a/csharp/ql/lib/change-notes/released/0.2.1.md b/csharp/ql/lib/change-notes/released/0.2.1.md new file mode 100644 index 00000000000..c260de2a9ee --- /dev/null +++ b/csharp/ql/lib/change-notes/released/0.2.1.md @@ -0,0 +1 @@ +## 0.2.1 diff --git a/csharp/ql/lib/codeql-pack.release.yml b/csharp/ql/lib/codeql-pack.release.yml index 5274e27ed52..df29a726bcc 100644 --- a/csharp/ql/lib/codeql-pack.release.yml +++ b/csharp/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.2.0 +lastReleaseVersion: 0.2.1 diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml index f0f70451e5f..2b91ac08704 100644 --- a/csharp/ql/lib/qlpack.yml +++ b/csharp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-all -version: 0.2.1-dev +version: 0.2.2-dev groups: csharp dbscheme: semmlecode.csharp.dbscheme extractor: csharp diff --git a/csharp/ql/lib/semmle/code/cil/Instructions.qll b/csharp/ql/lib/semmle/code/cil/Instructions.qll index 370a91d8343..91bc1f37ea6 100644 --- a/csharp/ql/lib/semmle/code/cil/Instructions.qll +++ b/csharp/ql/lib/semmle/code/cil/Instructions.qll @@ -491,7 +491,7 @@ module Opcodes { override Callable getTarget() { none() } - /** Gets the function pointer type targetted by this instruction. */ + /** Gets the function pointer type targeted by this instruction. */ FunctionPointerType getTargetType() { cil_access(this, result) } // The number of items popped/pushed from the stack depends on the target of diff --git a/csharp/ql/lib/semmle/code/csharp/Member.qll b/csharp/ql/lib/semmle/code/csharp/Member.qll index 01a19ff87e0..ad314217024 100644 --- a/csharp/ql/lib/semmle/code/csharp/Member.qll +++ b/csharp/ql/lib/semmle/code/csharp/Member.qll @@ -117,7 +117,7 @@ class Modifiable extends Declaration, @modifiable { * Note that explicit interface implementations are also considered effectively * `private` if the implemented interface is itself effectively `private`. Finally, * `private protected` members are not considered effectively `private`, because - * they can be overriden within the declaring assembly. + * they can be overridden within the declaring assembly. */ predicate isEffectivelyPrivate() { this.isReallyPrivate() or @@ -143,7 +143,7 @@ class Modifiable extends Declaration, @modifiable { * considered. Explicit interface implementations are also considered effectively * `internal` if the implemented interface is itself effectively `internal`. Finally, * `internal protected` members are not considered effectively `internal`, because - * they can be overriden outside the declaring assembly. + * they can be overridden outside the declaring assembly. */ predicate isEffectivelyInternal() { this.isReallyInternal() or diff --git a/csharp/ql/lib/semmle/code/csharp/PrintAst.qll b/csharp/ql/lib/semmle/code/csharp/PrintAst.qll index a3d36fba69d..d179da2e194 100644 --- a/csharp/ql/lib/semmle/code/csharp/PrintAst.qll +++ b/csharp/ql/lib/semmle/code/csharp/PrintAst.qll @@ -265,7 +265,7 @@ class TypeMentionNode extends PrintAstNode, TTypeMentionNode { final TypeMention getTypeMention() { result = typeMention } /** - * Gets the `Element` targetted by the `TypeMention`. + * Gets the `Element` targeted by the `TypeMention`. */ final Element getTarget() { result = typeMention.getTarget() } diff --git a/csharp/ql/lib/semmle/code/csharp/Unification.qll b/csharp/ql/lib/semmle/code/csharp/Unification.qll index ae2ee5a2e49..4df258c1d00 100644 --- a/csharp/ql/lib/semmle/code/csharp/Unification.qll +++ b/csharp/ql/lib/semmle/code/csharp/Unification.qll @@ -672,7 +672,7 @@ module Unification { * `ConstrainedTypeParameter::unifiable()` can be used. * * - * For performance reasons, type paramater constraints inside `t1` and `t2` are + * For performance reasons, type parameter constraints inside `t1` and `t2` are * *not* taken into account, and there is also no guarantee that the same type * parameter can be substituted with two different terms. For example, in * diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll index e7ae2e489a2..47fcd24883c 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll @@ -744,7 +744,7 @@ cached private module Cached { /** * If needed, call this predicate from `ControlFlowGraphImplSpecific.qll` in order to - * force a stage-dependency on the `ControlFlowGraphImplShared.qll` stage and therby + * force a stage-dependency on the `ControlFlowGraphImplShared.qll` stage and thereby * collapsing the two stages. */ cached diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 5bd84566df5..fb773ea89f8 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 5bd84566df5..fb773ea89f8 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 5bd84566df5..fb773ea89f8 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 5bd84566df5..fb773ea89f8 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 5bd84566df5..fb773ea89f8 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll index e60505d9248..0079b259260 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -305,7 +305,7 @@ cached private module Cached { /** * If needed, call this predicate from `DataFlowImplSpecific.qll` in order to - * force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby + * force a stage-dependency on the `DataFlowImplCommon.qll` stage and thereby * collapsing the two stages. */ cached diff --git a/csharp/ql/lib/semmle/code/csharp/dispatch/OverridableCallable.qll b/csharp/ql/lib/semmle/code/csharp/dispatch/OverridableCallable.qll index f346a660137..ffb14f1e915 100644 --- a/csharp/ql/lib/semmle/code/csharp/dispatch/OverridableCallable.qll +++ b/csharp/ql/lib/semmle/code/csharp/dispatch/OverridableCallable.qll @@ -9,7 +9,7 @@ import csharp * A callable that can be overridden or implemented. * * Unlike the class `Overridable`, this class only includes callables that - * can actually be overriden/implemented. + * can actually be overridden/implemented. */ class OverridableCallable extends Callable, Overridable { OverridableCallable() { this.isOverridableOrImplementable() } diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll index bbed4062a97..e62b95a04cf 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll @@ -937,7 +937,7 @@ class ThrowExpr extends Expr, ThrowElement, @throw_expr { * For example, `new ArgumentException("i")` in * `return i != 0 ? 1 / i : throw new ArgumentException("i");`. */ - // overriden for more precise qldoc + // overridden for more precise qldoc override Expr getExpr() { result = ThrowElement.super.getExpr() } override string getAPrimaryQlClass() { result = "ThrowExpr" } @@ -1173,7 +1173,7 @@ class WithExpr extends Expr, @with_expr { /** Gets the expression on which this `with` is called. */ Expr getExpr() { result = this.getChild(0) } - /** Gets the clone method of the `record` that is targetted by this `with` expression. */ + /** Gets the clone method of the `record` that is targeted by this `with` expression. */ RecordCloneMethod getCloneMethod() { result = this.getExpr().getType().(RecordClass).getCloneMethod() } diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/EntityFramework.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/EntityFramework.qll index f0ec251db03..30930f6de18 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/EntityFramework.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/EntityFramework.qll @@ -258,6 +258,30 @@ module EntityFramework { } } + /** A sink method in `Microsoft.EntityFrameworkCore.RelationalQueryableExtensions` that executes SQL. */ + private class MicrosoftEntityFrameworkCoreRelationalQueryableExtensionsSinkModelCsv extends SinkModelCsv { + override predicate row(string row) { + row = + [ + "Microsoft.EntityFrameworkCore;RelationalQueryableExtensions;false;FromSqlRaw<>;(Microsoft.EntityFrameworkCore.DbSet,System.String,System.Object[]);;Argument[1];sql", + ] + } + } + + /** A sink method in `Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions` that executes SQL. */ + private class MicrosoftEntityFrameworkCoreRelationalDatabaseFacadeExtensionsSinkModelCsv extends SinkModelCsv { + override predicate row(string row) { + row = + [ + "Microsoft.EntityFrameworkCore;RelationalDatabaseFacadeExtensions;false;ExecuteSqlRaw;(Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade,System.String,System.Collections.Generic.IEnumerable);;Argument[1];sql", + "Microsoft.EntityFrameworkCore;RelationalDatabaseFacadeExtensions;false;ExecuteSqlRaw;(Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade,System.String,System.Object[]);;Argument[1];sql", + "Microsoft.EntityFrameworkCore;RelationalDatabaseFacadeExtensions;false;ExecuteSqlRawAsync;(Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade,System.String,System.Threading.CancellationToken);;Argument[1];sql", + "Microsoft.EntityFrameworkCore;RelationalDatabaseFacadeExtensions;false;ExecuteSqlRawAsync;(Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade,System.String,System.Object[]);;Argument[1];sql", + "Microsoft.EntityFrameworkCore;RelationalDatabaseFacadeExtensions;false;ExecuteSqlRawAsync;(Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade,System.String,System.Collections.Generic.IEnumerable,System.Threading.CancellationToken);;Argument[1];sql", + ] + } + } + /** Holds if `t` is compatible with a DB column type. */ private predicate isColumnType(Type t) { t instanceof SimpleType diff --git a/csharp/ql/src/CHANGELOG.md b/csharp/ql/src/CHANGELOG.md index c6b210ab15b..77df7a74581 100644 --- a/csharp/ql/src/CHANGELOG.md +++ b/csharp/ql/src/CHANGELOG.md @@ -1,3 +1,5 @@ +## 0.1.2 + ## 0.1.1 ## 0.1.0 diff --git a/csharp/ql/src/change-notes/released/0.1.2.md b/csharp/ql/src/change-notes/released/0.1.2.md new file mode 100644 index 00000000000..66bd49d11eb --- /dev/null +++ b/csharp/ql/src/change-notes/released/0.1.2.md @@ -0,0 +1 @@ +## 0.1.2 diff --git a/csharp/ql/src/codeql-pack.release.yml b/csharp/ql/src/codeql-pack.release.yml index 92d1505475f..6abd14b1ef8 100644 --- a/csharp/ql/src/codeql-pack.release.yml +++ b/csharp/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.1.1 +lastReleaseVersion: 0.1.2 diff --git a/csharp/ql/src/definitions.qll b/csharp/ql/src/definitions.qll index 8580f88d05d..4feaf20629c 100644 --- a/csharp/ql/src/definitions.qll +++ b/csharp/ql/src/definitions.qll @@ -105,7 +105,7 @@ private class AccessUse extends Access, Use { not this.(PropertyAccess).getParent().getParent() instanceof Property // Property initializer } - /** Gets the qualifier of this acccess, if any. */ + /** Gets the qualifier of this access, if any. */ private Expr getFormatQualifier() { result = this.(QualifiableExpr).getQualifier() and not result.isImplicit() diff --git a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql index 31c00e8a378..4745daf6b8b 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql +++ b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql @@ -70,7 +70,7 @@ class DateTimeStruct extends Struct { } /** - * Holds if the Callable is used for DateTime comparision + * Holds if the Callable is used for DateTime comparison */ Callable getAComparisonCallable() { (result = this.getAnOperator() or result = this.getAMethod()) and diff --git a/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll b/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll index 32e36bb6787..91e1fe03e23 100644 --- a/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll +++ b/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll @@ -67,7 +67,7 @@ class DefaultEdge extends EdgeKind, TDefaultEdge { /** * A "case" edge, representing the successor of a `Switch` instruction when the - * the condition value matches a correponding `case` label. + * the condition value matches a corresponding `case` label. */ class CaseEdge extends EdgeKind, TCaseEdge { string minValue; diff --git a/csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll b/csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll index 796fb792366..ca3c378cd7e 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll @@ -34,7 +34,7 @@ class ValueNumber extends TValueNumber { final Instruction getAnInstruction() { this = valueNumber(result) } /** - * Gets one of the instructions that was assigned this value number. The chosen instuction is + * Gets one of the instructions that was assigned this value number. The chosen instruction is * deterministic but arbitrary. Intended for use only in debugging. */ final Instruction getExampleInstruction() { diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll index ef40d716fea..19b773c2622 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll @@ -183,7 +183,7 @@ abstract class TranslatedCompilerGeneratedVariableAccess extends TranslatedCompi override Instruction getChildSuccessor(TranslatedElement child) { none() } /** - * Returns the type of the accessed variable. Can be overriden when the return + * Returns the type of the accessed variable. Can be overridden when the return * type is different than the type of the underlying variable. */ Type getVariableType() { result = getResultType() } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll index 796fb792366..ca3c378cd7e 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll @@ -34,7 +34,7 @@ class ValueNumber extends TValueNumber { final Instruction getAnInstruction() { this = valueNumber(result) } /** - * Gets one of the instructions that was assigned this value number. The chosen instuction is + * Gets one of the instructions that was assigned this value number. The chosen instruction is * deterministic but arbitrary. Intended for use only in debugging. */ final Instruction getExampleInstruction() { diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 13ec2ca4ca4..303a9683011 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -1005,7 +1005,7 @@ predicate canReuseSsaForMemoryResult(Instruction instruction) { deprecated predicate canReuseSSAForMemoryResult = canReuseSsaForMemoryResult/1; /** - * Expose some of the internal predicates to PrintSSA.qll. We do this by publically importing those modules in the + * Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the * `DebugSSA` module, which is then imported by PrintSSA. */ module DebugSsa { diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml index 979ad1cd37b..873dbdff8c6 100644 --- a/csharp/ql/src/qlpack.yml +++ b/csharp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-queries -version: 0.1.2-dev +version: 0.1.3-dev groups: - csharp - queries diff --git a/csharp/ql/test/TestUtilities/InlineExpectationsTest.qll b/csharp/ql/test/TestUtilities/InlineExpectationsTest.qll index a4d264b2703..3891fcf13a1 100644 --- a/csharp/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/csharp/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -181,7 +181,7 @@ private string expectationCommentPattern() { result = "\\s*\\$((?:[^/]|/[^/])*)( /** * The possible columns in an expectation comment. The `TDefaultColumn` branch represents the first * column in a comment. This column is not precedeeded by a name. `TNamedColumn(name)` represents a - * column containing expected results preceeded by the string `name:`. + * column containing expected results preceded by the string `name:`. */ private newtype TColumn = TDefaultColumn() or diff --git a/csharp/ql/test/library-tests/frameworks/EntityFramework/Dataflow.expected b/csharp/ql/test/library-tests/frameworks/EntityFramework/Dataflow.expected index 6120caaad32..5f7866b09d1 100644 --- a/csharp/ql/test/library-tests/frameworks/EntityFramework/Dataflow.expected +++ b/csharp/ql/test/library-tests/frameworks/EntityFramework/Dataflow.expected @@ -82,97 +82,97 @@ edges | EntityFramework.cs:219:18:219:36 | call to method First [property Addresses, element, property Street] : String | EntityFramework.cs:219:18:219:46 | access to property Addresses [element, property Street] : String | | EntityFramework.cs:219:18:219:46 | access to property Addresses [element, property Street] : String | EntityFramework.cs:219:18:219:54 | call to method First
[property Street] : String | | EntityFramework.cs:219:18:219:54 | call to method First
[property Street] : String | EntityFramework.cs:219:18:219:61 | access to property Street | -| EntityFrameworkCore.cs:75:31:75:39 | "tainted" : String | EntityFrameworkCore.cs:76:18:76:28 | access to local variable taintSource | -| EntityFrameworkCore.cs:75:31:75:39 | "tainted" : String | EntityFrameworkCore.cs:77:35:77:45 | access to local variable taintSource : String | -| EntityFrameworkCore.cs:75:31:75:39 | "tainted" : String | EntityFrameworkCore.cs:78:18:78:42 | (...) ... | -| EntityFrameworkCore.cs:75:31:75:39 | "tainted" : String | EntityFrameworkCore.cs:78:32:78:42 | access to local variable taintSource : String | -| EntityFrameworkCore.cs:77:18:77:46 | object creation of type RawSqlString : RawSqlString | EntityFrameworkCore.cs:77:18:77:46 | (...) ... | -| EntityFrameworkCore.cs:77:35:77:45 | access to local variable taintSource : String | EntityFrameworkCore.cs:77:18:77:46 | object creation of type RawSqlString : RawSqlString | -| EntityFrameworkCore.cs:78:18:78:42 | call to operator implicit conversion : RawSqlString | EntityFrameworkCore.cs:78:18:78:42 | (...) ... | -| EntityFrameworkCore.cs:78:32:78:42 | access to local variable taintSource : String | EntityFrameworkCore.cs:78:18:78:42 | call to operator implicit conversion : RawSqlString | -| EntityFrameworkCore.cs:85:13:88:13 | { ..., ... } [property Name] : String | EntityFrameworkCore.cs:92:29:92:30 | access to local variable p1 [property Name] : String | -| EntityFrameworkCore.cs:87:24:87:32 | "tainted" : String | EntityFrameworkCore.cs:85:13:88:13 | { ..., ... } [property Name] : String | -| EntityFrameworkCore.cs:92:13:92:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | EntityFrameworkCore.cs:94:13:94:15 | access to local variable ctx [property Persons, element, property Name] : String | -| EntityFrameworkCore.cs:92:13:92:23 | [post] access to property Persons [element, property Name] : String | EntityFrameworkCore.cs:92:13:92:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | -| EntityFrameworkCore.cs:92:29:92:30 | access to local variable p1 [property Name] : String | EntityFrameworkCore.cs:92:13:92:23 | [post] access to property Persons [element, property Name] : String | -| EntityFrameworkCore.cs:94:13:94:15 | access to local variable ctx [property Persons, element, property Name] : String | EntityFrameworkCore.cs:230:18:230:28 | access to property Persons [element, property Name] : String | -| EntityFrameworkCore.cs:107:13:110:13 | { ..., ... } [property Name] : String | EntityFrameworkCore.cs:114:29:114:30 | access to local variable p1 [property Name] : String | -| EntityFrameworkCore.cs:109:24:109:32 | "tainted" : String | EntityFrameworkCore.cs:107:13:110:13 | { ..., ... } [property Name] : String | -| EntityFrameworkCore.cs:114:13:114:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | EntityFrameworkCore.cs:116:19:116:21 | access to local variable ctx [property Persons, element, property Name] : String | -| EntityFrameworkCore.cs:114:13:114:23 | [post] access to property Persons [element, property Name] : String | EntityFrameworkCore.cs:114:13:114:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | -| EntityFrameworkCore.cs:114:29:114:30 | access to local variable p1 [property Name] : String | EntityFrameworkCore.cs:114:13:114:23 | [post] access to property Persons [element, property Name] : String | -| EntityFrameworkCore.cs:116:19:116:21 | access to local variable ctx [property Persons, element, property Name] : String | EntityFrameworkCore.cs:230:18:230:28 | access to property Persons [element, property Name] : String | -| EntityFrameworkCore.cs:129:13:132:13 | { ..., ... } [property Name] : String | EntityFrameworkCore.cs:135:27:135:28 | access to local variable p1 [property Name] : String | -| EntityFrameworkCore.cs:131:24:131:32 | "tainted" : String | EntityFrameworkCore.cs:129:13:132:13 | { ..., ... } [property Name] : String | -| EntityFrameworkCore.cs:135:27:135:28 | access to local variable p1 [property Name] : String | EntityFrameworkCore.cs:219:35:219:35 | p [property Name] : String | -| EntityFrameworkCore.cs:148:13:151:13 | { ..., ... } [property Title] : String | EntityFrameworkCore.cs:155:18:155:19 | access to local variable p1 [property Title] : String | -| EntityFrameworkCore.cs:150:25:150:33 | "tainted" : String | EntityFrameworkCore.cs:148:13:151:13 | { ..., ... } [property Title] : String | -| EntityFrameworkCore.cs:155:18:155:19 | access to local variable p1 [property Title] : String | EntityFrameworkCore.cs:155:18:155:25 | access to property Title | -| EntityFrameworkCore.cs:167:13:174:13 | { ..., ... } [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:175:29:175:30 | access to local variable p1 [property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:168:29:173:17 | array creation of type Address[] [element, property Street] : String | EntityFrameworkCore.cs:167:13:174:13 | { ..., ... } [property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:168:35:173:17 | { ..., ... } [element, property Street] : String | EntityFrameworkCore.cs:168:29:173:17 | array creation of type Address[] [element, property Street] : String | -| EntityFrameworkCore.cs:169:21:172:21 | object creation of type Address [property Street] : String | EntityFrameworkCore.cs:168:35:173:17 | { ..., ... } [element, property Street] : String | -| EntityFrameworkCore.cs:169:33:172:21 | { ..., ... } [property Street] : String | EntityFrameworkCore.cs:169:21:172:21 | object creation of type Address [property Street] : String | -| EntityFrameworkCore.cs:171:34:171:42 | "tainted" : String | EntityFrameworkCore.cs:169:33:172:21 | { ..., ... } [property Street] : String | -| EntityFrameworkCore.cs:175:13:175:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:176:13:176:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:175:13:175:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:180:13:180:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:175:13:175:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:175:13:175:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:175:13:175:23 | [post] access to property Persons [element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:175:13:175:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:175:29:175:30 | access to local variable p1 [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:175:13:175:23 | [post] access to property Persons [element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:176:13:176:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [element, property Street] : String | -| EntityFrameworkCore.cs:176:13:176:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:180:13:180:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [element, property Street] : String | -| EntityFrameworkCore.cs:180:13:180:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:183:13:186:13 | { ..., ... } [property Street] : String | EntityFrameworkCore.cs:187:31:187:32 | access to local variable a1 [property Street] : String | -| EntityFrameworkCore.cs:185:26:185:34 | "tainted" : String | EntityFrameworkCore.cs:183:13:186:13 | { ..., ... } [property Street] : String | -| EntityFrameworkCore.cs:187:13:187:15 | [post] access to local variable ctx [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:187:13:187:15 | [post] access to local variable ctx [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:187:13:187:25 | [post] access to property Addresses [element, property Street] : String | EntityFrameworkCore.cs:187:13:187:15 | [post] access to local variable ctx [property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:187:31:187:32 | access to local variable a1 [property Street] : String | EntityFrameworkCore.cs:187:13:187:25 | [post] access to property Addresses [element, property Street] : String | -| EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [element, property Street] : String | -| EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [element, property Street] : String | -| EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [element, property Street] : String | -| EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [element, property Street] : String | -| EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:199:13:202:13 | { ..., ... } [property Name] : String | EntityFrameworkCore.cs:208:71:208:72 | access to local variable p1 [property Name] : String | -| EntityFrameworkCore.cs:201:24:201:32 | "tainted" : String | EntityFrameworkCore.cs:199:13:202:13 | { ..., ... } [property Name] : String | -| EntityFrameworkCore.cs:204:13:207:13 | { ..., ... } [property Street] : String | EntityFrameworkCore.cs:208:85:208:86 | access to local variable a1 [property Street] : String | -| EntityFrameworkCore.cs:206:26:206:34 | "tainted" : String | EntityFrameworkCore.cs:204:13:207:13 | { ..., ... } [property Street] : String | -| EntityFrameworkCore.cs:208:60:208:88 | { ..., ... } [property Address, property Street] : String | EntityFrameworkCore.cs:209:37:209:53 | access to local variable personAddressMap1 [property Address, property Street] : String | -| EntityFrameworkCore.cs:208:60:208:88 | { ..., ... } [property Person, property Name] : String | EntityFrameworkCore.cs:209:37:209:53 | access to local variable personAddressMap1 [property Person, property Name] : String | -| EntityFrameworkCore.cs:208:71:208:72 | access to local variable p1 [property Name] : String | EntityFrameworkCore.cs:208:60:208:88 | { ..., ... } [property Person, property Name] : String | -| EntityFrameworkCore.cs:208:85:208:86 | access to local variable a1 [property Street] : String | EntityFrameworkCore.cs:208:60:208:88 | { ..., ... } [property Address, property Street] : String | -| EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | EntityFrameworkCore.cs:210:13:210:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | -| EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | EntityFrameworkCore.cs:216:13:216:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | -| EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | EntityFrameworkCore.cs:210:13:210:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | -| EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | EntityFrameworkCore.cs:216:13:216:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | -| EntityFrameworkCore.cs:209:13:209:31 | [post] access to property PersonAddresses [element, property Address, property Street] : String | EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | -| EntityFrameworkCore.cs:209:13:209:31 | [post] access to property PersonAddresses [element, property Person, property Name] : String | EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | -| EntityFrameworkCore.cs:209:37:209:53 | access to local variable personAddressMap1 [property Address, property Street] : String | EntityFrameworkCore.cs:209:13:209:31 | [post] access to property PersonAddresses [element, property Address, property Street] : String | -| EntityFrameworkCore.cs:209:37:209:53 | access to local variable personAddressMap1 [property Person, property Name] : String | EntityFrameworkCore.cs:209:13:209:31 | [post] access to property PersonAddresses [element, property Person, property Name] : String | -| EntityFrameworkCore.cs:210:13:210:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [element, property Street] : String | -| EntityFrameworkCore.cs:210:13:210:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:210:13:210:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | EntityFrameworkCore.cs:230:18:230:28 | access to property Persons [element, property Name] : String | -| EntityFrameworkCore.cs:216:13:216:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [element, property Street] : String | -| EntityFrameworkCore.cs:216:13:216:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:216:13:216:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | EntityFrameworkCore.cs:230:18:230:28 | access to property Persons [element, property Name] : String | -| EntityFrameworkCore.cs:219:35:219:35 | p [property Name] : String | EntityFrameworkCore.cs:222:29:222:29 | access to parameter p [property Name] : String | -| EntityFrameworkCore.cs:222:13:222:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | EntityFrameworkCore.cs:223:13:223:15 | access to local variable ctx [property Persons, element, property Name] : String | -| EntityFrameworkCore.cs:222:13:222:23 | [post] access to property Persons [element, property Name] : String | EntityFrameworkCore.cs:222:13:222:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | -| EntityFrameworkCore.cs:222:29:222:29 | access to parameter p [property Name] : String | EntityFrameworkCore.cs:222:13:222:23 | [post] access to property Persons [element, property Name] : String | -| EntityFrameworkCore.cs:223:13:223:15 | access to local variable ctx [property Persons, element, property Name] : String | EntityFrameworkCore.cs:230:18:230:28 | access to property Persons [element, property Name] : String | -| EntityFrameworkCore.cs:230:18:230:28 | access to property Persons [element, property Name] : String | EntityFrameworkCore.cs:230:18:230:36 | call to method First [property Name] : String | -| EntityFrameworkCore.cs:230:18:230:36 | call to method First [property Name] : String | EntityFrameworkCore.cs:230:18:230:41 | access to property Name | -| EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [element, property Street] : String | EntityFrameworkCore.cs:238:18:238:38 | call to method First
[property Street] : String | -| EntityFrameworkCore.cs:238:18:238:38 | call to method First
[property Street] : String | EntityFrameworkCore.cs:238:18:238:45 | access to property Street | -| EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:245:18:245:36 | call to method First [property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:245:18:245:36 | call to method First [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:245:18:245:46 | access to property Addresses [element, property Street] : String | -| EntityFrameworkCore.cs:245:18:245:46 | access to property Addresses [element, property Street] : String | EntityFrameworkCore.cs:245:18:245:54 | call to method First
[property Street] : String | -| EntityFrameworkCore.cs:245:18:245:54 | call to method First
[property Street] : String | EntityFrameworkCore.cs:245:18:245:61 | access to property Street | +| EntityFrameworkCore.cs:82:31:82:39 | "tainted" : String | EntityFrameworkCore.cs:83:18:83:28 | access to local variable taintSource | +| EntityFrameworkCore.cs:82:31:82:39 | "tainted" : String | EntityFrameworkCore.cs:84:35:84:45 | access to local variable taintSource : String | +| EntityFrameworkCore.cs:82:31:82:39 | "tainted" : String | EntityFrameworkCore.cs:85:18:85:42 | (...) ... | +| EntityFrameworkCore.cs:82:31:82:39 | "tainted" : String | EntityFrameworkCore.cs:85:32:85:42 | access to local variable taintSource : String | +| EntityFrameworkCore.cs:84:18:84:46 | object creation of type RawSqlString : RawSqlString | EntityFrameworkCore.cs:84:18:84:46 | (...) ... | +| EntityFrameworkCore.cs:84:35:84:45 | access to local variable taintSource : String | EntityFrameworkCore.cs:84:18:84:46 | object creation of type RawSqlString : RawSqlString | +| EntityFrameworkCore.cs:85:18:85:42 | call to operator implicit conversion : RawSqlString | EntityFrameworkCore.cs:85:18:85:42 | (...) ... | +| EntityFrameworkCore.cs:85:32:85:42 | access to local variable taintSource : String | EntityFrameworkCore.cs:85:18:85:42 | call to operator implicit conversion : RawSqlString | +| EntityFrameworkCore.cs:92:13:95:13 | { ..., ... } [property Name] : String | EntityFrameworkCore.cs:99:29:99:30 | access to local variable p1 [property Name] : String | +| EntityFrameworkCore.cs:94:24:94:32 | "tainted" : String | EntityFrameworkCore.cs:92:13:95:13 | { ..., ... } [property Name] : String | +| EntityFrameworkCore.cs:99:13:99:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | EntityFrameworkCore.cs:101:13:101:15 | access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:99:13:99:23 | [post] access to property Persons [element, property Name] : String | EntityFrameworkCore.cs:99:13:99:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:99:29:99:30 | access to local variable p1 [property Name] : String | EntityFrameworkCore.cs:99:13:99:23 | [post] access to property Persons [element, property Name] : String | +| EntityFrameworkCore.cs:101:13:101:15 | access to local variable ctx [property Persons, element, property Name] : String | EntityFrameworkCore.cs:237:18:237:28 | access to property Persons [element, property Name] : String | +| EntityFrameworkCore.cs:114:13:117:13 | { ..., ... } [property Name] : String | EntityFrameworkCore.cs:121:29:121:30 | access to local variable p1 [property Name] : String | +| EntityFrameworkCore.cs:116:24:116:32 | "tainted" : String | EntityFrameworkCore.cs:114:13:117:13 | { ..., ... } [property Name] : String | +| EntityFrameworkCore.cs:121:13:121:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | EntityFrameworkCore.cs:123:19:123:21 | access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:121:13:121:23 | [post] access to property Persons [element, property Name] : String | EntityFrameworkCore.cs:121:13:121:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:121:29:121:30 | access to local variable p1 [property Name] : String | EntityFrameworkCore.cs:121:13:121:23 | [post] access to property Persons [element, property Name] : String | +| EntityFrameworkCore.cs:123:19:123:21 | access to local variable ctx [property Persons, element, property Name] : String | EntityFrameworkCore.cs:237:18:237:28 | access to property Persons [element, property Name] : String | +| EntityFrameworkCore.cs:136:13:139:13 | { ..., ... } [property Name] : String | EntityFrameworkCore.cs:142:27:142:28 | access to local variable p1 [property Name] : String | +| EntityFrameworkCore.cs:138:24:138:32 | "tainted" : String | EntityFrameworkCore.cs:136:13:139:13 | { ..., ... } [property Name] : String | +| EntityFrameworkCore.cs:142:27:142:28 | access to local variable p1 [property Name] : String | EntityFrameworkCore.cs:226:35:226:35 | p [property Name] : String | +| EntityFrameworkCore.cs:155:13:158:13 | { ..., ... } [property Title] : String | EntityFrameworkCore.cs:162:18:162:19 | access to local variable p1 [property Title] : String | +| EntityFrameworkCore.cs:157:25:157:33 | "tainted" : String | EntityFrameworkCore.cs:155:13:158:13 | { ..., ... } [property Title] : String | +| EntityFrameworkCore.cs:162:18:162:19 | access to local variable p1 [property Title] : String | EntityFrameworkCore.cs:162:18:162:25 | access to property Title | +| EntityFrameworkCore.cs:174:13:181:13 | { ..., ... } [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:182:29:182:30 | access to local variable p1 [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:175:29:180:17 | array creation of type Address[] [element, property Street] : String | EntityFrameworkCore.cs:174:13:181:13 | { ..., ... } [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:175:35:180:17 | { ..., ... } [element, property Street] : String | EntityFrameworkCore.cs:175:29:180:17 | array creation of type Address[] [element, property Street] : String | +| EntityFrameworkCore.cs:176:21:179:21 | object creation of type Address [property Street] : String | EntityFrameworkCore.cs:175:35:180:17 | { ..., ... } [element, property Street] : String | +| EntityFrameworkCore.cs:176:33:179:21 | { ..., ... } [property Street] : String | EntityFrameworkCore.cs:176:21:179:21 | object creation of type Address [property Street] : String | +| EntityFrameworkCore.cs:178:34:178:42 | "tainted" : String | EntityFrameworkCore.cs:176:33:179:21 | { ..., ... } [property Street] : String | +| EntityFrameworkCore.cs:182:13:182:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:183:13:183:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:182:13:182:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:187:13:187:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:182:13:182:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:195:13:195:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:182:13:182:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:199:13:199:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:182:13:182:23 | [post] access to property Persons [element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:182:13:182:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:182:29:182:30 | access to local variable p1 [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:182:13:182:23 | [post] access to property Persons [element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:183:13:183:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:245:18:245:30 | access to property Addresses [element, property Street] : String | +| EntityFrameworkCore.cs:183:13:183:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:252:18:252:28 | access to property Persons [element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:187:13:187:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:245:18:245:30 | access to property Addresses [element, property Street] : String | +| EntityFrameworkCore.cs:187:13:187:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:252:18:252:28 | access to property Persons [element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:190:13:193:13 | { ..., ... } [property Street] : String | EntityFrameworkCore.cs:194:31:194:32 | access to local variable a1 [property Street] : String | +| EntityFrameworkCore.cs:192:26:192:34 | "tainted" : String | EntityFrameworkCore.cs:190:13:193:13 | { ..., ... } [property Street] : String | +| EntityFrameworkCore.cs:194:13:194:15 | [post] access to local variable ctx [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:195:13:195:15 | access to local variable ctx [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:194:13:194:15 | [post] access to local variable ctx [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:199:13:199:15 | access to local variable ctx [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:194:13:194:25 | [post] access to property Addresses [element, property Street] : String | EntityFrameworkCore.cs:194:13:194:15 | [post] access to local variable ctx [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:194:31:194:32 | access to local variable a1 [property Street] : String | EntityFrameworkCore.cs:194:13:194:25 | [post] access to property Addresses [element, property Street] : String | +| EntityFrameworkCore.cs:195:13:195:15 | access to local variable ctx [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:245:18:245:30 | access to property Addresses [element, property Street] : String | +| EntityFrameworkCore.cs:195:13:195:15 | access to local variable ctx [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:252:18:252:28 | access to property Persons [element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:195:13:195:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:245:18:245:30 | access to property Addresses [element, property Street] : String | +| EntityFrameworkCore.cs:195:13:195:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:252:18:252:28 | access to property Persons [element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:199:13:199:15 | access to local variable ctx [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:245:18:245:30 | access to property Addresses [element, property Street] : String | +| EntityFrameworkCore.cs:199:13:199:15 | access to local variable ctx [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:252:18:252:28 | access to property Persons [element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:199:13:199:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:245:18:245:30 | access to property Addresses [element, property Street] : String | +| EntityFrameworkCore.cs:199:13:199:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:252:18:252:28 | access to property Persons [element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:206:13:209:13 | { ..., ... } [property Name] : String | EntityFrameworkCore.cs:215:71:215:72 | access to local variable p1 [property Name] : String | +| EntityFrameworkCore.cs:208:24:208:32 | "tainted" : String | EntityFrameworkCore.cs:206:13:209:13 | { ..., ... } [property Name] : String | +| EntityFrameworkCore.cs:211:13:214:13 | { ..., ... } [property Street] : String | EntityFrameworkCore.cs:215:85:215:86 | access to local variable a1 [property Street] : String | +| EntityFrameworkCore.cs:213:26:213:34 | "tainted" : String | EntityFrameworkCore.cs:211:13:214:13 | { ..., ... } [property Street] : String | +| EntityFrameworkCore.cs:215:60:215:88 | { ..., ... } [property Address, property Street] : String | EntityFrameworkCore.cs:216:37:216:53 | access to local variable personAddressMap1 [property Address, property Street] : String | +| EntityFrameworkCore.cs:215:60:215:88 | { ..., ... } [property Person, property Name] : String | EntityFrameworkCore.cs:216:37:216:53 | access to local variable personAddressMap1 [property Person, property Name] : String | +| EntityFrameworkCore.cs:215:71:215:72 | access to local variable p1 [property Name] : String | EntityFrameworkCore.cs:215:60:215:88 | { ..., ... } [property Person, property Name] : String | +| EntityFrameworkCore.cs:215:85:215:86 | access to local variable a1 [property Street] : String | EntityFrameworkCore.cs:215:60:215:88 | { ..., ... } [property Address, property Street] : String | +| EntityFrameworkCore.cs:216:13:216:15 | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | EntityFrameworkCore.cs:217:13:217:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | +| EntityFrameworkCore.cs:216:13:216:15 | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | EntityFrameworkCore.cs:223:13:223:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | +| EntityFrameworkCore.cs:216:13:216:15 | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | EntityFrameworkCore.cs:217:13:217:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | +| EntityFrameworkCore.cs:216:13:216:15 | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | EntityFrameworkCore.cs:223:13:223:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | +| EntityFrameworkCore.cs:216:13:216:31 | [post] access to property PersonAddresses [element, property Address, property Street] : String | EntityFrameworkCore.cs:216:13:216:15 | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | +| EntityFrameworkCore.cs:216:13:216:31 | [post] access to property PersonAddresses [element, property Person, property Name] : String | EntityFrameworkCore.cs:216:13:216:15 | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | +| EntityFrameworkCore.cs:216:37:216:53 | access to local variable personAddressMap1 [property Address, property Street] : String | EntityFrameworkCore.cs:216:13:216:31 | [post] access to property PersonAddresses [element, property Address, property Street] : String | +| EntityFrameworkCore.cs:216:37:216:53 | access to local variable personAddressMap1 [property Person, property Name] : String | EntityFrameworkCore.cs:216:13:216:31 | [post] access to property PersonAddresses [element, property Person, property Name] : String | +| EntityFrameworkCore.cs:217:13:217:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | EntityFrameworkCore.cs:245:18:245:30 | access to property Addresses [element, property Street] : String | +| EntityFrameworkCore.cs:217:13:217:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | EntityFrameworkCore.cs:252:18:252:28 | access to property Persons [element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:217:13:217:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | EntityFrameworkCore.cs:237:18:237:28 | access to property Persons [element, property Name] : String | +| EntityFrameworkCore.cs:223:13:223:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | EntityFrameworkCore.cs:245:18:245:30 | access to property Addresses [element, property Street] : String | +| EntityFrameworkCore.cs:223:13:223:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | EntityFrameworkCore.cs:252:18:252:28 | access to property Persons [element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:223:13:223:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | EntityFrameworkCore.cs:237:18:237:28 | access to property Persons [element, property Name] : String | +| EntityFrameworkCore.cs:226:35:226:35 | p [property Name] : String | EntityFrameworkCore.cs:229:29:229:29 | access to parameter p [property Name] : String | +| EntityFrameworkCore.cs:229:13:229:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | EntityFrameworkCore.cs:230:13:230:15 | access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:229:13:229:23 | [post] access to property Persons [element, property Name] : String | EntityFrameworkCore.cs:229:13:229:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:229:29:229:29 | access to parameter p [property Name] : String | EntityFrameworkCore.cs:229:13:229:23 | [post] access to property Persons [element, property Name] : String | +| EntityFrameworkCore.cs:230:13:230:15 | access to local variable ctx [property Persons, element, property Name] : String | EntityFrameworkCore.cs:237:18:237:28 | access to property Persons [element, property Name] : String | +| EntityFrameworkCore.cs:237:18:237:28 | access to property Persons [element, property Name] : String | EntityFrameworkCore.cs:237:18:237:36 | call to method First [property Name] : String | +| EntityFrameworkCore.cs:237:18:237:36 | call to method First [property Name] : String | EntityFrameworkCore.cs:237:18:237:41 | access to property Name | +| EntityFrameworkCore.cs:245:18:245:30 | access to property Addresses [element, property Street] : String | EntityFrameworkCore.cs:245:18:245:38 | call to method First
[property Street] : String | +| EntityFrameworkCore.cs:245:18:245:38 | call to method First
[property Street] : String | EntityFrameworkCore.cs:245:18:245:45 | access to property Street | +| EntityFrameworkCore.cs:252:18:252:28 | access to property Persons [element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:252:18:252:36 | call to method First [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:252:18:252:36 | call to method First [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:252:18:252:46 | access to property Addresses [element, property Street] : String | +| EntityFrameworkCore.cs:252:18:252:46 | access to property Addresses [element, property Street] : String | EntityFrameworkCore.cs:252:18:252:54 | call to method First
[property Street] : String | +| EntityFrameworkCore.cs:252:18:252:54 | call to method First
[property Street] : String | EntityFrameworkCore.cs:252:18:252:61 | access to property Street | nodes | EntityFramework.cs:59:13:62:13 | { ..., ... } [property Name] : String | semmle.label | { ..., ... } [property Name] : String | | EntityFramework.cs:61:24:61:32 | "tainted" : String | semmle.label | "tainted" : String | @@ -247,87 +247,87 @@ nodes | EntityFramework.cs:219:18:219:46 | access to property Addresses [element, property Street] : String | semmle.label | access to property Addresses [element, property Street] : String | | EntityFramework.cs:219:18:219:54 | call to method First
[property Street] : String | semmle.label | call to method First
[property Street] : String | | EntityFramework.cs:219:18:219:61 | access to property Street | semmle.label | access to property Street | -| EntityFrameworkCore.cs:75:31:75:39 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFrameworkCore.cs:76:18:76:28 | access to local variable taintSource | semmle.label | access to local variable taintSource | -| EntityFrameworkCore.cs:77:18:77:46 | (...) ... | semmle.label | (...) ... | -| EntityFrameworkCore.cs:77:18:77:46 | object creation of type RawSqlString : RawSqlString | semmle.label | object creation of type RawSqlString : RawSqlString | -| EntityFrameworkCore.cs:77:35:77:45 | access to local variable taintSource : String | semmle.label | access to local variable taintSource : String | -| EntityFrameworkCore.cs:78:18:78:42 | (...) ... | semmle.label | (...) ... | -| EntityFrameworkCore.cs:78:18:78:42 | call to operator implicit conversion : RawSqlString | semmle.label | call to operator implicit conversion : RawSqlString | -| EntityFrameworkCore.cs:78:32:78:42 | access to local variable taintSource : String | semmle.label | access to local variable taintSource : String | -| EntityFrameworkCore.cs:85:13:88:13 | { ..., ... } [property Name] : String | semmle.label | { ..., ... } [property Name] : String | -| EntityFrameworkCore.cs:87:24:87:32 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFrameworkCore.cs:92:13:92:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | semmle.label | [post] access to local variable ctx [property Persons, element, property Name] : String | -| EntityFrameworkCore.cs:92:13:92:23 | [post] access to property Persons [element, property Name] : String | semmle.label | [post] access to property Persons [element, property Name] : String | -| EntityFrameworkCore.cs:92:29:92:30 | access to local variable p1 [property Name] : String | semmle.label | access to local variable p1 [property Name] : String | -| EntityFrameworkCore.cs:94:13:94:15 | access to local variable ctx [property Persons, element, property Name] : String | semmle.label | access to local variable ctx [property Persons, element, property Name] : String | -| EntityFrameworkCore.cs:107:13:110:13 | { ..., ... } [property Name] : String | semmle.label | { ..., ... } [property Name] : String | -| EntityFrameworkCore.cs:109:24:109:32 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFrameworkCore.cs:114:13:114:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | semmle.label | [post] access to local variable ctx [property Persons, element, property Name] : String | -| EntityFrameworkCore.cs:114:13:114:23 | [post] access to property Persons [element, property Name] : String | semmle.label | [post] access to property Persons [element, property Name] : String | -| EntityFrameworkCore.cs:114:29:114:30 | access to local variable p1 [property Name] : String | semmle.label | access to local variable p1 [property Name] : String | -| EntityFrameworkCore.cs:116:19:116:21 | access to local variable ctx [property Persons, element, property Name] : String | semmle.label | access to local variable ctx [property Persons, element, property Name] : String | -| EntityFrameworkCore.cs:129:13:132:13 | { ..., ... } [property Name] : String | semmle.label | { ..., ... } [property Name] : String | -| EntityFrameworkCore.cs:131:24:131:32 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFrameworkCore.cs:135:27:135:28 | access to local variable p1 [property Name] : String | semmle.label | access to local variable p1 [property Name] : String | -| EntityFrameworkCore.cs:148:13:151:13 | { ..., ... } [property Title] : String | semmle.label | { ..., ... } [property Title] : String | -| EntityFrameworkCore.cs:150:25:150:33 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFrameworkCore.cs:155:18:155:19 | access to local variable p1 [property Title] : String | semmle.label | access to local variable p1 [property Title] : String | -| EntityFrameworkCore.cs:155:18:155:25 | access to property Title | semmle.label | access to property Title | -| EntityFrameworkCore.cs:167:13:174:13 | { ..., ... } [property Addresses, element, property Street] : String | semmle.label | { ..., ... } [property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:168:29:173:17 | array creation of type Address[] [element, property Street] : String | semmle.label | array creation of type Address[] [element, property Street] : String | -| EntityFrameworkCore.cs:168:35:173:17 | { ..., ... } [element, property Street] : String | semmle.label | { ..., ... } [element, property Street] : String | -| EntityFrameworkCore.cs:169:21:172:21 | object creation of type Address [property Street] : String | semmle.label | object creation of type Address [property Street] : String | -| EntityFrameworkCore.cs:169:33:172:21 | { ..., ... } [property Street] : String | semmle.label | { ..., ... } [property Street] : String | -| EntityFrameworkCore.cs:171:34:171:42 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFrameworkCore.cs:175:13:175:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:175:13:175:23 | [post] access to property Persons [element, property Addresses, element, property Street] : String | semmle.label | [post] access to property Persons [element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:175:29:175:30 | access to local variable p1 [property Addresses, element, property Street] : String | semmle.label | access to local variable p1 [property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:176:13:176:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:180:13:180:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:183:13:186:13 | { ..., ... } [property Street] : String | semmle.label | { ..., ... } [property Street] : String | -| EntityFrameworkCore.cs:185:26:185:34 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFrameworkCore.cs:187:13:187:15 | [post] access to local variable ctx [property Addresses, element, property Street] : String | semmle.label | [post] access to local variable ctx [property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:187:13:187:25 | [post] access to property Addresses [element, property Street] : String | semmle.label | [post] access to property Addresses [element, property Street] : String | -| EntityFrameworkCore.cs:187:31:187:32 | access to local variable a1 [property Street] : String | semmle.label | access to local variable a1 [property Street] : String | -| EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:199:13:202:13 | { ..., ... } [property Name] : String | semmle.label | { ..., ... } [property Name] : String | -| EntityFrameworkCore.cs:201:24:201:32 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFrameworkCore.cs:204:13:207:13 | { ..., ... } [property Street] : String | semmle.label | { ..., ... } [property Street] : String | -| EntityFrameworkCore.cs:206:26:206:34 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFrameworkCore.cs:208:60:208:88 | { ..., ... } [property Address, property Street] : String | semmle.label | { ..., ... } [property Address, property Street] : String | -| EntityFrameworkCore.cs:208:60:208:88 | { ..., ... } [property Person, property Name] : String | semmle.label | { ..., ... } [property Person, property Name] : String | -| EntityFrameworkCore.cs:208:71:208:72 | access to local variable p1 [property Name] : String | semmle.label | access to local variable p1 [property Name] : String | -| EntityFrameworkCore.cs:208:85:208:86 | access to local variable a1 [property Street] : String | semmle.label | access to local variable a1 [property Street] : String | -| EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | semmle.label | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | -| EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | semmle.label | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | -| EntityFrameworkCore.cs:209:13:209:31 | [post] access to property PersonAddresses [element, property Address, property Street] : String | semmle.label | [post] access to property PersonAddresses [element, property Address, property Street] : String | -| EntityFrameworkCore.cs:209:13:209:31 | [post] access to property PersonAddresses [element, property Person, property Name] : String | semmle.label | [post] access to property PersonAddresses [element, property Person, property Name] : String | -| EntityFrameworkCore.cs:209:37:209:53 | access to local variable personAddressMap1 [property Address, property Street] : String | semmle.label | access to local variable personAddressMap1 [property Address, property Street] : String | -| EntityFrameworkCore.cs:209:37:209:53 | access to local variable personAddressMap1 [property Person, property Name] : String | semmle.label | access to local variable personAddressMap1 [property Person, property Name] : String | -| EntityFrameworkCore.cs:210:13:210:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | semmle.label | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | -| EntityFrameworkCore.cs:210:13:210:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | semmle.label | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | -| EntityFrameworkCore.cs:216:13:216:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | semmle.label | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | -| EntityFrameworkCore.cs:216:13:216:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | semmle.label | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | -| EntityFrameworkCore.cs:219:35:219:35 | p [property Name] : String | semmle.label | p [property Name] : String | -| EntityFrameworkCore.cs:222:13:222:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | semmle.label | [post] access to local variable ctx [property Persons, element, property Name] : String | -| EntityFrameworkCore.cs:222:13:222:23 | [post] access to property Persons [element, property Name] : String | semmle.label | [post] access to property Persons [element, property Name] : String | -| EntityFrameworkCore.cs:222:29:222:29 | access to parameter p [property Name] : String | semmle.label | access to parameter p [property Name] : String | -| EntityFrameworkCore.cs:223:13:223:15 | access to local variable ctx [property Persons, element, property Name] : String | semmle.label | access to local variable ctx [property Persons, element, property Name] : String | -| EntityFrameworkCore.cs:230:18:230:28 | access to property Persons [element, property Name] : String | semmle.label | access to property Persons [element, property Name] : String | -| EntityFrameworkCore.cs:230:18:230:36 | call to method First [property Name] : String | semmle.label | call to method First [property Name] : String | -| EntityFrameworkCore.cs:230:18:230:41 | access to property Name | semmle.label | access to property Name | -| EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [element, property Street] : String | semmle.label | access to property Addresses [element, property Street] : String | -| EntityFrameworkCore.cs:238:18:238:38 | call to method First
[property Street] : String | semmle.label | call to method First
[property Street] : String | -| EntityFrameworkCore.cs:238:18:238:45 | access to property Street | semmle.label | access to property Street | -| EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [element, property Addresses, element, property Street] : String | semmle.label | access to property Persons [element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:245:18:245:36 | call to method First [property Addresses, element, property Street] : String | semmle.label | call to method First [property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:245:18:245:46 | access to property Addresses [element, property Street] : String | semmle.label | access to property Addresses [element, property Street] : String | -| EntityFrameworkCore.cs:245:18:245:54 | call to method First
[property Street] : String | semmle.label | call to method First
[property Street] : String | -| EntityFrameworkCore.cs:245:18:245:61 | access to property Street | semmle.label | access to property Street | +| EntityFrameworkCore.cs:82:31:82:39 | "tainted" : String | semmle.label | "tainted" : String | +| EntityFrameworkCore.cs:83:18:83:28 | access to local variable taintSource | semmle.label | access to local variable taintSource | +| EntityFrameworkCore.cs:84:18:84:46 | (...) ... | semmle.label | (...) ... | +| EntityFrameworkCore.cs:84:18:84:46 | object creation of type RawSqlString : RawSqlString | semmle.label | object creation of type RawSqlString : RawSqlString | +| EntityFrameworkCore.cs:84:35:84:45 | access to local variable taintSource : String | semmle.label | access to local variable taintSource : String | +| EntityFrameworkCore.cs:85:18:85:42 | (...) ... | semmle.label | (...) ... | +| EntityFrameworkCore.cs:85:18:85:42 | call to operator implicit conversion : RawSqlString | semmle.label | call to operator implicit conversion : RawSqlString | +| EntityFrameworkCore.cs:85:32:85:42 | access to local variable taintSource : String | semmle.label | access to local variable taintSource : String | +| EntityFrameworkCore.cs:92:13:95:13 | { ..., ... } [property Name] : String | semmle.label | { ..., ... } [property Name] : String | +| EntityFrameworkCore.cs:94:24:94:32 | "tainted" : String | semmle.label | "tainted" : String | +| EntityFrameworkCore.cs:99:13:99:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | semmle.label | [post] access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:99:13:99:23 | [post] access to property Persons [element, property Name] : String | semmle.label | [post] access to property Persons [element, property Name] : String | +| EntityFrameworkCore.cs:99:29:99:30 | access to local variable p1 [property Name] : String | semmle.label | access to local variable p1 [property Name] : String | +| EntityFrameworkCore.cs:101:13:101:15 | access to local variable ctx [property Persons, element, property Name] : String | semmle.label | access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:114:13:117:13 | { ..., ... } [property Name] : String | semmle.label | { ..., ... } [property Name] : String | +| EntityFrameworkCore.cs:116:24:116:32 | "tainted" : String | semmle.label | "tainted" : String | +| EntityFrameworkCore.cs:121:13:121:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | semmle.label | [post] access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:121:13:121:23 | [post] access to property Persons [element, property Name] : String | semmle.label | [post] access to property Persons [element, property Name] : String | +| EntityFrameworkCore.cs:121:29:121:30 | access to local variable p1 [property Name] : String | semmle.label | access to local variable p1 [property Name] : String | +| EntityFrameworkCore.cs:123:19:123:21 | access to local variable ctx [property Persons, element, property Name] : String | semmle.label | access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:136:13:139:13 | { ..., ... } [property Name] : String | semmle.label | { ..., ... } [property Name] : String | +| EntityFrameworkCore.cs:138:24:138:32 | "tainted" : String | semmle.label | "tainted" : String | +| EntityFrameworkCore.cs:142:27:142:28 | access to local variable p1 [property Name] : String | semmle.label | access to local variable p1 [property Name] : String | +| EntityFrameworkCore.cs:155:13:158:13 | { ..., ... } [property Title] : String | semmle.label | { ..., ... } [property Title] : String | +| EntityFrameworkCore.cs:157:25:157:33 | "tainted" : String | semmle.label | "tainted" : String | +| EntityFrameworkCore.cs:162:18:162:19 | access to local variable p1 [property Title] : String | semmle.label | access to local variable p1 [property Title] : String | +| EntityFrameworkCore.cs:162:18:162:25 | access to property Title | semmle.label | access to property Title | +| EntityFrameworkCore.cs:174:13:181:13 | { ..., ... } [property Addresses, element, property Street] : String | semmle.label | { ..., ... } [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:175:29:180:17 | array creation of type Address[] [element, property Street] : String | semmle.label | array creation of type Address[] [element, property Street] : String | +| EntityFrameworkCore.cs:175:35:180:17 | { ..., ... } [element, property Street] : String | semmle.label | { ..., ... } [element, property Street] : String | +| EntityFrameworkCore.cs:176:21:179:21 | object creation of type Address [property Street] : String | semmle.label | object creation of type Address [property Street] : String | +| EntityFrameworkCore.cs:176:33:179:21 | { ..., ... } [property Street] : String | semmle.label | { ..., ... } [property Street] : String | +| EntityFrameworkCore.cs:178:34:178:42 | "tainted" : String | semmle.label | "tainted" : String | +| EntityFrameworkCore.cs:182:13:182:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:182:13:182:23 | [post] access to property Persons [element, property Addresses, element, property Street] : String | semmle.label | [post] access to property Persons [element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:182:29:182:30 | access to local variable p1 [property Addresses, element, property Street] : String | semmle.label | access to local variable p1 [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:183:13:183:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:187:13:187:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:190:13:193:13 | { ..., ... } [property Street] : String | semmle.label | { ..., ... } [property Street] : String | +| EntityFrameworkCore.cs:192:26:192:34 | "tainted" : String | semmle.label | "tainted" : String | +| EntityFrameworkCore.cs:194:13:194:15 | [post] access to local variable ctx [property Addresses, element, property Street] : String | semmle.label | [post] access to local variable ctx [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:194:13:194:25 | [post] access to property Addresses [element, property Street] : String | semmle.label | [post] access to property Addresses [element, property Street] : String | +| EntityFrameworkCore.cs:194:31:194:32 | access to local variable a1 [property Street] : String | semmle.label | access to local variable a1 [property Street] : String | +| EntityFrameworkCore.cs:195:13:195:15 | access to local variable ctx [property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:195:13:195:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:199:13:199:15 | access to local variable ctx [property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:199:13:199:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:206:13:209:13 | { ..., ... } [property Name] : String | semmle.label | { ..., ... } [property Name] : String | +| EntityFrameworkCore.cs:208:24:208:32 | "tainted" : String | semmle.label | "tainted" : String | +| EntityFrameworkCore.cs:211:13:214:13 | { ..., ... } [property Street] : String | semmle.label | { ..., ... } [property Street] : String | +| EntityFrameworkCore.cs:213:26:213:34 | "tainted" : String | semmle.label | "tainted" : String | +| EntityFrameworkCore.cs:215:60:215:88 | { ..., ... } [property Address, property Street] : String | semmle.label | { ..., ... } [property Address, property Street] : String | +| EntityFrameworkCore.cs:215:60:215:88 | { ..., ... } [property Person, property Name] : String | semmle.label | { ..., ... } [property Person, property Name] : String | +| EntityFrameworkCore.cs:215:71:215:72 | access to local variable p1 [property Name] : String | semmle.label | access to local variable p1 [property Name] : String | +| EntityFrameworkCore.cs:215:85:215:86 | access to local variable a1 [property Street] : String | semmle.label | access to local variable a1 [property Street] : String | +| EntityFrameworkCore.cs:216:13:216:15 | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | semmle.label | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | +| EntityFrameworkCore.cs:216:13:216:15 | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | semmle.label | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | +| EntityFrameworkCore.cs:216:13:216:31 | [post] access to property PersonAddresses [element, property Address, property Street] : String | semmle.label | [post] access to property PersonAddresses [element, property Address, property Street] : String | +| EntityFrameworkCore.cs:216:13:216:31 | [post] access to property PersonAddresses [element, property Person, property Name] : String | semmle.label | [post] access to property PersonAddresses [element, property Person, property Name] : String | +| EntityFrameworkCore.cs:216:37:216:53 | access to local variable personAddressMap1 [property Address, property Street] : String | semmle.label | access to local variable personAddressMap1 [property Address, property Street] : String | +| EntityFrameworkCore.cs:216:37:216:53 | access to local variable personAddressMap1 [property Person, property Name] : String | semmle.label | access to local variable personAddressMap1 [property Person, property Name] : String | +| EntityFrameworkCore.cs:217:13:217:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | semmle.label | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | +| EntityFrameworkCore.cs:217:13:217:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | semmle.label | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | +| EntityFrameworkCore.cs:223:13:223:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | semmle.label | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | +| EntityFrameworkCore.cs:223:13:223:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | semmle.label | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | +| EntityFrameworkCore.cs:226:35:226:35 | p [property Name] : String | semmle.label | p [property Name] : String | +| EntityFrameworkCore.cs:229:13:229:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | semmle.label | [post] access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:229:13:229:23 | [post] access to property Persons [element, property Name] : String | semmle.label | [post] access to property Persons [element, property Name] : String | +| EntityFrameworkCore.cs:229:29:229:29 | access to parameter p [property Name] : String | semmle.label | access to parameter p [property Name] : String | +| EntityFrameworkCore.cs:230:13:230:15 | access to local variable ctx [property Persons, element, property Name] : String | semmle.label | access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:237:18:237:28 | access to property Persons [element, property Name] : String | semmle.label | access to property Persons [element, property Name] : String | +| EntityFrameworkCore.cs:237:18:237:36 | call to method First [property Name] : String | semmle.label | call to method First [property Name] : String | +| EntityFrameworkCore.cs:237:18:237:41 | access to property Name | semmle.label | access to property Name | +| EntityFrameworkCore.cs:245:18:245:30 | access to property Addresses [element, property Street] : String | semmle.label | access to property Addresses [element, property Street] : String | +| EntityFrameworkCore.cs:245:18:245:38 | call to method First
[property Street] : String | semmle.label | call to method First
[property Street] : String | +| EntityFrameworkCore.cs:245:18:245:45 | access to property Street | semmle.label | access to property Street | +| EntityFrameworkCore.cs:252:18:252:28 | access to property Persons [element, property Addresses, element, property Street] : String | semmle.label | access to property Persons [element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:252:18:252:36 | call to method First [property Addresses, element, property Street] : String | semmle.label | call to method First [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:252:18:252:46 | access to property Addresses [element, property Street] : String | semmle.label | access to property Addresses [element, property Street] : String | +| EntityFrameworkCore.cs:252:18:252:54 | call to method First
[property Street] : String | semmle.label | call to method First
[property Street] : String | +| EntityFrameworkCore.cs:252:18:252:61 | access to property Street | semmle.label | access to property Street | subpaths #select | EntityFramework.cs:129:18:129:25 | access to property Title | EntityFramework.cs:124:25:124:33 | "tainted" : String | EntityFramework.cs:129:18:129:25 | access to property Title | $@ | EntityFramework.cs:124:25:124:33 | "tainted" : String | "tainted" : String | @@ -341,17 +341,17 @@ subpaths | EntityFramework.cs:219:18:219:61 | access to property Street | EntityFramework.cs:145:34:145:42 | "tainted" : String | EntityFramework.cs:219:18:219:61 | access to property Street | $@ | EntityFramework.cs:145:34:145:42 | "tainted" : String | "tainted" : String | | EntityFramework.cs:219:18:219:61 | access to property Street | EntityFramework.cs:159:26:159:34 | "tainted" : String | EntityFramework.cs:219:18:219:61 | access to property Street | $@ | EntityFramework.cs:159:26:159:34 | "tainted" : String | "tainted" : String | | EntityFramework.cs:219:18:219:61 | access to property Street | EntityFramework.cs:180:26:180:34 | "tainted" : String | EntityFramework.cs:219:18:219:61 | access to property Street | $@ | EntityFramework.cs:180:26:180:34 | "tainted" : String | "tainted" : String | -| EntityFrameworkCore.cs:76:18:76:28 | access to local variable taintSource | EntityFrameworkCore.cs:75:31:75:39 | "tainted" : String | EntityFrameworkCore.cs:76:18:76:28 | access to local variable taintSource | $@ | EntityFrameworkCore.cs:75:31:75:39 | "tainted" : String | "tainted" : String | -| EntityFrameworkCore.cs:77:18:77:46 | (...) ... | EntityFrameworkCore.cs:75:31:75:39 | "tainted" : String | EntityFrameworkCore.cs:77:18:77:46 | (...) ... | $@ | EntityFrameworkCore.cs:75:31:75:39 | "tainted" : String | "tainted" : String | -| EntityFrameworkCore.cs:78:18:78:42 | (...) ... | EntityFrameworkCore.cs:75:31:75:39 | "tainted" : String | EntityFrameworkCore.cs:78:18:78:42 | (...) ... | $@ | EntityFrameworkCore.cs:75:31:75:39 | "tainted" : String | "tainted" : String | -| EntityFrameworkCore.cs:155:18:155:25 | access to property Title | EntityFrameworkCore.cs:150:25:150:33 | "tainted" : String | EntityFrameworkCore.cs:155:18:155:25 | access to property Title | $@ | EntityFrameworkCore.cs:150:25:150:33 | "tainted" : String | "tainted" : String | -| EntityFrameworkCore.cs:230:18:230:41 | access to property Name | EntityFrameworkCore.cs:87:24:87:32 | "tainted" : String | EntityFrameworkCore.cs:230:18:230:41 | access to property Name | $@ | EntityFrameworkCore.cs:87:24:87:32 | "tainted" : String | "tainted" : String | -| EntityFrameworkCore.cs:230:18:230:41 | access to property Name | EntityFrameworkCore.cs:109:24:109:32 | "tainted" : String | EntityFrameworkCore.cs:230:18:230:41 | access to property Name | $@ | EntityFrameworkCore.cs:109:24:109:32 | "tainted" : String | "tainted" : String | -| EntityFrameworkCore.cs:230:18:230:41 | access to property Name | EntityFrameworkCore.cs:131:24:131:32 | "tainted" : String | EntityFrameworkCore.cs:230:18:230:41 | access to property Name | $@ | EntityFrameworkCore.cs:131:24:131:32 | "tainted" : String | "tainted" : String | -| EntityFrameworkCore.cs:230:18:230:41 | access to property Name | EntityFrameworkCore.cs:201:24:201:32 | "tainted" : String | EntityFrameworkCore.cs:230:18:230:41 | access to property Name | $@ | EntityFrameworkCore.cs:201:24:201:32 | "tainted" : String | "tainted" : String | -| EntityFrameworkCore.cs:238:18:238:45 | access to property Street | EntityFrameworkCore.cs:171:34:171:42 | "tainted" : String | EntityFrameworkCore.cs:238:18:238:45 | access to property Street | $@ | EntityFrameworkCore.cs:171:34:171:42 | "tainted" : String | "tainted" : String | -| EntityFrameworkCore.cs:238:18:238:45 | access to property Street | EntityFrameworkCore.cs:185:26:185:34 | "tainted" : String | EntityFrameworkCore.cs:238:18:238:45 | access to property Street | $@ | EntityFrameworkCore.cs:185:26:185:34 | "tainted" : String | "tainted" : String | -| EntityFrameworkCore.cs:238:18:238:45 | access to property Street | EntityFrameworkCore.cs:206:26:206:34 | "tainted" : String | EntityFrameworkCore.cs:238:18:238:45 | access to property Street | $@ | EntityFrameworkCore.cs:206:26:206:34 | "tainted" : String | "tainted" : String | -| EntityFrameworkCore.cs:245:18:245:61 | access to property Street | EntityFrameworkCore.cs:171:34:171:42 | "tainted" : String | EntityFrameworkCore.cs:245:18:245:61 | access to property Street | $@ | EntityFrameworkCore.cs:171:34:171:42 | "tainted" : String | "tainted" : String | -| EntityFrameworkCore.cs:245:18:245:61 | access to property Street | EntityFrameworkCore.cs:185:26:185:34 | "tainted" : String | EntityFrameworkCore.cs:245:18:245:61 | access to property Street | $@ | EntityFrameworkCore.cs:185:26:185:34 | "tainted" : String | "tainted" : String | -| EntityFrameworkCore.cs:245:18:245:61 | access to property Street | EntityFrameworkCore.cs:206:26:206:34 | "tainted" : String | EntityFrameworkCore.cs:245:18:245:61 | access to property Street | $@ | EntityFrameworkCore.cs:206:26:206:34 | "tainted" : String | "tainted" : String | +| EntityFrameworkCore.cs:83:18:83:28 | access to local variable taintSource | EntityFrameworkCore.cs:82:31:82:39 | "tainted" : String | EntityFrameworkCore.cs:83:18:83:28 | access to local variable taintSource | $@ | EntityFrameworkCore.cs:82:31:82:39 | "tainted" : String | "tainted" : String | +| EntityFrameworkCore.cs:84:18:84:46 | (...) ... | EntityFrameworkCore.cs:82:31:82:39 | "tainted" : String | EntityFrameworkCore.cs:84:18:84:46 | (...) ... | $@ | EntityFrameworkCore.cs:82:31:82:39 | "tainted" : String | "tainted" : String | +| EntityFrameworkCore.cs:85:18:85:42 | (...) ... | EntityFrameworkCore.cs:82:31:82:39 | "tainted" : String | EntityFrameworkCore.cs:85:18:85:42 | (...) ... | $@ | EntityFrameworkCore.cs:82:31:82:39 | "tainted" : String | "tainted" : String | +| EntityFrameworkCore.cs:162:18:162:25 | access to property Title | EntityFrameworkCore.cs:157:25:157:33 | "tainted" : String | EntityFrameworkCore.cs:162:18:162:25 | access to property Title | $@ | EntityFrameworkCore.cs:157:25:157:33 | "tainted" : String | "tainted" : String | +| EntityFrameworkCore.cs:237:18:237:41 | access to property Name | EntityFrameworkCore.cs:94:24:94:32 | "tainted" : String | EntityFrameworkCore.cs:237:18:237:41 | access to property Name | $@ | EntityFrameworkCore.cs:94:24:94:32 | "tainted" : String | "tainted" : String | +| EntityFrameworkCore.cs:237:18:237:41 | access to property Name | EntityFrameworkCore.cs:116:24:116:32 | "tainted" : String | EntityFrameworkCore.cs:237:18:237:41 | access to property Name | $@ | EntityFrameworkCore.cs:116:24:116:32 | "tainted" : String | "tainted" : String | +| EntityFrameworkCore.cs:237:18:237:41 | access to property Name | EntityFrameworkCore.cs:138:24:138:32 | "tainted" : String | EntityFrameworkCore.cs:237:18:237:41 | access to property Name | $@ | EntityFrameworkCore.cs:138:24:138:32 | "tainted" : String | "tainted" : String | +| EntityFrameworkCore.cs:237:18:237:41 | access to property Name | EntityFrameworkCore.cs:208:24:208:32 | "tainted" : String | EntityFrameworkCore.cs:237:18:237:41 | access to property Name | $@ | EntityFrameworkCore.cs:208:24:208:32 | "tainted" : String | "tainted" : String | +| EntityFrameworkCore.cs:245:18:245:45 | access to property Street | EntityFrameworkCore.cs:178:34:178:42 | "tainted" : String | EntityFrameworkCore.cs:245:18:245:45 | access to property Street | $@ | EntityFrameworkCore.cs:178:34:178:42 | "tainted" : String | "tainted" : String | +| EntityFrameworkCore.cs:245:18:245:45 | access to property Street | EntityFrameworkCore.cs:192:26:192:34 | "tainted" : String | EntityFrameworkCore.cs:245:18:245:45 | access to property Street | $@ | EntityFrameworkCore.cs:192:26:192:34 | "tainted" : String | "tainted" : String | +| EntityFrameworkCore.cs:245:18:245:45 | access to property Street | EntityFrameworkCore.cs:213:26:213:34 | "tainted" : String | EntityFrameworkCore.cs:245:18:245:45 | access to property Street | $@ | EntityFrameworkCore.cs:213:26:213:34 | "tainted" : String | "tainted" : String | +| EntityFrameworkCore.cs:252:18:252:61 | access to property Street | EntityFrameworkCore.cs:178:34:178:42 | "tainted" : String | EntityFrameworkCore.cs:252:18:252:61 | access to property Street | $@ | EntityFrameworkCore.cs:178:34:178:42 | "tainted" : String | "tainted" : String | +| EntityFrameworkCore.cs:252:18:252:61 | access to property Street | EntityFrameworkCore.cs:192:26:192:34 | "tainted" : String | EntityFrameworkCore.cs:252:18:252:61 | access to property Street | $@ | EntityFrameworkCore.cs:192:26:192:34 | "tainted" : String | "tainted" : String | +| EntityFrameworkCore.cs:252:18:252:61 | access to property Street | EntityFrameworkCore.cs:213:26:213:34 | "tainted" : String | EntityFrameworkCore.cs:252:18:252:61 | access to property Street | $@ | EntityFrameworkCore.cs:213:26:213:34 | "tainted" : String | "tainted" : String | diff --git a/csharp/ql/test/library-tests/frameworks/EntityFramework/EntityFrameworkCore.cs b/csharp/ql/test/library-tests/frameworks/EntityFramework/EntityFrameworkCore.cs index 4cf1dd138c8..b45290dc799 100644 --- a/csharp/ql/test/library-tests/frameworks/EntityFramework/EntityFrameworkCore.cs +++ b/csharp/ql/test/library-tests/frameworks/EntityFramework/EntityFrameworkCore.cs @@ -56,7 +56,7 @@ namespace EFCoreTests Microsoft.EntityFrameworkCore.Storage.IRawSqlCommandBuilder builder; - async void SqlExprs(MyContext ctx) + async void SqlExprs(MyContext ctx, System.Threading.CancellationToken token) { // Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.ExecuteSqlCommand ctx.Database.ExecuteSqlCommand(""); // SqlExpr @@ -68,6 +68,13 @@ namespace EFCoreTests // Microsoft.EntityFrameworkCore.RawSqlString new RawSqlString(""); // SqlExpr RawSqlString str = ""; // SqlExpr + + ctx.Persons.FromSqlRaw("sql"); + ctx.Database.ExecuteSqlRaw("sql", (IEnumerable)null); + ctx.Database.ExecuteSqlRaw("sql"); + await ctx.Database.ExecuteSqlRawAsync("sql", token); + await ctx.Database.ExecuteSqlRawAsync("sql"); + await ctx.Database.ExecuteSqlRawAsync("sql", (IEnumerable)null, token); } void TestRawSqlStringDataFlow() diff --git a/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.expected b/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.expected index 9e043ec7486..9fb5be26eeb 100644 --- a/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.expected +++ b/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.expected @@ -1,3 +1,4 @@ +summary | Microsoft.EntityFrameworkCore;DbContext;false;SaveChanges;();;Argument[Qualifier].Property[EFCoreTests.MyContext.Addresses].Element.Property[EFCoreTests.Address.Id];ReturnValue[jump to get_Addresses].Element.Property[EFCoreTests.Address.Id];value | | Microsoft.EntityFrameworkCore;DbContext;false;SaveChanges;();;Argument[Qualifier].Property[EFCoreTests.MyContext.Addresses].Element.Property[EFCoreTests.Address.Id];ReturnValue[jump to get_PersonAddresses].Element.Property[EFCoreTests.PersonAddressMap.Address].Property[EFCoreTests.Address.Id];value | | Microsoft.EntityFrameworkCore;DbContext;false;SaveChanges;();;Argument[Qualifier].Property[EFCoreTests.MyContext.Addresses].Element.Property[EFCoreTests.Address.Id];ReturnValue[jump to get_Persons].Element.Property[EFCoreTests.Person.Addresses].Element.Property[EFCoreTests.Address.Id];value | @@ -130,3 +131,11 @@ | System.Data.Entity;DbSet<>;false;AttachRange;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[Qualifier].Element;value | | System.Data.Entity;DbSet<>;false;Update;(T);;Argument[0];Argument[Qualifier].Element;value | | System.Data.Entity;DbSet<>;false;UpdateRange;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[Qualifier].Element;value | +sourceNode +sinkNode +| EntityFrameworkCore.cs:72:36:72:40 | "sql" | sql | +| EntityFrameworkCore.cs:73:40:73:44 | "sql" | sql | +| EntityFrameworkCore.cs:74:40:74:44 | "sql" | sql | +| EntityFrameworkCore.cs:75:51:75:55 | "sql" | sql | +| EntityFrameworkCore.cs:76:51:76:55 | "sql" | sql | +| EntityFrameworkCore.cs:77:51:77:55 | "sql" | sql | diff --git a/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.ql b/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.ql index 61bee675bf1..41cc8379b3d 100644 --- a/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.ql +++ b/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.ql @@ -1,6 +1,13 @@ import semmle.code.csharp.frameworks.EntityFramework::EntityFramework import shared.FlowSummaries +import semmle.code.csharp.dataflow.ExternalFlow as ExternalFlow private class IncludeEFSummarizedCallable extends IncludeSummarizedCallable { IncludeEFSummarizedCallable() { this instanceof EFSummarizedCallable } } + +query predicate sourceNode(DataFlow::Node node, string kind) { + ExternalFlow::sourceNode(node, kind) +} + +query predicate sinkNode(DataFlow::Node node, string kind) { ExternalFlow::sinkNode(node, kind) } diff --git a/csharp/ql/test/library-tests/frameworks/EntityFramework/SqlExprs.expected b/csharp/ql/test/library-tests/frameworks/EntityFramework/SqlExprs.expected index faaddc5257b..5008ff2695c 100644 --- a/csharp/ql/test/library-tests/frameworks/EntityFramework/SqlExprs.expected +++ b/csharp/ql/test/library-tests/frameworks/EntityFramework/SqlExprs.expected @@ -3,5 +3,11 @@ | EntityFrameworkCore.cs:66:13:66:29 | call to method Build | | EntityFrameworkCore.cs:69:13:69:32 | object creation of type RawSqlString | | EntityFrameworkCore.cs:70:32:70:33 | call to operator implicit conversion | -| EntityFrameworkCore.cs:77:18:77:46 | object creation of type RawSqlString | -| EntityFrameworkCore.cs:78:18:78:42 | call to operator implicit conversion | +| EntityFrameworkCore.cs:72:13:72:41 | call to method FromSqlRaw | +| EntityFrameworkCore.cs:73:13:73:72 | call to method ExecuteSqlRaw | +| EntityFrameworkCore.cs:74:13:74:45 | call to method ExecuteSqlRaw | +| EntityFrameworkCore.cs:75:19:75:63 | call to method ExecuteSqlRawAsync | +| EntityFrameworkCore.cs:76:19:76:56 | call to method ExecuteSqlRawAsync | +| EntityFrameworkCore.cs:77:19:77:90 | call to method ExecuteSqlRawAsync | +| EntityFrameworkCore.cs:84:18:84:46 | object creation of type RawSqlString | +| EntityFrameworkCore.cs:85:18:85:42 | call to operator implicit conversion | diff --git a/csharp/ql/test/library-tests/frameworks/EntityFramework/StoredFlowSources.expected b/csharp/ql/test/library-tests/frameworks/EntityFramework/StoredFlowSources.expected index 4a0ecb82c3f..2b6c64790ce 100644 --- a/csharp/ql/test/library-tests/frameworks/EntityFramework/StoredFlowSources.expected +++ b/csharp/ql/test/library-tests/frameworks/EntityFramework/StoredFlowSources.expected @@ -10,11 +10,11 @@ | EntityFramework.cs:219:18:219:61 | access to property Street | | EntityFrameworkCore.cs:52:22:52:25 | access to property Id | | EntityFrameworkCore.cs:53:24:53:29 | access to property Name | -| EntityFrameworkCore.cs:229:18:229:39 | access to property Id | -| EntityFrameworkCore.cs:230:18:230:41 | access to property Name | -| EntityFrameworkCore.cs:237:18:237:41 | access to property Id | -| EntityFrameworkCore.cs:238:18:238:45 | access to property Street | -| EntityFrameworkCore.cs:244:18:244:46 | access to property Addresses | -| EntityFrameworkCore.cs:244:18:244:57 | access to property Id | -| EntityFrameworkCore.cs:245:18:245:46 | access to property Addresses | -| EntityFrameworkCore.cs:245:18:245:61 | access to property Street | +| EntityFrameworkCore.cs:236:18:236:39 | access to property Id | +| EntityFrameworkCore.cs:237:18:237:41 | access to property Name | +| EntityFrameworkCore.cs:244:18:244:41 | access to property Id | +| EntityFrameworkCore.cs:245:18:245:45 | access to property Street | +| EntityFrameworkCore.cs:251:18:251:46 | access to property Addresses | +| EntityFrameworkCore.cs:251:18:251:57 | access to property Id | +| EntityFrameworkCore.cs:252:18:252:46 | access to property Addresses | +| EntityFrameworkCore.cs:252:18:252:61 | access to property Street | diff --git a/csharp/ql/test/resources/stubs/EntityFramework.cs b/csharp/ql/test/resources/stubs/EntityFramework.cs index 85903ed8799..4612349a923 100644 --- a/csharp/ql/test/resources/stubs/EntityFramework.cs +++ b/csharp/ql/test/resources/stubs/EntityFramework.cs @@ -88,10 +88,16 @@ namespace Microsoft.EntityFrameworkCore } } - public static class RelationalDatabaseFacaseExtensions + public static class RelationalDatabaseFacadeExtensions { public static void ExecuteSqlCommand(this Infrastructure.DatabaseFacade db, string sql, params object[] parameters) { } public static Task ExecuteSqlCommandAsync(this Infrastructure.DatabaseFacade db, string sql, params object[] parameters) => throw null; + + public static int ExecuteSqlRaw(this Infrastructure.DatabaseFacade db, string sql, IEnumerable args) => throw null; + public static int ExecuteSqlRaw(this Infrastructure.DatabaseFacade db, string sql, params object[] args) => throw null; + public static Task ExecuteSqlRawAsync(this Infrastructure.DatabaseFacade db, string sql, System.Threading.CancellationToken token) => throw null; + public static Task ExecuteSqlRawAsync(this Infrastructure.DatabaseFacade db, string sql, params object[] args) => throw null; + public static Task ExecuteSqlRawAsync(this Infrastructure.DatabaseFacade db, string sql, IEnumerable args, System.Threading.CancellationToken token) => throw null; } struct RawSqlString @@ -100,6 +106,11 @@ namespace Microsoft.EntityFrameworkCore public static implicit operator Microsoft.EntityFrameworkCore.RawSqlString(FormattableString fs) => throw null; public static implicit operator Microsoft.EntityFrameworkCore.RawSqlString(string s) => throw null; } + + public static class RelationalQueryableExtensions + { + public static void FromSqlRaw(this DbSet set, string sql, params object[] args) => throw null; + } } namespace Microsoft.EntityFrameworkCore.Storage diff --git a/docs/codeql/support/reusables/versions-compilers.rst b/docs/codeql/support/reusables/versions-compilers.rst index 745fbb8a193..a5f68cb64e1 100644 --- a/docs/codeql/support/reusables/versions-compilers.rst +++ b/docs/codeql/support/reusables/versions-compilers.rst @@ -16,7 +16,7 @@ .NET Core up to 3.1 .NET 5, .NET 6","``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``" - Go (aka Golang), "Go up to 1.17", "Go 1.11 or more recent", ``.go`` + Go (aka Golang), "Go up to 1.18", "Go 1.11 or more recent", ``.go`` Java,"Java 7 to 18 [4]_","javac (OpenJDK and Oracle JDK), Eclipse compiler for Java (ECJ) [5]_",``.java`` diff --git a/java/documentation/library-coverage/coverage.csv b/java/documentation/library-coverage/coverage.csv index 061e4605d5c..bc147a2c914 100644 --- a/java/documentation/library-coverage/coverage.csv +++ b/java/documentation/library-coverage/coverage.csv @@ -1,120 +1,121 @@ -package,sink,source,summary,sink:bean-validation,sink:create-file,sink:groovy,sink:header-splitting,sink:information-leak,sink:intent-start,sink:jdbc-url,sink:jexl,sink:jndi-injection,sink:ldap,sink:logging,sink:mvel,sink:ognl-injection,sink:open-url,sink:pending-intent-sent,sink:set-hostname-verifier,sink:sql,sink:url-open-stream,sink:url-redirect,sink:write-file,sink:xpath,sink:xslt,sink:xss,source:android-widget,source:contentprovider,source:remote,summary:taint,summary:value -android.app,16,,103,,,,,,7,,,,,,,,,9,,,,,,,,,,,,18,85 -android.content,24,27,108,,,,,,16,,,,,,,,,,,8,,,,,,,,27,,31,77 -android.database,59,,30,,,,,,,,,,,,,,,,,59,,,,,,,,,,30, -android.net,,,60,,,,,,,,,,,,,,,,,,,,,,,,,,,45,15 -android.os,,,122,,,,,,,,,,,,,,,,,,,,,,,,,,,41,81 -android.util,6,16,,,,,,,,,,,,6,,,,,,,,,,,,,,,16,, -android.webkit,3,2,,,,,,,,,,,,,,,,,,,,,,,,3,,,2,, -android.widget,,1,1,,,,,,,,,,,,,,,,,,,,,,,,1,,,1, -androidx.slice,2,5,88,,,,,,,,,,,,,,,2,,,,,,,,,,5,,27,61 -cn.hutool.core.codec,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -com.esotericsoftware.kryo.io,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -com.esotericsoftware.kryo5.io,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -com.fasterxml.jackson.core,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -com.fasterxml.jackson.databind,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,6, -com.google.common.base,,,85,,,,,,,,,,,,,,,,,,,,,,,,,,,62,23 -com.google.common.cache,,,17,,,,,,,,,,,,,,,,,,,,,,,,,,,,17 -com.google.common.collect,,,553,,,,,,,,,,,,,,,,,,,,,,,,,,,2,551 -com.google.common.flogger,29,,,,,,,,,,,,,29,,,,,,,,,,,,,,,,, -com.google.common.io,6,,73,,,,,,,,,,,,,,,,,,6,,,,,,,,,72,1 -com.opensymphony.xwork2.ognl,3,,,,,,,,,,,,,,,3,,,,,,,,,,,,,,, -com.rabbitmq.client,,21,7,,,,,,,,,,,,,,,,,,,,,,,,,,21,7, -com.unboundid.ldap.sdk,17,,,,,,,,,,,,17,,,,,,,,,,,,,,,,,, -com.zaxxer.hikari,2,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,, -flexjson,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 -groovy.lang,26,,,,,26,,,,,,,,,,,,,,,,,,,,,,,,, -groovy.util,5,,,,,5,,,,,,,,,,,,,,,,,,,,,,,,, -jakarta.faces.context,2,7,,,,,,,,,,,,,,,,,,,,,,,,2,,,7,, -jakarta.json,,,123,,,,,,,,,,,,,,,,,,,,,,,,,,,100,23 -jakarta.ws.rs.client,1,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,, -jakarta.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,9,, -jakarta.ws.rs.core,2,,149,,,,,,,,,,,,,,,,,,,2,,,,,,,,94,55 -java.beans,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -java.io,37,,39,,15,,,,,,,,,,,,,,,,,,22,,,,,,,39, -java.lang,8,,58,,,,,,,,,,,8,,,,,,,,,,,,,,,,46,12 -java.net,10,3,7,,,,,,,,,,,,,,10,,,,,,,,,,,,3,7, -java.nio,15,,6,,13,,,,,,,,,,,,,,,,,,2,,,,,,,6, -java.sql,11,,,,,,,,,4,,,,,,,,,,7,,,,,,,,,,, -java.util,34,,438,,,,,,,,,,,34,,,,,,,,,,,,,,,,24,414 -javax.faces.context,2,7,,,,,,,,,,,,,,,,,,,,,,,,2,,,7,, -javax.jms,,9,57,,,,,,,,,,,,,,,,,,,,,,,,,,9,57, -javax.json,,,123,,,,,,,,,,,,,,,,,,,,,,,,,,,100,23 -javax.management.remote,2,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,, -javax.naming,7,,,,,,,,,,,6,1,,,,,,,,,,,,,,,,,, -javax.net.ssl,2,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,, -javax.script,1,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,, -javax.servlet,4,21,2,,,,3,1,,,,,,,,,,,,,,,,,,,,,21,2, -javax.validation,1,1,,1,,,,,,,,,,,,,,,,,,,,,,,,,1,, -javax.ws.rs.client,1,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,, -javax.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,9,, -javax.ws.rs.core,3,,149,,,,1,,,,,,,,,,,,,,,2,,,,,,,,94,55 -javax.xml.transform,1,,6,,,,,,,,,,,,,,,,,,,,,,1,,,,,6, -javax.xml.xpath,3,,,,,,,,,,,,,,,,,,,,,,,3,,,,,,, -jodd.json,,,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,10 -net.sf.saxon.s9api,5,,,,,,,,,,,,,,,,,,,,,,,,5,,,,,, -ognl,6,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,, -okhttp3,2,,47,,,,,,,,,,,,,,2,,,,,,,,,,,,,22,25 -org.apache.commons.codec,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,6, -org.apache.commons.collections,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 -org.apache.commons.collections4,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 -org.apache.commons.io,93,2,565,,78,,,,,,,,,,,,15,,,,,,,,,,,,2,551,14 -org.apache.commons.jexl2,15,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,, -org.apache.commons.jexl3,15,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,, -org.apache.commons.lang3,,,424,,,,,,,,,,,,,,,,,,,,,,,,,,,293,131 -org.apache.commons.logging,6,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,, -org.apache.commons.ognl,6,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,, -org.apache.commons.text,,,272,,,,,,,,,,,,,,,,,,,,,,,,,,,220,52 -org.apache.directory.ldap.client.api,1,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,, -org.apache.hc.core5.function,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -org.apache.hc.core5.http,1,2,39,,,,,,,,,,,,,,,,,,,,,,,1,,,2,39, -org.apache.hc.core5.net,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,2, -org.apache.hc.core5.util,,,24,,,,,,,,,,,,,,,,,,,,,,,,,,,18,6 -org.apache.http,27,3,70,,,,,,,,,,,,,,25,,,,,,,,,2,,,3,62,8 -org.apache.ibatis.jdbc,6,,57,,,,,,,,,,,,,,,,,6,,,,,,,,,,57, -org.apache.log4j,11,,,,,,,,,,,,,11,,,,,,,,,,,,,,,,, -org.apache.logging.log4j,359,,8,,,,,,,,,,,359,,,,,,,,,,,,,,,,4,4 -org.apache.shiro.codec,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -org.apache.shiro.jndi,1,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,, -org.codehaus.groovy.control,1,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,, -org.dom4j,20,,,,,,,,,,,,,,,,,,,,,,,20,,,,,,, -org.hibernate,7,,,,,,,,,,,,,,,,,,,7,,,,,,,,,,, -org.jboss.logging,324,,,,,,,,,,,,,324,,,,,,,,,,,,,,,,, -org.jdbi.v3.core,6,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,, -org.jooq,1,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,, -org.json,,,236,,,,,,,,,,,,,,,,,,,,,,,,,,,198,38 -org.mvel2,16,,,,,,,,,,,,,,16,,,,,,,,,,,,,,,, -org.scijava.log,13,,,,,,,,,,,,,13,,,,,,,,,,,,,,,,, -org.slf4j,55,,6,,,,,,,,,,,55,,,,,,,,,,,,,,,,2,4 -org.springframework.beans,,,30,,,,,,,,,,,,,,,,,,,,,,,,,,,,30 -org.springframework.boot.jdbc,1,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,, -org.springframework.cache,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,13 -org.springframework.context,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,3, -org.springframework.http,14,,70,,,,,,,,,,,,,,14,,,,,,,,,,,,,60,10 -org.springframework.jdbc.core,10,,,,,,,,,,,,,,,,,,,10,,,,,,,,,,, -org.springframework.jdbc.datasource,4,,,,,,,,,4,,,,,,,,,,,,,,,,,,,,, -org.springframework.jdbc.object,9,,,,,,,,,,,,,,,,,,,9,,,,,,,,,,, -org.springframework.jndi,1,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,, -org.springframework.ldap,47,,,,,,,,,,,33,14,,,,,,,,,,,,,,,,,, -org.springframework.security.web.savedrequest,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,6,, -org.springframework.ui,,,32,,,,,,,,,,,,,,,,,,,,,,,,,,,,32 -org.springframework.util,,,139,,,,,,,,,,,,,,,,,,,,,,,,,,,87,52 -org.springframework.validation,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,13, -org.springframework.web.client,13,3,,,,,,,,,,,,,,,13,,,,,,,,,,,,3,, -org.springframework.web.context.request,,8,,,,,,,,,,,,,,,,,,,,,,,,,,,8,, -org.springframework.web.multipart,,12,13,,,,,,,,,,,,,,,,,,,,,,,,,,12,13, -org.springframework.web.reactive.function.client,2,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,, -org.springframework.web.util,,,163,,,,,,,,,,,,,,,,,,,,,,,,,,,138,25 -org.xml.sax,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -org.xmlpull.v1,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,3,, -play.mvc,,4,,,,,,,,,,,,,,,,,,,,,,,,,,,4,, -ratpack.core.form,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,3, -ratpack.core.handling,,6,4,,,,,,,,,,,,,,,,,,,,,,,,,,6,4, -ratpack.core.http,,10,10,,,,,,,,,,,,,,,,,,,,,,,,,,10,10, -ratpack.exec,,,48,,,,,,,,,,,,,,,,,,,,,,,,,,,,48 -ratpack.form,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,3, -ratpack.func,,,35,,,,,,,,,,,,,,,,,,,,,,,,,,,,35 -ratpack.handling,,6,4,,,,,,,,,,,,,,,,,,,,,,,,,,6,4, -ratpack.http,,10,10,,,,,,,,,,,,,,,,,,,,,,,,,,10,10, -ratpack.util,,,35,,,,,,,,,,,,,,,,,,,,,,,,,,,,35 -retrofit2,1,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,, +package,sink,source,summary,sink:bean-validation,sink:create-file,sink:groovy,sink:header-splitting,sink:information-leak,sink:intent-start,sink:jdbc-url,sink:jexl,sink:jndi-injection,sink:ldap,sink:logging,sink:mvel,sink:ognl-injection,sink:open-url,sink:pending-intent-sent,sink:regex-use[-1],sink:regex-use[0],sink:regex-use[],sink:regex-use[f-1],sink:regex-use[f1],sink:regex-use[f],sink:set-hostname-verifier,sink:sql,sink:url-open-stream,sink:url-redirect,sink:write-file,sink:xpath,sink:xslt,sink:xss,source:android-widget,source:contentprovider,source:remote,summary:taint,summary:value +android.app,16,,103,,,,,,7,,,,,,,,,9,,,,,,,,,,,,,,,,,,18,85 +android.content,24,27,108,,,,,,16,,,,,,,,,,,,,,,,,8,,,,,,,,27,,31,77 +android.database,59,,30,,,,,,,,,,,,,,,,,,,,,,,59,,,,,,,,,,30, +android.net,,,60,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,45,15 +android.os,,,122,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,41,81 +android.util,6,16,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,16,, +android.webkit,3,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,2,, +android.widget,,1,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,1, +androidx.slice,2,5,88,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,5,,27,61 +cn.hutool.core.codec,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +com.esotericsoftware.kryo.io,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +com.esotericsoftware.kryo5.io,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +com.fasterxml.jackson.core,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +com.fasterxml.jackson.databind,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6, +com.google.common.base,4,,85,,,,,,,,,,,,,,,,,3,1,,,,,,,,,,,,,,,62,23 +com.google.common.cache,,,17,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17 +com.google.common.collect,,,553,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,551 +com.google.common.flogger,29,,,,,,,,,,,,,29,,,,,,,,,,,,,,,,,,,,,,, +com.google.common.io,6,,73,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,72,1 +com.opensymphony.xwork2.ognl,3,,,,,,,,,,,,,,,3,,,,,,,,,,,,,,,,,,,,, +com.rabbitmq.client,,21,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,21,7, +com.unboundid.ldap.sdk,17,,,,,,,,,,,,17,,,,,,,,,,,,,,,,,,,,,,,, +com.zaxxer.hikari,2,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,, +flexjson,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 +groovy.lang,26,,,,,26,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +groovy.util,5,,,,,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +jakarta.faces.context,2,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,7,, +jakarta.json,,,123,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,100,23 +jakarta.ws.rs.client,1,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,, +jakarta.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,, +jakarta.ws.rs.core,2,,149,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,94,55 +java.beans,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +java.io,37,,39,,15,,,,,,,,,,,,,,,,,,,,,,,,22,,,,,,,39, +java.lang,13,,58,,,,,,,,,,,8,,,,,4,,,1,,,,,,,,,,,,,,46,12 +java.net,10,3,7,,,,,,,,,,,,,,10,,,,,,,,,,,,,,,,,,3,7, +java.nio,15,,6,,13,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,6, +java.sql,11,,,,,,,,,4,,,,,,,,,,,,,,,,7,,,,,,,,,,, +java.util,44,,438,,,,,,,,,,,34,,,,,,5,2,,1,2,,,,,,,,,,,,24,414 +javax.faces.context,2,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,7,, +javax.jms,,9,57,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,57, +javax.json,,,123,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,100,23 +javax.management.remote,2,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,, +javax.naming,7,,,,,,,,,,,6,1,,,,,,,,,,,,,,,,,,,,,,,, +javax.net.ssl,2,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,, +javax.script,1,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,, +javax.servlet,4,21,2,,,,3,1,,,,,,,,,,,,,,,,,,,,,,,,,,,21,2, +javax.validation,1,1,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,, +javax.ws.rs.client,1,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,, +javax.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,, +javax.ws.rs.core,3,,149,,,,1,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,94,55 +javax.xml.transform,1,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,6, +javax.xml.xpath,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,,,, +jodd.json,,,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10 +kotlin.jvm.internal,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 +net.sf.saxon.s9api,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,5,,,,,, +ognl,6,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,, +okhttp3,2,,47,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,22,25 +org.apache.commons.codec,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6, +org.apache.commons.collections,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 +org.apache.commons.collections4,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 +org.apache.commons.io,93,2,565,,78,,,,,,,,,,,,15,,,,,,,,,,,,,,,,,,2,551,14 +org.apache.commons.jexl2,15,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.commons.jexl3,15,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.commons.lang3,,,424,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,293,131 +org.apache.commons.logging,6,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,, +org.apache.commons.ognl,6,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,, +org.apache.commons.text,,,272,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,220,52 +org.apache.directory.ldap.client.api,1,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.hc.core5.function,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +org.apache.hc.core5.http,1,2,39,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,2,39, +org.apache.hc.core5.net,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2, +org.apache.hc.core5.util,,,24,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18,6 +org.apache.http,27,3,70,,,,,,,,,,,,,,25,,,,,,,,,,,,,,,2,,,3,62,8 +org.apache.ibatis.jdbc,6,,57,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,57, +org.apache.log4j,11,,,,,,,,,,,,,11,,,,,,,,,,,,,,,,,,,,,,, +org.apache.logging.log4j,359,,8,,,,,,,,,,,359,,,,,,,,,,,,,,,,,,,,,,4,4 +org.apache.shiro.codec,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +org.apache.shiro.jndi,1,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,, +org.codehaus.groovy.control,1,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.dom4j,20,,,,,,,,,,,,,,,,,,,,,,,,,,,,,20,,,,,,, +org.hibernate,7,,,,,,,,,,,,,,,,,,,,,,,,,7,,,,,,,,,,, +org.jboss.logging,324,,,,,,,,,,,,,324,,,,,,,,,,,,,,,,,,,,,,, +org.jdbi.v3.core,6,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.jooq,1,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,, +org.json,,,236,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,198,38 +org.mvel2,16,,,,,,,,,,,,,,16,,,,,,,,,,,,,,,,,,,,,, +org.scijava.log,13,,,,,,,,,,,,,13,,,,,,,,,,,,,,,,,,,,,,, +org.slf4j,55,,6,,,,,,,,,,,55,,,,,,,,,,,,,,,,,,,,,,2,4 +org.springframework.beans,,,30,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,30 +org.springframework.boot.jdbc,1,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.springframework.cache,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13 +org.springframework.context,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, +org.springframework.http,14,,70,,,,,,,,,,,,,,14,,,,,,,,,,,,,,,,,,,60,10 +org.springframework.jdbc.core,10,,,,,,,,,,,,,,,,,,,,,,,,,10,,,,,,,,,,, +org.springframework.jdbc.datasource,4,,,,,,,,,4,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.springframework.jdbc.object,9,,,,,,,,,,,,,,,,,,,,,,,,,9,,,,,,,,,,, +org.springframework.jndi,1,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,, +org.springframework.ldap,47,,,,,,,,,,,33,14,,,,,,,,,,,,,,,,,,,,,,,, +org.springframework.security.web.savedrequest,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,, +org.springframework.ui,,,32,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,32 +org.springframework.util,,,139,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,87,52 +org.springframework.validation,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13, +org.springframework.web.client,13,3,,,,,,,,,,,,,,,13,,,,,,,,,,,,,,,,,,3,, +org.springframework.web.context.request,,8,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,8,, +org.springframework.web.multipart,,12,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,12,13, +org.springframework.web.reactive.function.client,2,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,, +org.springframework.web.util,,,163,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,138,25 +org.xml.sax,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +org.xmlpull.v1,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,, +play.mvc,,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,4,, +ratpack.core.form,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, +ratpack.core.handling,,6,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,4, +ratpack.core.http,,10,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10,10, +ratpack.exec,,,48,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,48 +ratpack.form,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, +ratpack.func,,,35,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35 +ratpack.handling,,6,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,4, +ratpack.http,,10,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10,10, +ratpack.util,,,35,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35 +retrofit2,1,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,, diff --git a/java/documentation/library-coverage/coverage.rst b/java/documentation/library-coverage/coverage.rst index e4e599b5f01..4569039fd98 100644 --- a/java/documentation/library-coverage/coverage.rst +++ b/java/documentation/library-coverage/coverage.rst @@ -13,11 +13,11 @@ Java framework & library support `Apache Commons Lang `_,``org.apache.commons.lang3``,,424,,,,,,,, `Apache Commons Text `_,``org.apache.commons.text``,,272,,,,,,,, `Apache HttpComponents `_,"``org.apache.hc.core5.*``, ``org.apache.http``",5,136,28,,,3,,,,25 - `Google Guava `_,``com.google.common.*``,,728,35,,6,,,,, + `Google Guava `_,``com.google.common.*``,,728,39,,6,,,,, `JSON-java `_,``org.json``,,236,,,,,,,, - Java Standard Library,``java.*``,3,549,115,28,,,7,,,10 + Java Standard Library,``java.*``,3,549,130,28,,,7,,,10 Java extensions,"``javax.*``, ``jakarta.*``",63,609,32,,,4,,1,1,2 `Spring `_,``org.springframework.*``,29,476,101,,,,19,14,,29 - Others,"``androidx.slice``, ``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``groovy.lang``, ``groovy.util``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.logging.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.hibernate``, ``org.jboss.logging``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.mvel2``, ``org.scijava.log``, ``org.slf4j``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",65,394,932,,,,14,18,,3 - Totals,,213,6413,1444,106,6,10,107,33,1,84 + Others,"``androidx.slice``, ``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``groovy.lang``, ``groovy.util``, ``jodd.json``, ``kotlin.jvm.internal``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.logging.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.hibernate``, ``org.jboss.logging``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.mvel2``, ``org.scijava.log``, ``org.slf4j``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",65,395,932,,,,14,18,,3 + Totals,,213,6414,1463,106,6,10,107,33,1,84 diff --git a/java/kotlin-extractor/build.py b/java/kotlin-extractor/build.py index f7077401251..a2e03ffdf6d 100755 --- a/java/kotlin-extractor/build.py +++ b/java/kotlin-extractor/build.py @@ -56,7 +56,10 @@ def run_process(cmd, capture_output=False): cmd = ' '.join(map(quote_for_batch, cmd)) print("Converted to Windows command: " + cmd) try: - return subprocess.run(cmd, check=True, capture_output=capture_output) + if capture_output: + return subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + else: + return subprocess.run(cmd, check=True) except subprocess.CalledProcessError as e: print("In: " + os.getcwd(), file=sys.stderr) shell_cmd = cmd if is_windows() else shlex.join(cmd) diff --git a/java/kotlin-extractor/kotlin_plugin_versions.py b/java/kotlin-extractor/kotlin_plugin_versions.py index 7568a1aff66..6ce27c1b884 100755 --- a/java/kotlin-extractor/kotlin_plugin_versions.py +++ b/java/kotlin-extractor/kotlin_plugin_versions.py @@ -24,7 +24,7 @@ many_versions_tuples = [version_string_to_tuple(v) for v in many_versions] def get_single_version(fakeVersionOutput = None): # TODO: `shell=True` is a workaround to get CI working on Windows. It breaks the build on Linux. - versionOutput = subprocess.run(['kotlinc', '-version'], capture_output=True, text=True, shell=is_windows()).stderr if fakeVersionOutput is None else fakeVersionOutput + versionOutput = subprocess.run(['kotlinc', '-version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=is_windows()).stderr if fakeVersionOutput is None else fakeVersionOutput m = re.match(r'.* kotlinc-jvm ([0-9]+\.[0-9]+\.[0-9]+) .*', versionOutput) if m is None: raise Exception('Cannot detect version of kotlinc (got ' + str(versionOutput) + ')') diff --git a/java/kotlin-extractor/src/main/kotlin/ExternalDeclExtractor.kt b/java/kotlin-extractor/src/main/kotlin/ExternalDeclExtractor.kt index d036fe2e27a..61097aea593 100644 --- a/java/kotlin-extractor/src/main/kotlin/ExternalDeclExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/ExternalDeclExtractor.kt @@ -93,9 +93,9 @@ class ExternalDeclExtractor(val logger: FileLogger, val invocationTrapFile: Stri ftw.writeHasLocation(ftw.fileId, ftw.getWholeFileLocation()) ftw.writeCupackage(ftw.fileId, pkgId) - fileExtractor.extractClassSource(irDecl, !irDecl.isFileClass, false) + fileExtractor.extractClassSource(irDecl, extractDeclarations = !irDecl.isFileClass, extractStaticInitializer = false, extractPrivateMembers = false, extractFunctionBodies = false) } else { - fileExtractor.extractDeclaration(irDecl) + fileExtractor.extractDeclaration(irDecl, extractPrivateMembers = false, extractFunctionBodies = false) } } diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt index c5f29a3eff7..1e8965f73e8 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt @@ -74,7 +74,7 @@ open class KotlinFileExtractor( } } - file.declarations.map { extractDeclaration(it) } + file.declarations.map { extractDeclaration(it, extractPrivateMembers = true, extractFunctionBodies = true) } extractStaticInitializer(file, null) CommentExtractor(this, file, tw.fileId).extract() } @@ -91,20 +91,29 @@ open class KotlinFileExtractor( return false } - fun extractDeclaration(declaration: IrDeclaration) { + private fun shouldExtractDecl(declaration: IrDeclaration, extractPrivateMembers: Boolean) = + extractPrivateMembers || + when(declaration) { + is IrDeclarationWithVisibility -> declaration.visibility.let { it != DescriptorVisibilities.PRIVATE && it != DescriptorVisibilities.PRIVATE_TO_THIS } + else -> true + } + + fun extractDeclaration(declaration: IrDeclaration, extractPrivateMembers: Boolean, extractFunctionBodies: Boolean) { with("declaration", declaration) { + if (!shouldExtractDecl(declaration, extractPrivateMembers)) + return when (declaration) { is IrClass -> { if (isExternalDeclaration(declaration)) { extractExternalClassLater(declaration) } else { - extractClassSource(declaration, extractDeclarations = true, extractStaticInitializer = true) + extractClassSource(declaration, extractDeclarations = true, extractStaticInitializer = true, extractPrivateMembers = extractPrivateMembers, extractFunctionBodies = extractFunctionBodies) } } is IrFunction -> { val parentId = useDeclarationParent(declaration.parent, false)?.cast() if (parentId != null) { - extractFunction(declaration, parentId, true, null, listOf()) + extractFunction(declaration, parentId, extractBody = extractFunctionBodies, extractMethodAndParameterTypeAccesses = extractFunctionBodies, null, listOf()) } Unit } @@ -114,14 +123,14 @@ open class KotlinFileExtractor( is IrProperty -> { val parentId = useDeclarationParent(declaration.parent, false)?.cast() if (parentId != null) { - extractProperty(declaration, parentId, true, null, listOf()) + extractProperty(declaration, parentId, extractBackingField = true, extractFunctionBodies = extractFunctionBodies, null, listOf()) } Unit } is IrEnumEntry -> { val parentId = useDeclarationParent(declaration.parent, false)?.cast() if (parentId != null) { - extractEnumEntry(declaration, parentId) + extractEnumEntry(declaration, parentId, extractFunctionBodies) } Unit } @@ -320,7 +329,7 @@ open class KotlinFileExtractor( // `argsIncludingOuterClasses` can be null to describe a raw generic type. // For non-generic types it will be zero-length list. - fun extractMemberPrototypes(c: IrClass, argsIncludingOuterClasses: List?, id: Label) { + fun extractNonPrivateMemberPrototypes(c: IrClass, argsIncludingOuterClasses: List?, id: Label) { with("member prototypes", c) { val typeParamSubstitution = when (argsIncludingOuterClasses) { @@ -339,17 +348,19 @@ open class KotlinFileExtractor( } c.declarations.map { - when(it) { - is IrFunction -> extractFunction(it, id, false, typeParamSubstitution, argsIncludingOuterClasses) - is IrProperty -> extractProperty(it, id, false, typeParamSubstitution, argsIncludingOuterClasses) - else -> {} + if (shouldExtractDecl(it, false)) { + when(it) { + is IrFunction -> extractFunction(it, id, extractBody = false, extractMethodAndParameterTypeAccesses = false, typeParamSubstitution, argsIncludingOuterClasses) + is IrProperty -> extractProperty(it, id, extractBackingField = false, extractFunctionBodies = false, typeParamSubstitution, argsIncludingOuterClasses) + else -> {} + } } } } } private fun extractLocalTypeDeclStmt(c: IrClass, callable: Label, parent: Label, idx: Int) { - val id = extractClassSource(c, extractDeclarations = true, extractStaticInitializer = true).cast() + val id = extractClassSource(c, extractDeclarations = true, extractStaticInitializer = true, extractPrivateMembers = true, extractFunctionBodies = true).cast() extractLocalTypeDeclStmt(id, c, callable, parent, idx) } @@ -361,7 +372,7 @@ open class KotlinFileExtractor( tw.writeHasLocation(stmtId, locId) } - fun extractClassSource(c: IrClass, extractDeclarations: Boolean, extractStaticInitializer: Boolean): Label { + fun extractClassSource(c: IrClass, extractDeclarations: Boolean, extractStaticInitializer: Boolean, extractPrivateMembers: Boolean, extractFunctionBodies: Boolean): Label { with("class source", c) { DeclarationStackAdjuster(c).use { @@ -395,7 +406,7 @@ open class KotlinFileExtractor( c.typeParameters.mapIndexed { idx, param -> extractTypeParameter(param, idx) } if (extractDeclarations) { - c.declarations.map { extractDeclaration(it) } + c.declarations.map { extractDeclaration(it, extractPrivateMembers = extractPrivateMembers, extractFunctionBodies = extractFunctionBodies) } if (extractStaticInitializer) extractStaticInitializer(c, id) } @@ -442,7 +453,7 @@ open class KotlinFileExtractor( val instance = useCompanionObjectClassInstance(innerDeclaration) if (instance != null) { val type = useSimpleTypeClass(innerDeclaration, emptyList(), false) - tw.writeFields(instance.id, instance.name, type.javaResult.id, innerId, instance.id) + tw.writeFields(instance.id, instance.name, type.javaResult.id, parentId, instance.id) tw.writeFieldsKotlinType(instance.id, type.kotlinResult.id) tw.writeHasLocation(instance.id, innerLocId) addModifiers(instance.id, "public", "static", "final") @@ -500,11 +511,11 @@ open class KotlinFileExtractor( return FieldResult(instanceId, instanceName) } - private fun extractValueParameter(vp: IrValueParameter, parent: Label, idx: Int, typeSubstitution: TypeSubstitution?, parentSourceDeclaration: Label, classTypeArgsIncludingOuterClasses: List?): TypeResults { + private fun extractValueParameter(vp: IrValueParameter, parent: Label, idx: Int, typeSubstitution: TypeSubstitution?, parentSourceDeclaration: Label, classTypeArgsIncludingOuterClasses: List?, extractTypeAccess: Boolean): TypeResults { with("value parameter", vp) { val location = getLocation(vp, classTypeArgsIncludingOuterClasses) val id = useValueParameter(vp, parent) - if (!isExternalDeclaration(vp)) { + if (extractTypeAccess) { extractTypeAccessRecursive(vp.type, location, id, -1) } return extractValueParameter(id, vp.type, vp.name.asString(), location, parent, idx, typeSubstitution, useValueParameter(vp, parentSourceDeclaration), vp.isVararg) @@ -539,7 +550,7 @@ open class KotlinFileExtractor( classTypeArgsIncludingOuterClasses = listOf() ) val clinitId = tw.getLabelFor(clinitLabel) - val returnType = useType(pluginContext.irBuiltIns.unitType) + val returnType = useType(pluginContext.irBuiltIns.unitType, TypeContext.RETURN) tw.writeMethods(clinitId, "", "()", returnType.javaResult.id, parentId, clinitId) tw.writeMethodsKotlinType(clinitId, returnType.kotlinResult.id) @@ -665,7 +676,7 @@ open class KotlinFileExtractor( } } - fun extractFunction(f: IrFunction, parentId: Label, extractBody: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List?, idOverride: Label? = null): Label? { + fun extractFunction(f: IrFunction, parentId: Label, extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List?, idOverride: Label? = null): Label? { if (isFake(f)) return null with("function", f) { @@ -678,7 +689,9 @@ open class KotlinFileExtractor( ?: if (f.isLocalFunction()) getLocallyVisibleFunctionLabels(f).function else - useFunction(f, parentId, classTypeArgsIncludingOuterClasses) + // If this is a class that would ordinarily be replaced by a Java equivalent (e.g. kotlin.Map -> java.util.Map), + // don't replace here, really extract the Kotlin version: + useFunction(f, parentId, classTypeArgsIncludingOuterClasses, noReplace = true) val sourceDeclaration = if (typeSubstitution != null) @@ -689,13 +702,13 @@ open class KotlinFileExtractor( val extReceiver = f.extensionReceiverParameter val idxOffset = if (extReceiver != null) 1 else 0 val paramTypes = f.valueParameters.mapIndexed { i, vp -> - extractValueParameter(vp, id, i + idxOffset, typeSubstitution, sourceDeclaration, classTypeArgsIncludingOuterClasses) + extractValueParameter(vp, id, i + idxOffset, typeSubstitution, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses) } val allParamTypes = if (extReceiver != null) { val extendedType = useType(extReceiver.type) tw.writeKtExtensionFunctions(id.cast(), extendedType.javaResult.id, extendedType.kotlinResult.id) - val t = extractValueParameter(extReceiver, id, 0, null, sourceDeclaration, classTypeArgsIncludingOuterClasses) + val t = extractValueParameter(extReceiver, id, 0, null, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses) listOf(t) + paramTypes } else { paramTypes @@ -724,7 +737,7 @@ open class KotlinFileExtractor( tw.writeMethods(methodId, shortName.nameInDB, "${shortName.nameInDB}$paramsSignature", returnType.javaResult.id, parentId, sourceDeclaration.cast()) tw.writeMethodsKotlinType(methodId, returnType.kotlinResult.id) - if (!isExternalDeclaration(f)) { + if (extractMethodAndParameterTypeAccesses) { extractTypeAccessRecursive(f.returnType, locId, id, -1) } @@ -765,19 +778,22 @@ open class KotlinFileExtractor( with("field", f) { DeclarationStackAdjuster(f).use { declarationStack.push(f) - return extractField(useField(f), f.name.asString(), f.type, parentId, tw.getLocation(f), f.visibility, f, isExternalDeclaration(f)) + return extractField(useField(f), f.name.asString(), f.type, parentId, tw.getLocation(f), f.visibility, f, isExternalDeclaration(f), f.isFinal) } } } - private fun extractField(id: Label, name: String, type: IrType, parentId: Label, locId: Label, visibility: DescriptorVisibility, errorElement: IrElement, isExternalDeclaration: Boolean): Label { + private fun extractField(id: Label, name: String, type: IrType, parentId: Label, locId: Label, visibility: DescriptorVisibility, errorElement: IrElement, isExternalDeclaration: Boolean, isFinal: Boolean): Label { val t = useType(type) tw.writeFields(id, name, t.javaResult.id, parentId, id) tw.writeFieldsKotlinType(id, t.kotlinResult.id) tw.writeHasLocation(id, locId) extractVisibility(errorElement, id, visibility) + if (isFinal) { + addModifiers(id, "final") + } if (!isExternalDeclaration) { val fieldDeclarationId = tw.getFreshIdLabel() @@ -791,14 +807,14 @@ open class KotlinFileExtractor( return id } - fun extractProperty(p: IrProperty, parentId: Label, extractBackingField: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgs: List?) { + fun extractProperty(p: IrProperty, parentId: Label, extractBackingField: Boolean, extractFunctionBodies: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List?) { with("property", p) { if (isFake(p)) return DeclarationStackAdjuster(p).use { - val id = useProperty(p, parentId) - val locId = getLocation(p, classTypeArgs) + val id = useProperty(p, parentId, classTypeArgsIncludingOuterClasses) + val locId = getLocation(p, classTypeArgsIncludingOuterClasses) tw.writeKtProperties(id, p.name.asString()) tw.writeHasLocation(id, locId) @@ -807,7 +823,7 @@ open class KotlinFileExtractor( val setter = p.setter if (getter != null) { - val getterId = extractFunction(getter, parentId, extractBackingField, typeSubstitution, classTypeArgs)?.cast() + val getterId = extractFunction(getter, parentId, extractBody = extractFunctionBodies, extractMethodAndParameterTypeAccesses = extractFunctionBodies, typeSubstitution, classTypeArgsIncludingOuterClasses)?.cast() if (getterId != null) { tw.writeKtPropertyGetters(id, getterId) } @@ -821,7 +837,7 @@ open class KotlinFileExtractor( if (!p.isVar) { logger.errorElement("!isVar property with a setter", p) } - val setterId = extractFunction(setter, parentId, extractBackingField, typeSubstitution, classTypeArgs)?.cast() + val setterId = extractFunction(setter, parentId, extractBody = extractFunctionBodies, extractMethodAndParameterTypeAccesses = extractFunctionBodies, typeSubstitution, classTypeArgsIncludingOuterClasses)?.cast() if (setterId != null) { tw.writeKtPropertySetters(id, setterId) } @@ -857,7 +873,7 @@ open class KotlinFileExtractor( } } - fun extractEnumEntry(ee: IrEnumEntry, parentId: Label) { + fun extractEnumEntry(ee: IrEnumEntry, parentId: Label, extractTypeAccess: Boolean) { with("enum entry", ee) { DeclarationStackAdjuster(ee).use { val id = useEnumEntry(ee) @@ -867,7 +883,7 @@ open class KotlinFileExtractor( val locId = tw.getLocation(ee) tw.writeHasLocation(id, locId) - if (!isExternalDeclaration(ee)) { + if (extractTypeAccess) { val fieldDeclarationId = tw.getFreshIdLabel() tw.writeFielddecls(fieldDeclarationId, parentId) tw.writeFieldDeclaredIn(id, fieldDeclarationId, 0) @@ -1341,6 +1357,23 @@ open class KotlinFileExtractor( return result } + private fun findTopLevelFunctionOrWarn(functionFilter: String, type: String, warnAgainstElement: IrElement): IrFunction? { + + val fn = pluginContext.referenceFunctions(FqName(functionFilter)) + .firstOrNull { it.owner.parentClassOrNull?.fqNameWhenAvailable?.asString() == type } + ?.owner + + if (fn != null) { + if (fn.parentClassOrNull != null) { + extractExternalClassLater(fn.parentAsClass) + } + } else { + logger.errorElement("Couldn't find JVM intrinsic function $functionFilter in $type", warnAgainstElement) + } + + return fn + } + val javaLangString by lazy { val result = pluginContext.referenceClass(FqName("java.lang.String"))?.owner result?.let { extractExternalClassLater(it) } @@ -1854,6 +1887,11 @@ open class KotlinFileExtractor( } } } + isFunction(target, "kotlin", "(some array type)", { isArrayType(it) }, "iterator") && c.origin == IrStatementOrigin.FOR_LOOP_ITERATOR -> { + findTopLevelFunctionOrWarn("kotlin.jvm.internal.iterator", "kotlin.jvm.internal.ArrayIteratorKt", c)?.let { iteratorFn -> + extractRawMethodAccess(iteratorFn, c, callable, parent, idx, enclosingStmt, listOf(c.dispatchReceiver), null, null, listOf((c.dispatchReceiver!!.type as IrSimpleType).arguments.first().typeOrNull!!)) + } + } isFunction(target, "kotlin", "(some array type)", { isArrayType(it) }, "get") && c.origin == IrStatementOrigin.GET_ARRAY_ELEMENT -> { val id = tw.getFreshIdLabel() val type = useType(c.type) @@ -2914,12 +2952,12 @@ open class KotlinFileExtractor( // only one of the following can be non-null: if (dispatchReceiver != null) { - extractField(dispatchFieldId!!, "", receiverType!!, classId, locId, DescriptorVisibilities.PRIVATE, callableReferenceExpr, false) + extractField(dispatchFieldId!!, "", receiverType!!, classId, locId, DescriptorVisibilities.PRIVATE, callableReferenceExpr, isExternalDeclaration = false, isFinal = true) extractParameterToFieldAssignmentInConstructor("", dispatchReceiver.type, dispatchFieldId, 0, firstAssignmentStmtIdx) } if (extensionReceiver != null) { - extractField(extensionFieldId!!, "", receiverType!!, classId, locId, DescriptorVisibilities.PRIVATE, callableReferenceExpr, false) + extractField(extensionFieldId!!, "", receiverType!!, classId, locId, DescriptorVisibilities.PRIVATE, callableReferenceExpr, isExternalDeclaration = false, isFinal = true) extractParameterToFieldAssignmentInConstructor( "", extensionReceiver.type, extensionFieldId, 0 + extensionParameterIndex, firstAssignmentStmtIdx + extensionParameterIndex) } } @@ -3970,13 +4008,13 @@ open class KotlinFileExtractor( // add field val fieldId = tw.getFreshIdLabel() - extractField(fieldId, "", functionType, classId, locId, DescriptorVisibilities.PRIVATE, e, false) + extractField(fieldId, "", functionType, classId, locId, DescriptorVisibilities.PRIVATE, e, isExternalDeclaration = false, isFinal = true) // adjust constructor helper.extractParameterToFieldAssignmentInConstructor("", functionType, fieldId, 0, 1) // add implementation function - extractFunction(samMember, classId, false, null, null, ids.function) + extractFunction(samMember, classId, extractBody = false, extractMethodAndParameterTypeAccesses = true, null, null, ids.function) //body val blockId = tw.getFreshIdLabel() @@ -4152,7 +4190,7 @@ open class KotlinFileExtractor( val id = extractGeneratedClass(ids, superTypes, tw.getLocation(localFunction), localFunction) // Extract local function as a member - extractFunction(localFunction, id, true, null, listOf()) + extractFunction(localFunction, id, extractBody = true, extractMethodAndParameterTypeAccesses = true, null, listOf()) return id } diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt index 2c58842e9e4..adaf5061e6c 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt @@ -4,21 +4,19 @@ import com.github.codeql.utils.* import com.github.codeql.utils.versions.isRawType import com.semmle.extractor.java.OdasaOutput import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext +import org.jetbrains.kotlin.backend.common.ir.allOverridden import org.jetbrains.kotlin.backend.common.lower.parentsWithSelf -import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap -import org.jetbrains.kotlin.descriptors.ClassKind -import org.jetbrains.kotlin.descriptors.DescriptorVisibilities +import org.jetbrains.kotlin.builtins.StandardNames +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.expressions.IrConst -import org.jetbrains.kotlin.ir.expressions.IrConstructorCall -import org.jetbrains.kotlin.ir.symbols.IrClassSymbol -import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.types.* -import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl -import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection +import org.jetbrains.kotlin.ir.types.impl.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.util.OperatorNameConventions @@ -49,6 +47,41 @@ open class KotlinUsesExtractor( TypeResult(fakeKotlinType(), "", "") ) + private data class MethodKey(val className: FqName, val functionName: Name) + + private fun makeDescription(className: FqName, functionName: String) = MethodKey(className, Name.guessByFirstCharacter(functionName)) + + // This essentially mirrors SpecialBridgeMethods.kt, a backend pass which isn't easily available to our extractor. + private val specialFunctions = mapOf( + makeDescription(StandardNames.FqNames.collection, "") to "size", + makeDescription(FqName("java.util.Collection"), "") to "size", + makeDescription(StandardNames.FqNames.map, "") to "size", + makeDescription(FqName("java.util.Map"), "") to "size", + makeDescription(StandardNames.FqNames.charSequence.toSafe(), "") to "length", + makeDescription(FqName("java.lang.CharSequence"), "") to "length", + makeDescription(StandardNames.FqNames.map, "") to "keySet", + makeDescription(FqName("java.util.Map"), "") to "keySet", + makeDescription(StandardNames.FqNames.map, "") to "values", + makeDescription(FqName("java.util.Map"), "") to "values", + makeDescription(StandardNames.FqNames.map, "") to "entrySet", + makeDescription(FqName("java.util.Map"), "") to "entrySet" + ) + + private val specialFunctionShortNames = specialFunctions.keys.map { it.functionName }.toSet() + + fun getSpecialJvmName(f: IrFunction): String? { + if (specialFunctionShortNames.contains(f.name) && f is IrSimpleFunction) { + f.allOverridden(true).forEach { overriddenFunc -> + overriddenFunc.parentAsClass.fqNameWhenAvailable?.let { parentFqName -> + specialFunctions[MethodKey(parentFqName, f.name)]?.let { + return it + } + } + } + } + return null + } + fun getJvmName(container: IrAnnotationContainer): String? { for(a: IrConstructorCall in container.annotations) { val t = a.type @@ -67,7 +100,7 @@ open class KotlinUsesExtractor( } } } - return null + return (container as? IrFunction)?.let { getSpecialJvmName(container) } } @OptIn(kotlin.ExperimentalStdlibApi::class) // Annotation required by kotlin versions < 1.5 @@ -122,10 +155,7 @@ open class KotlinUsesExtractor( } fun getJavaEquivalentClass(c: IrClass) = - c.fqNameWhenAvailable?.toUnsafe() - ?.let { JavaToKotlinClassMap.mapKotlinToJava(it) } - ?.let { pluginContext.referenceClass(it.asSingleFqName()) } - ?.owner + getJavaEquivalentClassId(c)?.let { pluginContext.referenceClass(it.asSingleFqName()) }?.owner /** * Gets a KotlinFileExtractor based on this one, except it attributes locations to the file that declares the given class. @@ -380,7 +410,7 @@ open class KotlinUsesExtractor( if (inReceiverContext && globalExtensionState.genericSpecialisationsExtracted.add(classLabelResult.classLabel)) { val supertypeMode = if (argsIncludingOuterClasses == null) ExtractSupertypesMode.Raw else ExtractSupertypesMode.Specialised(argsIncludingOuterClasses) extractorWithCSource.extractClassSupertypes(c, classLabel, supertypeMode, true) - extractorWithCSource.extractMemberPrototypes(c, argsIncludingOuterClasses, classLabel) + extractorWithCSource.extractNonPrivateMemberPrototypes(c, argsIncludingOuterClasses, classLabel) } } @@ -696,8 +726,26 @@ open class KotlinUsesExtractor( } when (f) { - getter -> return FunctionNames(getJvmName(getter) ?: JvmAbi.getterName(propName), JvmAbi.getterName(propName)) - setter -> return FunctionNames(getJvmName(setter) ?: JvmAbi.setterName(propName), JvmAbi.setterName(propName)) + getter -> { + val defaultFunctionName = JvmAbi.getterName(propName) + val defaultDbName = if (getter.visibility == DescriptorVisibilities.PRIVATE && getter.origin == IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR) { + // In JVM these functions don't exist, instead the backing field is accessed directly + defaultFunctionName + "\$private" + } else { + defaultFunctionName + } + return FunctionNames(getJvmName(getter) ?: defaultDbName, defaultFunctionName) + } + setter -> { + val defaultFunctionName = JvmAbi.setterName(propName) + val defaultDbName = if (setter.visibility == DescriptorVisibilities.PRIVATE && setter.origin == IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR) { + // In JVM these functions don't exist, instead the backing field is accessed directly + defaultFunctionName + "\$private" + } else { + defaultFunctionName + } + return FunctionNames(getJvmName(setter) ?: defaultDbName, defaultFunctionName) + } else -> { logger.error( "Function has a corresponding property, but is neither the getter nor the setter" @@ -774,7 +822,9 @@ open class KotlinUsesExtractor( // The type parameters of the function. This does not include type parameters of enclosing classes. functionTypeParameters: List, // The type arguments of enclosing classes of the function. - classTypeArgsIncludingOuterClasses: List? + classTypeArgsIncludingOuterClasses: List?, + // The prefix used in the label. "callable", unless a property label is created, then it's "property". + prefix: String = "callable" ): String { val parentId = maybeParentId ?: useDeclarationParent(parent, false, classTypeArgsIncludingOuterClasses, true) val allParams = if (extensionReceiverParameter == null) { @@ -810,7 +860,7 @@ open class KotlinUsesExtractor( // method (and presumably that disambiguation is never needed when the method belongs to a parameterized // instance of a generic class), but as of now I don't know when the raw method would be referred to. val typeArgSuffix = if (functionTypeParameters.isNotEmpty() && classTypeArgsIncludingOuterClasses.isNullOrEmpty()) "<${functionTypeParameters.size}>" else ""; - return "@\"callable;{$parentId}.$name($paramTypeIds){$returnTypeId}${typeArgSuffix}\"" + return "@\"$prefix;{$parentId}.$name($paramTypeIds){$returnTypeId}${typeArgSuffix}\"" } protected fun IrFunction.isLocalFunction(): Boolean { @@ -867,17 +917,62 @@ open class KotlinUsesExtractor( return id } - fun useFunction(f: IrFunction, classTypeArgsIncludingOuterClasses: List? = null): Label { + // These are classes with Java equivalents, but whose methods don't all exist on those Java equivalents-- + // for example, the numeric classes define arithmetic functions (Int.plus, Long.or and so on) that lower to + // primitive arithmetic on the JVM, but which we extract as calls to reflect the source syntax more closely. + private val expectedMissingEquivalents = setOf( + "kotlin.Boolean", "kotlin.Byte", "kotlin.Char", "kotlin.Double", "kotlin.Float", "kotlin.Int", "kotlin.Long", "kotlin.Number", "kotlin.Short" + ) + + fun kotlinFunctionToJavaEquivalent(f: IrFunction, noReplace: Boolean) = + if (noReplace) + f + else + f.parentClassOrNull?.let { parentClass -> + getJavaEquivalentClass(parentClass)?.let { javaClass -> + if (javaClass != parentClass) + // Look for an exact type match... + javaClass.declarations.find { decl -> + decl is IrFunction && + decl.name == f.name && + decl.valueParameters.size == f.valueParameters.size && + // Note matching by classifier not the whole type so that generic arguments are allowed to differ, + // as they always will for method type parameters occurring in parameter types (e.g. toArray(T[] array) + // Differing only by nullability would also be insignificant if it came up. + decl.valueParameters.zip(f.valueParameters).all { p -> p.first.type.classifierOrNull == p.second.type.classifierOrNull } + } ?: + // Or if there is none, look for the only viable overload + javaClass.declarations.singleOrNull { decl -> + decl is IrFunction && + decl.name == f.name && + decl.valueParameters.size == f.valueParameters.size + } ?: + run { + val parentFqName = parentClass.fqNameWhenAvailable?.asString() + if (!expectedMissingEquivalents.contains(parentFqName)) { + logger.warn("Couldn't find a Java equivalent function to $parentFqName.${f.name} in ${javaClass.fqNameWhenAvailable}") + } + null + } + else + null + } + } as IrFunction? ?: f + + fun useFunction(f: IrFunction, classTypeArgsIncludingOuterClasses: List? = null, noReplace: Boolean = false): Label { if (f.isLocalFunction()) { val ids = getLocallyVisibleFunctionLabels(f) return ids.function.cast() } else { - return useFunctionCommon(f, getFunctionLabel(f, classTypeArgsIncludingOuterClasses)) + val realFunction = kotlinFunctionToJavaEquivalent(f, noReplace) + return useFunctionCommon(realFunction, getFunctionLabel(realFunction, classTypeArgsIncludingOuterClasses)) } } - fun useFunction(f: IrFunction, parentId: Label, classTypeArgsIncludingOuterClasses: List?) = - useFunctionCommon(f, getFunctionLabel(f, parentId, classTypeArgsIncludingOuterClasses)) + fun useFunction(f: IrFunction, parentId: Label, classTypeArgsIncludingOuterClasses: List?, noReplace: Boolean = false) = + kotlinFunctionToJavaEquivalent(f, noReplace).let { + useFunctionCommon(it, getFunctionLabel(it, parentId, classTypeArgsIncludingOuterClasses)) + } fun getTypeArgumentLabel( arg: IrTypeArgument @@ -941,6 +1036,9 @@ open class KotlinUsesExtractor( is IrFunction -> { "{${useFunction(parent)}}.$cls" } + is IrField -> { + "{${useField(parent)}}.$cls" + } else -> { if (pkg.isEmpty()) cls else "$pkg.$cls" } @@ -1111,15 +1209,20 @@ open class KotlinUsesExtractor( * `parent` is null. */ fun getValueParameterLabel(vp: IrValueParameter, parent: Label?): String { - val parentId = parent ?: useDeclarationParent(vp.parent, false) - val idx = vp.index + val declarationParent = vp.parent + val parentId = parent ?: useDeclarationParent(declarationParent, false) + + val idx = if (declarationParent is IrFunction && declarationParent.extensionReceiverParameter != null) + // For extension functions increase the index to match what the java extractor sees: + vp.index + 1 + else + vp.index + if (idx < 0) { - val p = vp.parent - if (p !is IrFunction || p.extensionReceiverParameter != vp) { - // We're not extracting this and this@TYPE parameters of functions: - logger.error("Unexpected negative index for parameter") - } + // We're not extracting this and this@TYPE parameters of functions: + logger.error("Unexpected negative index for parameter") } + return "@\"params;{$parentId};$idx\"" } @@ -1140,24 +1243,29 @@ open class KotlinUsesExtractor( if (parentId == null) { return null } else { - return getPropertyLabel(p, parentId) + return getPropertyLabel(p, parentId, null) } } - fun getPropertyLabel(p: IrProperty, parentId: Label) = - "@\"property;{$parentId};${p.name.asString()}\"" + private fun getPropertyLabel(p: IrProperty, parentId: Label, classTypeArgsIncludingOuterClasses: List?): String { + val getter = p.getter + val setter = p.setter - fun useProperty(p: IrProperty): Label? { - val label = getPropertyLabel(p) - if (label == null) { - return null + val func = getter ?: setter + val ext = func?.extensionReceiverParameter + + return if (ext == null) { + "@\"property;{$parentId};${p.name.asString()}\"" } else { - return tw.getLabelFor(label).also { extractPropertyLaterIfExternalFileMember(p) } + val returnType = getter?.returnType ?: setter?.valueParameters?.singleOrNull()?.type ?: pluginContext.irBuiltIns.unitType + val typeParams = getFunctionTypeParameters(func) + + getFunctionLabel(p.parent, parentId, p.name.asString(), listOf(), returnType, ext, typeParams, classTypeArgsIncludingOuterClasses, "property") } } - fun useProperty(p: IrProperty, parentId: Label): Label = - tw.getLabelFor(getPropertyLabel(p, parentId)).also { extractPropertyLaterIfExternalFileMember(p) } + fun useProperty(p: IrProperty, parentId: Label, classTypeArgsIncludingOuterClasses: List?): Label = + tw.getLabelFor(getPropertyLabel(p, parentId, classTypeArgsIncludingOuterClasses)).also { extractPropertyLaterIfExternalFileMember(p) } fun getEnumEntryLabel(ee: IrEnumEntry): String { val parentId = useDeclarationParent(ee.parent, false) diff --git a/java/kotlin-extractor/src/main/kotlin/TrapWriter.kt b/java/kotlin-extractor/src/main/kotlin/TrapWriter.kt index d276f7cdc26..c2ec350640a 100644 --- a/java/kotlin-extractor/src/main/kotlin/TrapWriter.kt +++ b/java/kotlin-extractor/src/main/kotlin/TrapWriter.kt @@ -110,6 +110,10 @@ open class TrapWriter (protected val loggerBase: LoggerBase, val lm: TrapLabelMa } } + fun getExistingVariableLabelFor(v: IrVariable): Label? { + return variableLabelMapping.get(v) + } + /** * This returns a label for the location described by its arguments. * Typically users will not want to call this directly, but instead diff --git a/java/kotlin-extractor/src/main/kotlin/comments/CommentExtractor.kt b/java/kotlin-extractor/src/main/kotlin/comments/CommentExtractor.kt index 56c7442ccc7..93d3c0534de 100644 --- a/java/kotlin-extractor/src/main/kotlin/comments/CommentExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/comments/CommentExtractor.kt @@ -6,9 +6,7 @@ import com.github.codeql.utils.versions.Psi2Ir import com.intellij.psi.PsiComment import com.intellij.psi.PsiElement import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.declarations.path -import org.jetbrains.kotlin.ir.declarations.IrFile -import org.jetbrains.kotlin.ir.declarations.IrValueParameter +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.kdoc.psi.api.KDoc import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.KtVisitor @@ -98,8 +96,14 @@ class CommentExtractor(private val fileExtractor: KotlinFileExtractor, private v // Don't attribute comments to the implicit `this` parameter of a function. continue } - val label = fileExtractor.getLabel(ownerIr) ?: continue - val existingLabel = tw.getExistingLabelFor(label) + val label: String + val existingLabel = if (ownerIr is IrVariable) { + label = "variable ${ownerIr.name.asString()}" + tw.getExistingVariableLabelFor(ownerIr) + } else { + label = fileExtractor.getLabel(ownerIr) ?: continue + tw.getExistingLabelFor(label) + } if (existingLabel == null) { logger.warn("Couldn't get existing label for $label") continue diff --git a/java/kotlin-extractor/src/main/kotlin/utils/ClassNames.kt b/java/kotlin-extractor/src/main/kotlin/utils/ClassNames.kt index cdcdd535a2c..5a9713087eb 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/ClassNames.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/ClassNames.kt @@ -7,7 +7,9 @@ import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.parentClassOrNull import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource @@ -84,4 +86,7 @@ fun getContainingClassOrSelf(decl: IrDeclaration): IrClass? { is IrClass -> decl else -> decl.parentClassOrNull } -} \ No newline at end of file +} + +fun getJavaEquivalentClassId(c: IrClass) = + c.fqNameWhenAvailable?.toUnsafe()?.let { JavaToKotlinClassMap.mapKotlinToJava(it) } \ No newline at end of file diff --git a/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt b/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt index 5e0d392ca64..a4a15b45331 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt @@ -1,8 +1,10 @@ package com.github.codeql.utils import com.github.codeql.KotlinUsesExtractor +import com.github.codeql.getJavaEquivalentClassId import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor +import org.jetbrains.kotlin.backend.common.lower.parents import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.ir.builders.declarations.addConstructor import org.jetbrains.kotlin.ir.builders.declarations.buildClass @@ -19,12 +21,14 @@ import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection +import org.jetbrains.kotlin.ir.util.classId import org.jetbrains.kotlin.ir.util.constructedClassType import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull fun IrType.substituteTypeArguments(params: List, arguments: List) = when(this) { @@ -195,22 +199,35 @@ fun IrTypeArgument.withQuestionMark(b: Boolean): IrTypeArgument = typealias TypeSubstitution = (IrType, KotlinUsesExtractor.TypeContext, IrPluginContext) -> IrType +fun matchingTypeParameters(l: IrTypeParameter?, r: IrTypeParameter): Boolean { + if (l === r) + return true + if (l == null) + return false + // Special case: match List's E and MutableList's E, for example, because in the JVM lowering they will map to the same thing. + val lParent = l.parent as? IrClass ?: return false + val rParent = r.parent as? IrClass ?: return false + val lJavaId = getJavaEquivalentClassId(lParent) ?: lParent.classId + return (getJavaEquivalentClassId(rParent) ?: rParent.classId) == lJavaId && l.name == r.name +} + // Returns true if type is C where C is declared `class C { ... }` fun isUnspecialised(paramsContainer: IrTypeParametersContainer, args: List): Boolean { val unspecialisedHere = paramsContainer.typeParameters.zip(args).all { paramAndArg -> (paramAndArg.second as? IrTypeProjection)?.let { // Type arg refers to the class' own type parameter? it.variance == Variance.INVARIANT && - it.type.classifierOrNull?.owner === paramAndArg.first + matchingTypeParameters(it.type.classifierOrNull?.owner as? IrTypeParameter, paramAndArg.first) } ?: false } val remainingArgs = args.drop(paramsContainer.typeParameters.size) - val parent = paramsContainer.parent as? IrTypeParametersContainer + + val parentClass = paramsContainer.parents.firstIsInstanceOrNull() + val parentUnspecialised = when { remainingArgs.isEmpty() -> true - parent == null -> false - parent !is IrClass -> false - else -> isUnspecialised(paramsContainer.parentAsClass, remainingArgs) + parentClass == null -> false + else -> isUnspecialised(parentClass, remainingArgs) } return unspecialisedHere && parentUnspecialised } diff --git a/java/ql/lib/CHANGELOG.md b/java/ql/lib/CHANGELOG.md index ab5c12f5463..ee42afab311 100644 --- a/java/ql/lib/CHANGELOG.md +++ b/java/ql/lib/CHANGELOG.md @@ -1,3 +1,85 @@ +## 0.2.1 + +### New Features + +* A number of new classes and methods related to the upcoming Kotlin + support have been added. These are not yet stable, as Kotlin support + is still under development. + * `File::isSourceFile` + * `File::isJavaSourceFile` + * `File::isKotlinSourceFile` + * `Member::getKotlinType` + * `Element::isCompilerGenerated` + * `Expr::getKotlinType` + * `LambdaExpr::isKotlinFunctionN` + * `Callable::getReturnKotlinType` + * `Callable::getParameterKotlinType` + * `Method::isLocal` + * `Method::getKotlinName` + * `Field::getKotlinType` + * `Modifiable::isSealedKotlin` + * `Modifiable::isInternal` + * `Variable::getKotlinType` + * `LocalVariableDecl::getKotlinType` + * `Parameter::getKotlinType` + * `Parameter::isExtensionParameter` + * `Compilation` class + * `Diagnostic` class + * `KtInitializerAssignExpr` class + * `ValueEQExpr` class + * `ValueNEExpr` class + * `ValueOrReferenceEqualsExpr` class + * `ValueOrReferenceNotEqualsExpr` class + * `ReferenceEqualityTest` class + * `CastingExpr` class + * `SafeCastExpr` class + * `ImplicitCastExpr` class + * `ImplicitNotNullExpr` class + * `ImplicitCoercionToUnitExpr` class + * `UnsafeCoerceExpr` class + * `PropertyRefExpr` class + * `NotInstanceOfExpr` class + * `ExtensionReceiverAccess` class + * `WhenExpr` class + * `WhenBranch` class + * `ClassExpr` class + * `StmtExpr` class + * `StringTemplateExpr` class + * `NotNullExpr` class + * `TypeNullPointerException` class + * `KtComment` class + * `KtCommentSection` class + * `KotlinType` class + * `KotlinNullableType` class + * `KotlinNotnullType` class + * `KotlinTypeAlias` class + * `Property` class + * `DelegatedProperty` class + * `ExtensionMethod` class + * `KtInitializerNode` class + * `KtLoopStmt` class + * `KtBreakContinueStmt` class + * `KtBreakStmt` class + * `KtContinueStmt` class + * `ClassObject` class + * `CompanionObject` class + * `LiveLiteral` class + * `LiveLiteralMethod` class + * `CastConversionContext` renamed to `CastingConversionContext` +* The QL class `ValueDiscardingExpr` has been added, representing expressions for which the value of the expression as a whole is discarded. + +### Minor Analysis Improvements + +* Added models for the libraries OkHttp and Retrofit. +* Add taint models for the following `File` methods: + * `File::getAbsoluteFile` + * `File::getCanonicalFile` + * `File::getAbsolutePath` + * `File::getCanonicalPath` +* Added a flow step for `toString` calls on tainted `android.text.Editable` objects. +* Added a data flow step for tainted Android intents that are sent to other activities and accessed there via `getIntent()`. +* Added modeling of MyBatis (`org.apache.ibatis`) Providers, resulting in additional sinks for the queries `java/ognl-injection`, `java/sql-injection`, `java/sql-injection-local` and `java/concatenated-sql-query`. + ## 0.2.0 ### Breaking Changes diff --git a/java/ql/lib/change-notes/2022-03-15-mybatis-providers.md b/java/ql/lib/change-notes/2022-03-15-mybatis-providers.md deleted file mode 100644 index 32ba9c23c12..00000000000 --- a/java/ql/lib/change-notes/2022-03-15-mybatis-providers.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Added modeling of MyBatis (`org.apache.ibatis`) Providers, resulting in additional sinks for the queries `java/ognl-injection`, `java/sql-injection`, `java/sql-injection-local` and `java/concatenated-sql-query`. \ No newline at end of file diff --git a/java/ql/lib/change-notes/2022-04-26-additional-file-taint-flow.md b/java/ql/lib/change-notes/2022-04-26-additional-file-taint-flow.md deleted file mode 100644 index bd931220045..00000000000 --- a/java/ql/lib/change-notes/2022-04-26-additional-file-taint-flow.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -category: minorAnalysis ---- - * Add taint models for the following `File` methods: - * `File::getAbsoluteFile` - * `File::getCanonicalFile` - * `File::getAbsolutePath` - * `File::getCanonicalPath` \ No newline at end of file diff --git a/java/ql/lib/change-notes/2022-04-26-android-editable-tostring-flow-step.md b/java/ql/lib/change-notes/2022-04-26-android-editable-tostring-flow-step.md deleted file mode 100644 index 2c8e2e367fb..00000000000 --- a/java/ql/lib/change-notes/2022-04-26-android-editable-tostring-flow-step.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -Added a flow step for `toString` calls on tainted `android.text.Editable` objects. \ No newline at end of file diff --git a/java/ql/lib/change-notes/2022-04-26-startactivity-flow-step.md b/java/ql/lib/change-notes/2022-04-26-startactivity-flow-step.md deleted file mode 100644 index 82d58183edd..00000000000 --- a/java/ql/lib/change-notes/2022-04-26-startactivity-flow-step.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -Added a data flow step for tainted Android intents that are sent to other activities and accessed there via `getIntent()`. \ No newline at end of file diff --git a/java/ql/lib/change-notes/2022-04-29-intent-redirection-sanitizer-fix.md b/java/ql/lib/change-notes/2022-04-29-intent-redirection-sanitizer-fix.md new file mode 100644 index 00000000000..66fa93ec4db --- /dev/null +++ b/java/ql/lib/change-notes/2022-04-29-intent-redirection-sanitizer-fix.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +Fixed a sanitizer of the query `java/android/intent-redirection`. Now, for an intent to be considered +safe against intent redirection, both its package name and class name must be checked. \ No newline at end of file diff --git a/java/ql/lib/change-notes/2022-05-02-okhttp-retrofit-models.md b/java/ql/lib/change-notes/2022-05-02-okhttp-retrofit-models.md deleted file mode 100644 index f575b10cfec..00000000000 --- a/java/ql/lib/change-notes/2022-05-02-okhttp-retrofit-models.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Added models for the libraries OkHttp and Retrofit. \ No newline at end of file diff --git a/java/ql/lib/change-notes/2022-05-09-value-discarding-expression.md b/java/ql/lib/change-notes/2022-05-09-value-discarding-expression.md deleted file mode 100644 index 36adb0169d4..00000000000 --- a/java/ql/lib/change-notes/2022-05-09-value-discarding-expression.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: feature ---- -* The QL class `ValueDiscardingExpr` has been added, representing expressions for which the value of the expression as a whole is discarded. diff --git a/java/ql/lib/change-notes/2022-05-16-floating-point-literal-rename.md b/java/ql/lib/change-notes/2022-05-16-floating-point-literal-rename.md new file mode 100644 index 00000000000..a6603a7d490 --- /dev/null +++ b/java/ql/lib/change-notes/2022-05-16-floating-point-literal-rename.md @@ -0,0 +1,4 @@ +--- +category: deprecated +--- +* The QL class `FloatingPointLiteral` has been renamed to `FloatLiteral`. diff --git a/java/ql/lib/change-notes/2022-05-09-kotlin.md b/java/ql/lib/change-notes/released/0.2.1.md similarity index 64% rename from java/ql/lib/change-notes/2022-05-09-kotlin.md rename to java/ql/lib/change-notes/released/0.2.1.md index ce1a25ca183..9b0918742bd 100644 --- a/java/ql/lib/change-notes/2022-05-09-kotlin.md +++ b/java/ql/lib/change-notes/released/0.2.1.md @@ -1,9 +1,10 @@ ---- -category: feature ---- - * A number of new classes and methods related to the upcoming Kotlin - support have been added. These are not yet stable, as Kotlin support - is still under development. +## 0.2.1 + +### New Features + +* A number of new classes and methods related to the upcoming Kotlin + support have been added. These are not yet stable, as Kotlin support + is still under development. * `File::isSourceFile` * `File::isJavaSourceFile` * `File::isKotlinSourceFile` @@ -65,3 +66,16 @@ category: feature * `LiveLiteral` class * `LiveLiteralMethod` class * `CastConversionContext` renamed to `CastingConversionContext` +* The QL class `ValueDiscardingExpr` has been added, representing expressions for which the value of the expression as a whole is discarded. + +### Minor Analysis Improvements + +* Added models for the libraries OkHttp and Retrofit. +* Add taint models for the following `File` methods: + * `File::getAbsoluteFile` + * `File::getCanonicalFile` + * `File::getAbsolutePath` + * `File::getCanonicalPath` +* Added a flow step for `toString` calls on tainted `android.text.Editable` objects. +* Added a data flow step for tainted Android intents that are sent to other activities and accessed there via `getIntent()`. +* Added modeling of MyBatis (`org.apache.ibatis`) Providers, resulting in additional sinks for the queries `java/ognl-injection`, `java/sql-injection`, `java/sql-injection-local` and `java/concatenated-sql-query`. diff --git a/java/ql/lib/codeql-pack.release.yml b/java/ql/lib/codeql-pack.release.yml index 5274e27ed52..df29a726bcc 100644 --- a/java/ql/lib/codeql-pack.release.yml +++ b/java/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.2.0 +lastReleaseVersion: 0.2.1 diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml index 1a0a0929a12..c50997eef69 100644 --- a/java/ql/lib/qlpack.yml +++ b/java/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-all -version: 0.2.1-dev +version: 0.2.2-dev groups: java dbscheme: config/semmlecode.dbscheme extractor: java diff --git a/java/ql/lib/semmle/code/java/Expr.qll b/java/ql/lib/semmle/code/java/Expr.qll index abef9c6f530..48023e135af 100755 --- a/java/ql/lib/semmle/code/java/Expr.qll +++ b/java/ql/lib/semmle/code/java/Expr.qll @@ -716,20 +716,23 @@ class LongLiteral extends Literal, @longliteral { override string getAPrimaryQlClass() { result = "LongLiteral" } } +/** DEPRECATED: Alias for FloatLiteral */ +deprecated class FloatingPointLiteral = FloatLiteral; + /** * A float literal. For example, `4.2f`. * * A float literal is never negative; a preceding minus, if any, will always * be modeled as separate `MinusExpr`. */ -class FloatingPointLiteral extends Literal, @floatingpointliteral { +class FloatLiteral extends Literal, @floatingpointliteral { /** * Gets the value of this literal as CodeQL 64-bit `float`. The value will * be parsed as Java 32-bit `float` and then converted to a CodeQL `float`. */ float getFloatValue() { result = this.getValue().toFloat() } - override string getAPrimaryQlClass() { result = "FloatingPointLiteral" } + override string getAPrimaryQlClass() { result = "FloatLiteral" } } /** @@ -1014,7 +1017,7 @@ class ValueOrReferenceEqualsExpr extends BinaryExpr { * A binary expression using either Java or Kotlin's `!=` operator. * * This might test for reference equality or might function like `Objects.equals`. If you - * need to distinguish them, use `EQExpr` or `ValueEQExpr` instead. + * need to distinguish them, use `NEExpr` or `ValueNEExpr` instead. */ class ValueOrReferenceNotEqualsExpr extends BinaryExpr { ValueOrReferenceNotEqualsExpr() { this instanceof NEExpr or this instanceof ValueNEExpr } @@ -2461,7 +2464,7 @@ class ClassExpr extends Expr, @getclassexpr { } /** - * An statement expression. + * A statement expression. * * In some contexts, a Kotlin expression can contain a statement. */ diff --git a/java/ql/lib/semmle/code/java/PrintAst.qll b/java/ql/lib/semmle/code/java/PrintAst.qll index 22ee6a30d00..05453baa045 100644 --- a/java/ql/lib/semmle/code/java/PrintAst.qll +++ b/java/ql/lib/semmle/code/java/PrintAst.qll @@ -7,6 +7,7 @@ */ import java +import semmle.code.java.regex.RegexTreeView private newtype TPrintAstConfiguration = MkPrintAstConfiguration() @@ -132,6 +133,9 @@ private newtype TPrintAstNode = } or TImportsNode(CompilationUnit cu) { shouldPrint(cu, _) and exists(Import i | i.getCompilationUnit() = cu) + } or + TRegExpTermNode(RegExpTerm term) { + exists(StringLiteral str | term.getRootTerm() = getParsedRegExp(str) and shouldPrint(str, _)) } /** @@ -164,6 +168,19 @@ class PrintAstNode extends TPrintAstNode { */ Location getLocation() { none() } + /** + * Holds if this node is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } + /** * Gets the value of the property of this node, where the name of the property * is `key`. @@ -290,6 +307,47 @@ final class AnnotationPartNode extends ExprStmtNode { } } +/** + * A node representing a `StringLiteral`. + * If it is used as a regular expression, then it has a single child, the root of the parsed regular expression. + */ +final class StringLiteralNode extends ExprStmtNode { + StringLiteralNode() { element instanceof StringLiteral } + + override PrintAstNode getChild(int childIndex) { + childIndex = 0 and + result.(RegExpTermNode).getTerm() = getParsedRegExp(element) + } +} + +/** + * A node representing a regular expression term. + */ +class RegExpTermNode extends TRegExpTermNode, PrintAstNode { + RegExpTerm term; + + RegExpTermNode() { this = TRegExpTermNode(term) } + + /** Gets the `RegExpTerm` for this node. */ + RegExpTerm getTerm() { result = term } + + override PrintAstNode getChild(int childIndex) { + result.(RegExpTermNode).getTerm() = term.getChild(childIndex) + } + + override string toString() { + result = "[" + strictconcat(term.getPrimaryQLClass(), " | ") + "] " + term.toString() + } + + override Location getLocation() { result = term.getLocation() } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + term.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } +} + /** * A node representing a `LocalVariableDeclExpr`. */ diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index f186fd62bf5..3aa228c5c9c 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -142,6 +142,8 @@ private module Frameworks { private import semmle.code.java.frameworks.jOOQ private import semmle.code.java.frameworks.JMS private import semmle.code.java.frameworks.RabbitMQ + private import semmle.code.java.regex.RegexFlowModels + private import semmle.code.java.frameworks.KotlinStdLib } private predicate sourceModelCsv(string row) { diff --git a/java/ql/lib/semmle/code/java/dataflow/FlowSummary.qll b/java/ql/lib/semmle/code/java/dataflow/FlowSummary.qll index c80e026b6c7..1792c2e9f11 100644 --- a/java/ql/lib/semmle/code/java/dataflow/FlowSummary.qll +++ b/java/ql/lib/semmle/code/java/dataflow/FlowSummary.qll @@ -1,5 +1,5 @@ /** - * Provides classes and predicates for definining flow summaries. + * Provides classes and predicates for defining flow summaries. */ import java diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 5bd84566df5..fb773ea89f8 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 5bd84566df5..fb773ea89f8 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 5bd84566df5..fb773ea89f8 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 5bd84566df5..fb773ea89f8 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 5bd84566df5..fb773ea89f8 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll index 5bd84566df5..fb773ea89f8 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll index e60505d9248..0079b259260 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -305,7 +305,7 @@ cached private module Cached { /** * If needed, call this predicate from `DataFlowImplSpecific.qll` in order to - * force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby + * force a stage-dependency on the `DataFlowImplCommon.qll` stage and thereby * collapsing the two stages. */ cached diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll index 5bd84566df5..fb773ea89f8 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll index 5bd84566df5..fb773ea89f8 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll index 64b762a10ad..8a671a66040 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll @@ -1,5 +1,5 @@ /** - * Provides Java specific classes and predicates for definining flow summaries. + * Provides Java specific classes and predicates for defining flow summaries. */ private import java diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll b/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll index 6b4a4d52765..a83c0e6f124 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll @@ -49,7 +49,7 @@ module Private { /** Class to represent float and double literals. */ class RealLiteral extends J::Literal { RealLiteral() { - this instanceof J::FloatingPointLiteral or + this instanceof J::FloatLiteral or this instanceof J::DoubleLiteral } } @@ -191,7 +191,7 @@ private module Impl { /** Gets the constant `float` value of non-`ConstantIntegerExpr` expressions. */ float getNonIntegerValue(Expr e) { result = e.(LongLiteral).getValue().toFloat() or - result = e.(FloatingPointLiteral).getValue().toFloat() or + result = e.(FloatLiteral).getValue().toFloat() or result = e.(DoubleLiteral).getValue().toFloat() } diff --git a/java/ql/lib/semmle/code/java/deadcode/DeadCode.qll b/java/ql/lib/semmle/code/java/deadcode/DeadCode.qll index ed77dff0a82..f0ddffa9aa2 100644 --- a/java/ql/lib/semmle/code/java/deadcode/DeadCode.qll +++ b/java/ql/lib/semmle/code/java/deadcode/DeadCode.qll @@ -302,6 +302,8 @@ class RootdefCallable extends Callable { exists(MemberRefExpr mre | mre.getReferencedCallable() = this) or this.getAnAnnotation() instanceof OverrideAnnotation + or + this.hasModifier("override") } } diff --git a/java/ql/lib/semmle/code/java/frameworks/KotlinStdLib.qll b/java/ql/lib/semmle/code/java/frameworks/KotlinStdLib.qll new file mode 100644 index 00000000000..63cdb87acdf --- /dev/null +++ b/java/ql/lib/semmle/code/java/frameworks/KotlinStdLib.qll @@ -0,0 +1,11 @@ +/** Definitions of taint steps in the KotlinStdLib framework */ + +import java +private import semmle.code.java.dataflow.ExternalFlow + +private class KotlinStdLibSummaryCsv extends SummaryModelCsv { + override predicate row(string row) { + row = + "kotlin.jvm.internal;ArrayIteratorKt;false;iterator;(Object[]);;Argument[0].ArrayElement;ReturnValue.Element;value" + } +} diff --git a/java/ql/lib/semmle/code/java/regex/RegexFlowConfigs.qll b/java/ql/lib/semmle/code/java/regex/RegexFlowConfigs.qll new file mode 100644 index 00000000000..8936de5a923 --- /dev/null +++ b/java/ql/lib/semmle/code/java/regex/RegexFlowConfigs.qll @@ -0,0 +1,193 @@ +/** + * Defines configurations and steps for handling regexes + */ + +import java +import semmle.code.java.dataflow.ExternalFlow +private import semmle.code.java.dataflow.DataFlow +private import semmle.code.java.dataflow.DataFlow2 +private import RegexFlowModels +private import semmle.code.java.security.SecurityTests + +private class ExploitableStringLiteral extends StringLiteral { + ExploitableStringLiteral() { this.getValue().matches(["%+%", "%*%", "%{%}%"]) } +} + +/** + * Holds if `kind` is an external sink kind that is relevant for regex flow. + * `full` is true if sinks with this kind match against the full string of its input. + * `strArg` is the index of the argument to methods with this sink kind that contan the string to be matched against, + * where -1 is the qualifier; or -2 if no such argument exists. + */ +private predicate regexSinkKindInfo(string kind, boolean full, int strArg) { + sinkModel(_, _, _, _, _, _, _, kind, _) and + exists(string fullStr, string strArgStr | + ( + full = true and fullStr = "f" + or + full = false and fullStr = "" + ) and + ( + strArgStr.toInt() = strArg + or + strArg = -2 and + strArgStr = "" + ) + | + kind = "regex-use[" + fullStr + strArgStr + "]" + ) +} + +/** A sink that is relevant for regex flow. */ +private class RegexFlowSink extends DataFlow::Node { + boolean full; + int strArg; + + RegexFlowSink() { + exists(string kind | + regexSinkKindInfo(kind, full, strArg) and + sinkNode(this, kind) + ) + } + + /** Holds if a regex that flows here is matched against a full string (rather than a substring). */ + predicate matchesFullString() { full = true } + + /** Gets the string expression that a regex that flows here is matched against, if any. */ + Expr getStringArgument() { + exists(MethodAccess ma | + this.asExpr() = argOf(ma, _) and + result = argOf(ma, strArg) + ) + } +} + +private Expr argOf(MethodAccess ma, int arg) { + arg = -1 and result = ma.getQualifier() + or + result = ma.getArgument(arg) +} + +/** + * A unit class for adding additional regex flow steps. + * + * Extend this class to add additional flow steps that should apply to regex flow configurations. + */ +class RegexAdditionalFlowStep extends Unit { + /** + * Holds if the step from `node1` to `node2` should be considered a flow + * step for regex flow configurations. + */ + abstract predicate step(DataFlow::Node node1, DataFlow::Node node2); +} + +// TODO: This may be able to be done with models-as-data if query-specific flow steps beome supported. +private class JdkRegexFlowStep extends RegexAdditionalFlowStep { + override predicate step(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m, string package, string type, string name, int arg | + ma.getMethod().getSourceDeclaration().overrides*(m) and + m.hasQualifiedName(package, type, name) and + node1.asExpr() = argOf(ma, arg) and + node2.asExpr() = ma + | + package = "java.util.regex" and + type = "Pattern" and + ( + name = ["asMatchPredicate", "asPredicate", "matcher"] and + arg = -1 + or + name = "compile" and + arg = 0 + ) + or + package = "java.util.function" and + type = "Predicate" and + name = ["and", "or", "not", "negate"] and + arg = [-1, 0] + ) + } +} + +private class GuavaRegexFlowStep extends RegexAdditionalFlowStep { + override predicate step(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m, string package, string type, string name, int arg | + ma.getMethod().getSourceDeclaration().overrides*(m) and + m.hasQualifiedName(package, type, name) and + node1.asExpr() = argOf(ma, arg) and + node2.asExpr() = ma + | + package = "com.google.common.base" and + type = "Splitter" and + ( + name = "on" and + m.getParameterType(0).(RefType).hasQualifiedName("java.util.regex", "Pattern") and + arg = 0 + or + name = "withKeyValueSeparator" and + m.getParameterType(0).(RefType).hasQualifiedName("com.google.common.base", "Splitter") and + arg = 0 + or + name = "onPattern" and + arg = 0 + or + name = ["limit", "omitEmptyStrings", "trimResults", "withKeyValueSeparator"] and + arg = -1 + ) + ) + } +} + +private class RegexFlowConf extends DataFlow2::Configuration { + RegexFlowConf() { this = "RegexFlowConfig" } + + override predicate isSource(DataFlow::Node node) { + node.asExpr() instanceof ExploitableStringLiteral + } + + override predicate isSink(DataFlow::Node node) { node instanceof RegexFlowSink } + + override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { + any(RegexAdditionalFlowStep s).step(node1, node2) + } + + override predicate isBarrier(DataFlow::Node node) { + node.getEnclosingCallable().getDeclaringType() instanceof NonSecurityTestClass + } +} + +/** + * Holds if `regex` is used as a regex, with the mode `mode` (if known). + * If regex mode is not known, `mode` will be `"None"`. + * + * As an optimisation, only regexes containing an infinite repitition quatifier (`+`, `*`, or `{x,}`) + * and therefore may be relevant for ReDoS queries are considered. + */ +predicate usedAsRegex(StringLiteral regex, string mode, boolean match_full_string) { + any(RegexFlowConf c).hasFlow(DataFlow2::exprNode(regex), _) and + mode = "None" and // TODO: proper mode detection + (if matchesFullString(regex) then match_full_string = true else match_full_string = false) +} + +/** + * Holds if `regex` is used as a regular expression that is matched against a full string, + * as though it was implicitly surrounded by ^ and $. + */ +private predicate matchesFullString(StringLiteral regex) { + exists(RegexFlowConf c, RegexFlowSink sink | + sink.matchesFullString() and + c.hasFlow(DataFlow2::exprNode(regex), sink) + ) +} + +/** + * Holds if the string literal `regex` is a regular expression that is matched against the expression `str`. + * + * As an optimisation, only regexes containing an infinite repitition quatifier (`+`, `*`, or `{x,}`) + * and therefore may be relevant for ReDoS queries are considered. + */ +predicate regexMatchedAgainst(StringLiteral regex, Expr str) { + exists(RegexFlowConf c, RegexFlowSink sink | + str = sink.getStringArgument() and + c.hasFlow(DataFlow2::exprNode(regex), sink) + ) +} diff --git a/java/ql/lib/semmle/code/java/regex/RegexFlowModels.qll b/java/ql/lib/semmle/code/java/regex/RegexFlowModels.qll new file mode 100644 index 00000000000..6934540116f --- /dev/null +++ b/java/ql/lib/semmle/code/java/regex/RegexFlowModels.qll @@ -0,0 +1,32 @@ +/** Definitions of data flow steps for determining flow of regular expressions. */ + +import java +import semmle.code.java.dataflow.ExternalFlow + +private class RegexSinkCsv extends SinkModelCsv { + override predicate row(string row) { + row = + [ + //"namespace;type;subtypes;name;signature;ext;input;kind" + "java.util.regex;Matcher;false;matches;();;Argument[-1];regex-use[f]", + "java.util.regex;Pattern;false;asMatchPredicate;();;Argument[-1];regex-use[f]", + "java.util.regex;Pattern;false;compile;(String);;Argument[0];regex-use[]", + "java.util.regex;Pattern;false;compile;(String,int);;Argument[0];regex-use[]", + "java.util.regex;Pattern;false;matcher;(CharSequence);;Argument[-1];regex-use[0]", + "java.util.regex;Pattern;false;matches;(String,CharSequence);;Argument[0];regex-use[f1]", + "java.util.regex;Pattern;false;split;(CharSequence);;Argument[-1];regex-use[0]", + "java.util.regex;Pattern;false;split;(CharSequence,int);;Argument[-1];regex-use[0]", + "java.util.regex;Pattern;false;splitAsStream;(CharSequence);;Argument[-1];regex-use[0]", + "java.util.function;Predicate;false;test;(Object);;Argument[-1];regex-use[0]", + "java.lang;String;false;matches;(String);;Argument[0];regex-use[f-1]", + "java.lang;String;false;split;(String);;Argument[0];regex-use[-1]", + "java.lang;String;false;split;(String,int);;Argument[0];regex-use[-1]", + "java.lang;String;false;replaceAll;(String,String);;Argument[0];regex-use[-1]", + "java.lang;String;false;replaceFirst;(String,String);;Argument[0];regex-use[-1]", + "com.google.common.base;Splitter;false;onPattern;(String);;Argument[0];regex-use[]", + "com.google.common.base;Splitter;false;split;(CharSequence);;Argument[-1];regex-use[0]", + "com.google.common.base;Splitter;false;splitToList;(CharSequence);;Argument[-1];regex-use[0]", + "com.google.common.base;Splitter$MapSplitter;false;split;(CharSequence);;Argument[-1];regex-use[0]", + ] + } +} diff --git a/java/ql/lib/semmle/code/java/regex/RegexTreeView.qll b/java/ql/lib/semmle/code/java/regex/RegexTreeView.qll new file mode 100644 index 00000000000..c3592634fa0 --- /dev/null +++ b/java/ql/lib/semmle/code/java/regex/RegexTreeView.qll @@ -0,0 +1,1084 @@ +/** Provides a class hierarchy corresponding to a parse tree of regular expressions. */ + +private import java +private import semmle.code.java.regex.regex + +/** + * An element containing a regular expression term, that is, either + * a string literal (parsed as a regular expression; the root of the parse tree) + * or another regular expression term (a decendent of the root). + * + * For sequences and alternations, we require at least two children. + * Otherwise, we wish to represent the term differently. + * This avoids multiple representations of the same term. + */ +private newtype TRegExpParent = + /** A string literal used as a regular expression */ + TRegExpLiteral(Regex re) or + /** A quantified term */ + TRegExpQuantifier(Regex re, int start, int end) { re.quantifiedItem(start, end, _, _) } or + /** A sequence term */ + TRegExpSequence(Regex re, int start, int end) { + re.sequence(start, end) and + // Only create sequence nodes for sequences with two or more children. + exists(int mid | + re.item(start, mid) and + re.item(mid, _) + ) + } or + /** An alternation term */ + TRegExpAlt(Regex re, int start, int end) { + re.alternation(start, end) and + exists(int part_end | + re.alternationOption(start, end, start, part_end) and + part_end < end + ) // if an alternation does not have more than one element, it should be treated as that element instead. + } or + /** A character class term */ + TRegExpCharacterClass(Regex re, int start, int end) { re.charSet(start, end) } or + /** A character range term */ + TRegExpCharacterRange(Regex re, int start, int end) { re.charRange(_, start, _, _, end) } or + /** A group term */ + TRegExpGroup(Regex re, int start, int end) { re.group(start, end) } or + /** A special character */ + TRegExpSpecialChar(Regex re, int start, int end) { re.specialCharacter(start, end, _) } or + /** A normal character */ + TRegExpNormalChar(Regex re, int start, int end) { re.normalCharacter(start, end) } or + /** A quoted sequence */ + TRegExpQuote(Regex re, int start, int end) { re.quote(start, end) } or + /** A back reference */ + TRegExpBackRef(Regex re, int start, int end) { re.backreference(start, end) } + +/** + * An element containing a regular expression term, that is, either + * a string literal (parsed as a regular expression; the root of the parse tree) + * or another regular expression term (a decendent of the root). + */ +class RegExpParent extends TRegExpParent { + /** Gets a textual representation of this element. */ + string toString() { result = "RegExpParent" } + + /** Gets the `i`th child term. */ + RegExpTerm getChild(int i) { none() } + + /** Gets a child term . */ + RegExpTerm getAChild() { result = this.getChild(_) } + + /** Gets the number of child terms. */ + int getNumChild() { result = count(this.getAChild()) } + + /** Gets the associated regex. */ + abstract Regex getRegex(); +} + +/** + * A string literal used as a regular expression. + * + * As an optimisation, only regexes containing an infinite repitition quatifier (`+`, `*`, or `{x,}`) + * and therefore may be relevant for ReDoS queries are considered. + */ +class RegExpLiteral extends TRegExpLiteral, RegExpParent { + Regex re; + + RegExpLiteral() { this = TRegExpLiteral(re) } + + override string toString() { result = re.toString() } + + override RegExpTerm getChild(int i) { i = 0 and result.getRegex() = re and result.isRootTerm() } + + /** Holds if dot, `.`, matches all characters, including newlines. */ + predicate isDotAll() { re.getAMode() = "DOTALL" } + + /** Holds if this regex matching is case-insensitive for this regex. */ + predicate isIgnoreCase() { re.getAMode() = "IGNORECASE" } + + /** Get a string representing all modes for this regex. */ + string getFlags() { result = concat(string mode | mode = re.getAMode() | mode, " | ") } + + override Regex getRegex() { result = re } + + /** Gets the primary QL class for this regex. */ + string getPrimaryQLClass() { result = "RegExpLiteral" } +} + +/** + * A regular expression term, that is, a syntactic part of a regular expression. + * These are the tree nodes that form the parse tree of a regular expression literal. + */ +class RegExpTerm extends RegExpParent { + Regex re; + int start; + int end; + + RegExpTerm() { + this = TRegExpAlt(re, start, end) + or + this = TRegExpBackRef(re, start, end) + or + this = TRegExpCharacterClass(re, start, end) + or + this = TRegExpCharacterRange(re, start, end) + or + this = TRegExpNormalChar(re, start, end) + or + this = TRegExpQuote(re, start, end) + or + this = TRegExpGroup(re, start, end) + or + this = TRegExpQuantifier(re, start, end) + or + this = TRegExpSequence(re, start, end) + or + this = TRegExpSpecialChar(re, start, end) + } + + /** + * Gets the outermost term of this regular expression. + */ + RegExpTerm getRootTerm() { + this.isRootTerm() and result = this + or + result = this.getParent().(RegExpTerm).getRootTerm() + } + + /** + * Holds if this term is part of a string literal + * that is interpreted as a regular expression. + */ + predicate isUsedAsRegExp() { any() } + + /** + * Holds if this is the root term of a regular expression. + */ + predicate isRootTerm() { start = 0 and end = re.getText().length() } + + /** + * Gets the parent term of this regular expression term, or the + * regular expression literal if this is the root term. + */ + RegExpParent getParent() { result.getAChild() = this } + + override Regex getRegex() { result = re } + + /** Gets the offset at which this term starts. */ + int getStart() { result = start } + + /** Gets the offset at which this term ends. */ + int getEnd() { result = end } + + /** Holds if this term occurs in regex `inRe` offsets `startOffset` to `endOffset`. */ + predicate occursInRegex(Regex inRe, int startOffset, int endOffset) { + inRe = re and startOffset = start and endOffset = end + } + + override string toString() { result = re.getText().substring(start, end) } + + /** + * Gets the location of the surrounding regex, as locations inside the regex do not exist. + * To get location information corresponding to the term inside the regex, + * use `hasLocationInfo`. + */ + Location getLocation() { result = re.getLocation() } + + /** Holds if this term is found at the specified location offsets. */ + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + /* + * This is an approximation that handles the simple and common case of single, + * normal string literal written in the source, but does not give correct results in more complex cases + * such as compile-time concatenation, or multi-line string literals. + */ + + exists(int re_start, int re_end, int src_start, int src_end | + re.getLocation().hasLocationInfo(filepath, startline, re_start, endline, re_end) and + re.sourceCharacter(start, src_start, _) and + re.sourceCharacter(end - 1, _, src_end) and + startcolumn = re_start + src_start and + endcolumn = re_start + src_end - 1 + ) + } + + /** Gets the file in which this term is found. */ + File getFile() { result = this.getLocation().getFile() } + + /** Gets the raw source text of this term. */ + string getRawValue() { result = this.toString() } + + /** Gets the string literal in which this term is found. */ + RegExpLiteral getLiteral() { result = TRegExpLiteral(re) } + + /** Gets the regular expression term that is matched (textually) before this one, if any. */ + RegExpTerm getPredecessor() { + exists(RegExpTerm parent | parent = this.getParent() | + result = parent.(RegExpSequence).previousElement(this) + or + not exists(parent.(RegExpSequence).previousElement(this)) and + not parent instanceof RegExpSubPattern and + result = parent.getPredecessor() + ) + } + + /** Gets the regular expression term that is matched (textually) after this one, if any. */ + RegExpTerm getSuccessor() { + exists(RegExpTerm parent | parent = this.getParent() | + result = parent.(RegExpSequence).nextElement(this) + or + not exists(parent.(RegExpSequence).nextElement(this)) and + not parent instanceof RegExpSubPattern and + result = parent.getSuccessor() + ) + } + + /** Gets the primary QL class for this term. */ + string getPrimaryQLClass() { result = "RegExpTerm" } +} + +/** + * A quantified regular expression term. + * + * Example: + * + * ``` + * ((ECMA|Java)[sS]cript)* + * ``` + */ +class RegExpQuantifier extends RegExpTerm, TRegExpQuantifier { + int part_end; + boolean maybe_empty; + boolean may_repeat_forever; + + RegExpQuantifier() { + this = TRegExpQuantifier(re, start, end) and + re.quantifiedPart(start, part_end, end, maybe_empty, may_repeat_forever) + } + + override RegExpTerm getChild(int i) { + i = 0 and + result.occursInRegex(re, start, part_end) + } + + /** Holds if this term may match zero times. */ + predicate mayBeEmpty() { maybe_empty = true } + + /** Holds if this term may match an unlimited number of times. */ + predicate mayRepeatForever() { may_repeat_forever = true } + + /** Gets the quantifier for this term. That is e.g "?" for "a?". */ + string getQuantifier() { result = re.getText().substring(part_end, end) } + + /** Holds if this is a possessive quantifier, e.g. a*+. */ + predicate isPossessive() { + exists(string q | q = this.getQuantifier() | q.length() > 1 and q.charAt(q.length() - 1) = "+") + } + + override string getPrimaryQLClass() { result = "RegExpQuantifier" } +} + +/** + * A regular expression term that permits unlimited repetitions. + */ +class InfiniteRepetitionQuantifier extends RegExpQuantifier { + InfiniteRepetitionQuantifier() { this.mayRepeatForever() } +} + +/** + * A star-quantified term. + * + * Example: + * + * ``` + * \w* + * ``` + */ +class RegExpStar extends InfiniteRepetitionQuantifier { + RegExpStar() { this.getQuantifier().charAt(0) = "*" } + + override string getPrimaryQLClass() { result = "RegExpStar" } +} + +/** + * A plus-quantified term. + * + * Example: + * + * ``` + * \w+ + * ``` + */ +class RegExpPlus extends InfiniteRepetitionQuantifier { + RegExpPlus() { this.getQuantifier().charAt(0) = "+" } + + override string getPrimaryQLClass() { result = "RegExpPlus" } +} + +/** + * An optional term. + * + * Example: + * + * ``` + * ;? + * ``` + */ +class RegExpOpt extends RegExpQuantifier { + RegExpOpt() { this.getQuantifier().charAt(0) = "?" } + + override string getPrimaryQLClass() { result = "RegExpOpt" } +} + +/** + * A range-quantified term + * + * Examples: + * + * ``` + * \w{2,4} + * \w{2,} + * \w{2} + * ``` + */ +class RegExpRange extends RegExpQuantifier { + string upper; + string lower; + + RegExpRange() { re.multiples(part_end, end, lower, upper) } + + /** Gets the string defining the upper bound of this range, which is empty when no such bound exists. */ + string getUpper() { result = upper } + + /** Gets the string defining the lower bound of this range, which is empty when no such bound exists. */ + string getLower() { result = lower } + + /** + * Gets the upper bound of the range, if any. + * + * If there is no upper bound, any number of repetitions is allowed. + * For a term of the form `r{lo}`, both the lower and the upper bound + * are `lo`. + */ + int getUpperBound() { result = this.getUpper().toInt() } + + /** Gets the lower bound of the range. */ + int getLowerBound() { result = this.getLower().toInt() } + + override string getPrimaryQLClass() { result = "RegExpRange" } +} + +/** + * A sequence term. + * + * Example: + * + * ``` + * (ECMA|Java)Script + * ``` + * + * This is a sequence with the elements `(ECMA|Java)` and `Script`. + */ +class RegExpSequence extends RegExpTerm, TRegExpSequence { + RegExpSequence() { this = TRegExpSequence(re, start, end) } + + override RegExpTerm getChild(int i) { result = seqChild(re, start, end, i) } + + /** Gets the element preceding `element` in this sequence. */ + RegExpTerm previousElement(RegExpTerm element) { element = this.nextElement(result) } + + /** Gets the element following `element` in this sequence. */ + RegExpTerm nextElement(RegExpTerm element) { + exists(int i | + element = this.getChild(i) and + result = this.getChild(i + 1) + ) + } + + override string getPrimaryQLClass() { result = "RegExpSequence" } +} + +pragma[nomagic] +private int seqChildEnd(Regex re, int start, int end, int i) { + result = seqChild(re, start, end, i).getEnd() +} + +// moved out so we can use it in the charpred +private RegExpTerm seqChild(Regex re, int start, int end, int i) { + re.sequence(start, end) and + ( + i = 0 and + exists(int itemEnd | + re.item(start, itemEnd) and + result.occursInRegex(re, start, itemEnd) + ) + or + i > 0 and + exists(int itemStart, int itemEnd | itemStart = seqChildEnd(re, start, end, i - 1) | + re.item(itemStart, itemEnd) and + result.occursInRegex(re, itemStart, itemEnd) + ) + ) +} + +/** + * An alternative term, that is, a term of the form `a|b`. + * + * Example: + * + * ``` + * ECMA|Java + * ``` + */ +class RegExpAlt extends RegExpTerm, TRegExpAlt { + RegExpAlt() { this = TRegExpAlt(re, start, end) } + + override RegExpTerm getChild(int i) { + i = 0 and + exists(int part_end | + re.alternationOption(start, end, start, part_end) and + result.occursInRegex(re, start, part_end) + ) + or + i > 0 and + exists(int part_start, int part_end | + part_start = this.getChild(i - 1).getEnd() + 1 // allow for the | + | + re.alternationOption(start, end, part_start, part_end) and + result.occursInRegex(re, part_start, part_end) + ) + } + + override string getPrimaryQLClass() { result = "RegExpAlt" } +} + +/** + * An escaped regular expression term, that is, a regular expression + * term starting with a backslash, which is not a backreference. + * + * Example: + * + * ``` + * \. + * \w + * ``` + */ +class RegExpEscape extends RegExpNormalChar { + RegExpEscape() { re.escapedCharacter(start, end) } + + /** + * Gets the name of the escaped; for example, `w` for `\w`. + * TODO: Handle named escapes. + */ + override string getValue() { + this.isIdentityEscape() and result = this.getUnescaped() + or + this.getUnescaped() = "n" and result = "\n" + or + this.getUnescaped() = "r" and result = "\r" + or + this.getUnescaped() = "t" and result = "\t" + or + this.getUnescaped() = "f" and result = 12.toUnicode() // form feed + or + this.getUnescaped() = "a" and result = 7.toUnicode() // alert/bell + or + this.getUnescaped() = "e" and result = 27.toUnicode() // escape (0x1B) + or + this.isUnicode() and + result = this.getUnicode() + } + + /** Holds if this terms name is given by the part following the escape character. */ + predicate isIdentityEscape() { not this.getUnescaped() in ["n", "r", "t", "f", "a", "e"] } + + override string getPrimaryQLClass() { result = "RegExpEscape" } + + /** Gets the part of the term following the escape character. That is e.g. "w" if the term is "\w". */ + private string getUnescaped() { result = this.getText().suffix(1) } + + /** + * Gets the text for this escape. That is e.g. "\w". + */ + private string getText() { result = re.getText().substring(start, end) } + + /** + * Holds if this is a unicode escape. + */ + private predicate isUnicode() { this.getText().matches(["\\u%", "\\x%"]) } + + /** + * Gets the unicode char for this escape. + * E.g. for `\u0061` this returns "a". + */ + private string getUnicode() { + exists(int codepoint | codepoint = sum(this.getHexValueFromUnicode(_)) | + result = codepoint.toUnicode() + ) + } + + /** Gets the part of this escape that is a hexidecimal string */ + private string getHexString() { + this.isUnicode() and + if this.getText().matches("\\u%") // \uhhhh + then result = this.getText().suffix(2) + else + if this.getText().matches("\\x{%") // \x{h..h} + then result = this.getText().substring(3, this.getText().length() - 1) + else result = this.getText().suffix(2) // \xhh + } + + /** + * Gets int value for the `index`th char in the hex number of the unicode escape. + * E.g. for `\u0061` and `index = 2` this returns 96 (the number `6` interpreted as hex). + */ + private int getHexValueFromUnicode(int index) { + this.isUnicode() and + exists(string hex, string char | hex = this.getHexString() | + char = hex.charAt(index) and + result = 16.pow(hex.length() - index - 1) * toHex(char) + ) + } +} + +/** + * Gets the hex number for the `hex` char. + */ +private int toHex(string hex) { + result = [0 .. 9] and hex = result.toString() + or + result = 10 and hex = ["a", "A"] + or + result = 11 and hex = ["b", "B"] + or + result = 12 and hex = ["c", "C"] + or + result = 13 and hex = ["d", "D"] + or + result = 14 and hex = ["e", "E"] + or + result = 15 and hex = ["f", "F"] +} + +/** + * A character class escape in a regular expression. + * That is, an escaped character that denotes multiple characters. + * + * Examples: + * + * ``` + * \w + * \S + * ``` + */ +class RegExpCharacterClassEscape extends RegExpEscape { + RegExpCharacterClassEscape() { + this.getValue() in ["d", "D", "s", "S", "w", "W", "h", "H", "v", "V"] or + this.getValue().charAt(0) in ["p", "P"] + } + + override RegExpTerm getChild(int i) { none() } + + override string getPrimaryQLClass() { result = "RegExpCharacterClassEscape" } +} + +/** + * A named character class in a regular expression. + * + * Examples: + * + * ``` + * \p{Digit} + * \p{IsLowerCase} + */ +class RegExpNamedProperty extends RegExpCharacterClassEscape { + boolean inverted; + string name; + + RegExpNamedProperty() { + name = this.getValue().substring(2, this.getValue().length() - 1) and + ( + inverted = false and + this.getValue().charAt(0) = "p" + or + inverted = true and + this.getValue().charAt(0) = "P" + ) + } + + /** Holds if this class is inverted. */ + predicate isInverted() { inverted = true } + + /** Gets the name of this class. */ + string getClassName() { result = name } + + /** + * Gets an equivalent single-chcracter escape sequence for this class (e.g. \d) if possible, excluding the escape character. + */ + string getBackslashEquivalent() { + exists(string eq | if inverted = true then result = eq.toUpperCase() else result = eq | + name = ["Digit", "IsDigit"] and + eq = "d" + or + name = ["Space", "IsWhite_Space"] and + eq = "s" + ) + } +} + +/** + * A character class in a regular expression. + * + * Examples: + * + * ``` + * [a-z_] + * [^<>&] + * ``` + */ +class RegExpCharacterClass extends RegExpTerm, TRegExpCharacterClass { + RegExpCharacterClass() { this = TRegExpCharacterClass(re, start, end) } + + /** Holds if this character class is inverted, matching the opposite of its content. */ + predicate isInverted() { re.getChar(start + 1) = "^" } + + /** Holds if this character class can match anything. */ + predicate isUniversalClass() { + // [^] + this.isInverted() and not exists(this.getAChild()) + or + // [\w\W] and similar + not this.isInverted() and + exists(string cce1, string cce2 | + cce1 = this.getAChild().(RegExpCharacterClassEscape).getValue() and + cce2 = this.getAChild().(RegExpCharacterClassEscape).getValue() + | + cce1 != cce2 and cce1.toLowerCase() = cce2.toLowerCase() + ) + } + + override RegExpTerm getChild(int i) { + i = 0 and + exists(int itemStart, int itemEnd | + re.charSetStart(start, itemStart) and + re.charSetChild(start, itemStart, itemEnd) and + result.occursInRegex(re, itemStart, itemEnd) + ) + or + i > 0 and + exists(int itemStart, int itemEnd | itemStart = this.getChild(i - 1).getEnd() | + result.occursInRegex(re, itemStart, itemEnd) and + re.charSetChild(start, itemStart, itemEnd) + ) + } + + override string getPrimaryQLClass() { result = "RegExpCharacterClass" } +} + +/** + * A character range in a character class in a regular expression. + * + * Example: + * + * ``` + * a-z + * ``` + */ +class RegExpCharacterRange extends RegExpTerm, TRegExpCharacterRange { + int lower_end; + int upper_start; + + RegExpCharacterRange() { + this = TRegExpCharacterRange(re, start, end) and + re.charRange(_, start, lower_end, upper_start, end) + } + + /** Holds if this range goes from `lo` to `hi`, in effect is `lo-hi`. */ + predicate isRange(string lo, string hi) { + lo = re.getText().substring(start, lower_end) and + hi = re.getText().substring(upper_start, end) + } + + override RegExpTerm getChild(int i) { + i = 0 and + result.occursInRegex(re, start, lower_end) + or + i = 1 and + result.occursInRegex(re, upper_start, end) + } + + override string getPrimaryQLClass() { result = "RegExpCharacterRange" } +} + +/** + * A normal character in a regular expression, that is, a character + * without special meaning. This includes escaped characters. + * It also includes escape sequences that represent character classes. + * + * Examples: + * ``` + * t + * \t + * ``` + */ +class RegExpNormalChar extends RegExpTerm, TRegExpNormalChar { + RegExpNormalChar() { this = TRegExpNormalChar(re, start, end) } + + /** + * Holds if this constant represents a valid Unicode character (as opposed + * to a surrogate code point that does not correspond to a character by itself.) + */ + predicate isCharacter() { any() } + + /** Gets the string representation of the char matched by this term. */ + string getValue() { result = re.getText().substring(start, end) } + + override RegExpTerm getChild(int i) { none() } + + override string getPrimaryQLClass() { result = "RegExpNormalChar" } +} + +/** + * A quoted sequence. + * + * Example: + * ``` + * \Qabc\E + * ``` + */ +class RegExpQuote extends RegExpTerm, TRegExpQuote { + string value; + + RegExpQuote() { + exists(int inner_start, int inner_end | + this = TRegExpQuote(re, start, end) and + re.quote(start, end, inner_start, inner_end) and + value = re.getText().substring(inner_start, inner_end) + ) + } + + /** Gets the string matched by this quote term. */ + string getValue() { result = value } + + override string getPrimaryQLClass() { result = "RegExpQuote" } +} + +/** + * A constant regular expression term, that is, a regular expression + * term matching a single string. This can be a single character or a quoted sequence. + * + * Example: + * + * ``` + * a + * ``` + */ +class RegExpConstant extends RegExpTerm { + string value; + + RegExpConstant() { + (value = this.(RegExpNormalChar).getValue() or value = this.(RegExpQuote).getValue()) and + not this instanceof RegExpCharacterClassEscape + } + + /** + * Holds if this constant represents a valid Unicode character (as opposed + * to a surrogate code point that does not correspond to a character by itself.) + */ + predicate isCharacter() { any() } + + /** Gets the string matched by this constant term. */ + string getValue() { result = value } + + override RegExpTerm getChild(int i) { none() } + + override string getPrimaryQLClass() { result = "RegExpConstant" } +} + +/** + * A grouped regular expression. + * + * Examples: + * + * ``` + * (ECMA|Java) + * (?:ECMA|Java) + * (?['"]) + * ``` + */ +class RegExpGroup extends RegExpTerm, TRegExpGroup { + RegExpGroup() { this = TRegExpGroup(re, start, end) } + + /** + * Gets the index of this capture group within the enclosing regular + * expression literal. + * + * For example, in the regular expression `/((a?).)(?:b)/`, the + * group `((a?).)` has index 1, the group `(a?)` nested inside it + * has index 2, and the group `(?:b)` has no index, since it is + * not a capture group. + */ + int getNumber() { result = re.getGroupNumber(start, end) } + + /** Holds if this is a named capture group. */ + predicate isNamed() { exists(this.getName()) } + + /** Gets the name of this capture group, if any. */ + string getName() { result = re.getGroupName(start, end) } + + override RegExpTerm getChild(int i) { + i = 0 and + exists(int in_start, int in_end | re.groupContents(start, end, in_start, in_end) | + result.occursInRegex(re, in_start, in_end) + ) + } + + override string getPrimaryQLClass() { result = "RegExpGroup" } + + /** Holds if this is the `n`th numbered group of literal `lit`. */ + predicate isNumberedGroupOfLiteral(RegExpLiteral lit, int n) { + lit = this.getLiteral() and n = this.getNumber() + } + + /** Holds if this is a group with name `name` of literal `lit`. */ + predicate isNamedGroupOfLiteral(RegExpLiteral lit, string name) { + lit = this.getLiteral() and name = this.getName() + } +} + +/** + * A special character in a regular expression. + * + * Examples: + * ``` + * ^ + * $ + * . + * ``` + */ +class RegExpSpecialChar extends RegExpTerm, TRegExpSpecialChar { + string char; + + RegExpSpecialChar() { + this = TRegExpSpecialChar(re, start, end) and + re.specialCharacter(start, end, char) + } + + /** + * Holds if this constant represents a valid Unicode character (as opposed + * to a surrogate code point that does not correspond to a character by itself.) + */ + predicate isCharacter() { any() } + + /** Gets the char for this term. */ + string getChar() { result = char } + + override RegExpTerm getChild(int i) { none() } + + override string getPrimaryQLClass() { result = "RegExpSpecialChar" } +} + +/** + * A dot regular expression. + * + * Example: + * + * ``` + * . + * ``` + */ +class RegExpDot extends RegExpSpecialChar { + RegExpDot() { this.getChar() = "." } + + override string getPrimaryQLClass() { result = "RegExpDot" } +} + +/** + * A dollar assertion `$` matching the end of a line. + * + * Example: + * + * ``` + * $ + * ``` + */ +class RegExpDollar extends RegExpSpecialChar { + RegExpDollar() { this.getChar() = "$" } + + override string getPrimaryQLClass() { result = "RegExpDollar" } +} + +/** + * A caret assertion `^` matching the beginning of a line. + * + * Example: + * + * ``` + * ^ + * ``` + */ +class RegExpCaret extends RegExpSpecialChar { + RegExpCaret() { this.getChar() = "^" } + + override string getPrimaryQLClass() { result = "RegExpCaret" } +} + +/** + * A zero-width match, that is, either an empty group or an assertion. + * + * Examples: + * ``` + * () + * (?=\w) + * ``` + */ +class RegExpZeroWidthMatch extends RegExpGroup { + RegExpZeroWidthMatch() { re.zeroWidthMatch(start, end) } + + override RegExpTerm getChild(int i) { none() } + + override string getPrimaryQLClass() { result = "RegExpZeroWidthMatch" } +} + +/** + * A zero-width lookahead or lookbehind assertion. + * + * Examples: + * + * ``` + * (?=\w) + * (?!\n) + * (?<=\.) + * (?` + * in a regular expression. + * + * Examples: + * + * ``` + * \1 + * (?P=quote) + * ``` + */ +class RegExpBackRef extends RegExpTerm, TRegExpBackRef { + RegExpBackRef() { this = TRegExpBackRef(re, start, end) } + + /** + * Gets the number of the capture group this back reference refers to, if any. + */ + int getNumber() { result = re.getBackrefNumber(start, end) } + + /** + * Gets the name of the capture group this back reference refers to, if any. + */ + string getName() { result = re.getBackrefName(start, end) } + + /** Gets the capture group this back reference refers to. */ + RegExpGroup getGroup() { + result.isNumberedGroupOfLiteral(this.getLiteral(), this.getNumber()) + or + result.isNamedGroupOfLiteral(this.getLiteral(), this.getName()) + } + + override RegExpTerm getChild(int i) { none() } + + override string getPrimaryQLClass() { result = "RegExpBackRef" } +} + +/** Gets the parse tree resulting from parsing `re`, if such has been constructed. */ +RegExpTerm getParsedRegExp(StringLiteral re) { result.getRegex() = re and result.isRootTerm() } diff --git a/java/ql/lib/semmle/code/java/regex/regex.qll b/java/ql/lib/semmle/code/java/regex/regex.qll new file mode 100644 index 00000000000..ff20b17b6fa --- /dev/null +++ b/java/ql/lib/semmle/code/java/regex/regex.qll @@ -0,0 +1,917 @@ +/** + * Definitions for parsing regular expressions. + */ + +import java +private import RegexFlowConfigs + +// In all ranges handled by this library, `start` is inclusive and `end` is exclusive. +/** + * A string literal that is used as a regular expression. + */ +abstract class RegexString extends StringLiteral { + /** Gets the text of this regex */ + string getText() { result = this.(StringLiteral).getValue() } + + /** Gets the `i`th character of this regex. */ + string getChar(int i) { result = this.getText().charAt(i) } + + /** Holds if the regex failed to parse. */ + predicate failedToParse(int i) { + exists(this.getChar(i)) and + not exists(int start, int end | + this.topLevel(start, end) and + start <= i and + end > i + ) + } + + /** + * Helper predicate for `escapingChar`. + * In order to avoid negative recursion, we return a boolean. + * This way, we can refer to `escaping(pos - 1).booleanNot()` + * rather than to a negated version of `escaping(pos)`. + */ + private boolean escaping(int pos) { + pos = -1 and result = false + or + this.getChar(pos) = "\\" and + ( + if this.getChar(pos - 1) = "c" // in `\c\`, the latter `\` isn't escaping + then result = this.escaping(pos - 2).booleanNot() + else result = this.escaping(pos - 1).booleanNot() + ) + or + this.getChar(pos) != "\\" and result = false + } + + /** + * Helper predicate for `quote`. + * Holds if the char at `pos` could be the beginning of a quote delimiter, i.e. `\Q` (non-escaped) or `\E` (escaping not checked, as quote sequences turn off escapes). + * Result is `true` for `\Q` and `false` for `\E`. + */ + private boolean quoteDelimiter(int pos) { + result = true and + this.escaping(pos) = true and + this.getChar(pos + 1) = "Q" + or + result = false and + this.getChar(pos) = "\\" and + this.getChar(pos + 1) = "E" + } + + /** + * Helper predicate for `quote`. + * Holds if the char at `pos` is the one-based `index`th occurence of a quote delimiter (`\Q` or `\E`) + * Result is `true` for `\Q` and `false` for `\E`. + */ + private boolean quoteDelimiter(int index, int pos) { + result = this.quoteDelimiter(pos) and + pos = rank[index](int p | exists(this.quoteDelimiter(p))) + } + + /** Holds if a quoted sequence is found between `start` and `end` */ + predicate quote(int start, int end) { this.quote(start, end, _, _) } + + /** Holds if a quoted sequence is found between `start` and `end`, with content found between `inner_start` and `inner_end`. */ + predicate quote(int start, int end, int inner_start, int inner_end) { + exists(int index | + this.quoteDelimiter(index, start) = true and + ( + index = 1 + or + this.quoteDelimiter(index - 1, _) = false + ) and + inner_start = start + 2 and + inner_end = end - 2 and + inner_end = + min(int end_delimiter | + this.quoteDelimiter(end_delimiter) = false and end_delimiter > inner_start + ) + ) + } + + /** Holds if the character at `pos` is a "\" that is actually escaping what comes after. */ + predicate escapingChar(int pos) { + this.escaping(pos) = true and + not exists(int x, int y | this.quote(x, y) and pos in [x .. y - 1]) + } + + /** + * Holds if there is a control sequence, `\cx`, between `start` and `end`. + * `x` may be any ascii character including special characters. + */ + predicate controlEscape(int start, int end) { + this.escapingChar(start) and + this.getChar(start + 1) = "c" and + end = start + 3 + } + + private predicate namedBackreference(int start, int end, string name) { + this.escapingChar(start) and + this.getChar(start + 1) = "k" and + this.getChar(start + 2) = "<" and + end = min(int i | i > start + 2 and this.getChar(i) = ">") + 1 and + name = this.getText().substring(start + 3, end - 1) + } + + private predicate numberedBackreference(int start, int end, int value) { + this.escapingChar(start) and + // starting with 0 makes it an octal escape + not this.getChar(start + 1) = "0" and + exists(string text, string svalue, int len | + end = start + len and + text = this.getText() and + len in [2 .. 3] + | + svalue = text.substring(start + 1, start + len) and + value = svalue.toInt() and + // value is composed of digits + forall(int i | i in [start + 1 .. start + len - 1] | this.getChar(i) = [0 .. 9].toString()) and + // a longer reference is not possible + not ( + len = 2 and + exists(text.substring(start + 1, start + len + 1).toInt()) + ) and + // 3 octal digits makes it an octal escape + not forall(int i | i in [start + 1 .. start + 4] | this.isOctal(i)) + // TODO: Inside a character set, all numeric escapes are treated as characters. + ) + } + + /** Holds if the text in the range start,end is a back reference */ + predicate backreference(int start, int end) { + this.numberedBackreference(start, end, _) + or + this.namedBackreference(start, end, _) + } + + /** Gets the number of the back reference in start,end */ + int getBackrefNumber(int start, int end) { this.numberedBackreference(start, end, result) } + + /** Gets the name, if it has one, of the back reference in start,end */ + string getBackrefName(int start, int end) { this.namedBackreference(start, end, result) } + + pragma[inline] + private predicate isOctal(int index) { this.getChar(index) = [0 .. 7].toString() } + + /** An escape sequence that includes braces, such as named characters (\N{degree sign}), named classes (\p{Lower}), or hex values (\x{h..h}) */ + private predicate escapedBraces(int start, int end) { + this.escapingChar(start) and + this.getChar(start + 1) = ["N", "p", "P", "x"] and + this.getChar(start + 2) = "{" and + end = min(int i | start + 2 < i and this.getChar(i - 1) = "}") + } + + /** + * Holds if an escaped character is found between `start` and `end`. + * Escaped characters include hex values, octal values and named escapes, + * but excludes backreferences. + */ + predicate escapedCharacter(int start, int end) { + this.escapingChar(start) and + not this.backreference(start, _) and + ( + // hex value \xhh + this.getChar(start + 1) = "x" and + this.getChar(start + 2) != "{" and + end = start + 4 + or + // octal value \0o, \0oo, or \0ooo. Max of 0377. + this.getChar(start + 1) = "0" and + this.isOctal(start + 2) and + ( + if this.isOctal(start + 3) + then + if this.isOctal(start + 4) and this.getChar(start + 2) in ["0", "1", "2", "3"] + then end = start + 5 + else end = start + 4 + else end = start + 3 + ) + or + // 16-bit hex value \uhhhh + this.getChar(start + 1) = "u" and end = start + 6 + or + this.escapedBraces(start, end) + or + // Boundary matchers \b, \b{g} + this.getChar(start + 1) = "b" and + ( + if this.getText().substring(start + 2, start + 5) = "{g}" + then end = start + 5 + else end = start + 2 + ) + or + this.controlEscape(start, end) + or + // escape not handled above, update when adding a new case + not this.getChar(start + 1) in ["x", "0", "u", "p", "P", "N", "b", "c"] and + not exists(this.getChar(start + 1).toInt()) and + end = start + 2 + ) + } + + private string nonEscapedCharAt(int i) { + result = this.getChar(i) and + not exists(int x, int y | this.escapedCharacter(x, y) and i in [x .. y - 1]) and + not exists(int x, int y | this.quote(x, y) and i in [x .. y - 1]) + } + + /** Holds if a character set starts between `start` and `end`, including any negation character (`^`). */ + private predicate charSetStart0(int start, int end) { + this.nonEscapedCharAt(start) = "[" and + (if this.getChar(start + 1) = "^" then end = start + 2 else end = start + 1) + } + + /** Holds if the character at `pos` marks the end of a character class. */ + private predicate charSetEnd0(int pos) { + this.nonEscapedCharAt(pos) = "]" and + /* special case: `[]]` and `[^]]` are valid char classes. */ + not this.charSetStart0(_, pos) + } + + /** + * Holds if the character at `pos` starts a character set delimiter. + * Result is 1 for `[` and -1 for `]`. + */ + private int charSetDelimiter(int pos) { + result = 1 and this.charSetStart0(pos, _) + or + result = -1 and this.charSetEnd0(pos) + } + + /** + * Holds if the char at `pos` is the one-based `index`th occourence of a character set delimiter (`[` or `]`). + * Result is 1 for `[` and -1 for `]`. + */ + private int charSetDelimiter(int index, int pos) { + result = this.charSetDelimiter(pos) and + pos = rank[index](int p | exists(this.charSetDelimiter(p))) + } + + /** + * Gets the nesting depth of character classes after position `pos`, + * where `pos` is the position of a character set delimiter. + */ + private int charSetDepth(int index, int pos) { + index = 1 and result = 0.maximum(this.charSetDelimiter(index, pos)) + or + result = 0.maximum(this.charSetDelimiter(index, pos) + this.charSetDepth(index - 1, _)) + } + + /** Hold if a top-level character set starts between `start` and `end`. */ + predicate charSetStart(int start, int end) { + this.charSetStart0(start, end) and + this.charSetDepth(_, start) = 1 + } + + /** Holds if a top-level character set ends at `pos`. */ + predicate charSetEnd(int pos) { + this.charSetEnd0(pos) and + this.charSetDepth(_, pos) = 0 + } + + /** + * Holds if there is a top-level character class beginning at `start` (inclusive) and ending at `end` (exclusive) + * + * For now, nested character classes are approximated by only considering the top-level class for parsing. + * This leads to very similar results for ReDoS queries. + */ + predicate charSet(int start, int end) { + exists(int inner_start, int inner_end | this.charSetStart(start, inner_start) | + end = inner_end + 1 and + inner_end = + min(int end_delimiter | this.charSetEnd(end_delimiter) and end_delimiter > inner_start) + ) + } + + /** Either a char or a - */ + private predicate charSetToken(int charset_start, int start, int end) { + this.charSetStart(charset_start, start) and + ( + this.escapedCharacter(start, end) + or + exists(this.nonEscapedCharAt(start)) and end = start + 1 + or + this.quote(start, end) + ) + or + this.charSetToken(charset_start, _, start) and + ( + this.escapedCharacter(start, end) + or + exists(this.nonEscapedCharAt(start)) and + end = start + 1 and + not this.charSetEnd(start) + or + this.quote(start, end) + ) + } + + /** An indexed version of `charSetToken/3` */ + private predicate charSetToken(int charset_start, int index, int token_start, int token_end) { + token_start = rank[index](int start | this.charSetToken(charset_start, start, _) | start) and + this.charSetToken(charset_start, token_start, token_end) + } + + /** + * Helper predicate for `charRange`. + * We can determine where character ranges end by a left to right sweep. + * + * To avoid negative recursion we return a boolean. See `escaping`, + * the helper for `escapingChar`, for a clean use of this pattern. + */ + private boolean charRangeEnd(int charset_start, int index) { + this.charSetToken(charset_start, index, _, _) and + ( + index in [1, 2] and result = false + or + index > 2 and + exists(int connector_start | + this.charSetToken(charset_start, index - 1, connector_start, _) and + this.nonEscapedCharAt(connector_start) = "-" and + result = + this.charRangeEnd(charset_start, index - 2) + .booleanNot() + .booleanAnd(this.charRangeEnd(charset_start, index - 1).booleanNot()) + ) + or + not exists(int connector_start | + this.charSetToken(charset_start, index - 1, connector_start, _) and + this.nonEscapedCharAt(connector_start) = "-" + ) and + result = false + ) + } + + /** + * Holds if the character set starting at `charset_start` contains a character range + * with lower bound found between `start` and `lower_end` + * and upper bound found between `upper_start` and `end`. + */ + predicate charRange(int charset_start, int start, int lower_end, int upper_start, int end) { + exists(int index | + this.charRangeEnd(charset_start, index) = true and + this.charSetToken(charset_start, index - 2, start, lower_end) and + this.charSetToken(charset_start, index, upper_start, end) + ) + } + + /** + * Holds if the character set starting at `charset_start` contains either + * a character or a range found between `start` and `end`. + */ + predicate charSetChild(int charset_start, int start, int end) { + this.charSetToken(charset_start, start, end) and + not exists(int range_start, int range_end | + this.charRange(charset_start, range_start, _, _, range_end) and + range_start <= start and + range_end >= end + ) + or + this.charRange(charset_start, start, _, _, end) + } + + /** Holds if `index` is inside a character set. */ + predicate inCharSet(int index) { + exists(int x, int y | this.charSet(x, y) and index in [x + 1 .. y - 2]) + } + + /** + * 'simple' characters are any that don't alter the parsing of the regex. + */ + private predicate simpleCharacter(int start, int end) { + end = start + 1 and + not this.charSet(start, _) and + not this.charSet(_, start + 1) and + exists(string c | c = this.getChar(start) | + exists(int x, int y, int z | + this.charSet(x, z) and + this.charSetStart(x, y) + | + start = y + or + start = z - 2 + or + start > y and start < z - 2 and not this.charRange(_, _, start, end, _) + ) + or + not this.inCharSet(start) and + not c = "(" and + not c = "[" and + not c = ")" and + not c = "|" and + not c = "{" and + not exists(int qstart, int qend | this.quantifier(qstart, qend, _, _) | + qstart <= start and start < qend + ) + ) + } + + private predicate character(int start, int end) { + ( + this.simpleCharacter(start, end) and + not exists(int x, int y | this.escapedCharacter(x, y) and x <= start and y >= end) and + not exists(int x, int y | this.quote(x, y) and x <= start and y >= end) + or + this.escapedCharacter(start, end) + ) and + not exists(int x, int y | this.groupStart(x, y) and x <= start and y >= end) and + not exists(int x, int y | this.backreference(x, y) and x <= start and y >= end) + } + + /** Holds if a normal character or escape sequence is between `start` and `end`. */ + predicate normalCharacter(int start, int end) { + this.character(start, end) and + not this.specialCharacter(start, end, _) + } + + /** Holds if a special character `char` is between `start` and `end`. */ + predicate specialCharacter(int start, int end, string char) { + this.character(start, end) and + end = start + 1 and + char = this.getChar(start) and + (char = "$" or char = "^" or char = ".") and + not this.inCharSet(start) + } + + private predicate isGroupEnd(int i) { this.nonEscapedCharAt(i) = ")" and not this.inCharSet(i) } + + private predicate isGroupStart(int i) { this.nonEscapedCharAt(i) = "(" and not this.inCharSet(i) } + + /** Holds if an empty group is found between `start` and `end`. */ + predicate emptyGroup(int start, int end) { + exists(int endm1 | end = endm1 + 1 | + this.groupStart(start, endm1) and + this.isGroupEnd(endm1) + ) + } + + private predicate nonCapturingGroupStart(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + this.getChar(start + 2) = ":" and + end = start + 3 + } + + private predicate simpleGroupStart(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) != "?" and + end = start + 1 + } + + private predicate namedGroupStart(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + this.getChar(start + 2) = "<" and + not this.getChar(start + 3) = "=" and + not this.getChar(start + 3) = "!" and + exists(int name_end | + name_end = min(int i | i > start + 3 and this.getChar(i) = ">") and + end = name_end + 1 + ) + } + + private predicate flagGroupStart(int start, int end, string c) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + end = start + 3 and + c = this.getChar(start + 2) and + c in ["i", "m", "s", "u", "x", "U"] + } + + /** + * Gets the mode of this regular expression string if + * it is defined by a prefix. + */ + string getModeFromPrefix() { + exists(string c | this.flagGroupStart(_, _, c) | + c = "i" and result = "IGNORECASE" + or + c = "m" and result = "MULTILINE" + or + c = "s" and result = "DOTALL" + or + c = "u" and result = "UNICODE" + or + c = "x" and result = "VERBOSE" + or + c = "U" and result = "UNICODECLASS" + ) + } + + private predicate lookaheadAssertionStart(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + this.getChar(start + 2) = "=" and + end = start + 3 + } + + private predicate negativeLookaheadAssertionStart(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + this.getChar(start + 2) = "!" and + end = start + 3 + } + + private predicate lookbehindAssertionStart(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + this.getChar(start + 2) = "<" and + this.getChar(start + 3) = "=" and + end = start + 4 + } + + private predicate negativeLookbehindAssertionStart(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + this.getChar(start + 2) = "<" and + this.getChar(start + 3) = "!" and + end = start + 4 + } + + private predicate atomicGroupStart(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + this.getChar(start + 2) = ">" and + end = start + 3 + } + + private predicate groupStart(int start, int end) { + this.nonCapturingGroupStart(start, end) + or + this.flagGroupStart(start, end, _) + or + this.namedGroupStart(start, end) + or + this.lookaheadAssertionStart(start, end) + or + this.negativeLookaheadAssertionStart(start, end) + or + this.lookbehindAssertionStart(start, end) + or + this.negativeLookbehindAssertionStart(start, end) + or + this.atomicGroupStart(start, end) + or + this.simpleGroupStart(start, end) + } + + /** Holds if the text in the range start,end is a group with contents in the range in_start,in_end */ + predicate groupContents(int start, int end, int in_start, int in_end) { + this.groupStart(start, in_start) and + end = in_end + 1 and + this.topLevel(in_start, in_end) and + this.isGroupEnd(in_end) + } + + /** Holds if the text in the range start,end is a group */ + predicate group(int start, int end) { + this.groupContents(start, end, _, _) + or + this.emptyGroup(start, end) + } + + /** Gets the number of the group in start,end */ + int getGroupNumber(int start, int end) { + this.group(start, end) and + result = + count(int i | this.group(i, _) and i < start and not this.nonCapturingGroupStart(i, _)) + 1 + } + + /** Gets the name, if it has one, of the group in start,end */ + string getGroupName(int start, int end) { + this.group(start, end) and + exists(int name_end | + this.namedGroupStart(start, name_end) and + result = this.getText().substring(start + 3, name_end - 1) + ) + } + + /** Holds if a negative lookahead is found between `start` and `end` */ + predicate negativeLookaheadAssertionGroup(int start, int end) { + exists(int in_start | this.negativeLookaheadAssertionStart(start, in_start) | + this.groupContents(start, end, in_start, _) + ) + } + + /** Holds if a negative lookbehind is found between `start` and `end` */ + predicate negativeLookbehindAssertionGroup(int start, int end) { + exists(int in_start | this.negativeLookbehindAssertionStart(start, in_start) | + this.groupContents(start, end, in_start, _) + ) + } + + private predicate negativeAssertionGroup(int start, int end) { + exists(int in_start | + this.negativeLookaheadAssertionStart(start, in_start) + or + this.negativeLookbehindAssertionStart(start, in_start) + | + this.groupContents(start, end, in_start, _) + ) + } + + /** Holds if a positive lookahead is found between `start` and `end` */ + predicate positiveLookaheadAssertionGroup(int start, int end) { + exists(int in_start | this.lookaheadAssertionStart(start, in_start) | + this.groupContents(start, end, in_start, _) + ) + } + + /** Holds if a positive lookbehind is found between `start` and `end` */ + predicate positiveLookbehindAssertionGroup(int start, int end) { + exists(int in_start | this.lookbehindAssertionStart(start, in_start) | + this.groupContents(start, end, in_start, _) + ) + } + + /** Holds if the text in the range start, end is a group and can match the empty string. */ + predicate zeroWidthMatch(int start, int end) { + this.emptyGroup(start, end) + or + this.negativeAssertionGroup(start, end) + or + this.positiveLookaheadAssertionGroup(start, end) + or + this.positiveLookbehindAssertionGroup(start, end) + } + + private predicate baseItem(int start, int end) { + this.character(start, end) and + not exists(int x, int y | this.charSet(x, y) and x <= start and y >= end) + or + this.group(start, end) + or + this.charSet(start, end) + or + this.backreference(start, end) + or + this.quote(start, end) + } + + private predicate shortQuantifier( + int start, int end, boolean maybe_empty, boolean may_repeat_forever + ) { + ( + this.getChar(start) = "+" and maybe_empty = false and may_repeat_forever = true + or + this.getChar(start) = "*" and maybe_empty = true and may_repeat_forever = true + or + this.getChar(start) = "?" and maybe_empty = true and may_repeat_forever = false + ) and + end = start + 1 + or + exists(string lower, string upper | + this.multiples(start, end, lower, upper) and + (if lower = "" or lower.toInt() = 0 then maybe_empty = true else maybe_empty = false) and + if upper = "" then may_repeat_forever = true else may_repeat_forever = false + ) + } + + /** + * Holds if a repetition quantifier is found between `start` and `end`, + * with the given lower and upper bounds. If a bound is omitted, the corresponding + * string is empty. + */ + predicate multiples(int start, int end, string lower, string upper) { + exists(string text, string match, string inner | + text = this.getText() and + end = start + match.length() and + inner = match.substring(1, match.length() - 1) + | + match = text.regexpFind("\\{[0-9]+\\}", _, start) and + lower = inner and + upper = lower + or + match = text.regexpFind("\\{[0-9]*,[0-9]*\\}", _, start) and + exists(int commaIndex | + commaIndex = inner.indexOf(",") and + lower = inner.prefix(commaIndex) and + upper = inner.suffix(commaIndex + 1) + ) + ) + } + + private predicate quantifier(int start, int end, boolean maybe_empty, boolean may_repeat_forever) { + this.shortQuantifier(start, end, maybe_empty, may_repeat_forever) and + not this.getChar(end) = ["?", "+"] + or + exists(int short_end | this.shortQuantifier(start, short_end, maybe_empty, may_repeat_forever) | + if this.getChar(short_end) = ["?", "+"] then end = short_end + 1 else end = short_end + ) + } + + /** + * Holds if a quantified part is found between `start` and `part_end` and the quantifier is + * found between `part_end` and `end`. + * + * `maybe_empty` is true if the part is optional. + * `may_repeat_forever` is true if the part may be repeated unboundedly. + */ + predicate quantifiedPart( + int start, int part_end, int end, boolean maybe_empty, boolean may_repeat_forever + ) { + this.baseItem(start, part_end) and + this.quantifier(part_end, end, maybe_empty, may_repeat_forever) + } + + /** + * Holds if the text in the range start,end is a quantified item, where item is a character, + * a character set or a group. + */ + predicate quantifiedItem(int start, int end, boolean maybe_empty, boolean may_repeat_forever) { + this.quantifiedPart(start, _, end, maybe_empty, may_repeat_forever) + } + + /** Holds if the range `start`, `end` contains a character, a quantifier, a character set or a group. */ + predicate item(int start, int end) { + this.quantifiedItem(start, end, _, _) + or + this.baseItem(start, end) and not this.quantifier(end, _, _, _) + } + + private predicate itemStart(int start) { + this.character(start, _) or + this.isGroupStart(start) or + this.charSet(start, _) or + this.backreference(start, _) or + this.quote(start, _) + } + + private predicate itemEnd(int end) { + this.character(_, end) + or + exists(int endm1 | this.isGroupEnd(endm1) and end = endm1 + 1) + or + this.charSet(_, end) + or + this.quantifier(_, end, _, _) + or + this.quote(_, end) + } + + private predicate isOptionDivider(int i) { this.nonEscapedCharAt(i) = "|" } + + private predicate subsequence(int start, int end) { + ( + start = 0 or + this.groupStart(_, start) or + this.isOptionDivider(start - 1) + ) and + this.item(start, end) + or + exists(int mid | + this.subsequence(start, mid) and + this.item(mid, end) + ) + } + + private predicate sequenceOrQuantified(int start, int end) { + this.subsequence(start, end) and + not this.itemStart(end) + } + + /** + * Holds if the text in the range start,end is a sequence of 1 or more items, where an item is a character, + * a character set or a group. + */ + predicate sequence(int start, int end) { + this.sequenceOrQuantified(start, end) and + not this.quantifiedItem(start, end, _, _) + } + + private predicate subalternation(int start, int end, int itemStart) { + this.sequenceOrQuantified(start, end) and + not this.isOptionDivider(start - 1) and + itemStart = start + or + start = end and + not this.itemEnd(start) and + this.isOptionDivider(end) and + itemStart = start + or + exists(int mid | + this.subalternation(start, mid, _) and + this.isOptionDivider(mid) and + itemStart = mid + 1 + | + this.sequenceOrQuantified(itemStart, end) + or + not this.itemStart(end) and end = itemStart + ) + } + + private predicate topLevel(int start, int end) { + not this.inCharSet(start) and + this.subalternation(start, end, _) and + not this.isOptionDivider(end) + } + + /** + * Holds if the text in the range start,end is an alternation + */ + predicate alternation(int start, int end) { + this.topLevel(start, end) and + exists(int less | this.subalternation(start, less, _) and less < end) + } + + /** + * Holds if the text in the range start,end is an alternation and the text in part_start, part_end is one of the + * options in that alternation. + */ + predicate alternationOption(int start, int end, int part_start, int part_end) { + this.alternation(start, end) and + this.subalternation(start, part_end, part_start) + } + + /** + * Gets the `i`th character of this literal as it was written in the source code. + */ + string getSourceChar(int i) { result = this.(StringLiteral).getLiteral().charAt(i) } + + /** + * Helper predicate for `sourceEscapingChar` that + * results in a boolean in order to avoid negative recursion. + */ + private boolean sourceEscaping(int pos) { + pos = -1 and result = false + or + this.getSourceChar(pos) = "\\" and + result = this.sourceEscaping(pos - 1).booleanNot() + or + this.getSourceChar(pos) != "\\" and result = false + } + + /** + * Equivalent of `escapingChar` for the literal source rather than the string value. + * Holds if the character at position `pos` in the source literal is a '\' that is + * actually escaping what comes after it. + */ + private predicate sourceEcapingChar(int pos) { this.sourceEscaping(pos) = true } + + /** + * Holds if an escaped character exists between `start` and `end` in the source iteral. + */ + private predicate sourceEscapedCharacter(int start, int end) { + this.sourceEcapingChar(start) and + (if this.getSourceChar(start + 1) = "u" then end = start + 6 else end = start + 2) + } + + private predicate sourceNonEscapedCharacter(int i) { + exists(this.getSourceChar(i)) and + not exists(int x, int y | this.sourceEscapedCharacter(x, y) and i in [x .. y - 1]) + } + + /** + * Holds if a character is represented between `start` and `end` in the source literal. + */ + private predicate sourceCharacter(int start, int end) { + this.sourceEscapedCharacter(start, end) + or + this.sourceNonEscapedCharacter(start) and + end = start + 1 + } + + /** + * Holds if the `i`th character of the string is represented between offsets + * `start` (inclusive) and `end` (exclusive) in the source code of this literal. + * This only gives correct results if the literal is written as a normal single-line string literal; + * without compile-time concatenation involved. + */ + predicate sourceCharacter(int pos, int start, int end) { + exists(this.getChar(pos)) and + this.sourceCharacter(start, end) and + start = rank[pos + 2](int s | this.sourceCharacter(s, _)) + } +} + +/** A string literal used as a regular expression */ +class Regex extends RegexString { + boolean matches_full_string; + + Regex() { usedAsRegex(this, _, matches_full_string) } + + /** + * Gets a mode (if any) of this regular expression. Can be any of: + * DEBUG + * IGNORECASE + * MULTILINE + * DOTALL + * UNICODE + * VERBOSE + * UNICODECLASS + */ + string getAMode() { + result != "None" and + usedAsRegex(this, result, _) + or + result = this.getModeFromPrefix() + } + + /** + * Holds if this regex is used to match against a full string, + * as though it was implicitly surrounded by ^ and $. + */ + predicate matchesFullString() { matches_full_string = true } +} diff --git a/java/ql/lib/semmle/code/java/security/AndroidIntentRedirection.qll b/java/ql/lib/semmle/code/java/security/AndroidIntentRedirection.qll index 4a89b59f8c9..c549784ccbf 100644 --- a/java/ql/lib/semmle/code/java/security/AndroidIntentRedirection.qll +++ b/java/ql/lib/semmle/code/java/security/AndroidIntentRedirection.qll @@ -65,16 +65,24 @@ private class DefaultIntentRedirectionSink extends IntentRedirectionSink { } /** - * A default sanitizer for nodes dominated by calls to `ComponentName.getPackageName` - * or `ComponentName.getClassName`. These are used to check whether the origin or destination + * A default sanitizer for `Intent` nodes dominated by calls to `ComponentName.getPackageName` + * and `ComponentName.getClassName`. These are used to check whether the origin or destination * components are trusted. */ private class DefaultIntentRedirectionSanitizer extends IntentRedirectionSanitizer { DefaultIntentRedirectionSanitizer() { + this.getType() instanceof TypeIntent and exists(MethodAccess ma, Method m, Guard g, boolean branch | ma.getMethod() = m and m.getDeclaringType() instanceof TypeComponentName and - m.hasName(["getPackageName", "getClassName"]) and + m.hasName("getPackageName") and + g.isEquality(ma, _, branch) and + g.controls(this.asExpr().getBasicBlock(), branch) + ) and + exists(MethodAccess ma, Method m, Guard g, boolean branch | + ma.getMethod() = m and + m.getDeclaringType() instanceof TypeComponentName and + m.hasName("getClassName") and g.isEquality(ma, _, branch) and g.controls(this.asExpr().getBasicBlock(), branch) ) diff --git a/java/ql/lib/semmle/code/java/security/JexlInjectionQuery.qll b/java/ql/lib/semmle/code/java/security/JexlInjectionQuery.qll index 9e70be5c12f..655f78abcba 100644 --- a/java/ql/lib/semmle/code/java/security/JexlInjectionQuery.qll +++ b/java/ql/lib/semmle/code/java/security/JexlInjectionQuery.qll @@ -1,4 +1,4 @@ -/** Provides classes to reason about Expression Langauge (JEXL) injection vulnerabilities. */ +/** Provides classes to reason about Expression Language (JEXL) injection vulnerabilities. */ import java import semmle.code.java.dataflow.TaintTracking diff --git a/java/ql/lib/semmle/code/java/security/JexlInjectionSinkModels.qll b/java/ql/lib/semmle/code/java/security/JexlInjectionSinkModels.qll index aeffc160bfd..8f95ca406aa 100644 --- a/java/ql/lib/semmle/code/java/security/JexlInjectionSinkModels.qll +++ b/java/ql/lib/semmle/code/java/security/JexlInjectionSinkModels.qll @@ -1,4 +1,4 @@ -/** Provides sink models relating to Expression Langauge (JEXL) injection vulnerabilities. */ +/** Provides sink models relating to Expression Language (JEXL) injection vulnerabilities. */ private import semmle.code.java.dataflow.ExternalFlow diff --git a/java/ql/lib/semmle/code/java/security/SensitiveLoggingQuery.qll b/java/ql/lib/semmle/code/java/security/SensitiveLoggingQuery.qll index 7c87cec5aa5..0eebd1c79fe 100644 --- a/java/ql/lib/semmle/code/java/security/SensitiveLoggingQuery.qll +++ b/java/ql/lib/semmle/code/java/security/SensitiveLoggingQuery.qll @@ -4,14 +4,15 @@ import java private import semmle.code.java.dataflow.ExternalFlow import semmle.code.java.dataflow.TaintTracking import semmle.code.java.security.SensitiveActions +import semmle.code.java.frameworks.android.Compose import DataFlow -/** A variable that may hold sensitive information, judging by its name. * */ +/** A variable that may hold sensitive information, judging by its name. */ class CredentialExpr extends Expr { CredentialExpr() { exists(Variable v | this = v.getAnAccess() | - v.getName().regexpMatch([getCommonSensitiveInfoRegex(), "(?i).*(username).*"]) and - not v.isFinal() + v.getName().regexpMatch(getCommonSensitiveInfoRegex()) and + not this instanceof CompileTimeConstantExpr ) } } @@ -23,4 +24,8 @@ class SensitiveLoggerConfiguration extends TaintTracking::Configuration { override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CredentialExpr } override predicate isSink(DataFlow::Node sink) { sinkNode(sink, "logging") } + + override predicate isSanitizer(DataFlow::Node sanitizer) { + sanitizer.asExpr() instanceof LiveLiteral + } } diff --git a/java/ql/lib/semmle/code/java/security/XmlParsers.qll b/java/ql/lib/semmle/code/java/security/XmlParsers.qll index 2bd743da2b7..e67aea657ff 100644 --- a/java/ql/lib/semmle/code/java/security/XmlParsers.qll +++ b/java/ql/lib/semmle/code/java/security/XmlParsers.qll @@ -1049,7 +1049,7 @@ class SafeTransformerFactory extends VarAccess { } } -/** A `Transformer` created from a safely configured `TranformerFactory`. */ +/** A `Transformer` created from a safely configured `TransformerFactory`. */ class SafeTransformer extends MethodAccess { SafeTransformer() { exists(SafeTransformerFactoryFlowConfig stf, Method m | diff --git a/java/ql/lib/semmle/code/java/security/performance/ExponentialBackTracking.qll b/java/ql/lib/semmle/code/java/security/performance/ExponentialBackTracking.qll new file mode 100644 index 00000000000..99b4062dfdc --- /dev/null +++ b/java/ql/lib/semmle/code/java/security/performance/ExponentialBackTracking.qll @@ -0,0 +1,371 @@ +/** + * This library implements the analysis described in the following two papers: + * + * James Kirrage, Asiri Rathnayake, Hayo Thielecke: Static Analysis for + * Regular Expression Denial-of-Service Attacks. NSS 2013. + * (http://www.cs.bham.ac.uk/~hxt/research/reg-exp-sec.pdf) + * Asiri Rathnayake, Hayo Thielecke: Static Analysis for Regular Expression + * Exponential Runtime via Substructural Logics. 2014. + * (https://www.cs.bham.ac.uk/~hxt/research/redos_full.pdf) + * + * The basic idea is to search for overlapping cycles in the NFA, that is, + * states `q` such that there are two distinct paths from `q` to itself + * that consume the same word `w`. + * + * For any such state `q`, an attack string can be constructed as follows: + * concatenate a prefix `v` that takes the NFA to `q` with `n` copies of + * the word `w` that leads back to `q` along two different paths, followed + * by a suffix `x` that is _not_ accepted in state `q`. A backtracking + * implementation will need to explore at least 2^n different ways of going + * from `q` back to itself while trying to match the `n` copies of `w` + * before finally giving up. + * + * Now in order to identify overlapping cycles, all we have to do is find + * pumpable forks, that is, states `q` that can transition to two different + * states `r1` and `r2` on the same input symbol `c`, such that there are + * paths from both `r1` and `r2` to `q` that consume the same word. The latter + * condition is equivalent to saying that `(q, q)` is reachable from `(r1, r2)` + * in the product NFA. + * + * This is what the library does. It makes a simple attempt to construct a + * prefix `v` leading into `q`, but only to improve the alert message. + * And the library tries to prove the existence of a suffix that ensures + * rejection. This check might fail, which can cause false positives. + * + * Finally, sometimes it depends on the translation whether the NFA generated + * for a regular expression has a pumpable fork or not. We implement one + * particular translation, which may result in false positives or negatives + * relative to some particular JavaScript engine. + * + * More precisely, the library constructs an NFA from a regular expression `r` + * as follows: + * + * * Every sub-term `t` gives rise to an NFA state `Match(t,i)`, representing + * the state of the automaton before attempting to match the `i`th character in `t`. + * * There is one accepting state `Accept(r)`. + * * There is a special `AcceptAnySuffix(r)` state, which accepts any suffix string + * by using an epsilon transition to `Accept(r)` and an any transition to itself. + * * Transitions between states may be labelled with epsilon, or an abstract + * input symbol. + * * Each abstract input symbol represents a set of concrete input characters: + * either a single character, a set of characters represented by a + * character class, or the set of all characters. + * * The product automaton is constructed lazily, starting with pair states + * `(q, q)` where `q` is a fork, and proceeding along an over-approximate + * step relation. + * * The over-approximate step relation allows transitions along pairs of + * abstract input symbols where the symbols have overlap in the characters they accept. + * * Once a trace of pairs of abstract input symbols that leads from a fork + * back to itself has been identified, we attempt to construct a concrete + * string corresponding to it, which may fail. + * * Lastly we ensure that any state reached by repeating `n` copies of `w` has + * a suffix `x` (possible empty) that is most likely __not__ accepted. + */ + +import ReDoSUtil + +/** + * Holds if state `s` might be inside a backtracking repetition. + */ +pragma[noinline] +private predicate stateInsideBacktracking(State s) { + s.getRepr().getParent*() instanceof MaybeBacktrackingRepetition +} + +/** + * A infinitely repeating quantifier that might backtrack. + */ +private class MaybeBacktrackingRepetition extends InfiniteRepetitionQuantifier { + MaybeBacktrackingRepetition() { + exists(RegExpTerm child | + child instanceof RegExpAlt or + child instanceof RegExpQuantifier + | + child.getParent+() = this + ) + } +} + +/** + * A state in the product automaton. + */ +private newtype TStatePair = + /** + * We lazily only construct those states that we are actually + * going to need: `(q, q)` for every fork state `q`, and any + * pair of states that can be reached from a pair that we have + * already constructed. To cut down on the number of states, + * we only represent states `(q1, q2)` where `q1` is lexicographically + * no bigger than `q2`. + * + * States are only constructed if both states in the pair are + * inside a repetition that might backtrack. + */ + MkStatePair(State q1, State q2) { + isFork(q1, _, _, _, _) and q2 = q1 + or + (step(_, _, _, q1, q2) or step(_, _, _, q2, q1)) and + rankState(q1) <= rankState(q2) + } + +/** + * Gets a unique number for a `state`. + * Is used to create an ordering of states, where states with the same `toString()` will be ordered differently. + */ +private int rankState(State state) { + state = + rank[result](State s, Location l | + l = s.getRepr().getLocation() + | + s order by l.getStartLine(), l.getStartColumn(), s.toString() + ) +} + +/** + * A state in the product automaton. + */ +private class StatePair extends TStatePair { + State q1; + State q2; + + StatePair() { this = MkStatePair(q1, q2) } + + /** Gets a textual representation of this element. */ + string toString() { result = "(" + q1 + ", " + q2 + ")" } + + /** Gets the first component of the state pair. */ + State getLeft() { result = q1 } + + /** Gets the second component of the state pair. */ + State getRight() { result = q2 } +} + +/** + * Holds for all constructed state pairs. + * + * Used in `statePairDist` + */ +private predicate isStatePair(StatePair p) { any() } + +/** + * Holds if there are transitions from the components of `q` to the corresponding + * components of `r`. + * + * Used in `statePairDist` + */ +private predicate delta2(StatePair q, StatePair r) { step(q, _, _, r) } + +/** + * Gets the minimum length of a path from `q` to `r` in the + * product automaton. + */ +private int statePairDist(StatePair q, StatePair r) = + shortestDistances(isStatePair/1, delta2/2)(q, r, result) + +/** + * Holds if there are transitions from `q` to `r1` and from `q` to `r2` + * labelled with `s1` and `s2`, respectively, where `s1` and `s2` do not + * trivially have an empty intersection. + * + * This predicate only holds for states associated with regular expressions + * that have at least one repetition quantifier in them (otherwise the + * expression cannot be vulnerable to ReDoS attacks anyway). + */ +pragma[noopt] +private predicate isFork(State q, InputSymbol s1, InputSymbol s2, State r1, State r2) { + stateInsideBacktracking(q) and + exists(State q1, State q2 | + q1 = epsilonSucc*(q) and + delta(q1, s1, r1) and + q2 = epsilonSucc*(q) and + delta(q2, s2, r2) and + // Use pragma[noopt] to prevent intersect(s1,s2) from being the starting point of the join. + // From (s1,s2) it would find a huge number of intermediate state pairs (q1,q2) originating from different literals, + // and discover at the end that no `q` can reach both `q1` and `q2` by epsilon transitions. + exists(intersect(s1, s2)) + | + s1 != s2 + or + r1 != r2 + or + r1 = r2 and q1 != q2 + or + // If q can reach itself by epsilon transitions, then there are two distinct paths to the q1/q2 state: + // one that uses the loop and one that doesn't. The engine will separately attempt to match with each path, + // despite ending in the same state. The "fork" thus arises from the choice of whether to use the loop or not. + // To avoid every state in the loop becoming a fork state, + // we arbitrarily pick the InfiniteRepetitionQuantifier state as the canonical fork state for the loop + // (every epsilon-loop must contain such a state). + // + // We additionally require that the there exists another InfiniteRepetitionQuantifier `mid` on the path from `q` to itself. + // This is done to avoid flagging regular expressions such as `/(a?)*b/` - that only has polynomial runtime, and is detected by `js/polynomial-redos`. + // The below code is therefore a heuritic, that only flags regular expressions such as `/(a*)*b/`, + // and does not flag regular expressions such as `/(a?b?)c/`, but the latter pattern is not used frequently. + r1 = r2 and + q1 = q2 and + epsilonSucc+(q) = q and + exists(RegExpTerm term | term = q.getRepr() | term instanceof InfiniteRepetitionQuantifier) and + // One of the mid states is an infinite quantifier itself + exists(State mid, RegExpTerm term | + mid = epsilonSucc+(q) and + term = mid.getRepr() and + term instanceof InfiniteRepetitionQuantifier and + q = epsilonSucc+(mid) and + not mid = q + ) + ) and + stateInsideBacktracking(r1) and + stateInsideBacktracking(r2) +} + +/** + * Gets the state pair `(q1, q2)` or `(q2, q1)`; note that only + * one or the other is defined. + */ +private StatePair mkStatePair(State q1, State q2) { + result = MkStatePair(q1, q2) or result = MkStatePair(q2, q1) +} + +/** + * Holds if there are transitions from the components of `q` to the corresponding + * components of `r` labelled with `s1` and `s2`, respectively. + */ +private predicate step(StatePair q, InputSymbol s1, InputSymbol s2, StatePair r) { + exists(State r1, State r2 | step(q, s1, s2, r1, r2) and r = mkStatePair(r1, r2)) +} + +/** + * Holds if there are transitions from the components of `q` to `r1` and `r2` + * labelled with `s1` and `s2`, respectively. + * + * We only consider transitions where the resulting states `(r1, r2)` are both + * inside a repetition that might backtrack. + */ +pragma[noopt] +private predicate step(StatePair q, InputSymbol s1, InputSymbol s2, State r1, State r2) { + exists(State q1, State q2 | q.getLeft() = q1 and q.getRight() = q2 | + deltaClosed(q1, s1, r1) and + deltaClosed(q2, s2, r2) and + // use noopt to force the join on `intersect` to happen last. + exists(intersect(s1, s2)) + ) and + stateInsideBacktracking(r1) and + stateInsideBacktracking(r2) +} + +private newtype TTrace = + Nil() or + Step(InputSymbol s1, InputSymbol s2, TTrace t) { + exists(StatePair p | + isReachableFromFork(_, p, t, _) and + step(p, s1, s2, _) + ) + or + t = Nil() and isFork(_, s1, s2, _, _) + } + +/** + * A list of pairs of input symbols that describe a path in the product automaton + * starting from some fork state. + */ +private class Trace extends TTrace { + /** Gets a textual representation of this element. */ + string toString() { + this = Nil() and result = "Nil()" + or + exists(InputSymbol s1, InputSymbol s2, Trace t | this = Step(s1, s2, t) | + result = "Step(" + s1 + ", " + s2 + ", " + t + ")" + ) + } +} + +/** + * Holds if `r` is reachable from `(fork, fork)` under input `w`, and there is + * a path from `r` back to `(fork, fork)` with `rem` steps. + */ +private predicate isReachableFromFork(State fork, StatePair r, Trace w, int rem) { + // base case + exists(InputSymbol s1, InputSymbol s2, State q1, State q2 | + isFork(fork, s1, s2, q1, q2) and + r = MkStatePair(q1, q2) and + w = Step(s1, s2, Nil()) and + rem = statePairDist(r, MkStatePair(fork, fork)) + ) + or + // recursive case + exists(StatePair p, Trace v, InputSymbol s1, InputSymbol s2 | + isReachableFromFork(fork, p, v, rem + 1) and + step(p, s1, s2, r) and + w = Step(s1, s2, v) and + rem >= statePairDist(r, MkStatePair(fork, fork)) + ) +} + +/** + * Gets a state in the product automaton from which `(fork, fork)` is + * reachable in zero or more epsilon transitions. + */ +private StatePair getAForkPair(State fork) { + isFork(fork, _, _, _, _) and + result = MkStatePair(epsilonPred*(fork), epsilonPred*(fork)) +} + +private predicate hasSuffix(Trace suffix, Trace t, int i) { + // Declaring `t` to be a `RelevantTrace` currently causes a redundant check in the + // recursive case, so instead we check it explicitly here. + t instanceof RelevantTrace and + i = 0 and + suffix = t + or + hasSuffix(Step(_, _, suffix), t, i - 1) +} + +pragma[noinline] +private predicate hasTuple(InputSymbol s1, InputSymbol s2, Trace t, int i) { + hasSuffix(Step(s1, s2, _), t, i) +} + +private class RelevantTrace extends Trace, Step { + RelevantTrace() { + exists(State fork, StatePair q | + isReachableFromFork(fork, q, this, _) and + q = getAForkPair(fork) + ) + } + + pragma[noinline] + private string intersect(int i) { + exists(InputSymbol s1, InputSymbol s2 | + hasTuple(s1, s2, this, i) and + result = intersect(s1, s2) + ) + } + + /** Gets a string corresponding to this trace. */ + // the pragma is needed for the case where `intersect(s1, s2)` has multiple values, + // not for recursion + language[monotonicAggregates] + string concretise() { + result = strictconcat(int i | hasTuple(_, _, this, i) | this.intersect(i) order by i desc) + } +} + +/** + * Holds if `fork` is a pumpable fork with word `w`. + */ +private predicate isPumpable(State fork, string w) { + exists(StatePair q, RelevantTrace t | + isReachableFromFork(fork, q, t, _) and + q = getAForkPair(fork) and + w = t.concretise() + ) +} + +/** + * An instantiation of `ReDoSConfiguration` for exponential backtracking. + */ +class ExponentialReDoSConfiguration extends ReDoSConfiguration { + ExponentialReDoSConfiguration() { this = "ExponentialReDoSConfiguration" } + + override predicate isReDoSCandidate(State state, string pump) { isPumpable(state, pump) } +} diff --git a/java/ql/lib/semmle/code/java/security/performance/PolynomialReDoSQuery.qll b/java/ql/lib/semmle/code/java/security/performance/PolynomialReDoSQuery.qll new file mode 100644 index 00000000000..2a33e15c74a --- /dev/null +++ b/java/ql/lib/semmle/code/java/security/performance/PolynomialReDoSQuery.qll @@ -0,0 +1,56 @@ +/** Definitions and configurations for the Polynomial ReDoS query */ + +import semmle.code.java.security.performance.SuperlinearBackTracking +import semmle.code.java.dataflow.DataFlow +import semmle.code.java.regex.RegexTreeView +import semmle.code.java.regex.RegexFlowConfigs +import semmle.code.java.dataflow.FlowSources + +/** A sink for polynomial redos queries, where a regex is matched. */ +class PolynomialRedosSink extends DataFlow::Node { + RegExpLiteral reg; + + PolynomialRedosSink() { regexMatchedAgainst(reg.getRegex(), this.asExpr()) } + + /** Gets the regex that is matched against this node. */ + RegExpTerm getRegExp() { result.getParent() = reg } +} + +/** + * A method whose result typically has a limited length, + * such as HTTP headers, and values derrived from them. + */ +private class LengthRestrictedMethod extends Method { + LengthRestrictedMethod() { + this.getName().toLowerCase().matches(["%header%", "%requesturi%", "%requesturl%", "%cookie%"]) + or + this.getDeclaringType().getName().toLowerCase().matches("%cookie%") and + this.getName().matches("get%") + or + this.getDeclaringType().getName().toLowerCase().matches("%request%") and + this.getName().toLowerCase().matches(["%get%path%", "get%user%", "%querystring%"]) + } +} + +/** A configuration for Polynomial ReDoS queries. */ +class PolynomialRedosConfig extends TaintTracking::Configuration { + PolynomialRedosConfig() { this = "PolynomialRedosConfig" } + + override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof PolynomialRedosSink } + + override predicate isSanitizer(DataFlow::Node node) { + node.getType() instanceof PrimitiveType or + node.getType() instanceof BoxedType or + node.asExpr().(MethodAccess).getMethod() instanceof LengthRestrictedMethod + } +} + +/** Holds if there is flow from `source` to `sink` that is matched against the regexp term `regexp` that is vulnerable to Polynomial ReDoS. */ +predicate hasPolynomialReDoSResult( + DataFlow::PathNode source, DataFlow::PathNode sink, PolynomialBackTrackingTerm regexp +) { + any(PolynomialRedosConfig config).hasFlowPath(source, sink) and + regexp.getRootTerm() = sink.getNode().(PolynomialRedosSink).getRegExp() +} diff --git a/java/ql/lib/semmle/code/java/security/performance/ReDoSUtil.qll b/java/ql/lib/semmle/code/java/security/performance/ReDoSUtil.qll new file mode 100644 index 00000000000..8aa348bf62f --- /dev/null +++ b/java/ql/lib/semmle/code/java/security/performance/ReDoSUtil.qll @@ -0,0 +1,1198 @@ +/** + * Provides classes for working with regular expressions that can + * perform backtracking in superlinear/exponential time. + * + * This module contains a number of utility predicates for compiling a regular expression into a NFA and reasoning about this NFA. + * + * The `ReDoSConfiguration` contains a `isReDoSCandidate` predicate that is used to + * to determine which states the prefix/suffix search should happen on. + * There is only meant to exist one `ReDoSConfiguration` at a time. + * + * The predicate `hasReDoSResult` outputs a de-duplicated set of + * states that will cause backtracking (a rejecting suffix exists). + */ + +import ReDoSUtilSpecific + +/** + * A configuration for which parts of a regular expression should be considered relevant for + * the different predicates in `ReDoS.qll`. + * Used to adjust the computations for either superlinear or exponential backtracking. + */ +abstract class ReDoSConfiguration extends string { + bindingset[this] + ReDoSConfiguration() { any() } + + /** + * Holds if `state` with the pump string `pump` is a candidate for a + * ReDoS vulnerable state. + * This is used to determine which states are considered for the prefix/suffix construction. + */ + abstract predicate isReDoSCandidate(State state, string pump); +} + +/** + * Holds if repeating `pump` starting at `state` is a candidate for causing backtracking. + * No check whether a rejected suffix exists has been made. + */ +private predicate isReDoSCandidate(State state, string pump) { + any(ReDoSConfiguration conf).isReDoSCandidate(state, pump) and + ( + not any(ReDoSConfiguration conf).isReDoSCandidate(epsilonSucc+(state), _) + or + epsilonSucc+(state) = state and + state = + max(State s, Location l | + s = epsilonSucc+(state) and + l = s.getRepr().getLocation() and + any(ReDoSConfiguration conf).isReDoSCandidate(s, _) and + s.getRepr() instanceof InfiniteRepetitionQuantifier + | + s order by l.getStartLine(), l.getStartColumn(), l.getEndColumn(), l.getEndLine() + ) + ) +} + +/** + * Gets the char after `c` (from a simplified ASCII table). + */ +private string nextChar(string c) { exists(int code | code = ascii(c) | code + 1 = ascii(result)) } + +/** + * Gets an approximation for the ASCII code for `char`. + * Only the easily printable chars are included (so no newline, tab, null, etc). + */ +private int ascii(string char) { + char = + rank[result](string c | + c = + "! \"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" + .charAt(_) + ) +} + +/** + * Holds if `t` matches at least an epsilon symbol. + * + * That is, this term does not restrict the language of the enclosing regular expression. + * + * This is implemented as an under-approximation, and this predicate does not hold for sub-patterns in particular. + */ +predicate matchesEpsilon(RegExpTerm t) { + t instanceof RegExpStar + or + t instanceof RegExpOpt + or + t.(RegExpRange).getLowerBound() = 0 + or + exists(RegExpTerm child | + child = t.getAChild() and + matchesEpsilon(child) + | + t instanceof RegExpAlt or + t instanceof RegExpGroup or + t instanceof RegExpPlus or + t instanceof RegExpRange + ) + or + matchesEpsilon(t.(RegExpBackRef).getGroup()) + or + forex(RegExpTerm child | child = t.(RegExpSequence).getAChild() | matchesEpsilon(child)) +} + +/** + * A lookahead/lookbehind that matches the empty string. + */ +class EmptyPositiveSubPatttern extends RegExpSubPattern { + EmptyPositiveSubPatttern() { + ( + this instanceof RegExpPositiveLookahead + or + this instanceof RegExpPositiveLookbehind + ) and + matchesEpsilon(this.getOperand()) + } +} + +/** + * A branch in a disjunction that is the root node in a literal, or a literal + * whose root node is not a disjunction. + */ +class RegExpRoot extends RegExpTerm { + RegExpRoot() { + exists(RegExpParent parent | + exists(RegExpAlt alt | + alt.isRootTerm() and + this = alt.getAChild() and + parent = alt.getParent() + ) + or + this.isRootTerm() and + not this instanceof RegExpAlt and + parent = this.getParent() + ) + } + + /** + * Holds if this root term is relevant to the ReDoS analysis. + */ + predicate isRelevant() { + // there is at least one repetition + getRoot(any(InfiniteRepetitionQuantifier q)) = this and + // is actually used as a RegExp + this.isUsedAsRegExp() and + // not excluded for library specific reasons + not isExcluded(this.getRootTerm().getParent()) + } +} + +/** + * A constant in a regular expression that represents valid Unicode character(s). + */ +private class RegexpCharacterConstant extends RegExpConstant { + RegexpCharacterConstant() { this.isCharacter() } +} + +/** + * A regexp term that is relevant for this ReDoS analysis. + */ +class RelevantRegExpTerm extends RegExpTerm { + RelevantRegExpTerm() { getRoot(this).isRelevant() } +} + +/** + * Holds if `term` is the chosen canonical representative for all terms with string representation `str`. + * The string representation includes which flags are used with the regular expression. + * + * Using canonical representatives gives a huge performance boost when working with tuples containing multiple `InputSymbol`s. + * The number of `InputSymbol`s is decreased by 3 orders of magnitude or more in some larger benchmarks. + */ +private predicate isCanonicalTerm(RelevantRegExpTerm term, string str) { + term = + min(RelevantRegExpTerm t, Location loc, File file | + loc = t.getLocation() and + file = t.getFile() and + str = t.getRawValue() + "|" + getCanonicalizationFlags(t.getRootTerm()) + | + t order by t.getFile().getRelativePath(), loc.getStartLine(), loc.getStartColumn() + ) +} + +/** + * Gets a string reperesentation of the flags used with the regular expression. + * Only the flags that are relevant for the canonicalization are included. + */ +string getCanonicalizationFlags(RegExpTerm root) { + root.isRootTerm() and + (if RegExpFlags::isIgnoreCase(root) then result = "i" else result = "") +} + +/** + * An abstract input symbol, representing a set of concrete characters. + */ +private newtype TInputSymbol = + /** An input symbol corresponding to character `c`. */ + Char(string c) { + c = + any(RegexpCharacterConstant cc | + cc instanceof RelevantRegExpTerm and + not RegExpFlags::isIgnoreCase(cc.getRootTerm()) + ).getValue().charAt(_) + or + // normalize everything to lower case if the regexp is case insensitive + c = + any(RegexpCharacterConstant cc, string char | + cc instanceof RelevantRegExpTerm and + RegExpFlags::isIgnoreCase(cc.getRootTerm()) and + char = cc.getValue().charAt(_) + | + char.toLowerCase() + ) + } or + /** + * An input symbol representing all characters matched by + * a (non-universal) character class that has string representation `charClassString`. + */ + CharClass(string charClassString) { + exists(RelevantRegExpTerm recc | isCanonicalTerm(recc, charClassString) | + recc instanceof RegExpCharacterClass and + not recc.(RegExpCharacterClass).isUniversalClass() + or + isEscapeClass(recc, _) + ) + } or + /** An input symbol representing all characters matched by `.`. */ + Dot() or + /** An input symbol representing all characters. */ + Any() or + /** An epsilon transition in the automaton. */ + Epsilon() + +/** + * Gets the canonical CharClass for `term`. + */ +CharClass getCanonicalCharClass(RegExpTerm term) { + exists(string str | isCanonicalTerm(term, str) | result = CharClass(str)) +} + +/** + * Holds if `a` and `b` are input symbols from the same regexp. + */ +private predicate sharesRoot(TInputSymbol a, TInputSymbol b) { + exists(RegExpRoot root | + belongsTo(a, root) and + belongsTo(b, root) + ) +} + +/** + * Holds if the `a` is an input symbol from a regexp that has root `root`. + */ +private predicate belongsTo(TInputSymbol a, RegExpRoot root) { + exists(State s | getRoot(s.getRepr()) = root | + delta(s, a, _) + or + delta(_, a, s) + ) +} + +/** + * An abstract input symbol, representing a set of concrete characters. + */ +class InputSymbol extends TInputSymbol { + InputSymbol() { not this instanceof Epsilon } + + /** + * Gets a string representation of this input symbol. + */ + string toString() { + this = Char(result) + or + this = CharClass(result) + or + this = Dot() and result = "." + or + this = Any() and result = "[^]" + } +} + +/** + * An abstract input symbol that represents a character class. + */ +abstract class CharacterClass extends InputSymbol { + /** + * Gets a character that is relevant for intersection-tests involving this + * character class. + * + * Specifically, this is any of the characters mentioned explicitly in the + * character class, offset by one if it is inverted. For character class escapes, + * the result is as if the class had been written out as a series of intervals. + * + * This set is large enough to ensure that for any two intersecting character + * classes, one contains a relevant character from the other. + */ + abstract string getARelevantChar(); + + /** + * Holds if this character class matches `char`. + */ + bindingset[char] + abstract predicate matches(string char); + + /** + * Gets a character matched by this character class. + */ + string choose() { result = this.getARelevantChar() and this.matches(result) } +} + +/** + * Provides implementations for `CharacterClass`. + */ +private module CharacterClasses { + /** + * Holds if the character class `cc` has a child (constant or range) that matches `char`. + */ + pragma[noinline] + predicate hasChildThatMatches(RegExpCharacterClass cc, string char) { + if RegExpFlags::isIgnoreCase(cc.getRootTerm()) + then + // normalize everything to lower case if the regexp is case insensitive + exists(string c | hasChildThatMatchesIgnoringCasingFlags(cc, c) | char = c.toLowerCase()) + else hasChildThatMatchesIgnoringCasingFlags(cc, char) + } + + /** + * Holds if the character class `cc` has a child (constant or range) that matches `char`. + * Ignores whether the character class is inside a regular expression that has the ignore case flag. + */ + pragma[noinline] + predicate hasChildThatMatchesIgnoringCasingFlags(RegExpCharacterClass cc, string char) { + exists(getCanonicalCharClass(cc)) and + exists(RegExpTerm child | child = cc.getAChild() | + char = child.(RegexpCharacterConstant).getValue() + or + rangeMatchesOnLetterOrDigits(child, char) + or + not rangeMatchesOnLetterOrDigits(child, _) and + char = getARelevantChar() and + exists(string lo, string hi | child.(RegExpCharacterRange).isRange(lo, hi) | + lo <= char and + char <= hi + ) + or + exists(string charClass | isEscapeClass(child, charClass) | + charClass.toLowerCase() = charClass and + classEscapeMatches(charClass, char) + or + char = getARelevantChar() and + charClass.toUpperCase() = charClass and + not classEscapeMatches(charClass, char) + ) + ) + } + + /** + * Holds if `range` is a range on lower-case, upper-case, or digits, and matches `char`. + * This predicate is used to restrict the searchspace for ranges by only joining `getAnyPossiblyMatchedChar` + * on a few ranges. + */ + private predicate rangeMatchesOnLetterOrDigits(RegExpCharacterRange range, string char) { + exists(string lo, string hi | + range.isRange(lo, hi) and lo = lowercaseLetter() and hi = lowercaseLetter() + | + lo <= char and + char <= hi and + char = lowercaseLetter() + ) + or + exists(string lo, string hi | + range.isRange(lo, hi) and lo = upperCaseLetter() and hi = upperCaseLetter() + | + lo <= char and + char <= hi and + char = upperCaseLetter() + ) + or + exists(string lo, string hi | range.isRange(lo, hi) and lo = digit() and hi = digit() | + lo <= char and + char <= hi and + char = digit() + ) + } + + private string lowercaseLetter() { result = "abdcefghijklmnopqrstuvwxyz".charAt(_) } + + private string upperCaseLetter() { result = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".charAt(_) } + + private string digit() { result = [0 .. 9].toString() } + + /** + * Gets a char that could be matched by a regular expression. + * Includes all printable ascii chars, all constants mentioned in a regexp, and all chars matches by the regexp `/\s|\d|\w/`. + */ + string getARelevantChar() { + exists(ascii(result)) + or + exists(RegexpCharacterConstant c | result = c.getValue().charAt(_)) + or + classEscapeMatches(_, result) + } + + /** + * Gets a char that is mentioned in the character class `c`. + */ + private string getAMentionedChar(RegExpCharacterClass c) { + exists(RegExpTerm child | child = c.getAChild() | + result = child.(RegexpCharacterConstant).getValue() + or + child.(RegExpCharacterRange).isRange(result, _) + or + child.(RegExpCharacterRange).isRange(_, result) + or + exists(string charClass | isEscapeClass(child, charClass) | + result = min(string s | classEscapeMatches(charClass.toLowerCase(), s)) + or + result = max(string s | classEscapeMatches(charClass.toLowerCase(), s)) + ) + ) + } + + /** + * An implementation of `CharacterClass` for positive (non inverted) character classes. + */ + private class PositiveCharacterClass extends CharacterClass { + RegExpCharacterClass cc; + + PositiveCharacterClass() { this = getCanonicalCharClass(cc) and not cc.isInverted() } + + override string getARelevantChar() { result = getAMentionedChar(cc) } + + override predicate matches(string char) { hasChildThatMatches(cc, char) } + } + + /** + * An implementation of `CharacterClass` for inverted character classes. + */ + private class InvertedCharacterClass extends CharacterClass { + RegExpCharacterClass cc; + + InvertedCharacterClass() { this = getCanonicalCharClass(cc) and cc.isInverted() } + + override string getARelevantChar() { + result = nextChar(getAMentionedChar(cc)) or + nextChar(result) = getAMentionedChar(cc) + } + + bindingset[char] + override predicate matches(string char) { not hasChildThatMatches(cc, char) } + } + + /** + * Holds if the character class escape `clazz` (\d, \s, or \w) matches `char`. + */ + pragma[noinline] + private predicate classEscapeMatches(string clazz, string char) { + clazz = "d" and + char = "0123456789".charAt(_) + or + clazz = "s" and + char = [" ", "\t", "\r", "\n", 11.toUnicode(), 12.toUnicode()] // 11.toUnicode() = \v, 12.toUnicode() = \f + or + clazz = "w" and + char = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_".charAt(_) + } + + /** + * An implementation of `CharacterClass` for \d, \s, and \w. + */ + private class PositiveCharacterClassEscape extends CharacterClass { + string charClass; + + PositiveCharacterClassEscape() { + exists(RegExpTerm cc | + isEscapeClass(cc, charClass) and + this = getCanonicalCharClass(cc) and + charClass = ["d", "s", "w"] + ) + } + + override string getARelevantChar() { + charClass = "d" and + result = ["0", "9"] + or + charClass = "s" and + result = " " + or + charClass = "w" and + result = ["a", "Z", "_", "0", "9"] + } + + override predicate matches(string char) { classEscapeMatches(charClass, char) } + + override string choose() { + charClass = "d" and + result = "9" + or + charClass = "s" and + result = " " + or + charClass = "w" and + result = "a" + } + } + + /** + * An implementation of `CharacterClass` for \D, \S, and \W. + */ + private class NegativeCharacterClassEscape extends CharacterClass { + string charClass; + + NegativeCharacterClassEscape() { + exists(RegExpTerm cc | + isEscapeClass(cc, charClass) and + this = getCanonicalCharClass(cc) and + charClass = ["D", "S", "W"] + ) + } + + override string getARelevantChar() { + charClass = "D" and + result = ["a", "Z", "!"] + or + charClass = "S" and + result = ["a", "9", "!"] + or + charClass = "W" and + result = [" ", "!"] + } + + bindingset[char] + override predicate matches(string char) { + not classEscapeMatches(charClass.toLowerCase(), char) + } + } +} + +private class EdgeLabel extends TInputSymbol { + string toString() { + this = Epsilon() and result = "" + or + exists(InputSymbol s | this = s and result = s.toString()) + } +} + +/** + * A RegExp term that acts like a plus. + * Either it's a RegExpPlus, or it is a range {1,X} where X is >= 30. + * 30 has been chosen as a threshold because for exponential blowup 2^30 is enough to get a decent DOS attack. + */ +private class EffectivelyPlus extends RegExpTerm { + EffectivelyPlus() { + this instanceof RegExpPlus + or + exists(RegExpRange range | + range.getLowerBound() = 1 and + (range.getUpperBound() >= 30 or not exists(range.getUpperBound())) + | + this = range + ) + } +} + +/** + * A RegExp term that acts like a star. + * Either it's a RegExpStar, or it is a range {0,X} where X is >= 30. + */ +private class EffectivelyStar extends RegExpTerm { + EffectivelyStar() { + this instanceof RegExpStar + or + exists(RegExpRange range | + range.getLowerBound() = 0 and + (range.getUpperBound() >= 30 or not exists(range.getUpperBound())) + | + this = range + ) + } +} + +/** + * A RegExp term that acts like a question mark. + * Either it's a RegExpQuestion, or it is a range {0,1}. + */ +private class EffectivelyQuestion extends RegExpTerm { + EffectivelyQuestion() { + this instanceof RegExpOpt + or + exists(RegExpRange range | range.getLowerBound() = 0 and range.getUpperBound() = 1 | + this = range + ) + } +} + +/** + * Gets the state before matching `t`. + */ +pragma[inline] +private State before(RegExpTerm t) { result = Match(t, 0) } + +/** + * Gets a state the NFA may be in after matching `t`. + */ +State after(RegExpTerm t) { + exists(RegExpAlt alt | t = alt.getAChild() | result = after(alt)) + or + exists(RegExpSequence seq, int i | t = seq.getChild(i) | + result = before(seq.getChild(i + 1)) + or + i + 1 = seq.getNumChild() and result = after(seq) + ) + or + exists(RegExpGroup grp | t = grp.getAChild() | result = after(grp)) + or + exists(EffectivelyStar star | t = star.getAChild() | + not isPossessive(star) and + result = before(star) + ) + or + exists(EffectivelyPlus plus | t = plus.getAChild() | + not isPossessive(plus) and + result = before(plus) + or + result = after(plus) + ) + or + exists(EffectivelyQuestion opt | t = opt.getAChild() | result = after(opt)) + or + exists(RegExpRoot root | t = root | + if matchesAnySuffix(root) then result = AcceptAnySuffix(root) else result = Accept(root) + ) +} + +/** + * Holds if the NFA has a transition from `q1` to `q2` labelled with `lbl`. + */ +predicate delta(State q1, EdgeLabel lbl, State q2) { + exists(RegexpCharacterConstant s, int i | + q1 = Match(s, i) and + ( + not RegExpFlags::isIgnoreCase(s.getRootTerm()) and + lbl = Char(s.getValue().charAt(i)) + or + // normalize everything to lower case if the regexp is case insensitive + RegExpFlags::isIgnoreCase(s.getRootTerm()) and + exists(string c | c = s.getValue().charAt(i) | lbl = Char(c.toLowerCase())) + ) and + ( + q2 = Match(s, i + 1) + or + s.getValue().length() = i + 1 and + q2 = after(s) + ) + ) + or + exists(RegExpDot dot | q1 = before(dot) and q2 = after(dot) | + if RegExpFlags::isDotAll(dot.getRootTerm()) then lbl = Any() else lbl = Dot() + ) + or + exists(RegExpCharacterClass cc | + cc.isUniversalClass() and q1 = before(cc) and lbl = Any() and q2 = after(cc) + or + q1 = before(cc) and + lbl = CharClass(cc.getRawValue() + "|" + getCanonicalizationFlags(cc.getRootTerm())) and + q2 = after(cc) + ) + or + exists(RegExpTerm cc | isEscapeClass(cc, _) | + q1 = before(cc) and + lbl = CharClass(cc.getRawValue() + "|" + getCanonicalizationFlags(cc.getRootTerm())) and + q2 = after(cc) + ) + or + exists(RegExpAlt alt | lbl = Epsilon() | q1 = before(alt) and q2 = before(alt.getAChild())) + or + exists(RegExpSequence seq | lbl = Epsilon() | q1 = before(seq) and q2 = before(seq.getChild(0))) + or + exists(RegExpGroup grp | lbl = Epsilon() | q1 = before(grp) and q2 = before(grp.getChild(0))) + or + exists(EffectivelyStar star | lbl = Epsilon() | + q1 = before(star) and q2 = before(star.getChild(0)) + or + q1 = before(star) and q2 = after(star) + ) + or + exists(EffectivelyPlus plus | lbl = Epsilon() | + q1 = before(plus) and q2 = before(plus.getChild(0)) + ) + or + exists(EffectivelyQuestion opt | lbl = Epsilon() | + q1 = before(opt) and q2 = before(opt.getChild(0)) + or + q1 = before(opt) and q2 = after(opt) + ) + or + exists(RegExpRoot root | q1 = AcceptAnySuffix(root) | + lbl = Any() and q2 = q1 + or + lbl = Epsilon() and q2 = Accept(root) + ) + or + exists(RegExpRoot root | q1 = Match(root, 0) | matchesAnyPrefix(root) and lbl = Any() and q2 = q1) + or + exists(RegExpDollar dollar | q1 = before(dollar) | + lbl = Epsilon() and q2 = Accept(getRoot(dollar)) + ) + or + exists(EmptyPositiveSubPatttern empty | q1 = before(empty) | + lbl = Epsilon() and q2 = after(empty) + ) +} + +/** + * Gets a state that `q` has an epsilon transition to. + */ +State epsilonSucc(State q) { delta(q, Epsilon(), result) } + +/** + * Gets a state that has an epsilon transition to `q`. + */ +State epsilonPred(State q) { q = epsilonSucc(result) } + +/** + * Holds if there is a state `q` that can be reached from `q1` + * along epsilon edges, such that there is a transition from + * `q` to `q2` that consumes symbol `s`. + */ +predicate deltaClosed(State q1, InputSymbol s, State q2) { delta(epsilonSucc*(q1), s, q2) } + +/** + * Gets the root containing the given term, that is, the root of the literal, + * or a branch of the root disjunction. + */ +RegExpRoot getRoot(RegExpTerm term) { + result = term or + result = getRoot(term.getParent()) +} + +/** + * A state in the NFA. + */ +newtype TState = + /** + * A state representing that the NFA is about to match a term. + * `i` is used to index into multi-char literals. + */ + Match(RelevantRegExpTerm t, int i) { + i = 0 + or + exists(t.(RegexpCharacterConstant).getValue().charAt(i)) + } or + /** + * An accept state, where exactly the given input string is accepted. + */ + Accept(RegExpRoot l) { l.isRelevant() } or + /** + * An accept state, where the given input string, or any string that has this + * string as a prefix, is accepted. + */ + AcceptAnySuffix(RegExpRoot l) { l.isRelevant() } + +/** + * Gets a state that is about to match the regular expression `t`. + */ +State mkMatch(RegExpTerm t) { result = Match(t, 0) } + +/** + * A state in the NFA corresponding to a regular expression. + * + * Each regular expression literal `l` has one accepting state + * `Accept(l)`, one state that accepts all suffixes `AcceptAnySuffix(l)`, + * and a state `Match(t, i)` for every subterm `t`, + * which represents the state of the NFA before starting to + * match `t`, or the `i`th character in `t` if `t` is a constant. + */ +class State extends TState { + RegExpTerm repr; + + State() { + this = Match(repr, _) or + this = Accept(repr) or + this = AcceptAnySuffix(repr) + } + + /** + * Gets a string representation for this state in a regular expression. + */ + string toString() { + exists(int i | this = Match(repr, i) | result = "Match(" + repr + "," + i + ")") + or + this instanceof Accept and + result = "Accept(" + repr + ")" + or + this instanceof AcceptAnySuffix and + result = "AcceptAny(" + repr + ")" + } + + /** + * Gets the location for this state. + */ + Location getLocation() { result = repr.getLocation() } + + /** + * Gets the term represented by this state. + */ + RegExpTerm getRepr() { result = repr } +} + +/** + * Gets the minimum char that is matched by both the character classes `c` and `d`. + */ +private string getMinOverlapBetweenCharacterClasses(CharacterClass c, CharacterClass d) { + result = min(getAOverlapBetweenCharacterClasses(c, d)) +} + +/** + * Gets a char that is matched by both the character classes `c` and `d`. + * And `c` and `d` is not the same character class. + */ +private string getAOverlapBetweenCharacterClasses(CharacterClass c, CharacterClass d) { + sharesRoot(c, d) and + result = [c.getARelevantChar(), d.getARelevantChar()] and + c.matches(result) and + d.matches(result) and + not c = d +} + +/** + * Gets a character that is represented by both `c` and `d`. + */ +string intersect(InputSymbol c, InputSymbol d) { + (sharesRoot(c, d) or [c, d] = Any()) and + ( + c = Char(result) and + d = getAnInputSymbolMatching(result) + or + result = getMinOverlapBetweenCharacterClasses(c, d) + or + result = c.(CharacterClass).choose() and + ( + d = c + or + d = Dot() and + not (result = "\n" or result = "\r") + or + d = Any() + ) + or + (c = Dot() or c = Any()) and + (d = Dot() or d = Any()) and + result = "a" + ) + or + result = intersect(d, c) +} + +/** + * Gets a symbol that matches `char`. + */ +bindingset[char] +InputSymbol getAnInputSymbolMatching(string char) { + result = Char(char) + or + result.(CharacterClass).matches(char) + or + result = Dot() and + not (char = "\n" or char = "\r") + or + result = Any() +} + +/** + * Holds if `state` is a start state. + */ +predicate isStartState(State state) { + state = mkMatch(any(RegExpRoot r)) + or + exists(RegExpCaret car | state = after(car)) +} + +/** + * Predicates for constructing a prefix string that leads to a given state. + */ +private module PrefixConstruction { + /** + * Holds if `state` is the textually last start state for the regular expression. + */ + private predicate lastStartState(State state) { + exists(RegExpRoot root | + state = + max(StateInPumpableRegexp s, Location l | + isStartState(s) and getRoot(s.getRepr()) = root and l = s.getRepr().getLocation() + | + s + order by + l.getStartLine(), l.getStartColumn(), s.getRepr().toString(), l.getEndColumn(), + l.getEndLine() + ) + ) + } + + /** + * Holds if there exists any transition (Epsilon() or other) from `a` to `b`. + */ + private predicate existsTransition(State a, State b) { delta(a, _, b) } + + /** + * Gets the minimum number of transitions it takes to reach `state` from the `start` state. + */ + int prefixLength(State start, State state) = + shortestDistances(lastStartState/1, existsTransition/2)(start, state, result) + + /** + * Gets the minimum number of transitions it takes to reach `state` from the start state. + */ + private int lengthFromStart(State state) { result = prefixLength(_, state) } + + /** + * Gets a string for which the regular expression will reach `state`. + * + * Has at most one result for any given `state`. + * This predicate will not always have a result even if there is a ReDoS issue in + * the regular expression. + */ + string prefix(State state) { + lastStartState(state) and + result = "" + or + // the search stops past the last redos candidate state. + lengthFromStart(state) <= max(lengthFromStart(any(State s | isReDoSCandidate(s, _)))) and + exists(State prev | + // select a unique predecessor (by an arbitrary measure) + prev = + min(State s, Location loc | + lengthFromStart(s) = lengthFromStart(state) - 1 and + loc = s.getRepr().getLocation() and + delta(s, _, state) + | + s + order by + loc.getStartLine(), loc.getStartColumn(), loc.getEndLine(), loc.getEndColumn(), + s.getRepr().toString() + ) + | + // greedy search for the shortest prefix + result = prefix(prev) and delta(prev, Epsilon(), state) + or + not delta(prev, Epsilon(), state) and + result = prefix(prev) + getCanonicalEdgeChar(prev, state) + ) + } + + /** + * Gets a canonical char for which there exists a transition from `prev` to `next` in the NFA. + */ + private string getCanonicalEdgeChar(State prev, State next) { + result = + min(string c | delta(prev, any(InputSymbol symbol | c = intersect(Any(), symbol)), next)) + } + + /** + * A state within a regular expression that has a pumpable state. + */ + class StateInPumpableRegexp extends State { + pragma[noinline] + StateInPumpableRegexp() { + exists(State s | isReDoSCandidate(s, _) | getRoot(s.getRepr()) = getRoot(this.getRepr())) + } + } +} + +/** + * Predicates for testing the presence of a rejecting suffix. + * + * These predicates are used to ensure that the all states reached from the fork + * by repeating `w` have a rejecting suffix. + * + * For example, a regexp like `/^(a+)+/` will accept any string as long the prefix is + * some number of `"a"`s, and it is therefore not possible to construct a rejecting suffix. + * + * A regexp like `/(a+)+$/` or `/(a+)+b/` trivially has a rejecting suffix, + * as the suffix "X" will cause both the regular expressions to be rejected. + * + * The string `w` is repeated any number of times because it needs to be + * infinitely repeatedable for the attack to work. + * For the regular expression `/((ab)+)*abab/` the accepting state is not reachable from the fork + * using epsilon transitions. But any attempt at repeating `w` will end in a state that accepts all suffixes. + */ +private module SuffixConstruction { + import PrefixConstruction + + /** + * Holds if all states reachable from `fork` by repeating `w` + * are likely rejectable by appending some suffix. + */ + predicate reachesOnlyRejectableSuffixes(State fork, string w) { + isReDoSCandidate(fork, w) and + forex(State next | next = process(fork, w, w.length() - 1) | isLikelyRejectable(next)) + } + + /** + * Holds if there likely exists a suffix starting from `s` that leads to the regular expression being rejected. + * This predicate might find impossible suffixes when searching for suffixes of length > 1, which can cause FPs. + */ + pragma[noinline] + private predicate isLikelyRejectable(StateInPumpableRegexp s) { + // exists a reject edge with some char. + hasRejectEdge(s) + or + hasEdgeToLikelyRejectable(s) + or + // stopping here is rejection + isRejectState(s) + } + + /** + * Holds if `s` is not an accept state, and there is no epsilon transition to an accept state. + */ + predicate isRejectState(StateInPumpableRegexp s) { not epsilonSucc*(s) = Accept(_) } + + /** + * Holds if there is likely a non-empty suffix leading to rejection starting in `s`. + */ + pragma[noopt] + predicate hasEdgeToLikelyRejectable(StateInPumpableRegexp s) { + // all edges (at least one) with some char leads to another state that is rejectable. + // the `next` states might not share a common suffix, which can cause FPs. + exists(string char | char = hasEdgeToLikelyRejectableHelper(s) | + // noopt to force `hasEdgeToLikelyRejectableHelper` to be first in the join-order. + exists(State next | deltaClosedChar(s, char, next) | isLikelyRejectable(next)) and + forall(State next | deltaClosedChar(s, char, next) | isLikelyRejectable(next)) + ) + } + + /** + * Gets a char for there exists a transition away from `s`, + * and `s` has not been found to be rejectable by `hasRejectEdge` or `isRejectState`. + */ + pragma[noinline] + private string hasEdgeToLikelyRejectableHelper(StateInPumpableRegexp s) { + not hasRejectEdge(s) and + not isRejectState(s) and + deltaClosedChar(s, result, _) + } + + /** + * Holds if there is a state `next` that can be reached from `prev` + * along epsilon edges, such that there is a transition from + * `prev` to `next` that the character symbol `char`. + */ + predicate deltaClosedChar(StateInPumpableRegexp prev, string char, StateInPumpableRegexp next) { + deltaClosed(prev, getAnInputSymbolMatchingRelevant(char), next) + } + + pragma[noinline] + InputSymbol getAnInputSymbolMatchingRelevant(string char) { + char = relevant(_) and + result = getAnInputSymbolMatching(char) + } + + /** + * Gets a char used for finding possible suffixes inside `root`. + */ + pragma[noinline] + private string relevant(RegExpRoot root) { + exists(ascii(result)) and exists(root) + or + exists(InputSymbol s | belongsTo(s, root) | result = intersect(s, _)) + or + // The characters from `hasSimpleRejectEdge`. Only `\n` is really needed (as `\n` is not in the `ascii` relation). + // The three chars must be kept in sync with `hasSimpleRejectEdge`. + result = ["|", "\n", "Z"] and exists(root) + } + + /** + * Holds if there exists a `char` such that there is no edge from `s` labeled `char` in our NFA. + * The NFA does not model reject states, so the above is the same as saying there is a reject edge. + */ + private predicate hasRejectEdge(State s) { + hasSimpleRejectEdge(s) + or + not hasSimpleRejectEdge(s) and + exists(string char | char = relevant(getRoot(s.getRepr())) | not deltaClosedChar(s, char, _)) + } + + /** + * Holds if there is no edge from `s` labeled with "|", "\n", or "Z" in our NFA. + * This predicate is used as a cheap pre-processing to speed up `hasRejectEdge`. + */ + private predicate hasSimpleRejectEdge(State s) { + // The three chars were chosen arbitrarily. The three chars must be kept in sync with `relevant`. + exists(string char | char = ["|", "\n", "Z"] | not deltaClosedChar(s, char, _)) + } + + /** + * Gets a state that can be reached from pumpable `fork` consuming all + * chars in `w` any number of times followed by the first `i+1` characters of `w`. + */ + pragma[noopt] + private State process(State fork, string w, int i) { + exists(State prev | prev = getProcessPrevious(fork, i, w) | + exists(string char, InputSymbol sym | + char = w.charAt(i) and + deltaClosed(prev, sym, result) and + // noopt to prevent joining `prev` with all possible `chars` that could transition away from `prev`. + // Instead only join with the set of `chars` where a relevant `InputSymbol` has already been found. + sym = getAProcessInputSymbol(char) + ) + ) + } + + /** + * Gets a state that can be reached from pumpable `fork` consuming all + * chars in `w` any number of times followed by the first `i` characters of `w`. + */ + private State getProcessPrevious(State fork, int i, string w) { + isReDoSCandidate(fork, w) and + ( + i = 0 and result = fork + or + result = process(fork, w, i - 1) + or + // repeat until fixpoint + i = 0 and + result = process(fork, w, w.length() - 1) + ) + } + + /** + * Gets an InputSymbol that matches `char`. + * The predicate is specialized to only have a result for the `char`s that are relevant for the `process` predicate. + */ + private InputSymbol getAProcessInputSymbol(string char) { + char = getAProcessChar() and + result = getAnInputSymbolMatching(char) + } + + /** + * Gets a `char` that occurs in a `pump` string. + */ + private string getAProcessChar() { result = any(string s | isReDoSCandidate(_, s)).charAt(_) } +} + +/** + * Gets the result of backslash-escaping newlines, carriage-returns and + * backslashes in `s`. + */ +bindingset[s] +private string escape(string s) { + result = + s.replaceAll("\\", "\\\\") + .replaceAll("\n", "\\n") + .replaceAll("\r", "\\r") + .replaceAll("\t", "\\t") +} + +/** + * Gets `str` with the last `i` characters moved to the front. + * + * We use this to adjust the pump string to match with the beginning of + * a RegExpTerm, so it doesn't start in the middle of a constant. + */ +bindingset[str, i] +private string rotate(string str, int i) { + result = str.suffix(str.length() - i) + str.prefix(str.length() - i) +} + +/** + * Holds if `term` may cause superlinear backtracking on strings containing many repetitions of `pump`. + * Gets the shortest string that causes superlinear backtracking. + */ +private predicate isReDoSAttackable(RegExpTerm term, string pump, State s) { + exists(int i, string c | s = Match(term, i) | + c = + min(string w | + any(ReDoSConfiguration conf).isReDoSCandidate(s, w) and + SuffixConstruction::reachesOnlyRejectableSuffixes(s, w) + | + w order by w.length(), w + ) and + pump = escape(rotate(c, i)) + ) +} + +/** + * Holds if the state `s` (represented by the term `t`) can have backtracking with repetitions of `pump`. + * + * `prefixMsg` contains a friendly message for a prefix that reaches `s` (or `prefixMsg` is the empty string if the prefix is empty or if no prefix could be found). + */ +predicate hasReDoSResult(RegExpTerm t, string pump, State s, string prefixMsg) { + isReDoSAttackable(t, pump, s) and + ( + prefixMsg = "starting with '" + escape(PrefixConstruction::prefix(s)) + "' and " and + not PrefixConstruction::prefix(s) = "" + or + PrefixConstruction::prefix(s) = "" and prefixMsg = "" + or + not exists(PrefixConstruction::prefix(s)) and prefixMsg = "" + ) +} diff --git a/java/ql/lib/semmle/code/java/security/performance/ReDoSUtilSpecific.qll b/java/ql/lib/semmle/code/java/security/performance/ReDoSUtilSpecific.qll new file mode 100644 index 00000000000..d72d6770848 --- /dev/null +++ b/java/ql/lib/semmle/code/java/security/performance/ReDoSUtilSpecific.qll @@ -0,0 +1,76 @@ +/** + * This module should provide a class hierarchy corresponding to a parse tree of regular expressions. + * This is the interface to the shared ReDoS library. + */ + +private import java +import semmle.code.FileSystem +import semmle.code.java.regex.RegexTreeView + +/** + * Holds if `term` is an escape class representing e.g. `\d`. + * `clazz` is which character class it represents, e.g. "d" for `\d`. + */ +predicate isEscapeClass(RegExpTerm term, string clazz) { + term.(RegExpCharacterClassEscape).getValue() = clazz + or + term.(RegExpNamedProperty).getBackslashEquivalent() = clazz +} + +/** + * Holds if `term` is a possessive quantifier, e.g. `a*+`. + */ +predicate isPossessive(RegExpQuantifier term) { term.isPossessive() } + +/** + * Holds if the regex that `term` is part of is used in a way that ignores any leading prefix of the input it's matched against. + */ +predicate matchesAnyPrefix(RegExpTerm term) { not term.getRegex().matchesFullString() } + +/** + * Holds if the regex that `term` is part of is used in a way that ignores any trailing suffix of the input it's matched against. + */ +predicate matchesAnySuffix(RegExpTerm term) { not term.getRegex().matchesFullString() } + +/** + * Holds if the regular expression should not be considered. + * + * We make the pragmatic performance optimization to ignore regular expressions in files + * that do not belong to the project code (such as installed dependencies). + */ +predicate isExcluded(RegExpParent parent) { + not exists(parent.getRegex().getLocation().getFile().getRelativePath()) + or + // Regexes with many occurrences of ".*" may cause the polynomial ReDoS computation to explode, so + // we explicitly exclude these. + strictcount(int i | exists(parent.getRegex().getText().regexpFind("\\.\\*", i, _)) | i) > 10 +} + +/** + * A module containing predicates for determining which flags a regular expression have. + */ +module RegExpFlags { + /** + * Holds if `root` has the `i` flag for case-insensitive matching. + */ + predicate isIgnoreCase(RegExpTerm root) { + root.isRootTerm() and + root.getLiteral().isIgnoreCase() + } + + /** + * Gets the flags for `root`, or the empty string if `root` has no flags. + */ + string getFlags(RegExpTerm root) { + root.isRootTerm() and + result = root.getLiteral().getFlags() + } + + /** + * Holds if `root` has the `s` flag for multi-line matching. + */ + predicate isDotAll(RegExpTerm root) { + root.isRootTerm() and + root.getLiteral().isDotAll() + } +} diff --git a/java/ql/lib/semmle/code/java/security/performance/SuperlinearBackTracking.qll b/java/ql/lib/semmle/code/java/security/performance/SuperlinearBackTracking.qll new file mode 100644 index 00000000000..4ba9520cdcc --- /dev/null +++ b/java/ql/lib/semmle/code/java/security/performance/SuperlinearBackTracking.qll @@ -0,0 +1,454 @@ +/** + * Provides classes for working with regular expressions that can + * perform backtracking in superlinear time. + */ + +import ReDoSUtil + +/* + * This module implements the analysis described in the paper: + * Valentin Wustholz, Oswaldo Olivo, Marijn J. H. Heule, and Isil Dillig: + * Static Detection of DoS Vulnerabilities in + * Programs that use Regular Expressions + * (Extended Version). + * (https://arxiv.org/pdf/1701.04045.pdf) + * + * Theorem 3 from the paper describes the basic idea. + * + * The following explains the idea using variables and predicate names that are used in the implementation: + * We consider a pair of repetitions, which we will call `pivot` and `succ`. + * + * We create a product automaton of 3-tuples of states (see `StateTuple`). + * There exists a transition `(a,b,c) -> (d,e,f)` in the product automaton + * iff there exists three transitions in the NFA `a->d, b->e, c->f` where those three + * transitions all match a shared character `char`. (see `getAThreewayIntersect`) + * + * We start a search in the product automaton at `(pivot, pivot, succ)`, + * and search for a series of transitions (a `Trace`), such that we end + * at `(pivot, succ, succ)` (see `isReachableFromStartTuple`). + * + * For example, consider the regular expression `/^\d*5\w*$/`. + * The search will start at the tuple `(\d*, \d*, \w*)` and search + * for a path to `(\d*, \w*, \w*)`. + * This path exists, and consists of a single transition in the product automaton, + * where the three corresponding NFA edges all match the character `"5"`. + * + * The start-state in the NFA has an any-transition to itself, this allows us to + * flag regular expressions such as `/a*$/` - which does not have a start anchor - + * and can thus start matching anywhere. + * + * The implementation is not perfect. + * It has the same suffix detection issue as the `js/redos` query, which can cause false positives. + * It also doesn't find all transitions in the product automaton, which can cause false negatives. + */ + +/** + * An instantiaion of `ReDoSConfiguration` for superlinear ReDoS. + */ +class SuperLinearReDoSConfiguration extends ReDoSConfiguration { + SuperLinearReDoSConfiguration() { this = "SuperLinearReDoSConfiguration" } + + override predicate isReDoSCandidate(State state, string pump) { isPumpable(_, state, pump) } +} + +/** + * Gets any root (start) state of a regular expression. + */ +private State getRootState() { result = mkMatch(any(RegExpRoot r)) } + +private newtype TStateTuple = + MkStateTuple(State q1, State q2, State q3) { + // starts at (pivot, pivot, succ) + isStartLoops(q1, q3) and q1 = q2 + or + step(_, _, _, _, q1, q2, q3) and FeasibleTuple::isFeasibleTuple(q1, q2, q3) + } + +/** + * A state in the product automaton. + * The product automaton contains 3-tuples of states. + * + * We lazily only construct those states that we are actually + * going to need. + * Either a start state `(pivot, pivot, succ)`, or a state + * where there exists a transition from an already existing state. + * + * The exponential variant of this query (`js/redos`) uses an optimization + * trick where `q1 <= q2`. This trick cannot be used here as the order + * of the elements matter. + */ +class StateTuple extends TStateTuple { + State q1; + State q2; + State q3; + + StateTuple() { this = MkStateTuple(q1, q2, q3) } + + /** + * Gest a string repesentation of this tuple. + */ + string toString() { result = "(" + q1 + ", " + q2 + ", " + q3 + ")" } + + /** + * Holds if this tuple is `(r1, r2, r3)`. + */ + pragma[noinline] + predicate isTuple(State r1, State r2, State r3) { r1 = q1 and r2 = q2 and r3 = q3 } +} + +/** + * A module for determining feasible tuples for the product automaton. + * + * The implementation is split into many predicates for performance reasons. + */ +private module FeasibleTuple { + /** + * Holds if the tuple `(r1, r2, r3)` might be on path from a start-state to an end-state in the product automaton. + */ + pragma[inline] + predicate isFeasibleTuple(State r1, State r2, State r3) { + // The first element is either inside a repetition (or the start state itself) + isRepetitionOrStart(r1) and + // The last element is inside a repetition + stateInsideRepetition(r3) and + // The states are reachable in the NFA in the order r1 -> r2 -> r3 + delta+(r1) = r2 and + delta+(r2) = r3 and + // The first element can reach a beginning (the "pivot" state in a `(pivot, succ)` pair). + canReachABeginning(r1) and + // The last element can reach a target (the "succ" state in a `(pivot, succ)` pair). + canReachATarget(r3) + } + + /** + * Holds if `s` is either inside a repetition, or is the start state (which is a repetition). + */ + pragma[noinline] + private predicate isRepetitionOrStart(State s) { stateInsideRepetition(s) or s = getRootState() } + + /** + * Holds if state `s` might be inside a backtracking repetition. + */ + pragma[noinline] + private predicate stateInsideRepetition(State s) { + s.getRepr().getParent*() instanceof InfiniteRepetitionQuantifier + } + + /** + * Holds if there exists a path in the NFA from `s` to a "pivot" state + * (from a `(pivot, succ)` pair that starts the search). + */ + pragma[noinline] + private predicate canReachABeginning(State s) { + delta+(s) = any(State pivot | isStartLoops(pivot, _)) + } + + /** + * Holds if there exists a path in the NFA from `s` to a "succ" state + * (from a `(pivot, succ)` pair that starts the search). + */ + pragma[noinline] + private predicate canReachATarget(State s) { delta+(s) = any(State succ | isStartLoops(_, succ)) } +} + +/** + * Holds if `pivot` and `succ` are a pair of loops that could be the beginning of a quadratic blowup. + * + * There is a slight implementation difference compared to the paper: this predicate requires that `pivot != succ`. + * The case where `pivot = succ` causes exponential backtracking and is handled by the `js/redos` query. + */ +predicate isStartLoops(State pivot, State succ) { + pivot != succ and + succ.getRepr() instanceof InfiniteRepetitionQuantifier and + delta+(pivot) = succ and + ( + pivot.getRepr() instanceof InfiniteRepetitionQuantifier + or + pivot = mkMatch(any(RegExpRoot root)) + ) +} + +/** + * Gets a state for which there exists a transition in the NFA from `s'. + */ +State delta(State s) { delta(s, _, result) } + +/** + * Holds if there are transitions from the components of `q` to the corresponding + * components of `r` labelled with `s1`, `s2`, and `s3`, respectively. + */ +pragma[noinline] +predicate step(StateTuple q, InputSymbol s1, InputSymbol s2, InputSymbol s3, StateTuple r) { + exists(State r1, State r2, State r3 | + step(q, s1, s2, s3, r1, r2, r3) and r = MkStateTuple(r1, r2, r3) + ) +} + +/** + * Holds if there are transitions from the components of `q` to `r1`, `r2`, and `r3 + * labelled with `s1`, `s2`, and `s3`, respectively. + */ +pragma[noopt] +predicate step( + StateTuple q, InputSymbol s1, InputSymbol s2, InputSymbol s3, State r1, State r2, State r3 +) { + exists(State q1, State q2, State q3 | q.isTuple(q1, q2, q3) | + deltaClosed(q1, s1, r1) and + deltaClosed(q2, s2, r2) and + deltaClosed(q3, s3, r3) and + // use noopt to force the join on `getAThreewayIntersect` to happen last. + exists(getAThreewayIntersect(s1, s2, s3)) + ) +} + +/** + * Gets a char that is matched by all the edges `s1`, `s2`, and `s3`. + * + * The result is not complete, and might miss some combination of edges that share some character. + */ +pragma[noinline] +string getAThreewayIntersect(InputSymbol s1, InputSymbol s2, InputSymbol s3) { + result = minAndMaxIntersect(s1, s2) and result = [intersect(s2, s3), intersect(s1, s3)] + or + result = minAndMaxIntersect(s1, s3) and result = [intersect(s2, s3), intersect(s1, s2)] + or + result = minAndMaxIntersect(s2, s3) and result = [intersect(s1, s2), intersect(s1, s3)] +} + +/** + * Gets the minimum and maximum characters that intersect between `a` and `b`. + * This predicate is used to limit the size of `getAThreewayIntersect`. + */ +pragma[noinline] +string minAndMaxIntersect(InputSymbol a, InputSymbol b) { + result = [min(intersect(a, b)), max(intersect(a, b))] +} + +private newtype TTrace = + Nil() or + Step(InputSymbol s1, InputSymbol s2, InputSymbol s3, TTrace t) { + exists(StateTuple p | + isReachableFromStartTuple(_, _, p, t, _) and + step(p, s1, s2, s3, _) + ) + or + exists(State pivot, State succ | isStartLoops(pivot, succ) | + t = Nil() and step(MkStateTuple(pivot, pivot, succ), s1, s2, s3, _) + ) + } + +/** + * A list of tuples of input symbols that describe a path in the product automaton + * starting from some start state. + */ +class Trace extends TTrace { + /** + * Gets a string representation of this Trace that can be used for debug purposes. + */ + string toString() { + this = Nil() and result = "Nil()" + or + exists(InputSymbol s1, InputSymbol s2, InputSymbol s3, Trace t | this = Step(s1, s2, s3, t) | + result = "Step(" + s1 + ", " + s2 + ", " + s3 + ", " + t + ")" + ) + } +} + +/** + * Holds if there exists a transition from `r` to `q` in the product automaton. + * Notice that the arguments are flipped, and thus the direction is backwards. + */ +pragma[noinline] +predicate tupleDeltaBackwards(StateTuple q, StateTuple r) { step(r, _, _, _, q) } + +/** + * Holds if `tuple` is an end state in our search. + * That means there exists a pair of loops `(pivot, succ)` such that `tuple = (pivot, succ, succ)`. + */ +predicate isEndTuple(StateTuple tuple) { tuple = getAnEndTuple(_, _) } + +/** + * Gets the minimum length of a path from `r` to some an end state `end`. + * + * The implementation searches backwards from the end-tuple. + * This approach was chosen because it is way more efficient if the first predicate given to `shortestDistances` is small. + * The `end` argument must always be an end state. + */ +int distBackFromEnd(StateTuple r, StateTuple end) = + shortestDistances(isEndTuple/1, tupleDeltaBackwards/2)(end, r, result) + +/** + * Holds if there exists a pair of repetitions `(pivot, succ)` in the regular expression such that: + * `tuple` is reachable from `(pivot, pivot, succ)` in the product automaton, + * and there is a distance of `dist` from `tuple` to the nearest end-tuple `(pivot, succ, succ)`, + * and a path from a start-state to `tuple` follows the transitions in `trace`. + */ +predicate isReachableFromStartTuple(State pivot, State succ, StateTuple tuple, Trace trace, int dist) { + // base case. The first step is inlined to start the search after all possible 1-steps, and not just the ones with the shortest path. + exists(InputSymbol s1, InputSymbol s2, InputSymbol s3, State q1, State q2, State q3 | + isStartLoops(pivot, succ) and + step(MkStateTuple(pivot, pivot, succ), s1, s2, s3, tuple) and + tuple = MkStateTuple(q1, q2, q3) and + trace = Step(s1, s2, s3, Nil()) and + dist = distBackFromEnd(tuple, MkStateTuple(pivot, succ, succ)) + ) + or + // recursive case + exists(StateTuple p, Trace v, InputSymbol s1, InputSymbol s2, InputSymbol s3 | + isReachableFromStartTuple(pivot, succ, p, v, dist + 1) and + dist = isReachableFromStartTupleHelper(pivot, succ, tuple, p, s1, s2, s3) and + trace = Step(s1, s2, s3, v) + ) +} + +/** + * Helper predicate for the recursive case in `isReachableFromStartTuple`. + */ +pragma[noinline] +private int isReachableFromStartTupleHelper( + State pivot, State succ, StateTuple r, StateTuple p, InputSymbol s1, InputSymbol s2, + InputSymbol s3 +) { + result = distBackFromEnd(r, MkStateTuple(pivot, succ, succ)) and + step(p, s1, s2, s3, r) +} + +/** + * Gets the tuple `(pivot, succ, succ)` from the product automaton. + */ +StateTuple getAnEndTuple(State pivot, State succ) { + isStartLoops(pivot, succ) and + result = MkStateTuple(pivot, succ, succ) +} + +private predicate hasSuffix(Trace suffix, Trace t, int i) { + // Declaring `t` to be a `RelevantTrace` currently causes a redundant check in the + // recursive case, so instead we check it explicitly here. + t instanceof RelevantTrace and + i = 0 and + suffix = t + or + hasSuffix(Step(_, _, _, suffix), t, i - 1) +} + +pragma[noinline] +private predicate hasTuple(InputSymbol s1, InputSymbol s2, InputSymbol s3, Trace t, int i) { + hasSuffix(Step(s1, s2, s3, _), t, i) +} + +private class RelevantTrace extends Trace, Step { + RelevantTrace() { + exists(State pivot, State succ, StateTuple q | + isReachableFromStartTuple(pivot, succ, q, this, _) and + q = getAnEndTuple(pivot, succ) + ) + } + + pragma[noinline] + private string getAThreewayIntersect(int i) { + exists(InputSymbol s1, InputSymbol s2, InputSymbol s3 | + hasTuple(s1, s2, s3, this, i) and + result = getAThreewayIntersect(s1, s2, s3) + ) + } + + /** Gets a string corresponding to this trace. */ + // the pragma is needed for the case where `getAThreewayIntersect(s1, s2, s3)` has multiple values, + // not for recursion + language[monotonicAggregates] + string concretise() { + result = + strictconcat(int i | + hasTuple(_, _, _, this, i) + | + this.getAThreewayIntersect(i) order by i desc + ) + } +} + +/** + * Holds if matching repetitions of `pump` can: + * 1) Transition from `pivot` back to `pivot`. + * 2) Transition from `pivot` to `succ`. + * 3) Transition from `succ` to `succ`. + * + * From theorem 3 in the paper linked in the top of this file we can therefore conclude that + * the regular expression has polynomial backtracking - if a rejecting suffix exists. + * + * This predicate is used by `SuperLinearReDoSConfiguration`, and the final results are + * available in the `hasReDoSResult` predicate. + */ +predicate isPumpable(State pivot, State succ, string pump) { + exists(StateTuple q, RelevantTrace t | + isReachableFromStartTuple(pivot, succ, q, t, _) and + q = getAnEndTuple(pivot, succ) and + pump = t.concretise() + ) +} + +/** + * Holds if repetitions of `pump` at `t` will cause polynomial backtracking. + */ +predicate polynimalReDoS(RegExpTerm t, string pump, string prefixMsg, RegExpTerm prev) { + exists(State s, State pivot | + hasReDoSResult(t, pump, s, prefixMsg) and + isPumpable(pivot, s, _) and + prev = pivot.getRepr() + ) +} + +/** + * Gets a message for why `term` can cause polynomial backtracking. + */ +string getReasonString(RegExpTerm term, string pump, string prefixMsg, RegExpTerm prev) { + polynimalReDoS(term, pump, prefixMsg, prev) and + result = + "Strings " + prefixMsg + "with many repetitions of '" + pump + + "' can start matching anywhere after the start of the preceeding " + prev +} + +/** + * A term that may cause a regular expression engine to perform a + * polynomial number of match attempts, relative to the input length. + */ +class PolynomialBackTrackingTerm extends InfiniteRepetitionQuantifier { + string reason; + string pump; + string prefixMsg; + RegExpTerm prev; + + PolynomialBackTrackingTerm() { + reason = getReasonString(this, pump, prefixMsg, prev) and + // there might be many reasons for this term to have polynomial backtracking - we pick the shortest one. + reason = min(string msg | msg = getReasonString(this, _, _, _) | msg order by msg.length(), msg) + } + + /** + * Holds if all non-empty successors to the polynomial backtracking term matches the end of the line. + */ + predicate isAtEndLine() { + forall(RegExpTerm succ | this.getSuccessor+() = succ and not matchesEpsilon(succ) | + succ instanceof RegExpDollar + ) + } + + /** + * Gets the string that should be repeated to cause this regular expression to perform polynomially. + */ + string getPumpString() { result = pump } + + /** + * Gets a message for which prefix a matching string must start with for this term to cause polynomial backtracking. + */ + string getPrefixMessage() { result = prefixMsg } + + /** + * Gets a predecessor to `this`, which also loops on the pump string, and thereby causes polynomial backtracking. + */ + RegExpTerm getPreviousLoop() { result = prev } + + /** + * Gets the reason for the number of match attempts. + */ + string getReason() { result = reason } +} diff --git a/java/ql/src/CHANGELOG.md b/java/ql/src/CHANGELOG.md index dc7d34948f1..33afe732888 100644 --- a/java/ql/src/CHANGELOG.md +++ b/java/ql/src/CHANGELOG.md @@ -1,3 +1,16 @@ +## 0.1.2 + +### Query Metadata Changes + +* Query `java/predictable-seed` now has a tag for CWE-337. + +### Minor Analysis Improvements + +* Query `java/insecure-cookie` now tolerates setting a cookie's secure flag to `request.isSecure()`. This means servlets that intentionally accept unencrypted connections will no longer raise an alert. +* The query `java/non-https-urls` has been simplified +and no longer requires its sinks to be `MethodAccess`es. +* The logic to detect `WebView`s with JavaScript (and optionally file access) enabled in the query `java/android/unsafe-android-webview-fetch` has been improved. + ## 0.1.1 ### Minor Analysis Improvements diff --git a/java/ql/src/Likely Bugs/Comparison/MissingInstanceofInEquals.ql b/java/ql/src/Likely Bugs/Comparison/MissingInstanceofInEquals.ql index 25dec899af1..346b21bb847 100644 --- a/java/ql/src/Likely Bugs/Comparison/MissingInstanceofInEquals.ql +++ b/java/ql/src/Likely Bugs/Comparison/MissingInstanceofInEquals.ql @@ -26,6 +26,10 @@ class CheckedCast extends CastExpr { predicate hasTypeTest(Variable v) { any(InstanceOfExpr ioe).getExpr() = v.getAnAccess() or + any(NotInstanceOfExpr nioe).getExpr() = v.getAnAccess() + or + any(SafeCastExpr sce).getExpr() = v.getAnAccess() + or exists(MethodAccess ma | ma.getMethod().getName() = "getClass" and ma.getQualifier() = v.getAnAccess() diff --git a/java/ql/src/Likely Bugs/Comparison/NoComparisonOnFloats.ql b/java/ql/src/Likely Bugs/Comparison/NoComparisonOnFloats.ql index 9c96dc67d63..0b6f2f10d69 100644 --- a/java/ql/src/Likely Bugs/Comparison/NoComparisonOnFloats.ql +++ b/java/ql/src/Likely Bugs/Comparison/NoComparisonOnFloats.ql @@ -12,16 +12,6 @@ import semmle.code.java.Type import semmle.code.java.Expr -// Either `float`, `double`, `Float`, or `Double`. -class Floating extends Type { - Floating() { - exists(string s | s = this.getName().toLowerCase() | - s = "float" or - s = "double" - ) - } -} - predicate trivialLiteral(Literal e) { e.getValue() = "0.0" or e.getValue() = "0" or @@ -61,7 +51,7 @@ predicate similarVarComparison(EqualityTest e) { from EqualityTest ee where - ee.getAnOperand().getType() instanceof Floating and + ee.getAnOperand().getType() instanceof FloatingPointType and not ee.getAnOperand() instanceof NullLiteral and not trivialLiteral(ee.getAnOperand()) and not definedConstant(ee.getAnOperand()) and diff --git a/java/ql/src/Likely Bugs/Nullness/NullMaybe.ql b/java/ql/src/Likely Bugs/Nullness/NullMaybe.ql index d29ebd7fb89..13a800ae539 100644 --- a/java/ql/src/Likely Bugs/Nullness/NullMaybe.ql +++ b/java/ql/src/Likely Bugs/Nullness/NullMaybe.ql @@ -21,6 +21,8 @@ from VarAccess access, SsaSourceVariable var, string msg, Expr reason where nullDeref(var, access, msg, reason) and // Exclude definite nulls here, as these are covered by `NullAlways.ql`. - not alwaysNullDeref(var, access) + not alwaysNullDeref(var, access) and + // Kotlin enforces this already: + not access.getLocation().getFile().isKotlinSourceFile() select access, "Variable $@ may be null here " + msg + ".", var.getVariable(), var.getVariable().getName(), reason, "this" diff --git a/java/ql/src/Performance/InnerClassCouldBeStatic.ql b/java/ql/src/Performance/InnerClassCouldBeStatic.ql index 1a83db097f3..02ca5544da2 100644 --- a/java/ql/src/Performance/InnerClassCouldBeStatic.ql +++ b/java/ql/src/Performance/InnerClassCouldBeStatic.ql @@ -130,7 +130,9 @@ predicate potentiallyStatic(InnerClass c) { ) ) and // JUnit Nested test classes are required to be non-static. - not c.hasAnnotation("org.junit.jupiter.api", "Nested") + not c.hasAnnotation("org.junit.jupiter.api", "Nested") and + // There's no `static` in kotlin: + not c.getLocation().getFile().isKotlinSourceFile() } /** diff --git a/java/ql/src/Security/CWE/CWE-730/PolynomialReDoS.qhelp b/java/ql/src/Security/CWE/CWE-730/PolynomialReDoS.qhelp new file mode 100644 index 00000000000..dbb1f4c37f5 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-730/PolynomialReDoS.qhelp @@ -0,0 +1,108 @@ + + + + + + + +

+ + Consider this use of a regular expression, which removes + all leading and trailing whitespace in a string: + +

+ + + Pattern.compile("^\\s+|\\s+$").matcher(text).replaceAll("") // BAD + + +

+ + The sub-expression "\\s+$" will match the + whitespace characters in text from left to right, but it + can start matching anywhere within a whitespace sequence. This is + problematic for strings that do not end with a whitespace + character. Such a string will force the regular expression engine to + process each whitespace sequence once per whitespace character in the + sequence. + +

+ +

+ + This ultimately means that the time cost of trimming a + string is quadratic in the length of the string. So a string like + "a b" will take milliseconds to process, but a similar + string with a million spaces instead of just one will take several + minutes. + +

+ +

+ + Avoid this problem by rewriting the regular expression to + not contain the ambiguity about when to start matching whitespace + sequences. For instance, by using a negative look-behind + ("^\\s+|(?<!\\s)\\s+$"), or just by using the built-in trim + method (text.trim()). + +

+ +

+ + Note that the sub-expression "^\\s+" is + not problematic as the ^ anchor restricts + when that sub-expression can start matching, and as the regular + expression engine matches from left to right. + +

+ +
+ + + +

+ + As a similar, but slightly subtler problem, consider the + regular expression that matches lines with numbers, possibly written + using scientific notation: +

+ + + "^0\\.\\d+E?\\d+$"" + + +

+ + The problem with this regular expression is in the + sub-expression \d+E?\d+ because the second + \d+ can start matching digits anywhere after the first + match of the first \d+ if there is no E in + the input string. + +

+ +

+ + This is problematic for strings that do not + end with a digit. Such a string will force the regular expression + engine to process each digit sequence once per digit in the sequence, + again leading to a quadratic time complexity. + +

+ +

+ + To make the processing faster, the regular expression + should be rewritten such that the two \d+ sub-expressions + do not have overlapping matches: "^0\\.\\d+(E\\d+)?$". + +

+ +
+ + + +
diff --git a/java/ql/src/Security/CWE/CWE-730/PolynomialReDoS.ql b/java/ql/src/Security/CWE/CWE-730/PolynomialReDoS.ql new file mode 100644 index 00000000000..1a52173183f --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-730/PolynomialReDoS.ql @@ -0,0 +1,24 @@ +/** + * @name Polynomial regular expression used on uncontrolled data + * @description A regular expression that can require polynomial time + * to match may be vulnerable to denial-of-service attacks. + * @kind path-problem + * @problem.severity warning + * @security-severity 7.5 + * @precision high + * @id java/polynomial-redos + * @tags security + * external/cwe/cwe-730 + * external/cwe/cwe-400 + */ + +import java +import semmle.code.java.security.performance.PolynomialReDoSQuery +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, PolynomialBackTrackingTerm regexp +where hasPolynomialReDoSResult(source, sink, regexp) +select sink, source, sink, + "This $@ that depends on $@ may run slow on strings " + regexp.getPrefixMessage() + + "with many repetitions of '" + regexp.getPumpString() + "'.", regexp, "regular expression", + source.getNode(), "a user-provided value" diff --git a/java/ql/src/Security/CWE/CWE-730/ReDoS.qhelp b/java/ql/src/Security/CWE/CWE-730/ReDoS.qhelp new file mode 100644 index 00000000000..08b67acb638 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-730/ReDoS.qhelp @@ -0,0 +1,34 @@ + + + + + + + +

+ Consider this regular expression: +

+ + ^_(__|.)+_$ + +

+ Its sub-expression "(__|.)+?" can match the string "__" either by the + first alternative "__" to the left of the "|" operator, or by two + repetitions of the second alternative "." to the right. Thus, a string consisting + of an odd number of underscores followed by some other character will cause the regular + expression engine to run for an exponential amount of time before rejecting the input. +

+

+ This problem can be avoided by rewriting the regular expression to remove the ambiguity between + the two branches of the alternative inside the repetition: +

+ + ^_(__|[^_])+_$ + +
+ + + +
diff --git a/java/ql/src/Security/CWE/CWE-730/ReDoS.ql b/java/ql/src/Security/CWE/CWE-730/ReDoS.ql new file mode 100644 index 00000000000..c5d9661a63b --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-730/ReDoS.ql @@ -0,0 +1,26 @@ +/** + * @name Inefficient regular expression + * @description A regular expression that requires exponential time to match certain inputs + * can be a performance bottleneck, and may be vulnerable to denial-of-service + * attacks. + * @kind problem + * @problem.severity error + * @security-severity 7.5 + * @precision high + * @id java/redos + * @tags security + * external/cwe/cwe-730 + * external/cwe/cwe-400 + */ + +import java +import semmle.code.java.security.performance.ExponentialBackTracking + +from RegExpTerm t, string pump, State s, string prefixMsg +where + hasReDoSResult(t, pump, s, prefixMsg) and + // exclude verbose mode regexes for now + not t.getRegex().getAMode() = "VERBOSE" +select t, + "This part of the regular expression may cause exponential backtracking on strings " + prefixMsg + + "containing many repetitions of '" + pump + "'." diff --git a/java/ql/src/Security/CWE/CWE-730/ReDoSIntroduction.inc.qhelp b/java/ql/src/Security/CWE/CWE-730/ReDoSIntroduction.inc.qhelp new file mode 100644 index 00000000000..f6e4dbd0a5f --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-730/ReDoSIntroduction.inc.qhelp @@ -0,0 +1,61 @@ + + + +

+ + Some regular expressions take a long time to match certain + input strings to the point where the time it takes to match a string + of length n is proportional to nk or even + 2n. Such regular expressions can negatively affect + performance, or even allow a malicious user to perform a Denial of + Service ("DoS") attack by crafting an expensive input string for the + regular expression to match. + +

+ +

+ + The regular expression engine provided by Java uses a backtracking non-deterministic finite + automata to implement regular expression matching. While this approach + is space-efficient and allows supporting advanced features like + capture groups, it is not time-efficient in general. The worst-case + time complexity of such an automaton can be polynomial or even + exponential, meaning that for strings of a certain shape, increasing + the input length by ten characters may make the automaton about 1000 + times slower. + +

+ +

+ + Typically, a regular expression is affected by this + problem if it contains a repetition of the form r* or + r+ where the sub-expression r is ambiguous + in the sense that it can match some string in multiple ways. More + information about the precise circumstances can be found in the + references. + +

+ +

+ Note that Java versions 9 and above have some mitigations against ReDoS; however they aren't perfect + and more complex regular expressions can still be affected by this problem. +

+
+ + + +

+ + Modify the regular expression to remove the ambiguity, or + ensure that the strings matched with the regular expression are short + enough that the time-complexity does not matter. + + Alternatively, an alternate regex library that guarantees linear time execution, such as Google's RE2J, may be used. + +

+ +
+
diff --git a/java/ql/src/Security/CWE/CWE-730/ReDoSReferences.inc.qhelp b/java/ql/src/Security/CWE/CWE-730/ReDoSReferences.inc.qhelp new file mode 100644 index 00000000000..2b3e5f17c62 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-730/ReDoSReferences.inc.qhelp @@ -0,0 +1,16 @@ + + + +
  • + OWASP: + Regular expression Denial of Service - ReDoS. +
  • +
  • Wikipedia: ReDoS.
  • +
  • Wikipedia: Time complexity.
  • +
  • James Kirrage, Asiri Rathnayake, Hayo Thielecke: + Static Analysis for Regular Expression Denial-of-Service Attack. +
  • +
    +
    diff --git a/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstants.qll b/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstants.qll index 585921bb823..11dbd5cd8d3 100644 --- a/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstants.qll +++ b/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstants.qll @@ -55,7 +55,7 @@ private predicate powerOfTen(float f) { } private predicate floatTrivial(Literal lit) { - (lit instanceof FloatingPointLiteral or lit instanceof DoubleLiteral) and + (lit instanceof FloatLiteral or lit instanceof DoubleLiteral) and exists(float f | f = lit.getValue().toFloat() and (f.abs() <= 20.0 or powerOfTen(f)) diff --git a/java/ql/src/change-notes/2022-03-03-redos.md b/java/ql/src/change-notes/2022-03-03-redos.md new file mode 100644 index 00000000000..daf1dd51be1 --- /dev/null +++ b/java/ql/src/change-notes/2022-03-03-redos.md @@ -0,0 +1,6 @@ +--- +category: newQuery +--- + +* Two new queries "Inefficient regular expression" (`java/redos`) and "Polynomial regular expression used on uncontrolled data" (`java/polynomial-redos`) have been added. +These queries help find instances of Regular Expression Denial of Service vulnerabilities. \ No newline at end of file diff --git a/java/ql/src/change-notes/2022-03-24-unsafe-android-access-improvements.md b/java/ql/src/change-notes/2022-03-24-unsafe-android-access-improvements.md deleted file mode 100644 index 8f0089f616a..00000000000 --- a/java/ql/src/change-notes/2022-03-24-unsafe-android-access-improvements.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: minorAnalysis ---- - * The logic to detect `WebView`s with JavaScript (and optionally file access) enabled in the query `java/android/unsafe-android-webview-fetch` has been improved. - \ No newline at end of file diff --git a/java/ql/src/change-notes/2022-05-02-non-https-urls-simplified.md b/java/ql/src/change-notes/2022-05-02-non-https-urls-simplified.md deleted file mode 100644 index 9baa9a9bbae..00000000000 --- a/java/ql/src/change-notes/2022-05-02-non-https-urls-simplified.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: minorAnalysis ---- -* The query `java/non-https-urls` has been simplified -and no longer requires its sinks to be `MethodAccess`es. \ No newline at end of file diff --git a/java/ql/src/change-notes/2022-05-03-predictable-seed-tag.md b/java/ql/src/change-notes/2022-05-03-predictable-seed-tag.md deleted file mode 100644 index 3133c82ef95..00000000000 --- a/java/ql/src/change-notes/2022-05-03-predictable-seed-tag.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: queryMetadata ---- -* Query `java/predictable-seed` now has a tag for CWE-337. \ No newline at end of file diff --git a/java/ql/src/change-notes/2022-05-11-insecure-cookie.md b/java/ql/src/change-notes/2022-05-11-insecure-cookie.md deleted file mode 100644 index 73d884b46a1..00000000000 --- a/java/ql/src/change-notes/2022-05-11-insecure-cookie.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Query `java/insecure-cookie` now tolerates setting a cookie's secure flag to `request.isSecure()`. This means servlets that intentionally accept unencrypted connections will no longer raise an alert. diff --git a/java/ql/src/change-notes/2022-05-12-sensitive-log-improvements.md b/java/ql/src/change-notes/2022-05-12-sensitive-log-improvements.md new file mode 100644 index 00000000000..bbd6e58e589 --- /dev/null +++ b/java/ql/src/change-notes/2022-05-12-sensitive-log-improvements.md @@ -0,0 +1,7 @@ +--- +category: minorAnalysis +--- +* Query `java/sensitive-log` has received several improvements. + * It no longer considers usernames as sensitive information. + * The conditions to consider a variable a constant (and therefore exclude it as user-provided sensitive information) have been tightened. + * A sanitizer has been added to handle certain elements introduced by a Kotlin compiler plugin that have deceptive names. diff --git a/java/ql/src/change-notes/released/0.1.2.md b/java/ql/src/change-notes/released/0.1.2.md new file mode 100644 index 00000000000..30d252be3de --- /dev/null +++ b/java/ql/src/change-notes/released/0.1.2.md @@ -0,0 +1,12 @@ +## 0.1.2 + +### Query Metadata Changes + +* Query `java/predictable-seed` now has a tag for CWE-337. + +### Minor Analysis Improvements + +* Query `java/insecure-cookie` now tolerates setting a cookie's secure flag to `request.isSecure()`. This means servlets that intentionally accept unencrypted connections will no longer raise an alert. +* The query `java/non-https-urls` has been simplified +and no longer requires its sinks to be `MethodAccess`es. +* The logic to detect `WebView`s with JavaScript (and optionally file access) enabled in the query `java/android/unsafe-android-webview-fetch` has been improved. diff --git a/java/ql/src/codeql-pack.release.yml b/java/ql/src/codeql-pack.release.yml index 92d1505475f..6abd14b1ef8 100644 --- a/java/ql/src/codeql-pack.release.yml +++ b/java/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.1.1 +lastReleaseVersion: 0.1.2 diff --git a/java/ql/src/experimental/Security/CWE/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/Security/CWE/CWE-939/IncorrectURLVerification.ql index 9d51316a854..192aa8d4fa0 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-939/IncorrectURLVerification.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-939/IncorrectURLVerification.ql @@ -43,7 +43,7 @@ class UriGetHostMethod extends Method { } /** - * The method access with incorrect string comparision + * The method access with incorrect string comparison */ class HostVerificationMethodAccess extends MethodAccess { HostVerificationMethodAccess() { diff --git a/java/ql/src/qlpack.yml b/java/ql/src/qlpack.yml index ab897e87726..821e23b0f20 100644 --- a/java/ql/src/qlpack.yml +++ b/java/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-queries -version: 0.1.2-dev +version: 0.1.3-dev groups: - java - queries diff --git a/java/ql/test/TestUtilities/InlineExpectationsTest.qll b/java/ql/test/TestUtilities/InlineExpectationsTest.qll index a4d264b2703..3891fcf13a1 100644 --- a/java/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/java/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -181,7 +181,7 @@ private string expectationCommentPattern() { result = "\\s*\\$((?:[^/]|/[^/])*)( /** * The possible columns in an expectation comment. The `TDefaultColumn` branch represents the first * column in a comment. This column is not precedeeded by a name. `TNamedColumn(name)` represents a - * column containing expected results preceeded by the string `name:`. + * column containing expected results preceded by the string `name:`. */ private newtype TColumn = TDefaultColumn() or diff --git a/java/ql/test/kotlin/library-tests/classes/PrintAst.expected b/java/ql/test/kotlin/library-tests/classes/PrintAst.expected index 4cbec7bf704..0346a4e0292 100644 --- a/java/ql/test/kotlin/library-tests/classes/PrintAst.expected +++ b/java/ql/test/kotlin/library-tests/classes/PrintAst.expected @@ -578,7 +578,7 @@ generic_anonymous.kt: # 3| 1: [ExprStmt] ; # 3| 0: [ClassInstanceExpr] new (...) # 3| -3: [TypeAccess] Object -# 3| 5: [Method] getX +# 3| 5: [Method] getX$private # 3| 3: [TypeAccess] new Object(...) { ... } # 3| 0: [TypeAccess] T # 3| 5: [BlockStmt] { ... } @@ -590,8 +590,69 @@ generic_anonymous.kt: # 7| 5: [BlockStmt] { ... } # 7| 0: [ReturnStmt] return ... # 7| 0: [MethodAccess] getMember(...) -# 7| -1: [MethodAccess] getX(...) +# 7| -1: [MethodAccess] getX$private(...) # 7| -1: [ThisAccess] this +localClassField.kt: +# 0| [CompilationUnit] localClassField +# 1| 1: [Class] A +# 1| 1: [Constructor] A +# 1| 5: [BlockStmt] { ... } +# 1| 0: [SuperConstructorInvocationStmt] super(...) +# 1| 1: [BlockStmt] { ... } +# 2| 0: [ExprStmt] ; +# 2| 0: [KtInitializerAssignExpr] ...=... +# 2| 0: [VarAccess] x +# 7| 1: [ExprStmt] ; +# 7| 0: [KtInitializerAssignExpr] ...=... +# 7| 0: [VarAccess] y +# 2| 2: [Method] getX +# 2| 3: [TypeAccess] Object +# 2| 5: [BlockStmt] { ... } +# 2| 0: [ReturnStmt] return ... +# 2| 0: [VarAccess] this.x +# 2| -1: [ThisAccess] this +# 2| 2: [FieldDeclaration] Object x; +# 2| -1: [TypeAccess] Object +# 2| 0: [WhenExpr] when ... +# 2| 0: [WhenBranch] ... -> ... +# 2| 0: [BooleanLiteral] true +# 2| 1: [BlockStmt] { ... } +# 3| 0: [LocalTypeDeclStmt] class ... +# 3| 0: [LocalClass] L +# 3| 1: [Constructor] L +# 3| 5: [BlockStmt] { ... } +# 3| 0: [SuperConstructorInvocationStmt] super(...) +# 3| 1: [BlockStmt] { ... } +# 4| 1: [ExprStmt] ; +# 4| 0: [ClassInstanceExpr] new L(...) +# 4| -3: [TypeAccess] L +# 2| 1: [WhenBranch] ... -> ... +# 2| 0: [BooleanLiteral] true +# 5| 1: [BlockStmt] { ... } +# 7| 4: [Method] getY +# 7| 3: [TypeAccess] Object +# 7| 5: [BlockStmt] { ... } +# 7| 0: [ReturnStmt] return ... +# 7| 0: [VarAccess] this.y +# 7| -1: [ThisAccess] this +# 7| 4: [FieldDeclaration] Object y; +# 7| -1: [TypeAccess] Object +# 7| 0: [WhenExpr] when ... +# 7| 0: [WhenBranch] ... -> ... +# 7| 0: [BooleanLiteral] true +# 7| 1: [BlockStmt] { ... } +# 8| 0: [LocalTypeDeclStmt] class ... +# 8| 0: [LocalClass] L +# 8| 1: [Constructor] L +# 8| 5: [BlockStmt] { ... } +# 8| 0: [SuperConstructorInvocationStmt] super(...) +# 8| 1: [BlockStmt] { ... } +# 9| 1: [ExprStmt] ; +# 9| 0: [ClassInstanceExpr] new L(...) +# 9| -3: [TypeAccess] L +# 7| 1: [WhenBranch] ... -> ... +# 7| 0: [BooleanLiteral] true +# 10| 1: [BlockStmt] { ... } local_anonymous.kt: # 0| [CompilationUnit] local_anonymous # 3| 1: [Class] Class1 diff --git a/java/ql/test/kotlin/library-tests/classes/classes.expected b/java/ql/test/kotlin/library-tests/classes/classes.expected index 9f67caca2e1..2e3fd5a4305 100644 --- a/java/ql/test/kotlin/library-tests/classes/classes.expected +++ b/java/ql/test/kotlin/library-tests/classes/classes.expected @@ -37,6 +37,9 @@ | generic_anonymous.kt:0:0:0:0 | Generic_anonymousKt | Generic_anonymousKt | final, public | | generic_anonymous.kt:1:1:9:1 | Generic | Generic | final, private | | generic_anonymous.kt:3:19:5:3 | new Object(...) { ... } | | final, private | +| localClassField.kt:1:1:11:1 | A | A | final, public | +| localClassField.kt:3:9:3:19 | L | A$L | final, private | +| localClassField.kt:8:9:8:19 | L | A$L | final, private | | local_anonymous.kt:3:1:36:1 | Class1 | LocalAnonymous.Class1 | final, public | | local_anonymous.kt:5:16:7:9 | new Object(...) { ... } | | final, private | | local_anonymous.kt:11:9:11:24 | | Class1$ | final, private | diff --git a/java/ql/test/kotlin/library-tests/classes/ctorCalls.expected b/java/ql/test/kotlin/library-tests/classes/ctorCalls.expected index 691a1e84d4d..6567b235b6c 100644 --- a/java/ql/test/kotlin/library-tests/classes/ctorCalls.expected +++ b/java/ql/test/kotlin/library-tests/classes/ctorCalls.expected @@ -36,6 +36,9 @@ superCall | classes.kt:129:17:131:17 | super(...) | | generic_anonymous.kt:1:1:9:1 | super(...) | | generic_anonymous.kt:3:19:5:3 | super(...) | +| localClassField.kt:1:1:11:1 | super(...) | +| localClassField.kt:3:9:3:19 | super(...) | +| localClassField.kt:8:9:8:19 | super(...) | | local_anonymous.kt:3:1:36:1 | super(...) | | local_anonymous.kt:5:16:7:9 | super(...) | | local_anonymous.kt:11:9:11:24 | super(...) | diff --git a/java/ql/test/kotlin/library-tests/classes/diags.expected b/java/ql/test/kotlin/library-tests/classes/diags.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/ql/test/kotlin/library-tests/classes/diags.ql b/java/ql/test/kotlin/library-tests/classes/diags.ql new file mode 100644 index 00000000000..f791c30d153 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/classes/diags.ql @@ -0,0 +1,8 @@ +import semmle.code.java.Diagnostics + +from Diagnostic d +where d.getSeverity() > 2 +select d, d.getGeneratedBy(), d.getSeverity(), d.getTag(), d.getMessage(), + d.getFullMessage() + .regexpReplaceAll("^\\[[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} K\\] ", + "[DATE TIME K] ") diff --git a/java/ql/test/kotlin/library-tests/classes/genericExprTypes.expected b/java/ql/test/kotlin/library-tests/classes/genericExprTypes.expected index 1443bcd5e69..aa9514774a6 100644 --- a/java/ql/test/kotlin/library-tests/classes/genericExprTypes.expected +++ b/java/ql/test/kotlin/library-tests/classes/genericExprTypes.expected @@ -27,7 +27,7 @@ | generic_anonymous.kt:4:20:4:20 | Generic.this | Generic | | generic_anonymous.kt:4:20:4:20 | getT(...) | T | | generic_anonymous.kt:7:3:7:22 | T | T | -| generic_anonymous.kt:7:15:7:15 | getX(...) | new Object(...) { ... } | +| generic_anonymous.kt:7:15:7:15 | getX$private(...) | new Object(...) { ... } | | generic_anonymous.kt:7:15:7:15 | this | Generic | | generic_anonymous.kt:7:17:7:22 | getMember(...) | T | | generic_anonymous.kt:11:1:11:56 | String | String | diff --git a/java/ql/test/kotlin/library-tests/classes/localClass.expected b/java/ql/test/kotlin/library-tests/classes/localClass.expected index 53548310414..751b6649982 100644 --- a/java/ql/test/kotlin/library-tests/classes/localClass.expected +++ b/java/ql/test/kotlin/library-tests/classes/localClass.expected @@ -2,5 +2,7 @@ | classes.kt:118:9:123:9 | class ... | classes.kt:118:9:123:9 | | classes.kt:117:5:124:5 | fn2 | classes.kt:109:1:136:1 | C1 | | classes.kt:119:13:121:13 | class ... | classes.kt:119:13:121:13 | Local2 | classes.kt:118:9:123:9 | localFn | classes.kt:109:1:136:1 | C1 | | classes.kt:129:17:131:17 | class ... | classes.kt:129:17:131:17 | Local3 | classes.kt:128:13:133:13 | fn | classes.kt:127:16:134:9 | new Object(...) { ... } | +| localClassField.kt:3:9:3:19 | class ... | localClassField.kt:3:9:3:19 | L | localClassField.kt:1:1:11:1 | A | localClassField.kt:1:1:11:1 | A | +| localClassField.kt:8:9:8:19 | class ... | localClassField.kt:8:9:8:19 | L | localClassField.kt:1:1:11:1 | A | localClassField.kt:1:1:11:1 | A | | local_anonymous.kt:11:9:11:24 | class ... | local_anonymous.kt:11:9:11:24 | | local_anonymous.kt:10:5:13:5 | fn2 | local_anonymous.kt:3:1:36:1 | Class1 | | local_anonymous.kt:25:9:25:27 | class ... | local_anonymous.kt:25:9:25:27 | LocalClass | local_anonymous.kt:24:5:27:5 | fn5 | local_anonymous.kt:3:1:36:1 | Class1 | diff --git a/java/ql/test/kotlin/library-tests/classes/localClassField.kt b/java/ql/test/kotlin/library-tests/classes/localClassField.kt new file mode 100644 index 00000000000..f1db3f45a79 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/classes/localClassField.kt @@ -0,0 +1,11 @@ +class A { + val x = if (true) { + class L { } + L() + } else {} + + val y = if (true) { + class L { } + L() + } else {} +} diff --git a/java/ql/test/kotlin/library-tests/classes/superTypes.expected b/java/ql/test/kotlin/library-tests/classes/superTypes.expected index 3fa2b881183..f0b7f0ca3e9 100644 --- a/java/ql/test/kotlin/library-tests/classes/superTypes.expected +++ b/java/ql/test/kotlin/library-tests/classes/superTypes.expected @@ -49,6 +49,9 @@ | file:///SuperChain2.class:0:0:0:0 | SuperChain2 | file:///SuperChain1.class:0:0:0:0 | SuperChain1 | | generic_anonymous.kt:1:1:9:1 | Generic | file:///Object.class:0:0:0:0 | Object | | generic_anonymous.kt:3:19:5:3 | new Object(...) { ... } | file:///Object.class:0:0:0:0 | Object | +| localClassField.kt:1:1:11:1 | A | file:///Object.class:0:0:0:0 | Object | +| localClassField.kt:3:9:3:19 | L | file:///Object.class:0:0:0:0 | Object | +| localClassField.kt:8:9:8:19 | L | file:///Object.class:0:0:0:0 | Object | | local_anonymous.kt:3:1:36:1 | Class1 | file:///Object.class:0:0:0:0 | Object | | local_anonymous.kt:5:16:7:9 | new Object(...) { ... } | file:///Object.class:0:0:0:0 | Object | | local_anonymous.kt:11:9:11:24 | | file:///Object.class:0:0:0:0 | Object | diff --git a/java/ql/test/kotlin/library-tests/comments/comments.expected b/java/ql/test/kotlin/library-tests/comments/comments.expected index 10d2cb46e73..740f50d8b56 100644 --- a/java/ql/test/kotlin/library-tests/comments/comments.expected +++ b/java/ql/test/kotlin/library-tests/comments/comments.expected @@ -7,15 +7,17 @@ comments | comments.kt:28:5:30:6 | /*\n A block comment\n */ | /*\n A block comment\n */ | | comments.kt:35:5:35:34 | /** Medium is in the middle */ | /** Medium is in the middle */ | | comments.kt:37:5:37:23 | /** This is high */ | /** This is high */ | +| comments.kt:42:5:44:6 | /**\n * A variable.\n */ | /**\n * A variable.\n */ | commentOwners | comments.kt:4:1:11:3 | /**\n * A group of *members*.\n *\n * This class has no useful logic; it's just a documentation example.\n *\n * @property name the name of this group.\n * @constructor Creates an empty group.\n */ | comments.kt:12:1:31:1 | Group | | comments.kt:4:1:11:3 | /**\n * A group of *members*.\n *\n * This class has no useful logic; it's just a documentation example.\n *\n * @property name the name of this group.\n * @constructor Creates an empty group.\n */ | comments.kt:12:1:31:1 | Group | | comments.kt:14:5:16:7 | /**\n * Members of this group.\n */ | comments.kt:17:5:17:46 | members | | comments.kt:14:5:16:7 | /**\n * Members of this group.\n */ | comments.kt:17:5:17:46 | members | -| comments.kt:14:5:16:7 | /**\n * Members of this group.\n */ | comments.kt:17:13:17:46 | getMembers | +| comments.kt:14:5:16:7 | /**\n * Members of this group.\n */ | comments.kt:17:13:17:46 | getMembers$private | | comments.kt:19:5:22:7 | /**\n * Adds a [member] to this group.\n * @return the new size of the group.\n */ | comments.kt:23:5:26:5 | add | | comments.kt:35:5:35:34 | /** Medium is in the middle */ | comments.kt:36:5:36:14 | Medium | | comments.kt:37:5:37:23 | /** This is high */ | comments.kt:38:5:38:11 | High | +| comments.kt:42:5:44:6 | /**\n * A variable.\n */ | comments.kt:45:5:45:13 | int a | commentSections | comments.kt:1:1:1:25 | /** Kdoc with no owner */ | Kdoc with no owner | | comments.kt:4:1:11:3 | /**\n * A group of *members*.\n *\n * This class has no useful logic; it's just a documentation example.\n *\n * @property name the name of this group.\n * @constructor Creates an empty group.\n */ | A group of *members*.\n\nThis class has no useful logic; it's just a documentation example.\n\n | @@ -25,8 +27,10 @@ commentSections | comments.kt:19:5:22:7 | /**\n * Adds a [member] to this group.\n * @return the new size of the group.\n */ | Adds a [member] to this group.\n | | comments.kt:35:5:35:34 | /** Medium is in the middle */ | Medium is in the middle | | comments.kt:37:5:37:23 | /** This is high */ | This is high | +| comments.kt:42:5:44:6 | /**\n * A variable.\n */ | A variable. | commentSectionContents | A group of *members*.\n\nThis class has no useful logic; it's just a documentation example.\n\n | A group of *members*.\n\nThis class has no useful logic; it's just a documentation example.\n\n | +| A variable. | A variable. | | Adds a [member] to this group.\n | Adds a [member] to this group.\n | | Creates an empty group. | Creates an empty group. | | Kdoc with no owner | Kdoc with no owner | diff --git a/java/ql/test/kotlin/library-tests/comments/comments.kt b/java/ql/test/kotlin/library-tests/comments/comments.kt index 6147596d3cd..0981f19e7fa 100644 --- a/java/ql/test/kotlin/library-tests/comments/comments.kt +++ b/java/ql/test/kotlin/library-tests/comments/comments.kt @@ -37,3 +37,10 @@ enum class Severity(val sev: Int) { /** This is high */ High(3) } + +fun fn1() { + /** + * A variable. + */ + val a = 1 +} diff --git a/java/ql/test/kotlin/library-tests/companion_objects/companion_objects.expected b/java/ql/test/kotlin/library-tests/companion_objects/companion_objects.expected index b3a594cbc57..1766f462578 100644 --- a/java/ql/test/kotlin/library-tests/companion_objects/companion_objects.expected +++ b/java/ql/test/kotlin/library-tests/companion_objects/companion_objects.expected @@ -1,2 +1,2 @@ -| companion_objects.kt:1:1:6:1 | MyClass | companion_objects.kt:3:5:5:5 | MyClassCompanion | companion_objects.kt:3:5:5:5 | MyClassCompanion | final,public,static | -| companion_objects.kt:8:1:13:1 | MyInterface | companion_objects.kt:10:5:12:5 | MyInterfaceCompanion | companion_objects.kt:10:5:12:5 | MyInterfaceCompanion | final,public,static | +| companion_objects.kt:1:1:6:1 | MyClass | companion_objects.kt:3:5:5:5 | MyClassCompanion | companion_objects.kt:3:5:5:5 | MyClassCompanion | companion_objects.kt:1:1:6:1 | MyClass | final,public,static | +| companion_objects.kt:8:1:13:1 | MyInterface | companion_objects.kt:10:5:12:5 | MyInterfaceCompanion | companion_objects.kt:10:5:12:5 | MyInterfaceCompanion | companion_objects.kt:8:1:13:1 | MyInterface | final,public,static | diff --git a/java/ql/test/kotlin/library-tests/companion_objects/companion_objects.ql b/java/ql/test/kotlin/library-tests/companion_objects/companion_objects.ql index a170248eaae..a6df9bb27b6 100644 --- a/java/ql/test/kotlin/library-tests/companion_objects/companion_objects.ql +++ b/java/ql/test/kotlin/library-tests/companion_objects/companion_objects.ql @@ -5,4 +5,4 @@ where c.fromSource() and cco = c.getCompanionObject() and f = cco.getInstance() -select c, f, cco, concat(f.getAModifier().toString(), ",") +select c, f, cco, f.getDeclaringType(), concat(f.getAModifier().toString(), ",") diff --git a/java/ql/test/kotlin/library-tests/data-classes/callees.expected b/java/ql/test/kotlin/library-tests/data-classes/callees.expected index b2dd4085a2a..c4b66f2d3a0 100644 --- a/java/ql/test/kotlin/library-tests/data-classes/callees.expected +++ b/java/ql/test/kotlin/library-tests/data-classes/callees.expected @@ -5,4 +5,4 @@ | dc.kt:0:0:0:0 | times(...) | Int.times | | dc.kt:0:0:0:0 | toString(...) | Arrays.toString | | dc.kt:0:0:0:0 | toString(...) | Arrays.toString | -| dc.kt:1:1:1:71 | super(...) | Any.Any | +| dc.kt:1:1:1:71 | super(...) | Object.Object | diff --git a/java/ql/test/kotlin/library-tests/dataflow/foreach/C1.java b/java/ql/test/kotlin/library-tests/dataflow/foreach/C1.java new file mode 100644 index 00000000000..164f9bd1795 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/dataflow/foreach/C1.java @@ -0,0 +1,22 @@ +public final class C1 { + public final String taint(String t) { + return t; + } + + public final void sink(Object a) { + } + + public final void test() { + String[] l = new String[]{this.taint("a"), ""}; + this.sink(l); + this.sink(l[0]); + + for(int i = 0; i < l.length; i++) { + this.sink(l[i]); + } + + for (String s : l) { + this.sink(s); + } + } +} diff --git a/java/ql/test/kotlin/library-tests/dataflow/foreach/C2.kt b/java/ql/test/kotlin/library-tests/dataflow/foreach/C2.kt new file mode 100644 index 00000000000..7a98abaa110 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/dataflow/foreach/C2.kt @@ -0,0 +1,18 @@ +class C2 { + fun taint(t: String): String { + return t + } + + fun sink(a: Any?) {} + fun test() { + val l = arrayOf(taint("a"), "") + sink(l) + sink(l[0]) + for (i in l.indices) { + sink(l[i]) + } + for (s in l) { + sink(s) + } + } +} diff --git a/java/ql/test/kotlin/library-tests/dataflow/foreach/test.expected b/java/ql/test/kotlin/library-tests/dataflow/foreach/test.expected new file mode 100644 index 00000000000..f204c12ebe2 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/dataflow/foreach/test.expected @@ -0,0 +1,8 @@ +| C1.java:10:44:10:46 | "a" | C1.java:11:17:11:17 | l | +| C1.java:10:44:10:46 | "a" | C1.java:12:17:12:20 | ...[...] | +| C1.java:10:44:10:46 | "a" | C1.java:15:20:15:23 | ...[...] | +| C1.java:10:44:10:46 | "a" | C1.java:19:20:19:20 | s | +| C2.kt:8:32:8:32 | a | C2.kt:9:14:9:14 | l | +| C2.kt:8:32:8:32 | a | C2.kt:10:14:10:17 | ...[...] | +| C2.kt:8:32:8:32 | a | C2.kt:12:18:12:21 | ...[...] | +| C2.kt:8:32:8:32 | a | C2.kt:15:18:15:18 | s | diff --git a/java/ql/test/kotlin/library-tests/dataflow/foreach/test.ql b/java/ql/test/kotlin/library-tests/dataflow/foreach/test.ql new file mode 100644 index 00000000000..c14c0ca83d2 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/dataflow/foreach/test.ql @@ -0,0 +1,19 @@ +import java +import semmle.code.java.dataflow.TaintTracking +import semmle.code.java.dataflow.ExternalFlow + +class Conf extends TaintTracking::Configuration { + Conf() { this = "qltest:foreach-array-iterator" } + + override predicate isSource(DataFlow::Node n) { + n.asExpr().(Argument).getCall().getCallee().hasName("taint") + } + + override predicate isSink(DataFlow::Node n) { + n.asExpr().(Argument).getCall().getCallee().hasName("sink") + } +} + +from DataFlow::Node src, DataFlow::Node sink, Conf conf +where conf.hasFlow(src, sink) +select src, sink diff --git a/java/ql/test/kotlin/library-tests/exprs/exprs.expected b/java/ql/test/kotlin/library-tests/exprs/exprs.expected index 2d31bbf92cf..21548a78ed9 100644 --- a/java/ql/test/kotlin/library-tests/exprs/exprs.expected +++ b/java/ql/test/kotlin/library-tests/exprs/exprs.expected @@ -1717,86 +1717,6 @@ | exprs.kt:268:3:268:9 | updated | exprs.kt:261:1:270:1 | inPlaceOperators | VarAccess | | exprs.kt:268:3:268:14 | ...%=... | exprs.kt:261:1:270:1 | inPlaceOperators | AssignRemExpr | | exprs.kt:268:14:268:14 | 1 | exprs.kt:261:1:270:1 | inPlaceOperators | IntegerLiteral | -| file:///!unknown-binary-location/SomePredicate.class:0:0:0:0 | T | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/SomePredicate.class:0:0:0:0 | boolean | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function0.class:0:0:0:0 | R | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function1.class:0:0:0:0 | P1 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function1.class:0:0:0:0 | R | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function2.class:0:0:0:0 | P1 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function2.class:0:0:0:0 | P2 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function2.class:0:0:0:0 | R | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P1 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P2 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P3 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P4 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P5 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P6 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P7 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P8 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P9 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P10 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P11 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P12 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P13 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P14 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P15 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P16 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P17 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P18 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P19 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P20 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P21 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | P22 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function22.class:0:0:0:0 | R | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P1 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P2 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P3 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P4 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P5 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P6 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P7 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P8 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P9 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P10 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P11 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P12 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P13 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P14 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P15 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P16 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P17 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P18 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P19 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P20 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P21 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P22 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | P23 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function23.class:0:0:0:0 | R | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P1 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P2 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P3 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P4 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P5 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P6 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P7 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P8 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P9 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P10 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P11 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P12 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P13 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P14 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P15 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P16 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P17 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P18 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P19 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P20 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P21 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P22 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P23 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | P24 | file://:0:0:0:0 | | TypeAccess | -| file:///!unknown-binary-location/kotlin/Function24.class:0:0:0:0 | R | file://:0:0:0:0 | | TypeAccess | | funcExprs.kt:1:1:1:46 | Unit | file://:0:0:0:0 | | TypeAccess | | funcExprs.kt:1:26:1:37 | Function0 | file://:0:0:0:0 | | TypeAccess | | funcExprs.kt:1:26:1:37 | Integer | file://:0:0:0:0 | | TypeAccess | diff --git a/java/ql/test/kotlin/library-tests/extensions/A.java b/java/ql/test/kotlin/library-tests/extensions/A.java new file mode 100644 index 00000000000..acb3b819de5 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/extensions/A.java @@ -0,0 +1,5 @@ +class A { + void method() { + ExtensionsKt.someFun(new SomeClass(), ""); + } +} \ No newline at end of file diff --git a/java/ql/test/kotlin/library-tests/extensions/methodaccesses.expected b/java/ql/test/kotlin/library-tests/extensions/methodaccesses.expected index ba9440a9bc2..e2864ed1fdb 100644 --- a/java/ql/test/kotlin/library-tests/extensions/methodaccesses.expected +++ b/java/ql/test/kotlin/library-tests/extensions/methodaccesses.expected @@ -1,3 +1,5 @@ +| A.java:3:9:3:49 | someFun(...) | A.java:3:9:3:20 | ExtensionsKt | A.java:3:30:3:44 | new SomeClass(...) | +| A.java:3:9:3:49 | someFun(...) | A.java:3:9:3:20 | ExtensionsKt | A.java:3:47:3:48 | "" | | extensions.kt:21:17:21:38 | someClassMethod(...) | extensions.kt:21:5:21:15 | new SomeClass(...) | extensions.kt:21:34:21:36 | foo | | extensions.kt:22:17:22:30 | someFun(...) | extensions.kt:22:17:22:30 | ExtensionsKt | extensions.kt:22:5:22:15 | new SomeClass(...) | | extensions.kt:22:17:22:30 | someFun(...) | extensions.kt:22:17:22:30 | ExtensionsKt | extensions.kt:22:26:22:28 | foo | diff --git a/java/ql/test/kotlin/library-tests/extensions/methods.expected b/java/ql/test/kotlin/library-tests/extensions/methods.expected index 133477a047a..3c2e4114a78 100644 --- a/java/ql/test/kotlin/library-tests/extensions/methods.expected +++ b/java/ql/test/kotlin/library-tests/extensions/methods.expected @@ -1,3 +1,4 @@ +| A.java:2:10:2:15 | method | file://:0:0:0:0 | void | | extensions.kt:3:5:3:38 | someClassMethod | file://:0:0:0:0 | void | | extensions.kt:6:5:6:41 | anotherClassMethod | file://:0:0:0:0 | void | | extensions.kt:9:1:9:36 | someFun | file://:0:0:0:0 | void | diff --git a/java/ql/test/kotlin/library-tests/extensions/parameters.expected b/java/ql/test/kotlin/library-tests/extensions/parameters.expected index 8081534e885..5cb7e0986d3 100644 --- a/java/ql/test/kotlin/library-tests/extensions/parameters.expected +++ b/java/ql/test/kotlin/library-tests/extensions/parameters.expected @@ -1,7 +1,9 @@ parametersWithArgs | extensions.kt:3:25:3:34 | p1 | 0 | extensions.kt:21:34:21:36 | foo | | extensions.kt:6:28:6:37 | p1 | 0 | extensions.kt:25:40:25:42 | foo | +| extensions.kt:9:5:9:13 | | 0 | A.java:3:30:3:44 | new SomeClass(...) | | extensions.kt:9:5:9:13 | | 0 | extensions.kt:22:5:22:15 | new SomeClass(...) | +| extensions.kt:9:23:9:32 | p1 | 1 | A.java:3:47:3:48 | "" | | extensions.kt:9:23:9:32 | p1 | 1 | extensions.kt:22:26:22:28 | foo | | extensions.kt:10:5:10:16 | | 0 | extensions.kt:26:5:26:18 | new AnotherClass(...) | | extensions.kt:10:29:10:38 | p1 | 1 | extensions.kt:26:32:26:34 | foo | diff --git a/java/ql/test/kotlin/library-tests/field-initializer-flow/test.expected b/java/ql/test/kotlin/library-tests/field-initializer-flow/test.expected new file mode 100644 index 00000000000..ac60487f5bf --- /dev/null +++ b/java/ql/test/kotlin/library-tests/field-initializer-flow/test.expected @@ -0,0 +1,4 @@ +isFinalField +| test.kt:3:3:3:18 | x | +#select +| test.kt:3:3:3:18 | this.x | test.kt:6:10:6:10 | getX(...) | diff --git a/java/ql/test/kotlin/library-tests/field-initializer-flow/test.kt b/java/ql/test/kotlin/library-tests/field-initializer-flow/test.kt new file mode 100644 index 00000000000..a8598658da4 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/field-initializer-flow/test.kt @@ -0,0 +1,11 @@ +class Test { + + val x = "Source" + + fun test() { + sink(x) + } + + fun sink(s: String) { } + +} diff --git a/java/ql/test/kotlin/library-tests/field-initializer-flow/test.ql b/java/ql/test/kotlin/library-tests/field-initializer-flow/test.ql new file mode 100644 index 00000000000..c1fdb928da2 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/field-initializer-flow/test.ql @@ -0,0 +1,22 @@ +import java +import semmle.code.java.dataflow.DataFlow + +class Config extends DataFlow::Configuration { + Config() { this = "Config" } + + override predicate isSource(DataFlow::Node n) { + n.asExpr().(CompileTimeConstantExpr).getStringValue() = "Source" + } + + override predicate isSink(DataFlow::Node n) { + n.asExpr().(Argument).getCall().getCallee().getName() = "sink" + } +} + +query predicate isFinalField(Field f) { + exists(FieldDeclaration f2 | f = f2.getAField()) and f.isFinal() +} + +from DataFlow::Node source, DataFlow::Node sink +where any(Config c).hasFlow(source, sink) +select source, sink diff --git a/java/ql/test/kotlin/library-tests/inherited-callee/test.expected b/java/ql/test/kotlin/library-tests/inherited-callee/test.expected index 3f5cee5b85f..38f8f9f0666 100644 --- a/java/ql/test/kotlin/library-tests/inherited-callee/test.expected +++ b/java/ql/test/kotlin/library-tests/inherited-callee/test.expected @@ -3,8 +3,8 @@ | Test.java:25:5:25:16 | hashCode(...) | hashCode | Object | | Test.java:26:5:26:17 | inheritMe(...) | inheritMe | Test | | Test.java:28:5:28:34 | inheritedInterfaceMethodJ(...) | inheritedInterfaceMethodJ | ParentIf | -| Test.kt:23:7:23:16 | toString(...) | toString | Any | -| Test.kt:24:7:24:15 | equals(...) | equals | Any | -| Test.kt:25:7:25:16 | hashCode(...) | hashCode | Any | +| Test.kt:23:7:23:16 | toString(...) | toString | Object | +| Test.kt:24:7:24:15 | equals(...) | equals | Object | +| Test.kt:25:7:25:16 | hashCode(...) | hashCode | Object | | Test.kt:26:7:26:17 | inheritMe(...) | inheritMe | TestKt | | Test.kt:28:9:28:35 | inheritedInterfaceMethodK(...) | inheritedInterfaceMethodK | ParentIf | diff --git a/java/ql/test/kotlin/library-tests/java-map-methods/test.expected b/java/ql/test/kotlin/library-tests/java-map-methods/test.expected new file mode 100644 index 00000000000..0a646e52fe1 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/java-map-methods/test.expected @@ -0,0 +1,2 @@ +| Integer | +| Object | diff --git a/java/ql/test/kotlin/library-tests/java-map-methods/test.kt b/java/ql/test/kotlin/library-tests/java-map-methods/test.kt new file mode 100644 index 00000000000..9a40d3c29bf --- /dev/null +++ b/java/ql/test/kotlin/library-tests/java-map-methods/test.kt @@ -0,0 +1 @@ +fun test(m: Map) = m.getOrDefault(1, 2) diff --git a/java/ql/test/kotlin/library-tests/java-map-methods/test.ql b/java/ql/test/kotlin/library-tests/java-map-methods/test.ql new file mode 100644 index 00000000000..2694f59162d --- /dev/null +++ b/java/ql/test/kotlin/library-tests/java-map-methods/test.ql @@ -0,0 +1,4 @@ +import java + +from MethodAccess ma +select ma.getCallee().getAParameter().getType().toString() diff --git a/java/ql/test/kotlin/library-tests/literals/literals.expected b/java/ql/test/kotlin/library-tests/literals/literals.expected index afcffb731d9..86d23aa0d05 100644 --- a/java/ql/test/kotlin/library-tests/literals/literals.expected +++ b/java/ql/test/kotlin/library-tests/literals/literals.expected @@ -15,9 +15,9 @@ | literals.kt:17:30:17:33 | 15 | LongLiteral | | literals.kt:18:30:18:39 | 11 | LongLiteral | | literals.kt:19:30:19:38 | 1234567 | LongLiteral | -| literals.kt:20:32:20:35 | 0.0 | FloatingPointLiteral | -| literals.kt:21:32:21:37 | 123.4 | FloatingPointLiteral | -| literals.kt:22:32:22:38 | -123.4 | FloatingPointLiteral | +| literals.kt:20:32:20:35 | 0.0 | FloatLiteral | +| literals.kt:21:32:21:37 | 123.4 | FloatLiteral | +| literals.kt:22:32:22:38 | -123.4 | FloatLiteral | | literals.kt:23:34:23:36 | 0.0 | DoubleLiteral | | literals.kt:24:34:24:38 | 123.4 | DoubleLiteral | | literals.kt:25:34:25:39 | -123.4 | DoubleLiteral | diff --git a/java/ql/test/kotlin/library-tests/methods/clinit.expected b/java/ql/test/kotlin/library-tests/methods/clinit.expected new file mode 100644 index 00000000000..8e4a65ab39a --- /dev/null +++ b/java/ql/test/kotlin/library-tests/methods/clinit.expected @@ -0,0 +1 @@ +| clinit.kt:0:0:0:0 | | file://:0:0:0:0 | void | diff --git a/java/ql/test/kotlin/library-tests/methods/clinit.kt b/java/ql/test/kotlin/library-tests/methods/clinit.kt new file mode 100644 index 00000000000..291dc7cad4b --- /dev/null +++ b/java/ql/test/kotlin/library-tests/methods/clinit.kt @@ -0,0 +1,3 @@ +package foo.bar + +var topLevelInt: Int = 0 \ No newline at end of file diff --git a/java/ql/test/kotlin/library-tests/methods/clinit.ql b/java/ql/test/kotlin/library-tests/methods/clinit.ql new file mode 100644 index 00000000000..11ea8515abb --- /dev/null +++ b/java/ql/test/kotlin/library-tests/methods/clinit.ql @@ -0,0 +1,5 @@ +import java + +from Method m +where m.getName() = "" +select m, m.getReturnType() diff --git a/java/ql/test/kotlin/library-tests/methods/exprs.expected b/java/ql/test/kotlin/library-tests/methods/exprs.expected index 7b3f15f512b..a08c7cda44e 100644 --- a/java/ql/test/kotlin/library-tests/methods/exprs.expected +++ b/java/ql/test/kotlin/library-tests/methods/exprs.expected @@ -1,3 +1,17 @@ +| clinit.kt:3:1:3:24 | ...=... | AssignExpr | +| clinit.kt:3:1:3:24 | ...=... | KtInitializerAssignExpr | +| clinit.kt:3:1:3:24 | | VarAccess | +| clinit.kt:3:1:3:24 | ClinitKt | TypeAccess | +| clinit.kt:3:1:3:24 | ClinitKt | TypeAccess | +| clinit.kt:3:1:3:24 | ClinitKt | TypeAccess | +| clinit.kt:3:1:3:24 | ClinitKt.topLevelInt | VarAccess | +| clinit.kt:3:1:3:24 | ClinitKt.topLevelInt | VarAccess | +| clinit.kt:3:1:3:24 | ClinitKt.topLevelInt | VarAccess | +| clinit.kt:3:1:3:24 | Unit | TypeAccess | +| clinit.kt:3:1:3:24 | int | TypeAccess | +| clinit.kt:3:1:3:24 | int | TypeAccess | +| clinit.kt:3:1:3:24 | int | TypeAccess | +| clinit.kt:3:24:3:24 | 0 | IntegerLiteral | | methods2.kt:4:1:5:1 | Unit | TypeAccess | | methods2.kt:4:26:4:31 | int | TypeAccess | | methods2.kt:4:34:4:39 | int | TypeAccess | diff --git a/java/ql/test/kotlin/library-tests/methods/methods.expected b/java/ql/test/kotlin/library-tests/methods/methods.expected index b48a979dc33..87832f2ed87 100644 --- a/java/ql/test/kotlin/library-tests/methods/methods.expected +++ b/java/ql/test/kotlin/library-tests/methods/methods.expected @@ -1,4 +1,7 @@ methods +| clinit.kt:0:0:0:0 | ClinitKt | clinit.kt:0:0:0:0 | | () | | +| clinit.kt:0:0:0:0 | ClinitKt | clinit.kt:3:1:3:24 | getTopLevelInt | getTopLevelInt() | public, static | +| clinit.kt:0:0:0:0 | ClinitKt | clinit.kt:3:1:3:24 | setTopLevelInt | setTopLevelInt(int) | public, static | | methods2.kt:0:0:0:0 | Methods2Kt | methods2.kt:4:1:5:1 | fooBarTopLevelMethod | fooBarTopLevelMethod(int,int) | public, static | | methods2.kt:7:1:10:1 | Class2 | methods2.kt:8:5:9:5 | fooBarClassMethod | fooBarClassMethod(int,int) | public | | methods3.kt:0:0:0:0 | Methods3Kt | methods3.kt:3:1:3:42 | fooBarTopLevelMethodExt | fooBarTopLevelMethodExt(int,int) | public, static | diff --git a/java/ql/test/kotlin/library-tests/methods/parameters.expected b/java/ql/test/kotlin/library-tests/methods/parameters.expected index 75f8eea234b..3e34c2c3b86 100644 --- a/java/ql/test/kotlin/library-tests/methods/parameters.expected +++ b/java/ql/test/kotlin/library-tests/methods/parameters.expected @@ -1,3 +1,4 @@ +| clinit.kt:3:1:3:24 | setTopLevelInt | clinit.kt:3:1:3:24 | | 0 | | methods2.kt:4:1:5:1 | fooBarTopLevelMethod | methods2.kt:4:26:4:31 | x | 0 | | methods2.kt:4:1:5:1 | fooBarTopLevelMethod | methods2.kt:4:34:4:39 | y | 1 | | methods2.kt:8:5:9:5 | fooBarClassMethod | methods2.kt:8:27:8:32 | x | 0 | diff --git a/java/ql/test/kotlin/library-tests/modifiers/modifiers.expected b/java/ql/test/kotlin/library-tests/modifiers/modifiers.expected index b499378e07c..70345c576b0 100644 --- a/java/ql/test/kotlin/library-tests/modifiers/modifiers.expected +++ b/java/ql/test/kotlin/library-tests/modifiers/modifiers.expected @@ -1,20 +1,25 @@ | modifiers.kt:1:1:25:1 | X | Class | public | | modifiers.kt:1:6:25:1 | X | Constructor | public | +| modifiers.kt:2:5:2:21 | a | Field | final | | modifiers.kt:2:5:2:21 | a | Field | private | | modifiers.kt:2:5:2:21 | a | Property | private | -| modifiers.kt:2:13:2:21 | getA | Method | private | +| modifiers.kt:2:13:2:21 | getA$private | Method | private | +| modifiers.kt:3:5:3:23 | b | Field | final | | modifiers.kt:3:5:3:23 | b | Field | private | | modifiers.kt:3:5:3:23 | b | Property | protected | | modifiers.kt:3:15:3:23 | getB | Method | protected | +| modifiers.kt:4:5:4:22 | c | Field | final | | modifiers.kt:4:5:4:22 | c | Field | private | | modifiers.kt:4:5:4:22 | c | Property | internal | | modifiers.kt:4:14:4:22 | getC | Method | internal | +| modifiers.kt:5:5:5:34 | d | Field | final | | modifiers.kt:5:5:5:34 | d | Field | private | | modifiers.kt:5:5:5:34 | d | Property | public | | modifiers.kt:5:5:5:34 | getD | Method | public | | modifiers.kt:7:5:9:5 | Nested | Class | final | | modifiers.kt:7:5:9:5 | Nested | Class | protected | | modifiers.kt:7:15:9:5 | Nested | Constructor | public | +| modifiers.kt:8:9:8:29 | e | Field | final | | modifiers.kt:8:9:8:29 | e | Field | private | | modifiers.kt:8:9:8:29 | e | Property | public | | modifiers.kt:8:16:8:29 | getE | Method | public | diff --git a/java/ql/test/kotlin/library-tests/private-anonymous-types/other.kt b/java/ql/test/kotlin/library-tests/private-anonymous-types/other.kt new file mode 100644 index 00000000000..ace100f9173 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/private-anonymous-types/other.kt @@ -0,0 +1 @@ +class Ext : A("Hello") { } diff --git a/java/ql/test/kotlin/library-tests/private-anonymous-types/test.expected b/java/ql/test/kotlin/library-tests/private-anonymous-types/test.expected new file mode 100644 index 00000000000..4c6907f99d4 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/private-anonymous-types/test.expected @@ -0,0 +1,18 @@ +| file:///!unknown-binary-location/A.class:0:0:0:0 | A | file:///!unknown-binary-location/A.class:0:0:0:0 | A | +| file:///!unknown-binary-location/A.class:0:0:0:0 | A | file:///!unknown-binary-location/A.class:0:0:0:0 | getAnonType | +| file:///!unknown-binary-location/If.class:0:0:0:0 | If | file:///!unknown-binary-location/If.class:0:0:0:0 | getX | +| file:///!unknown-binary-location/If.class:0:0:0:0 | If | file:///!unknown-binary-location/If.class:0:0:0:0 | getX | +| other.kt:1:1:1:34 | Ext | other.kt:1:1:1:34 | Ext | +| test.kt:0:0:0:0 | TestKt | test.kt:19:1:19:38 | user | +| test.kt:1:1:5:1 | If | test.kt:3:3:3:11 | getX | +| test.kt:7:1:17:1 | A | test.kt:7:6:17:1 | A | +| test.kt:7:1:17:1 | A | test.kt:9:3:11:3 | anonType | +| test.kt:7:1:17:1 | A | test.kt:9:3:11:3 | getAnonType | +| test.kt:7:1:17:1 | A | test.kt:13:3:15:3 | privateAnonType | +| test.kt:7:1:17:1 | A | test.kt:13:11:15:3 | getPrivateAnonType$private | +| test.kt:9:18:11:3 | new If(...) { ... } | test.kt:9:18:11:3 | | +| test.kt:9:18:11:3 | new If(...) { ... } | test.kt:10:5:10:22 | x | +| test.kt:9:18:11:3 | new If(...) { ... } | test.kt:10:14:10:22 | getX | +| test.kt:13:33:15:3 | new If(...) { ... } | test.kt:13:33:15:3 | | +| test.kt:13:33:15:3 | new If(...) { ... } | test.kt:14:5:14:22 | x | +| test.kt:13:33:15:3 | new If(...) { ... } | test.kt:14:14:14:22 | getX | diff --git a/java/ql/test/kotlin/library-tests/private-anonymous-types/test.kt b/java/ql/test/kotlin/library-tests/private-anonymous-types/test.kt new file mode 100644 index 00000000000..b0d49124eac --- /dev/null +++ b/java/ql/test/kotlin/library-tests/private-anonymous-types/test.kt @@ -0,0 +1,19 @@ +interface If { + + val x : T + +} + +open class A(t: T) { + + val anonType = object : If { + override val x = t + } + + private val privateAnonType = object : If { + override val x = t + } + +} + +fun user(x: A) = x.anonType.x diff --git a/java/ql/test/kotlin/library-tests/private-anonymous-types/test.ql b/java/ql/test/kotlin/library-tests/private-anonymous-types/test.ql new file mode 100644 index 00000000000..74bbc59a7fd --- /dev/null +++ b/java/ql/test/kotlin/library-tests/private-anonymous-types/test.ql @@ -0,0 +1,5 @@ +import java + +from ClassOrInterface ci, Member m +where m = ci.getAMember() and ci.getSourceDeclaration().fromSource() +select ci, m diff --git a/java/ql/test/kotlin/library-tests/properties/properties.expected b/java/ql/test/kotlin/library-tests/properties/properties.expected index e1ebdabfd2a..05870c7b6e1 100644 --- a/java/ql/test/kotlin/library-tests/properties/properties.expected +++ b/java/ql/test/kotlin/library-tests/properties/properties.expected @@ -20,6 +20,8 @@ fieldDeclarations | properties.kt:38:5:38:34 | int internalProp; | properties.kt:38:5:38:34 | internalProp | 0 | | properties.kt:67:1:67:23 | int constVal; | properties.kt:67:1:67:23 | constVal | 0 | | properties.kt:70:5:70:16 | int prop; | properties.kt:70:5:70:16 | prop | 0 | +| properties.kt:84:5:84:29 | int data; | properties.kt:84:5:84:29 | data | 0 | +| properties.kt:92:5:93:18 | int data; | properties.kt:92:5:93:18 | data | 0 | #select | properties.kt:2:27:2:50 | constructorProp | properties.kt:2:27:2:50 | getConstructorProp | file://:0:0:0:0 | | properties.kt:2:27:2:50 | constructorProp | public | | properties.kt:2:53:2:83 | mutableConstructorProp | properties.kt:2:53:2:83 | getMutableConstructorProp | properties.kt:2:53:2:83 | setMutableConstructorProp | properties.kt:2:53:2:83 | mutableConstructorProp | public | @@ -40,9 +42,13 @@ fieldDeclarations | properties.kt:30:5:31:29 | overrideGetterUseField | properties.kt:31:13:31:29 | getOverrideGetterUseField | properties.kt:30:5:31:29 | setOverrideGetterUseField | properties.kt:30:5:31:29 | overrideGetterUseField | public | | properties.kt:32:5:33:29 | useField | properties.kt:33:13:33:29 | getUseField | file://:0:0:0:0 | | properties.kt:32:5:33:29 | useField | public | | properties.kt:34:5:34:36 | lateInitVar | properties.kt:34:14:34:36 | getLateInitVar | properties.kt:34:14:34:36 | setLateInitVar | properties.kt:34:5:34:36 | lateInitVar | public | -| properties.kt:35:5:35:32 | privateProp | properties.kt:35:13:35:32 | getPrivateProp | file://:0:0:0:0 | | properties.kt:35:5:35:32 | privateProp | private | +| properties.kt:35:5:35:32 | privateProp | properties.kt:35:13:35:32 | getPrivateProp$private | file://:0:0:0:0 | | properties.kt:35:5:35:32 | privateProp | private | | properties.kt:36:5:36:36 | protectedProp | properties.kt:36:15:36:36 | getProtectedProp | file://:0:0:0:0 | | properties.kt:36:5:36:36 | protectedProp | protected | | properties.kt:37:5:37:30 | publicProp | properties.kt:37:12:37:30 | getPublicProp | file://:0:0:0:0 | | properties.kt:37:5:37:30 | publicProp | public | | properties.kt:38:5:38:34 | internalProp | properties.kt:38:14:38:34 | getInternalProp | file://:0:0:0:0 | | properties.kt:38:5:38:34 | internalProp | internal | | properties.kt:67:1:67:23 | constVal | properties.kt:67:7:67:23 | getConstVal | file://:0:0:0:0 | | properties.kt:67:1:67:23 | constVal | public | | properties.kt:70:5:70:16 | prop | properties.kt:70:5:70:16 | getProp | file://:0:0:0:0 | | properties.kt:70:5:70:16 | prop | public | +| properties.kt:78:1:79:13 | x | properties.kt:79:5:79:13 | getX | file://:0:0:0:0 | | file://:0:0:0:0 | | public | +| properties.kt:80:1:81:13 | x | properties.kt:81:5:81:13 | getX | file://:0:0:0:0 | | file://:0:0:0:0 | | public | +| properties.kt:84:5:84:29 | data | properties.kt:84:13:84:29 | getData$private | properties.kt:84:13:84:29 | setData$private | properties.kt:84:5:84:29 | data | private | +| properties.kt:92:5:93:18 | data | properties.kt:93:9:93:18 | getData | properties.kt:92:13:93:18 | setData$private | properties.kt:92:5:93:18 | data | private | diff --git a/java/ql/test/kotlin/library-tests/properties/properties.kt b/java/ql/test/kotlin/library-tests/properties/properties.kt index b9f7073f636..bde7994f990 100644 --- a/java/ql/test/kotlin/library-tests/properties/properties.kt +++ b/java/ql/test/kotlin/library-tests/properties/properties.kt @@ -73,3 +73,26 @@ class C { println(c.prop) } } + + +val Int.x : Int + get() = 5 +val Double.x : Int + get() = 5 + +class A { + private var data: Int = 0 + + fun setData(p: Int) { + data = p + } +} + +class B { + private var data: Int = 5 + get() = 42 + + fun setData(p: Int) { + data = p + } +} diff --git a/java/ql/test/kotlin/library-tests/reflection/PrintAst.expected b/java/ql/test/kotlin/library-tests/reflection/PrintAst.expected index 3918bc031b6..13b6b6e63b2 100644 --- a/java/ql/test/kotlin/library-tests/reflection/PrintAst.expected +++ b/java/ql/test/kotlin/library-tests/reflection/PrintAst.expected @@ -11,7 +11,7 @@ reflection.kt: # 47| 0: [MethodAccess] get(...) # 47| -1: [ExtensionReceiverAccess] this # 47| 0: [SubExpr] ... - ... -# 47| 0: [MethodAccess] getLength(...) +# 47| 0: [MethodAccess] length(...) # 47| -1: [ExtensionReceiverAccess] this # 47| 1: [IntegerLiteral] 1 # 49| 2: [Method] fn2 diff --git a/java/ql/test/kotlin/library-tests/special-method-getters/test.expected b/java/ql/test/kotlin/library-tests/special-method-getters/test.expected new file mode 100644 index 00000000000..fdec7b0e605 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/special-method-getters/test.expected @@ -0,0 +1,9 @@ +| test.kt:1:84:1:89 | length(...) | length | +| test.kt:1:97:1:100 | size(...) | size | +| test.kt:1:108:1:111 | size(...) | size | +| test.kt:1:119:1:122 | keySet(...) | keySet | +| test.kt:1:124:1:127 | size(...) | size | +| test.kt:1:135:1:140 | values(...) | values | +| test.kt:1:142:1:145 | size(...) | size | +| test.kt:1:153:1:159 | entrySet(...) | entrySet | +| test.kt:1:161:1:164 | size(...) | size | diff --git a/java/ql/test/kotlin/library-tests/special-method-getters/test.kt b/java/ql/test/kotlin/library-tests/special-method-getters/test.kt new file mode 100644 index 00000000000..d83aee0f131 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/special-method-getters/test.kt @@ -0,0 +1 @@ +fun test(cs: CharSequence, col: Collection, map: Map) = cs.length + col.size + map.size + map.keys.size + map.values.size + map.entries.size diff --git a/java/ql/test/kotlin/library-tests/special-method-getters/test.ql b/java/ql/test/kotlin/library-tests/special-method-getters/test.ql new file mode 100644 index 00000000000..257b3344501 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/special-method-getters/test.ql @@ -0,0 +1,4 @@ +import java + +from MethodAccess ma +select ma, ma.getCallee().toString() diff --git a/java/ql/test/kotlin/library-tests/this/call.expected b/java/ql/test/kotlin/library-tests/this/call.expected index afb0a7ede60..59ca46c4a04 100644 --- a/java/ql/test/kotlin/library-tests/this/call.expected +++ b/java/ql/test/kotlin/library-tests/this/call.expected @@ -1,13 +1,13 @@ -| this.kt:2:1:58:1 | super(...) | Any | -| this.kt:3:5:53:5 | super(...) | Any | +| this.kt:2:1:58:1 | super(...) | Object | +| this.kt:3:5:53:5 | super(...) | Object | | this.kt:9:66:17:13 | ...->... | | -| this.kt:9:66:17:13 | super(...) | Any | +| this.kt:9:66:17:13 | super(...) | Object | | this.kt:12:82:16:17 | ...->... | | -| this.kt:12:82:16:17 | super(...) | Any | +| this.kt:12:82:16:17 | super(...) | Object | | this.kt:19:42:21:13 | ...->... | | -| this.kt:19:42:21:13 | super(...) | Any | +| this.kt:19:42:21:13 | super(...) | Object | | this.kt:23:30:25:13 | ...->... | | -| this.kt:23:30:25:13 | super(...) | Any | +| this.kt:23:30:25:13 | super(...) | Object | | this.kt:36:13:36:25 | topLevelFun(...) | topLevelFun | | this.kt:37:13:37:22 | outerFun(...) | outerFun | | this.kt:38:13:38:22 | innerFun(...) | innerFun | @@ -19,5 +19,5 @@ | this.kt:44:18:44:35 | topLevelInnerFun(...) | topLevelInnerFun | | this.kt:45:18:45:32 | outerInnerFun(...) | outerInnerFun | | this.kt:46:18:46:40 | topLevelOuterInnerFun(...) | topLevelOuterInnerFun | -| this.kt:64:1:65:1 | super(...) | Any | -| this.kt:67:1:68:1 | super(...) | Any | +| this.kt:64:1:65:1 | super(...) | Object | +| this.kt:67:1:68:1 | super(...) | Object | diff --git a/java/ql/test/kotlin/library-tests/types/types.expected b/java/ql/test/kotlin/library-tests/types/types.expected index 7802402a108..5fe5d97d0b2 100644 --- a/java/ql/test/kotlin/library-tests/types/types.expected +++ b/java/ql/test/kotlin/library-tests/types/types.expected @@ -1406,7 +1406,6 @@ | ListIterator | GenericType, Interface, ParameterizedType | | ListIterator<> | Interface, RawType | | ListIterator | Interface, ParameterizedType | -| ListIterator | Interface, ParameterizedType | | LoadOperation | GenericType, Interface, ParameterizedType | | LoadOperation<> | Interface, RawType | | LoadOperation | Interface, ParameterizedType | diff --git a/java/ql/test/kotlin/library-tests/variables/variables.expected b/java/ql/test/kotlin/library-tests/variables/variables.expected index 7f40e3782df..c4aaa4a1620 100644 --- a/java/ql/test/kotlin/library-tests/variables/variables.expected +++ b/java/ql/test/kotlin/library-tests/variables/variables.expected @@ -3,7 +3,11 @@ isFinal | variables.kt:8:9:8:26 | int local2 | non-final | | variables.kt:10:9:10:26 | int local3 | final | compileTimeConstant +| variables.kt:3:5:3:21 | prop | +| variables.kt:3:5:3:21 | this.prop | | variables.kt:7:17:7:22 | local1 | +| variables.kt:15:1:15:21 | VariablesKt.topLevel | +| variables.kt:15:1:15:21 | VariablesKt.topLevel | #select | variables.kt:3:5:3:21 | prop | int | variables.kt:3:21:3:21 | 1 | | variables.kt:5:20:5:29 | param | int | file://:0:0:0:0 | | diff --git a/java/ql/test/kotlin/query-tests/InnerClassCouldBeStatic/InnerClassCouldBeStatic.expected b/java/ql/test/kotlin/query-tests/InnerClassCouldBeStatic/InnerClassCouldBeStatic.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/ql/test/kotlin/query-tests/InnerClassCouldBeStatic/InnerClassCouldBeStatic.qlref b/java/ql/test/kotlin/query-tests/InnerClassCouldBeStatic/InnerClassCouldBeStatic.qlref new file mode 100644 index 00000000000..3d3b5444609 --- /dev/null +++ b/java/ql/test/kotlin/query-tests/InnerClassCouldBeStatic/InnerClassCouldBeStatic.qlref @@ -0,0 +1 @@ +Performance/InnerClassCouldBeStatic.ql \ No newline at end of file diff --git a/java/ql/test/kotlin/query-tests/InnerClassCouldBeStatic/Test.kt b/java/ql/test/kotlin/query-tests/InnerClassCouldBeStatic/Test.kt new file mode 100644 index 00000000000..2a7be54aa28 --- /dev/null +++ b/java/ql/test/kotlin/query-tests/InnerClassCouldBeStatic/Test.kt @@ -0,0 +1,6 @@ +class A { + fun fn1() {} + companion object { + fun fn2() {} + } +} diff --git a/java/ql/test/kotlin/query-tests/MissingInstanceofInEquals/MissingInstanceofInEquals.expected b/java/ql/test/kotlin/query-tests/MissingInstanceofInEquals/MissingInstanceofInEquals.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/ql/test/kotlin/query-tests/MissingInstanceofInEquals/MissingInstanceofInEquals.qlref b/java/ql/test/kotlin/query-tests/MissingInstanceofInEquals/MissingInstanceofInEquals.qlref new file mode 100644 index 00000000000..40038cf027a --- /dev/null +++ b/java/ql/test/kotlin/query-tests/MissingInstanceofInEquals/MissingInstanceofInEquals.qlref @@ -0,0 +1 @@ +Likely Bugs/Comparison/MissingInstanceofInEquals.ql \ No newline at end of file diff --git a/java/ql/test/kotlin/query-tests/MissingInstanceofInEquals/Test.kt b/java/ql/test/kotlin/query-tests/MissingInstanceofInEquals/Test.kt new file mode 100644 index 00000000000..7e8fa2619e2 --- /dev/null +++ b/java/ql/test/kotlin/query-tests/MissingInstanceofInEquals/Test.kt @@ -0,0 +1,7 @@ +data class D(val x: Int) {} + +data class E(val x: Int) { + override fun equals(other: Any?): Boolean { + return (other as? E)?.x == this.x + } +} diff --git a/java/ql/test/kotlin/query-tests/NullMaybe/NullMaybe.expected b/java/ql/test/kotlin/query-tests/NullMaybe/NullMaybe.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/ql/test/kotlin/query-tests/NullMaybe/NullMaybe.qlref b/java/ql/test/kotlin/query-tests/NullMaybe/NullMaybe.qlref new file mode 100644 index 00000000000..ab01473d8e5 --- /dev/null +++ b/java/ql/test/kotlin/query-tests/NullMaybe/NullMaybe.qlref @@ -0,0 +1 @@ +Likely Bugs/Nullness/NullMaybe.ql diff --git a/java/ql/test/kotlin/query-tests/NullMaybe/Test.kt b/java/ql/test/kotlin/query-tests/NullMaybe/Test.kt new file mode 100644 index 00000000000..dc86a0eb34c --- /dev/null +++ b/java/ql/test/kotlin/query-tests/NullMaybe/Test.kt @@ -0,0 +1,7 @@ +fun fn(b: Boolean) { + var d: Double? = null + if (b) { + d = 1.0 + } + println(d!!) +} diff --git a/java/ql/test/kotlin/query-tests/UselessParameter/Test.kt b/java/ql/test/kotlin/query-tests/UselessParameter/Test.kt new file mode 100644 index 00000000000..f476eba616c --- /dev/null +++ b/java/ql/test/kotlin/query-tests/UselessParameter/Test.kt @@ -0,0 +1,9 @@ +interface A { + fun setValue(a: T, b: V) +} + +class B : A { + override fun setValue(a: B, b: Int) { + println("a") + } +} diff --git a/java/ql/test/kotlin/query-tests/UselessParameter/UselessParameter.expected b/java/ql/test/kotlin/query-tests/UselessParameter/UselessParameter.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/ql/test/kotlin/query-tests/UselessParameter/UselessParameter.qlref b/java/ql/test/kotlin/query-tests/UselessParameter/UselessParameter.qlref new file mode 100644 index 00000000000..b1ceb2751a6 --- /dev/null +++ b/java/ql/test/kotlin/query-tests/UselessParameter/UselessParameter.qlref @@ -0,0 +1 @@ +DeadCode/UselessParameter.ql \ No newline at end of file diff --git a/java/ql/test/library-tests/JDK/PrintAst.expected b/java/ql/test/library-tests/JDK/PrintAst.expected index e6f240b325e..8074ef1b965 100644 --- a/java/ql/test/library-tests/JDK/PrintAst.expected +++ b/java/ql/test/library-tests/JDK/PrintAst.expected @@ -73,6 +73,11 @@ jdk/StringMatch.java: # 5| 0: [MethodAccess] matches(...) # 5| -1: [VarAccess] STR # 5| 0: [StringLiteral] "[a-z]+" +# 5| 0: [RegExpPlus] [a-z]+ +# 5| 0: [RegExpCharacterClass] [a-z] +# 5| 0: [RegExpCharacterRange] a-z +# 5| 0: [RegExpConstant | RegExpNormalChar] a +# 5| 1: [RegExpConstant | RegExpNormalChar] z # 8| 5: [Method] b # 8| 3: [TypeAccess] void # 8| 5: [BlockStmt] { ... } diff --git a/java/ql/test/library-tests/fields/PrintAst.expected b/java/ql/test/library-tests/fields/PrintAst.expected index cd24cef4fe0..b762ad0bc34 100644 --- a/java/ql/test/library-tests/fields/PrintAst.expected +++ b/java/ql/test/library-tests/fields/PrintAst.expected @@ -3,7 +3,7 @@ fields/FieldTest.java: # 3| 1: [Class] FieldTest # 4| 4: [FieldDeclaration] float ff, ...; # 4| -1: [TypeAccess] float -# 4| 1: [FloatingPointLiteral] 2.3f +# 4| 1: [FloatLiteral] 2.3f # 5| 5: [FieldDeclaration] Object obj, ...; # 5| -1: [TypeAccess] Object # 5| 0: [NullLiteral] null diff --git a/java/ql/test/library-tests/literals/floatLiterals/floatLiterals.ql b/java/ql/test/library-tests/literals/floatLiterals/floatLiterals.ql index 6a4a9093225..69051a50fe9 100644 --- a/java/ql/test/library-tests/literals/floatLiterals/floatLiterals.ql +++ b/java/ql/test/library-tests/literals/floatLiterals/floatLiterals.ql @@ -1,4 +1,4 @@ import semmle.code.java.Expr -from FloatingPointLiteral lit +from FloatLiteral lit select lit, lit.getValue(), lit.getFloatValue() diff --git a/java/ql/test/library-tests/literals/literals-numeric/negativeNumericLiterals.ql b/java/ql/test/library-tests/literals/literals-numeric/negativeNumericLiterals.ql index 0fbb3989c7a..f8125960983 100644 --- a/java/ql/test/library-tests/literals/literals-numeric/negativeNumericLiterals.ql +++ b/java/ql/test/library-tests/literals/literals-numeric/negativeNumericLiterals.ql @@ -4,6 +4,6 @@ from Literal l where l instanceof IntegerLiteral or l instanceof LongLiteral or - l instanceof FloatingPointLiteral or + l instanceof FloatLiteral or l instanceof DoubleLiteral select l, l.getValue(), l.getParent() diff --git a/java/ql/test/library-tests/regex/Test.java b/java/ql/test/library-tests/regex/Test.java index b351c31812a..fd9be63b68b 100644 --- a/java/ql/test/library-tests/regex/Test.java +++ b/java/ql/test/library-tests/regex/Test.java @@ -101,4 +101,4 @@ public class Test { } -} +} \ No newline at end of file diff --git a/java/ql/test/library-tests/regex/parser/RegexParseTests.expected b/java/ql/test/library-tests/regex/parser/RegexParseTests.expected new file mode 100644 index 00000000000..ad94d005289 --- /dev/null +++ b/java/ql/test/library-tests/regex/parser/RegexParseTests.expected @@ -0,0 +1,207 @@ +parseFailures +#select +| Test.java:5:10:5:17 | [A-Z\\d] | [RegExpCharacterClass] | +| Test.java:5:10:5:19 | [A-Z\\d]++ | [RegExpPlus] | +| Test.java:5:11:5:11 | A | [RegExpConstant,RegExpNormalChar] | +| Test.java:5:11:5:13 | A-Z | [RegExpCharacterRange] | +| Test.java:5:13:5:13 | Z | [RegExpConstant,RegExpNormalChar] | +| Test.java:5:14:5:16 | \\d | [RegExpCharacterClassEscape] | +| Test.java:6:10:6:42 | \\Q hello world [ *** \\Q ) ( \\E | [RegExpConstant,RegExpQuote] | +| Test.java:6:10:6:43 | \\Q hello world [ *** \\Q ) ( \\E+ | [RegExpPlus] | +| Test.java:7:10:7:23 | [\\Q hi ] \\E] | [RegExpCharacterClass] | +| Test.java:7:10:7:24 | [\\Q hi ] \\E]+ | [RegExpPlus] | +| Test.java:7:11:7:22 | \\Q hi ] \\E | [RegExpConstant,RegExpQuote] | +| Test.java:8:10:8:12 | []] | [RegExpCharacterClass] | +| Test.java:8:10:8:13 | []]+ | [RegExpPlus] | +| Test.java:8:11:8:11 | ] | [RegExpConstant,RegExpNormalChar] | +| Test.java:9:10:9:13 | [^]] | [RegExpCharacterClass] | +| Test.java:9:10:9:14 | [^]]+ | [RegExpPlus] | +| Test.java:9:12:9:12 | ] | [RegExpConstant,RegExpNormalChar] | +| Test.java:10:10:10:20 | [abc[defg]] | [RegExpCharacterClass] | +| Test.java:10:10:10:21 | [abc[defg]]+ | [RegExpPlus] | +| Test.java:10:11:10:11 | a | [RegExpConstant,RegExpNormalChar] | +| Test.java:10:12:10:12 | b | [RegExpConstant,RegExpNormalChar] | +| Test.java:10:13:10:13 | c | [RegExpConstant,RegExpNormalChar] | +| Test.java:10:14:10:14 | [ | [RegExpConstant,RegExpNormalChar] | +| Test.java:10:15:10:15 | d | [RegExpConstant,RegExpNormalChar] | +| Test.java:10:16:10:16 | e | [RegExpConstant,RegExpNormalChar] | +| Test.java:10:17:10:17 | f | [RegExpConstant,RegExpNormalChar] | +| Test.java:10:18:10:18 | g | [RegExpConstant,RegExpNormalChar] | +| Test.java:10:19:10:19 | ] | [RegExpConstant,RegExpNormalChar] | +| Test.java:11:10:11:57 | [abc&&[\\W\\p{Lower}\\P{Space}\\N{degree sign}]] | [RegExpCharacterClass] | +| Test.java:11:10:11:69 | [abc&&[\\W\\p{Lower}\\P{Space}\\N{degree sign}]]\\b7\\b{g}8+ | [RegExpSequence] | +| Test.java:11:11:11:11 | a | [RegExpConstant,RegExpNormalChar] | +| Test.java:11:12:11:12 | b | [RegExpConstant,RegExpNormalChar] | +| Test.java:11:13:11:13 | c | [RegExpConstant,RegExpNormalChar] | +| Test.java:11:14:11:14 | & | [RegExpConstant,RegExpNormalChar] | +| Test.java:11:15:11:15 | & | [RegExpConstant,RegExpNormalChar] | +| Test.java:11:16:11:16 | [ | [RegExpConstant,RegExpNormalChar] | +| Test.java:11:17:11:19 | \\W | [RegExpCharacterClassEscape] | +| Test.java:11:20:11:29 | \\p{Lower} | [RegExpCharacterClassEscape] | +| Test.java:11:30:11:39 | \\P{Space} | [RegExpCharacterClassEscape] | +| Test.java:11:40:11:55 | \\N{degree sign} | [RegExpConstant,RegExpEscape] | +| Test.java:11:56:11:56 | ] | [RegExpConstant,RegExpNormalChar] | +| Test.java:11:58:11:60 | \\b | [RegExpConstant,RegExpEscape] | +| Test.java:11:61:11:61 | 7 | [RegExpConstant,RegExpNormalChar] | +| Test.java:11:62:11:67 | \\b{g} | [RegExpConstant,RegExpEscape] | +| Test.java:11:68:11:68 | 8 | [RegExpConstant,RegExpNormalChar] | +| Test.java:11:68:11:69 | 8+ | [RegExpPlus] | +| Test.java:12:10:12:13 | \\cA | [RegExpConstant,RegExpEscape] | +| Test.java:12:10:12:14 | \\cA+ | [RegExpPlus] | +| Test.java:13:10:13:13 | \\c( | [RegExpConstant,RegExpEscape] | +| Test.java:13:10:13:14 | \\c(+ | [RegExpPlus] | +| Test.java:14:10:14:14 | \\c\\ | [RegExpConstant,RegExpEscape] | +| Test.java:14:10:14:19 | \\c\\(ab)+ | [RegExpSequence] | +| Test.java:14:15:14:18 | (ab) | [RegExpGroup] | +| Test.java:14:15:14:19 | (ab)+ | [RegExpPlus] | +| Test.java:14:16:14:16 | a | [RegExpConstant,RegExpNormalChar] | +| Test.java:14:16:14:17 | ab | [RegExpSequence] | +| Test.java:14:17:14:17 | b | [RegExpConstant,RegExpNormalChar] | +| Test.java:15:10:15:15 | (?>hi) | [RegExpGroup] | +| Test.java:15:10:15:45 | (?>hi)(?hell*?o*+)123\\k | [RegExpSequence] | +| Test.java:15:13:15:13 | h | [RegExpConstant,RegExpNormalChar] | +| Test.java:15:13:15:14 | hi | [RegExpSequence] | +| Test.java:15:14:15:14 | i | [RegExpConstant,RegExpNormalChar] | +| Test.java:15:16:15:33 | (?hell*?o*+) | [RegExpGroup] | +| Test.java:15:24:15:24 | h | [RegExpConstant,RegExpNormalChar] | +| Test.java:15:24:15:32 | hell*?o*+ | [RegExpSequence] | +| Test.java:15:25:15:25 | e | [RegExpConstant,RegExpNormalChar] | +| Test.java:15:26:15:26 | l | [RegExpConstant,RegExpNormalChar] | +| Test.java:15:27:15:27 | l | [RegExpConstant,RegExpNormalChar] | +| Test.java:15:27:15:29 | l*? | [RegExpStar] | +| Test.java:15:30:15:30 | o | [RegExpConstant,RegExpNormalChar] | +| Test.java:15:30:15:32 | o*+ | [RegExpStar] | +| Test.java:15:34:15:34 | 1 | [RegExpConstant,RegExpNormalChar] | +| Test.java:15:35:15:35 | 2 | [RegExpConstant,RegExpNormalChar] | +| Test.java:15:36:15:36 | 3 | [RegExpConstant,RegExpNormalChar] | +| Test.java:15:37:15:45 | \\k | [RegExpBackRef] | +| Test.java:16:10:16:10 | a | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:10:16:11 | a+ | [RegExpPlus] | +| Test.java:16:10:16:108 | a+b*c?d{2}e{3,4}f{,5}g{6,}h+?i*?j??k{7}?l{8,9}?m{,10}?n{11,}?o++p*+q?+r{12}+s{13,14}+t{,15}+u{16,}+ | [RegExpSequence] | +| Test.java:16:12:16:12 | b | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:12:16:13 | b* | [RegExpStar] | +| Test.java:16:14:16:14 | c | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:14:16:15 | c? | [RegExpOpt] | +| Test.java:16:16:16:16 | d | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:16:16:19 | d{2} | [RegExpRange] | +| Test.java:16:20:16:20 | e | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:20:16:25 | e{3,4} | [RegExpRange] | +| Test.java:16:26:16:26 | f | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:26:16:30 | f{,5} | [RegExpRange] | +| Test.java:16:31:16:31 | g | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:31:16:35 | g{6,} | [RegExpRange] | +| Test.java:16:36:16:36 | h | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:36:16:38 | h+? | [RegExpPlus] | +| Test.java:16:39:16:39 | i | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:39:16:41 | i*? | [RegExpStar] | +| Test.java:16:42:16:42 | j | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:42:16:44 | j?? | [RegExpOpt] | +| Test.java:16:45:16:45 | k | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:45:16:49 | k{7}? | [RegExpQuantifier] | +| Test.java:16:50:16:50 | l | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:50:16:56 | l{8,9}? | [RegExpQuantifier] | +| Test.java:16:57:16:57 | m | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:57:16:63 | m{,10}? | [RegExpQuantifier] | +| Test.java:16:64:16:64 | n | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:64:16:70 | n{11,}? | [RegExpQuantifier] | +| Test.java:16:71:16:71 | o | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:71:16:73 | o++ | [RegExpPlus] | +| Test.java:16:74:16:74 | p | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:74:16:76 | p*+ | [RegExpStar] | +| Test.java:16:77:16:77 | q | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:77:16:79 | q?+ | [RegExpOpt] | +| Test.java:16:80:16:80 | r | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:80:16:85 | r{12}+ | [RegExpQuantifier] | +| Test.java:16:86:16:86 | s | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:86:16:94 | s{13,14}+ | [RegExpQuantifier] | +| Test.java:16:95:16:95 | t | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:95:16:101 | t{,15}+ | [RegExpQuantifier] | +| Test.java:16:102:16:102 | u | [RegExpConstant,RegExpNormalChar] | +| Test.java:16:102:16:108 | u{16,}+ | [RegExpQuantifier] | +| Test.java:17:10:17:13 | (?i) | [RegExpZeroWidthMatch] | +| Test.java:17:10:17:36 | (?i)(?=a)(?!b)(?<=c)(?hi)(?hell*?o*+)123\\k", + "a+b*c?d{2}e{3,4}f{,5}g{6,}h+?i*?j??k{7}?l{8,9}?m{,10}?n{11,}?o++p*+q?+r{12}+s{13,14}+t{,15}+u{16,}+", + "(?i)(?=a)(?!b)(?<=c)(?+()\\s-]+|\\*|\\[.*?\\])+)\\s*(,|$)", // $ hasExpRedos + + // NOT GOOD; attack: "'" + "\\a".repeat(100) + '"' + // Adapted from Prism (https://github.com/PrismJS/prism), which is licensed + // under the MIT license; see file Prism-LICENSE. + "(\"|')(\\\\?.)*?\\1", // $ hasExpRedos + + // NOT GOOD + "(b|a?b)*c", // $ hasExpRedos + + // NOT GOOD + "(a|aa?)*b", // $ hasExpRedos + + // GOOD + "(.|\\n)*!", + + // NOT GOOD; attack: "\n".repeat(100) + "." + "(?s)(.|\\n)*!", // $ hasExpRedos + + // GOOD + "([\\w.]+)*", + + // NOT GOOD + "(a|aa?)*b", // $ hasExpRedos + + // NOT GOOD + "(([\\s\\S]|[^a])*)\"", // $ hasExpRedos + + // GOOD - there is no witness in the end that could cause the regexp to not match + "([^\"']+)*", + + // NOT GOOD + "((.|[^a])*)\"", // $ hasExpRedos + + // GOOD + "((a|[^a])*)\"", + + // NOT GOOD + "((b|[^a])*)\"", // $ hasExpRedos + + // NOT GOOD + "((G|[^a])*)\"", // $ hasExpRedos + + // NOT GOOD + "(([0-9]|[^a])*)\"", // $ hasExpRedos + + // NOT GOOD + "(?:=(?:([!#\\$%&'\\*\\+\\-\\.\\^_`\\|~0-9A-Za-z]+)|\"((?:\\\\[\\x00-\\x7f]|[^\\x00-\\x08\\x0a-\\x1f\\x7f\"])*)\"))?", // $ MISSING: hasExpRedos + + // NOT GOOD + "\"((?:\\\\[\\x00-\\x7f]|[^\\x00-\\x08\\x0a-\\x1f\\x7f\"])*)\"", // $ MISSING: hasExpRedos + + // GOOD + "\"((?:\\\\[\\x00-\\x7f]|[^\\x00-\\x08\\x0a-\\x1f\\x7f\"\\\\])*)\"", + + // NOT GOOD + "(([a-z]|[d-h])*)\"", // $ hasExpRedos + + // NOT GOOD + "(([^a-z]|[^0-9])*)\"", // $ hasExpRedos + + // NOT GOOD + "((\\d|[0-9])*)\"", // $ hasExpRedos + + // NOT GOOD + "((\\s|\\s)*)\"", // $ hasExpRedos + + // NOT GOOD + "((\\w|G)*)\"", // $ hasExpRedos + + // GOOD + "((\\s|\\d)*)\"", + + // NOT GOOD + "((\\d|\\w)*)\"", // $ hasExpRedos + + // NOT GOOD + "((\\d|5)*)\"", // $ hasExpRedos + + // NOT GOOD + "((\\s|[\\f])*)\"", // $ hasExpRedos + + // NOT GOOD - but not detected (likely because \v is a character class in Java rather than a specific character in other langs) + "((\\s|[\\v]|\\\\v)*)\"", // $ MISSING: hasExpRedos + + // NOT GOOD + "((\\f|[\\f])*)\"", // $ hasExpRedos + + // NOT GOOD + "((\\W|\\D)*)\"", // $ hasExpRedos + + // NOT GOOD + "((\\S|\\w)*)\"", // $ hasExpRedos + + // NOT GOOD + "((\\S|[\\w])*)\"", // $ hasExpRedos + + // NOT GOOD + "((1s|[\\da-z])*)\"", // $ hasExpRedos + + // NOT GOOD + "((0|[\\d])*)\"", // $ hasExpRedos + + // NOT GOOD + "(([\\d]+)*)\"", // $ hasExpRedos + + // GOOD - there is no witness in the end that could cause the regexp to not match + "(\\d+(X\\d+)?)+", + + // GOOD - there is no witness in the end that could cause the regexp to not match + "([0-9]+(X[0-9]*)?)*", + + // GOOD + "^([^>]+)*(>|$)", + + // NOT GOOD + "^([^>a]+)*(>|$)", // $ hasExpRedos + + // NOT GOOD + "(\\n\\s*)+$", // $ hasExpRedos + + // NOT GOOD + "^(?:\\s+|#.*|\\(\\?#[^)]*\\))*(?:[?*+]|\\{\\d+(?:,\\d*)?})", // $ hasExpRedos + + // NOT GOOD + "\\{\\[\\s*([a-zA-Z]+)\\(([a-zA-Z]+)\\)((\\s*([a-zA-Z]+)\\: ?([ a-zA-Z{}]+),?)+)*\\s*\\]\\}", // $ hasExpRedos + + // NOT GOOD + "(a+|b+|c+)*c", // $ hasExpRedos + + // NOT GOOD + "(((a+a?)*)+b+)", // $ hasExpRedos + + // NOT GOOD + "(a+)+bbbb", // $ hasExpRedos + + // GOOD + "(a+)+aaaaa*a+", + + // NOT GOOD + "(a+)+aaaaa$", // $ hasExpRedos + + // GOOD + "(\\n+)+\\n\\n", + + // NOT GOOD + "(\\n+)+\\n\\n$", // $ hasExpRedos + + // NOT GOOD + "([^X]+)*$", // $ hasExpRedos + + // NOT GOOD + "(([^X]b)+)*$", // $ hasExpRedos + + // GOOD + "(([^X]b)+)*($|[^X]b)", + + // NOT GOOD + "(([^X]b)+)*($|[^X]c)", // $ hasExpRedos + + // GOOD + "((ab)+)*ababab", + + // GOOD + "((ab)+)*abab(ab)*(ab)+", + + // GOOD + "((ab)+)*", + + // NOT GOOD + "((ab)+)*$", // $ hasExpRedos + + // GOOD + "((ab)+)*[a1][b1][a2][b2][a3][b3]", + + // NOT GOOD + "([\\n\\s]+)*(.)", // $ hasExpRedos + + // GOOD - any witness passes through the accept state. + "(A*A*X)*", + + // GOOD + "([^\\\\\\]]+)*", + + // NOT GOOD + "(\\w*foobarbaz\\w*foobarbaz\\w*foobarbaz\\w*foobarbaz\\s*foobarbaz\\d*foobarbaz\\w*)+-", // $ hasExpRedos + + // NOT GOOD + "(.thisisagoddamnlongstringforstresstestingthequery|\\sthisisagoddamnlongstringforstresstestingthequery)*-", // $ hasExpRedos + + // NOT GOOD + "(thisisagoddamnlongstringforstresstestingthequery|this\\w+query)*-", // $ hasExpRedos + + // GOOD + "(thisisagoddamnlongstringforstresstestingthequery|imanotherbutunrelatedstringcomparedtotheotherstring)*-", + + // GOOD (but false positive caused by the extractor converting all four unpaired surrogates to \uFFFD) + "foo([\uDC66\uDC67]|[\uDC68\uDC69])*foo", // $ SPURIOUS: hasExpRedos + + // GOOD (but false positive caused by the extractor converting all four unpaired surrogates to \uFFFD) + "foo((\uDC66|\uDC67)|(\uDC68|\uDC69))*foo", // $ SPURIOUS: hasExpRedos + + // NOT GOOD (but cannot currently construct a prefix) + "a{2,3}(b+)+X", // $ hasExpRedos + + // NOT GOOD (and a good prefix test) + "^<(\\w+)((?:\\s+\\w+(?:\\s*=\\s*(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>\\s]+))?)*)\\s*(\\/?)>", // $ hasExpRedos + + // GOOD + "(a+)*[\\s\\S][\\s\\S][\\s\\S]?", + + // GOOD - but we fail to see that repeating the attack string ends in the "accept any" state (due to not parsing the range `[\s\S]{2,3}`). + "(a+)*[\\s\\S]{2,3}", // $ SPURIOUS: hasExpRedos + + // GOOD - but we spuriously conclude that a rejecting suffix exists (due to not parsing the range `[\s\S]{2,}` when constructing the NFA). + "(a+)*([\\s\\S]{2,}|X)$", // $ SPURIOUS: hasExpRedos + + // GOOD + "(a+)*([\\s\\S]*|X)$", + + // NOT GOOD + "((a+)*$|[\\s\\S]+)", // $ hasExpRedos + + // GOOD - but still flagged. The only change compared to the above is the order of alternatives, which we don't model. + "([\\s\\S]+|(a+)*$)", // $ SPURIOUS: hasExpRedos + + // GOOD + "((;|^)a+)+$", + + // NOT GOOD (a good prefix test) + "(^|;)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(e+)+f", // $ hasExpRedos + + // NOT GOOD + "^ab(c+)+$", // $ hasExpRedos + + // NOT GOOD + "(\\d(\\s+)*){20}", // $ hasExpRedos + + // GOOD - but we spuriously conclude that a rejecting suffix exists. + "(([^/]|X)+)(\\/[\\s\\S]*)*$", // $ SPURIOUS: hasExpRedos + + // GOOD - but we spuriously conclude that a rejecting suffix exists. + "^((x([^Y]+)?)*(Y|$))", // $ SPURIOUS: hasExpRedos + + // NOT GOOD + "(a*)+b", // $ hasExpRedos + + // NOT GOOD + "foo([\\w-]*)+bar", // $ hasExpRedos + + // NOT GOOD + "((ab)*)+c", // $ hasExpRedos + + // NOT GOOD + "(a?a?)*b", // $ hasExpRedos + + // GOOD + "(a?)*b", + + // NOT GOOD - but not detected + "(c?a?)*b", // $ MISSING: hasExpRedos + + // NOT GOOD + "(?:a|a?)+b", // $ hasExpRedos + + // NOT GOOD - but not detected. + "(a?b?)*$", // $ MISSING: hasExpRedos + + // NOT GOOD + "PRE(([a-c]|[c-d])T(e?e?e?e?|X))+(cTcT|cTXcTX$)", // $ hasExpRedos + + // NOT GOOD + "^((a)+\\w)+$", // $ hasExpRedos + + // NOT GOOD + "^(b+.)+$", // $ hasExpRedos + + // GOOD + "a*b", + + // All 4 bad combinations of nested * and + + "(a*)*b", // $ hasExpRedos + "(a+)*b", // $ hasExpRedos + "(a*)+b", // $ hasExpRedos + "(a+)+b", // $ hasExpRedos + + // GOOD + "(a|b)+", + "(?:[\\s;,\"'<>(){}|\\[\\]@=+*]|:(?![/\\\\]))+", + + "^((?:a{|-)|\\w\\{)+X$", // $ hasParseFailure + "^((?:a{0|-)|\\w\\{\\d)+X$", // $ hasParseFailure + "^((?:a{0,|-)|\\w\\{\\d,)+X$", // $ hasParseFailure + "^((?:a{0,2|-)|\\w\\{\\d,\\d)+X$", // $ hasParseFailure + + // GOOD + "^((?:a{0,2}|-)|\\w\\{\\d,\\d\\})+X$", + + // NOT GOOD + "X(\\u0061|a)*Y", // $ hasExpRedos + + // GOOD + "X(\\u0061|b)+Y", + + // NOT GOOD + "X(\\x61|a)*Y", // $ hasExpRedos + + // GOOD + "X(\\x61|b)+Y", + + // NOT GOOD + "X(\\x{061}|a)*Y", // $ hasExpRedos + + // GOOD + "X(\\x{061}|b)+Y", + + // NOT GOOD + "X(\\p{Digit}|7)*Y", // $ hasExpRedos + + // GOOD + "X(\\p{Digit}|b)+Y", + + // NOT GOOD + "X(\\P{Digit}|b)*Y", // $ hasExpRedos + + // GOOD + "X(\\P{Digit}|7)+Y", + + // NOT GOOD + "X(\\p{IsDigit}|7)*Y", // $ hasExpRedos + + // GOOD + "X(\\p{IsDigit}|b)+Y", + + // NOT GOOD - but not detected + "X(\\p{Alpha}|a)*Y", // $ MISSING: hasExpRedos + + // GOOD + "X(\\p{Alpha}|7)+Y", + + // GOOD + "(\"[^\"]*?\"|[^\"\\s]+)+(?=\\s*|\\s*$)", + + // BAD + "/(\"[^\"]*?\"|[^\"\\s]+)+(?=\\s*|\\s*$)X", // $ hasExpRedos + "/(\"[^\"]*?\"|[^\"\\s]+)+(?=X)", // $ hasExpRedos + + // BAD + "\\A(\\d|0)*x", // $ hasExpRedos + "(\\d|0)*\\Z", // $ hasExpRedos + "\\b(\\d|0)*x", // $ hasExpRedos + + // GOOD - possessive quantifiers don't backtrack + "(a*+)*+b", + "(a*)*+b", + "(a*+)*b", + + // BAD + "(a*)*b", // $ hasExpRedos + + // BAD - but not detected due to the way possessive quantifiers are approximated + "((aa|a*+)b)*c" // $ MISSING: hasExpRedos + }; + + void test() { + for (int i = 0; i < regs.length; i++) { + Pattern.compile(regs[i]); + } + } +} diff --git a/java/ql/test/query-tests/security/CWE-730/PolyRedosTest.java b/java/ql/test/query-tests/security/CWE-730/PolyRedosTest.java new file mode 100644 index 00000000000..44931190460 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-730/PolyRedosTest.java @@ -0,0 +1,84 @@ +import java.util.regex.Pattern; +import java.util.function.Predicate; +import javax.servlet.http.HttpServletRequest; +import com.google.common.base.Splitter; + +class PolyRedosTest { + void test(HttpServletRequest request) { + String tainted = request.getParameter("inp"); + String reg = "0\\.\\d+E?\\d+!"; + Predicate dummyPred = (s -> s.length() % 7 == 0); + + tainted.matches(reg); // $ hasPolyRedos + tainted.split(reg); // $ hasPolyRedos + tainted.split(reg, 7); // $ hasPolyRedos + tainted.replaceAll(reg, "a"); // $ hasPolyRedos + tainted.replaceFirst(reg, "a"); // $ hasPolyRedos + Pattern.matches(reg, tainted); // $ hasPolyRedos + Pattern.compile(reg).matcher(tainted).matches(); // $ hasPolyRedos + Pattern.compile(reg).split(tainted); // $ hasPolyRedos + Pattern.compile(reg, Pattern.DOTALL).split(tainted); // $ hasPolyRedos + Pattern.compile(reg).split(tainted, 7); // $ hasPolyRedos + Pattern.compile(reg).splitAsStream(tainted); // $ hasPolyRedos + Pattern.compile(reg).asPredicate().test(tainted); // $ hasPolyRedos + Pattern.compile(reg).asMatchPredicate().negate().and(dummyPred).or(dummyPred).test(tainted); // $ hasPolyRedos + Predicate.not(dummyPred.and(dummyPred.or(Pattern.compile(reg).asPredicate()))).test(tainted); // $ hasPolyRedos + + Splitter.on(Pattern.compile(reg)).split(tainted); // $ hasPolyRedos + Splitter.on(reg).split(tainted); + Splitter.onPattern(reg).split(tainted); // $ hasPolyRedos + Splitter.onPattern(reg).splitToList(tainted); // $ hasPolyRedos + Splitter.onPattern(reg).limit(7).omitEmptyStrings().trimResults().split(tainted); // $ hasPolyRedos + Splitter.onPattern(reg).withKeyValueSeparator(" => ").split(tainted); // $ hasPolyRedos + Splitter.on(";").withKeyValueSeparator(reg).split(tainted); + Splitter.on(";").withKeyValueSeparator(Splitter.onPattern(reg)).split(tainted); // $ hasPolyRedos + + } + + void test2(HttpServletRequest request) { + String tainted = request.getParameter("inp"); + + Pattern p1 = Pattern.compile(".*a"); + Pattern p2 = Pattern.compile(".*b"); + + p1.matcher(tainted).matches(); + p2.matcher(tainted).find(); // $ hasPolyRedos + } + + void test3(HttpServletRequest request) { + String tainted = request.getParameter("inp"); + + Pattern p1 = Pattern.compile("ab*b*"); + Pattern p2 = Pattern.compile("cd*d*"); + + p1.matcher(tainted).matches(); // $ hasPolyRedos + p2.matcher(tainted).find(); + } + + void test4(HttpServletRequest request) { + String tainted = request.getParameter("inp"); + + tainted.matches(".*a"); + tainted.replaceAll(".*b", "c"); // $ hasPolyRedos + } + + static Pattern p3 = Pattern.compile(".*a"); + static Pattern p4 = Pattern.compile(".*b"); + + + void test5(HttpServletRequest request) { + String tainted = request.getParameter("inp"); + + p3.asMatchPredicate().test(tainted); + p4.asPredicate().test(tainted); // $ hasPolyRedos + } + + void test6(HttpServletRequest request) { + Pattern p = Pattern.compile("^a*a*$"); + + p.matcher(request.getParameter("inp")).matches(); // $ hasPolyRedos + p.matcher(request.getHeader("If-None-Match")).matches(); + p.matcher(request.getRequestURI()).matches(); + p.matcher(request.getCookies()[0].getName()).matches(); + } +} \ No newline at end of file diff --git a/java/ql/test/query-tests/security/CWE-730/PolynomialReDoS.expected b/java/ql/test/query-tests/security/CWE-730/PolynomialReDoS.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/ql/test/query-tests/security/CWE-730/PolynomialReDoS.ql b/java/ql/test/query-tests/security/CWE-730/PolynomialReDoS.ql new file mode 100644 index 00000000000..19096cf6f95 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-730/PolynomialReDoS.ql @@ -0,0 +1,19 @@ +import java +import TestUtilities.InlineExpectationsTest +import semmle.code.java.security.performance.PolynomialReDoSQuery + +class HasPolyRedos extends InlineExpectationsTest { + HasPolyRedos() { this = "HasPolyRedos" } + + override string getARelevantTag() { result = "hasPolyRedos" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "hasPolyRedos" and + exists(DataFlow::PathNode source, DataFlow::PathNode sink, PolynomialBackTrackingTerm regexp | + hasPolynomialReDoSResult(source, sink, regexp) and + location = sink.getNode().getLocation() and + element = sink.getNode().toString() and + value = "" + ) + } +} diff --git a/java/ql/test/query-tests/security/CWE-730/ReDoS.expected b/java/ql/test/query-tests/security/CWE-730/ReDoS.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/ql/test/query-tests/security/CWE-730/ReDoS.ql b/java/ql/test/query-tests/security/CWE-730/ReDoS.ql new file mode 100644 index 00000000000..79cb8243cd7 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-730/ReDoS.ql @@ -0,0 +1,29 @@ +import java +import TestUtilities.InlineExpectationsTest +import semmle.code.java.security.performance.ExponentialBackTracking +import semmle.code.java.regex.regex + +class HasExpRedos extends InlineExpectationsTest { + HasExpRedos() { this = "HasExpRedos" } + + override string getARelevantTag() { result = ["hasExpRedos", "hasParseFailure"] } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "hasExpRedos" and + exists(RegExpTerm t, string pump, State s, string prefixMsg | + hasReDoSResult(t, pump, s, prefixMsg) and + not t.getRegex().getAMode() = "VERBOSE" and + value = "" and + location = t.getLocation() and + element = t.toString() + ) + or + tag = "hasParseFailure" and + exists(Regex r | + r.failedToParse(_) and + value = "" and + location = r.getLocation() and + element = r.toString() + ) + } +} diff --git a/java/ql/test/query-tests/security/CWE-730/options b/java/ql/test/query-tests/security/CWE-730/options new file mode 100644 index 00000000000..2f7d22dc61c --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-730/options @@ -0,0 +1 @@ +// semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/guava-30.0 \ No newline at end of file diff --git a/java/ql/test/query-tests/security/CWE-940/AndroidIntentRedirectionTest.java b/java/ql/test/query-tests/security/CWE-940/AndroidIntentRedirectionTest.java index c577ca96620..2ce945461b6 100644 --- a/java/ql/test/query-tests/security/CWE-940/AndroidIntentRedirectionTest.java +++ b/java/ql/test/query-tests/security/CWE-940/AndroidIntentRedirectionTest.java @@ -40,13 +40,23 @@ public class AndroidIntentRedirectionTest extends Activity { sendStickyOrderedBroadcastAsUser(intent, null, null, null, 0, null, null); // $ hasAndroidIntentRedirection // @formatter:on + // Sanitizing only the package or the class still allows redirecting + // to non-exported activities in the same package + // or activities with the same name in other packages, respectively. if (intent.getComponent().getPackageName().equals("something")) { - startActivity(intent); // Safe - sanitized + startActivity(intent); // $ hasAndroidIntentRedirection } else { startActivity(intent); // $ hasAndroidIntentRedirection } if (intent.getComponent().getClassName().equals("something")) { - startActivity(intent); // Safe - sanitized + startActivity(intent); // $ hasAndroidIntentRedirection + } else { + startActivity(intent); // $ hasAndroidIntentRedirection + } + + if (intent.getComponent().getPackageName().equals("something") + && intent.getComponent().getClassName().equals("something")) { + startActivity(intent); // Safe } else { startActivity(intent); // $ hasAndroidIntentRedirection } @@ -94,8 +104,7 @@ public class AndroidIntentRedirectionTest extends Activity { } { Intent fwdIntent = new Intent(); - ComponentName component = - new ComponentName("", intent.getStringExtra("className")); + ComponentName component = new ComponentName("", intent.getStringExtra("className")); fwdIntent.setComponent(component); startActivity(fwdIntent); // $ hasAndroidIntentRedirection } diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/base/CharMatcher.java b/java/ql/test/stubs/guava-30.0/com/google/common/base/CharMatcher.java new file mode 100644 index 00000000000..bcc9a0f30b4 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/base/CharMatcher.java @@ -0,0 +1,53 @@ +// Generated automatically from com.google.common.base.CharMatcher for testing purposes + +package com.google.common.base; + +import com.google.common.base.Predicate; + +abstract public class CharMatcher implements Predicate +{ + protected CharMatcher(){} + public CharMatcher and(CharMatcher p0){ return null; } + public CharMatcher negate(){ return null; } + public CharMatcher or(CharMatcher p0){ return null; } + public CharMatcher precomputed(){ return null; } + public String collapseFrom(CharSequence p0, char p1){ return null; } + public String removeFrom(CharSequence p0){ return null; } + public String replaceFrom(CharSequence p0, CharSequence p1){ return null; } + public String replaceFrom(CharSequence p0, char p1){ return null; } + public String retainFrom(CharSequence p0){ return null; } + public String toString(){ return null; } + public String trimAndCollapseFrom(CharSequence p0, char p1){ return null; } + public String trimFrom(CharSequence p0){ return null; } + public String trimLeadingFrom(CharSequence p0){ return null; } + public String trimTrailingFrom(CharSequence p0){ return null; } + public abstract boolean matches(char p0); + public boolean apply(Character p0){ return false; } + public boolean matchesAllOf(CharSequence p0){ return false; } + public boolean matchesAnyOf(CharSequence p0){ return false; } + public boolean matchesNoneOf(CharSequence p0){ return false; } + public int countIn(CharSequence p0){ return 0; } + public int indexIn(CharSequence p0){ return 0; } + public int indexIn(CharSequence p0, int p1){ return 0; } + public int lastIndexIn(CharSequence p0){ return 0; } + public static CharMatcher any(){ return null; } + public static CharMatcher anyOf(CharSequence p0){ return null; } + public static CharMatcher ascii(){ return null; } + public static CharMatcher breakingWhitespace(){ return null; } + public static CharMatcher digit(){ return null; } + public static CharMatcher forPredicate(Predicate p0){ return null; } + public static CharMatcher inRange(char p0, char p1){ return null; } + public static CharMatcher invisible(){ return null; } + public static CharMatcher is(char p0){ return null; } + public static CharMatcher isNot(char p0){ return null; } + public static CharMatcher javaDigit(){ return null; } + public static CharMatcher javaIsoControl(){ return null; } + public static CharMatcher javaLetter(){ return null; } + public static CharMatcher javaLetterOrDigit(){ return null; } + public static CharMatcher javaLowerCase(){ return null; } + public static CharMatcher javaUpperCase(){ return null; } + public static CharMatcher none(){ return null; } + public static CharMatcher noneOf(CharSequence p0){ return null; } + public static CharMatcher singleWidth(){ return null; } + public static CharMatcher whitespace(){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/base/Splitter.java b/java/ql/test/stubs/guava-30.0/com/google/common/base/Splitter.java index 521b6a605a5..0575f99cffd 100644 --- a/java/ql/test/stubs/guava-30.0/com/google/common/base/Splitter.java +++ b/java/ql/test/stubs/guava-30.0/com/google/common/base/Splitter.java @@ -1,48 +1,35 @@ -/* - * Copyright (C) 2009 The Guava Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ +// Generated automatically from com.google.common.base.Splitter for testing purposes package com.google.common.base; -import java.util.Iterator; +import com.google.common.base.CharMatcher; import java.util.List; import java.util.Map; +import java.util.regex.Pattern; +import java.util.stream.Stream; -public final class Splitter { - - public static Splitter on(final String separator) { - return null; - } - - public Splitter omitEmptyStrings() { - return null; - } - - public Iterable split(final CharSequence sequence) { - return null; - } - - public List splitToList(CharSequence sequence) { - return null; - } - - public MapSplitter withKeyValueSeparator(String separator) { - return null; - } - - public static final class MapSplitter { - public Map split(CharSequence sequence) { - return null; +public class Splitter +{ + protected Splitter() {} + public Iterable split(CharSequence p0){ return null; } + public List splitToList(CharSequence p0){ return null; } + public Splitter limit(int p0){ return null; } + public Splitter omitEmptyStrings(){ return null; } + public Splitter trimResults(){ return null; } + public Splitter trimResults(CharMatcher p0){ return null; } + public Splitter.MapSplitter withKeyValueSeparator(Splitter p0){ return null; } + public Splitter.MapSplitter withKeyValueSeparator(String p0){ return null; } + public Splitter.MapSplitter withKeyValueSeparator(char p0){ return null; } + public Stream splitToStream(CharSequence p0){ return null; } + public static Splitter fixedLength(int p0){ return null; } + public static Splitter on(CharMatcher p0){ return null; } + public static Splitter on(Pattern p0){ return null; } + public static Splitter on(String p0){ return null; } + public static Splitter on(char p0){ return null; } + public static Splitter onPattern(String p0){ return null; } + static public class MapSplitter + { + protected MapSplitter() {} + public Map split(CharSequence p0){ return null; } } - } } diff --git a/javascript/ql/examples/queries/dataflow/BackendIdor/BackendIdor.ql b/javascript/ql/examples/queries/dataflow/BackendIdor/BackendIdor.ql index 3842475ecf8..322cccd5d2b 100644 --- a/javascript/ql/examples/queries/dataflow/BackendIdor/BackendIdor.ql +++ b/javascript/ql/examples/queries/dataflow/BackendIdor/BackendIdor.ql @@ -34,7 +34,7 @@ class IdorTaint extends TaintTracking::Configuration { } /** - * A sanitizer for values that have succesfully been compared to another value. + * A sanitizer for values that have successfully been compared to another value. */ class EqualityGuard extends TaintTracking::SanitizerGuardNode, ValueNode { override EqualityTest astNode; diff --git a/javascript/ql/lib/CHANGELOG.md b/javascript/ql/lib/CHANGELOG.md index d50d7fa0dbb..2ffafc074a7 100644 --- a/javascript/ql/lib/CHANGELOG.md +++ b/javascript/ql/lib/CHANGELOG.md @@ -1,3 +1,18 @@ +## 0.1.2 + +### Deprecated APIs + +* The `ReflectedXss`, `StoredXss`, `XssThroughDom`, and `ExceptionXss` modules from `Xss.qll` have been deprecated. + Use the `Customizations.qll` file belonging to the query instead. + +### Minor Analysis Improvements + +* The [cash](https://github.com/fabiospampinato/cash) library is now modelled as an alias for JQuery. + Sinks and sources from cash should now be handled by all XSS queries. +* Added the `Selection` api as a DOM text source in the `js/xss-through-dom` query. +* The security queries now recognize drag and drop data as a source, enabling the queries to flag additional alerts. +* The security queries now recognize ClipboardEvent function parameters as a source, enabling the queries to flag additional alerts. + ## 0.1.1 ## 0.1.0 diff --git a/javascript/ql/lib/change-notes/2022-04-11-drag-and-drop-data.md b/javascript/ql/lib/change-notes/2022-04-11-drag-and-drop-data.md deleted file mode 100644 index 8d3208ffcd2..00000000000 --- a/javascript/ql/lib/change-notes/2022-04-11-drag-and-drop-data.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: minorAnalysis ---- -* The security queries now recognize drag and drop data as a source, enabling the queries to flag additional alerts. -* The security queries now recognize ClipboardEvent function parameters as a source, enabling the queries to flag additional alerts. diff --git a/javascript/ql/lib/change-notes/2022-04-22-xss-library.md b/javascript/ql/lib/change-notes/2022-04-22-xss-library.md deleted file mode 100644 index 561fc4f63a3..00000000000 --- a/javascript/ql/lib/change-notes/2022-04-22-xss-library.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: deprecated ---- -* The `ReflectedXss`, `StoredXss`, `XssThroughDom`, and `ExceptionXss` modules from `Xss.qll` have been deprecated. - Use the `Customizations.qll` file belonging to the query instead. diff --git a/javascript/ql/lib/change-notes/2022-04-30-xss-selection-source.md b/javascript/ql/lib/change-notes/2022-04-30-xss-selection-source.md deleted file mode 100644 index ac6e2c0ce06..00000000000 --- a/javascript/ql/lib/change-notes/2022-04-30-xss-selection-source.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Added the `Selection` api as a DOM text source in the `js/xss-through-dom` query. \ No newline at end of file diff --git a/javascript/ql/lib/change-notes/2022-05-09-cash.md b/javascript/ql/lib/change-notes/2022-05-09-cash.md deleted file mode 100644 index e5e0056e86c..00000000000 --- a/javascript/ql/lib/change-notes/2022-05-09-cash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: minorAnalysis ---- -* The [cash](https://github.com/fabiospampinato/cash) library is now modelled as an alias for JQuery. - Sinks and sources from cash should now be handled by all XSS queries. \ No newline at end of file diff --git a/javascript/ql/lib/change-notes/released/0.1.2.md b/javascript/ql/lib/change-notes/released/0.1.2.md new file mode 100644 index 00000000000..3f3e762813a --- /dev/null +++ b/javascript/ql/lib/change-notes/released/0.1.2.md @@ -0,0 +1,14 @@ +## 0.1.2 + +### Deprecated APIs + +* The `ReflectedXss`, `StoredXss`, `XssThroughDom`, and `ExceptionXss` modules from `Xss.qll` have been deprecated. + Use the `Customizations.qll` file belonging to the query instead. + +### Minor Analysis Improvements + +* The [cash](https://github.com/fabiospampinato/cash) library is now modelled as an alias for JQuery. + Sinks and sources from cash should now be handled by all XSS queries. +* Added the `Selection` api as a DOM text source in the `js/xss-through-dom` query. +* The security queries now recognize drag and drop data as a source, enabling the queries to flag additional alerts. +* The security queries now recognize ClipboardEvent function parameters as a source, enabling the queries to flag additional alerts. diff --git a/javascript/ql/lib/codeql-pack.release.yml b/javascript/ql/lib/codeql-pack.release.yml index 92d1505475f..6abd14b1ef8 100644 --- a/javascript/ql/lib/codeql-pack.release.yml +++ b/javascript/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.1.1 +lastReleaseVersion: 0.1.2 diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml index 9723715b1a8..251489bbc73 100644 --- a/javascript/ql/lib/qlpack.yml +++ b/javascript/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-all -version: 0.1.2-dev +version: 0.1.3-dev groups: javascript dbscheme: semmlecode.javascript.dbscheme extractor: javascript diff --git a/javascript/ql/lib/semmle/javascript/ES2015Modules.qll b/javascript/ql/lib/semmle/javascript/ES2015Modules.qll index 7ee6311393b..6e1be383362 100644 --- a/javascript/ql/lib/semmle/javascript/ES2015Modules.qll +++ b/javascript/ql/lib/semmle/javascript/ES2015Modules.qll @@ -68,7 +68,7 @@ private predicate hasDefaultExport(ES2015Module mod) { * Holds if `mod` contains both named and `default` exports. * * This is used to determine whether a default-import of the module should be reinterpreted - * as a namespace-import, to accomodate the non-standard behavior implemented by some compilers. + * as a namespace-import, to accommodate the non-standard behavior implemented by some compilers. */ private predicate hasBothNamedAndDefaultExports(ES2015Module mod) { hasNamedExports(mod) and @@ -615,7 +615,7 @@ class ReExportDefaultSpecifier extends ExportDefaultSpecifier { } /** - * A namespace export specifier, that is `*` or `* as x` occuring in an export declaration. + * A namespace export specifier, that is `*` or `* as x` occurring in an export declaration. * * Examples: * diff --git a/javascript/ql/lib/semmle/javascript/Expr.qll b/javascript/ql/lib/semmle/javascript/Expr.qll index 69dbdd11451..9295fbb3757 100644 --- a/javascript/ql/lib/semmle/javascript/Expr.qll +++ b/javascript/ql/lib/semmle/javascript/Expr.qll @@ -2904,7 +2904,7 @@ class ImportMetaExpr extends @import_meta_expr, Expr { * let data2 = {{{ user_data2 }}}; * ``` * - * Note that templating placeholders occuring inside strings literals are not parsed, + * Note that templating placeholders occurring inside strings literals are not parsed, * and are simply seen as being part of the string literal. * For example, following snippet does not contain any `GeneratedCodeExpr` nodes: * ```js diff --git a/javascript/ql/lib/semmle/javascript/GlobalAccessPaths.qll b/javascript/ql/lib/semmle/javascript/GlobalAccessPaths.qll index 967729d3fd4..e617f597870 100644 --- a/javascript/ql/lib/semmle/javascript/GlobalAccessPaths.qll +++ b/javascript/ql/lib/semmle/javascript/GlobalAccessPaths.qll @@ -420,7 +420,7 @@ module AccessPath { */ module DominatingPaths { /** - * A classification of acccess paths into reads and writes. + * A classification of access paths into reads and writes. */ private newtype AccessPathKind = AccessPathRead() or diff --git a/javascript/ql/lib/semmle/javascript/NodeModuleResolutionImpl.qll b/javascript/ql/lib/semmle/javascript/NodeModuleResolutionImpl.qll index 6df85792a56..26aa1163e7e 100644 --- a/javascript/ql/lib/semmle/javascript/NodeModuleResolutionImpl.qll +++ b/javascript/ql/lib/semmle/javascript/NodeModuleResolutionImpl.qll @@ -96,7 +96,7 @@ File resolveMainModule(PackageJson pkg, int priority) { or result = tryExtensions(main.resolve(), "index", priority) or - not exists(main.resolve()) and + not main.resolve() instanceof File and exists(int n | n = main.getNumComponent() | result = tryExtensions(main.resolveUpTo(n - 1), getStem(main.getComponent(n - 1)), priority) ) diff --git a/javascript/ql/lib/semmle/javascript/PrintAst.qll b/javascript/ql/lib/semmle/javascript/PrintAst.qll index f60b19ccb4e..3da7eac2de2 100644 --- a/javascript/ql/lib/semmle/javascript/PrintAst.qll +++ b/javascript/ql/lib/semmle/javascript/PrintAst.qll @@ -193,7 +193,7 @@ private module PrintJavaScript { /** * Gets the `i`th child of `element`. - * Can be overriden in subclasses to get more specific behavior for `getChild()`. + * Can be overridden in subclasses to get more specific behavior for `getChild()`. */ AstNode getChildNode(int childIndex) { result = getLocationSortedChild(element, childIndex) } } diff --git a/javascript/ql/lib/semmle/javascript/Regexp.qll b/javascript/ql/lib/semmle/javascript/Regexp.qll index fa9fe811be9..e683fb0db2a 100644 --- a/javascript/ql/lib/semmle/javascript/Regexp.qll +++ b/javascript/ql/lib/semmle/javascript/Regexp.qll @@ -1309,7 +1309,7 @@ module RegExp { } /** - * Holds if `term` can match any occurence of `char` within a string (not taking into account + * Holds if `term` can match any occurrence of `char` within a string (not taking into account * the context in which `term` appears). * * This predicate is under-approximate and never considers sequences to guarantee a match. diff --git a/javascript/ql/lib/semmle/javascript/Variables.qll b/javascript/ql/lib/semmle/javascript/Variables.qll index 73292cfed40..ce2ab2140a9 100644 --- a/javascript/ql/lib/semmle/javascript/Variables.qll +++ b/javascript/ql/lib/semmle/javascript/Variables.qll @@ -226,7 +226,7 @@ class ArgumentsVariable extends Variable { */ class VarRef extends @varref, Identifier, BindingPattern, LexicalRef { /** Gets the variable this identifier refers to. */ - override Variable getVariable() { none() } // Overriden in VarAccess and VarDecl + override Variable getVariable() { none() } // Overridden in VarAccess and VarDecl override string getName() { result = Identifier.super.getName() } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll b/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll index a0007de194d..431007cd944 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll @@ -413,7 +413,7 @@ module Fastify { /** * A call to `rep.view('file', { ... })`, seen as a template instantiation. * - * Assumes the presense of a plugin that provides the `view` method, such as the `point-of-view` plugin. + * Assumes the presence of a plugin that provides the `view` method, such as the `point-of-view` plugin. */ private class ViewCall extends Templating::TemplateInstantiation::Range, DataFlow::CallNode { ViewCall() { this = any(ReplySource rep).ref().getAMethodCall("view") } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/JWT.qll b/javascript/ql/lib/semmle/javascript/frameworks/JWT.qll index 21ac8aad249..48568450770 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/JWT.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/JWT.qll @@ -5,7 +5,7 @@ import javascript /** - * Provides classes and predicates modeling the `jwt-decode` libary. + * Provides classes and predicates modeling the `jwt-decode` library. */ private module JwtDecode { /** @@ -23,7 +23,7 @@ private module JwtDecode { } /** - * Provides classes and predicates modeling the `jsonwebtoken` libary. + * Provides classes and predicates modeling the `jsonwebtoken` library. */ private module JsonWebToken { /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll index b5c56a48cf9..f9519736b0e 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll @@ -74,7 +74,7 @@ module Koa { * Gets a reference to a request parameter defined by this route handler. */ DataFlow::Node getARequestParameterAccess() { - none() // overriden in subclasses. + none() // overridden in subclasses. } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Redux.qll b/javascript/ql/lib/semmle/javascript/frameworks/Redux.qll index 20222fa7842..fae5a1c76d7 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Redux.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Redux.qll @@ -951,7 +951,7 @@ module Redux { ) } - /** Gets the block to execute when `case` matches sucessfully. */ + /** Gets the block to execute when `case` matches successfully. */ private BasicBlock getCaseBlock(SwitchCase case) { result = case.getBodyStmt(0).getBasicBlock() or diff --git a/javascript/ql/lib/semmle/javascript/frameworks/RxJS.qll b/javascript/ql/lib/semmle/javascript/frameworks/RxJS.qll index 4131b9bd61e..e9599912865 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/RxJS.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/RxJS.qll @@ -45,7 +45,7 @@ private DataFlow::Node pipeOutput(DataFlow::CallNode pipe) { /** * Holds if `pipe` acts as the identity function for success values. * - * We currently lack a data-flow node to represent its input/ouput so it must + * We currently lack a data-flow node to represent its input/output so it must * be special-cased. */ private predicate isIdentityPipe(DataFlow::CallNode pipe) { diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Vuex.qll b/javascript/ql/lib/semmle/javascript/frameworks/Vuex.qll index 1f2d2b90dbf..8d062a447aa 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Vuex.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Vuex.qll @@ -227,7 +227,7 @@ module Vuex { result = getAMappedAccess(getMapHelperForCommitKind(kind), name).getParameter(0).getARhs() } - /** Gets a node that refers the payload of a comitted mutation with the given `name.` */ + /** Gets a node that refers the payload of a committed mutation with the given `name.` */ private DataFlow::Node committedPayloadSucc(string kind, string name) { // mutations: { // name: (state, payload) => { ... } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll index 4681c2b91a5..127d9ca5122 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll @@ -59,7 +59,7 @@ * A `(package,type)` pair may refer to a static type or a synthetic type name used internally in the model. * Synthetic type names can be used to reuse intermediate sub-paths, when there are multiple ways to access the same * element. - * See `ModelsAsData.qll` for the langauge-specific interpretation of packages and static type names. + * See `ModelsAsData.qll` for the language-specific interpretation of packages and static type names. * * By convention, if one wants to avoid clashes with static types from the package, the type name * should be prefixed with a tilde character (`~`). For example, `(foo, ~Bar)` can be used to indicate that @@ -396,7 +396,7 @@ predicate isValidTokenNameInIdentifyingAccessPath(string name) { } /** - * Holds if `name` is a valid name for an access path token with no arguments, occuring + * Holds if `name` is a valid name for an access path token with no arguments, occurring * in an identifying access path. */ bindingset[name] diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll index 9e08e8ed619..a5e366a671f 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll @@ -233,7 +233,7 @@ predicate isExtraValidTokenNameInIdentifyingAccessPath(string name) { } /** - * Holds if `name` is a valid name for an access path token with no arguments, occuring + * Holds if `name` is a valid name for an access path token with no arguments, occurring * in an identifying access path. */ predicate isExtraValidNoArgumentTokenInIdentifyingAccessPath(string name) { diff --git a/javascript/ql/lib/semmle/javascript/frameworks/jQuery.qll b/javascript/ql/lib/semmle/javascript/frameworks/jQuery.qll index 31d1d5b99d2..cc94c966c32 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/jQuery.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/jQuery.qll @@ -307,7 +307,7 @@ private module JQueryClientRequest { } /** - * Gets a node refering to the response contained in an `jqXHR` object. + * Gets a node referring to the response contained in an `jqXHR` object. */ private DataFlow::SourceNode getAResponseNodeFromAnXHRObject(DataFlow::SourceNode obj) { result = diff --git a/javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll b/javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll index e22c00ddc47..d935abce37a 100644 --- a/javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll +++ b/javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll @@ -28,14 +28,14 @@ private module RegexpMatching { * but if `ignorePrefix` is true, it will only match "foo". */ predicate test(string str, boolean ignorePrefix) { - none() // maybe overriden in subclasses + none() // maybe overridden in subclasses } /** * Same as `test(..)`, but where the `fillsCaptureGroup` afterwards tells which capture groups were filled by the given string. */ predicate testWithGroups(string str, boolean ignorePrefix) { - none() // maybe overriden in subclasses + none() // maybe overridden in subclasses } /** diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll index 19ecc84bcde..69427e12d7b 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll @@ -52,7 +52,7 @@ module CodeInjection { } /** - * A template tag occuring in JS code, viewed as a code injection sink. + * A template tag occurring in JS code, viewed as a code injection sink. */ class TemplateTagInScriptSink extends Sink { TemplateTagInScriptSink() { diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll index 9ba5964c2e5..a410bda46b5 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll @@ -132,7 +132,7 @@ module IndirectCommandInjection { } /** - * An array of command line arguments (`argv`) parsed by the `yargs` libary. + * An array of command line arguments (`argv`) parsed by the `yargs` library. */ class YargsArgv extends Source { YargsArgv() { diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/InsecureTemporaryFileCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/InsecureTemporaryFileCustomizations.qll new file mode 100644 index 00000000000..216482947ab --- /dev/null +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/InsecureTemporaryFileCustomizations.qll @@ -0,0 +1,102 @@ +/** + * Provides default sources, sinks and sanitizers for reasoning about + * insecure temporary file creation, as well as + * extension points for adding your own. + */ + +import javascript + +/** + * Classes and predicates for reasoning about insecure temporary file creation. + */ +module InsecureTemporaryFile { + /** + * A data flow source for insecure temporary file creation. + */ + abstract class Source extends DataFlow::Node { } + + /** + * A data flow sink for insecure temporary file creation. + */ + abstract class Sink extends DataFlow::Node { } + + /** + * A sanitizer for random insecure temporary file creation. + */ + abstract class Sanitizer extends DataFlow::Node { } + + /** A call that opens a file with a given path. */ + class OpenFileCall extends DataFlow::CallNode { + string methodName; + + OpenFileCall() { + methodName = + [ + "open", "openSync", "writeFile", "writeFileSync", "writeJson", "writeJSON", + "writeJsonSync", "writeJSONSync", "outputJson", "outputJSON", "outputJsonSync", + "outputJSONSync", "outputFile", "outputFileSync" + ] and + this = NodeJSLib::FS::moduleMember(methodName).getACall() + } + + DataFlow::Node getPath() { result = this.getArgument(0) } + + DataFlow::Node getMode() { + methodName = ["open", "openSync"] and + result = this.getArgument(2) + or + not methodName = ["open", "openSync"] and + result = this.getOptionArgument(2, "mode") + } + } + + /** Holds if the `mode` ensure no access to other users. */ + bindingset[mode] + private predicate isSecureMode(int mode) { + // the lowest 6 bits should be 0. + // E.g. `0o600` is secure (each digit in a octal number is 3 bits) + mode.bitAnd(1) = 0 and + mode.bitAnd(2) = 0 and + mode.bitAnd(4) = 0 and + mode.bitAnd(8) = 0 and + mode.bitAnd(16) = 0 and + mode.bitAnd(32) = 0 + } + + /** The path in a call that opens a file without specifying a secure `mode`. Seen as a sink for insecure temporary file creation. */ + class InsecureFileOpen extends Sink { + InsecureFileOpen() { + exists(OpenFileCall call | + not exists(call.getMode()) + or + exists(int mode | mode = call.getMode().getIntValue() | not isSecureMode(mode)) + | + this = call.getPath() + ) + } + } + + /** A string that references the global tmp dir. Seen as a source for insecure temporary file creation. */ + class OSTempDir extends Source { + OSTempDir() { + this = DataFlow::moduleImport("os").getAMemberCall("tmpdir") + or + this.getStringValue().matches("/tmp/%") + } + } + + /** A non-first leaf in a string-concatenation. Seen as a sanitizer for insecure temporary file creation. */ + class NonFirstStringConcatLeaf extends Sanitizer { + NonFirstStringConcatLeaf() { + exists(StringOps::ConcatenationRoot root | + this = root.getALeaf() and + not this = root.getFirstLeaf() + ) + or + exists(DataFlow::CallNode join | + join = DataFlow::moduleMember("path", "join").getACall() and + this = join.getArgument([1 .. join.getNumArgument() - 1]) + ) + } + } +} diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/InsecureTemporaryFileQuery.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/InsecureTemporaryFileQuery.qll new file mode 100644 index 00000000000..56c22972c16 --- /dev/null +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/InsecureTemporaryFileQuery.qll @@ -0,0 +1,27 @@ +/** + * Provides a taint tracking configuration for reasoning about insecure temporary + * file creation. + * + * Note, for performance reasons: only import this file if + * `InsecureTemporaryFile::Configuration` is needed, otherwise + * `InsecureTemporaryFileCustomizations` should be imported instead. + */ + +import javascript +import InsecureTemporaryFileCustomizations::InsecureTemporaryFile + +/** + * A taint-tracking configuration for reasoning about insecure temporary file creation. + */ +class Configuration extends TaintTracking::Configuration { + Configuration() { this = "InsecureTemporaryFile" } + + override predicate isSource(DataFlow::Node source) { source instanceof Source } + + override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + override predicate isSanitizer(DataFlow::Node node) { + super.isSanitizer(node) or + node instanceof Sanitizer + } +} diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeCodeConstruction.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeCodeConstruction.qll index 6fdb2df7f39..2c45483f0db 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeCodeConstruction.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeCodeConstruction.qll @@ -1,6 +1,6 @@ /** * Provides a taint-tracking configuration for reasoning about code - * constructed from libary input vulnerabilities. + * constructed from library input vulnerabilities. * * Note, for performance reasons: only import this file if * `UnsafeCodeConstruction::Configuration` is needed, otherwise diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeCodeConstructionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeCodeConstructionCustomizations.qll index 9534dfda70e..c75b36d29bb 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeCodeConstructionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeCodeConstructionCustomizations.qll @@ -1,6 +1,6 @@ /** * Provides default sources, sinks and sanitizers for reasoning about code - * constructed from libary input vulnerabilities, as well as extension points for + * constructed from library input vulnerabilities, as well as extension points for * adding your own. */ diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeHtmlConstructionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeHtmlConstructionCustomizations.qll index 66cec4dbec8..0edc5f94f30 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeHtmlConstructionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeHtmlConstructionCustomizations.qll @@ -45,7 +45,7 @@ module UnsafeHtmlConstruction { /** * Gets the kind of vulnerability to report in the alert message. * - * Defaults to `Cross-site scripting`, but may be overriden for sinks + * Defaults to `Cross-site scripting`, but may be overridden for sinks * that do not allow script injection, but injection of other undesirable HTML elements. */ abstract string getVulnerabilityKind(); diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/Xss.qll index 7c15fbb84aa..fd44d69435c 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/Xss.qll @@ -14,7 +14,7 @@ module Shared { /** * Gets the kind of vulnerability to report in the alert message. * - * Defaults to `Cross-site scripting`, but may be overriden for sinks + * Defaults to `Cross-site scripting`, but may be overridden for sinks * that do not allow script injection, but injection of other undesirable HTML elements. */ string getVulnerabilityKind() { result = "Cross-site scripting" } diff --git a/javascript/ql/lib/semmle/javascript/security/performance/ExponentialBackTracking.qll b/javascript/ql/lib/semmle/javascript/security/performance/ExponentialBackTracking.qll index 5e0fe18ea00..99b4062dfdc 100644 --- a/javascript/ql/lib/semmle/javascript/security/performance/ExponentialBackTracking.qll +++ b/javascript/ql/lib/semmle/javascript/security/performance/ExponentialBackTracking.qll @@ -51,7 +51,7 @@ * either a single character, a set of characters represented by a * character class, or the set of all characters. * * The product automaton is constructed lazily, starting with pair states - * `(q, q)` where `q` is a fork, and proceding along an over-approximate + * `(q, q)` where `q` is a fork, and proceeding along an over-approximate * step relation. * * The over-approximate step relation allows transitions along pairs of * abstract input symbols where the symbols have overlap in the characters they accept. diff --git a/javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll b/javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll index 6f695b5035b..8aa348bf62f 100644 --- a/javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll +++ b/javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll @@ -610,16 +610,23 @@ State after(RegExpTerm t) { or exists(RegExpGroup grp | t = grp.getAChild() | result = after(grp)) or - exists(EffectivelyStar star | t = star.getAChild() | result = before(star)) + exists(EffectivelyStar star | t = star.getAChild() | + not isPossessive(star) and + result = before(star) + ) or exists(EffectivelyPlus plus | t = plus.getAChild() | - result = before(plus) or + not isPossessive(plus) and + result = before(plus) + or result = after(plus) ) or exists(EffectivelyQuestion opt | t = opt.getAChild() | result = after(opt)) or - exists(RegExpRoot root | t = root | result = AcceptAnySuffix(root)) + exists(RegExpRoot root | t = root | + if matchesAnySuffix(root) then result = AcceptAnySuffix(root) else result = Accept(root) + ) } /** @@ -690,7 +697,7 @@ predicate delta(State q1, EdgeLabel lbl, State q2) { lbl = Epsilon() and q2 = Accept(root) ) or - exists(RegExpRoot root | q1 = Match(root, 0) | lbl = Any() and q2 = q1) + exists(RegExpRoot root | q1 = Match(root, 0) | matchesAnyPrefix(root) and lbl = Any() and q2 = q1) or exists(RegExpDollar dollar | q1 = before(dollar) | lbl = Epsilon() and q2 = Accept(getRoot(dollar)) diff --git a/javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtilSpecific.qll b/javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtilSpecific.qll index 4f247b0ce50..d363e25d83d 100644 --- a/javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtilSpecific.qll +++ b/javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtilSpecific.qll @@ -12,6 +12,24 @@ predicate isEscapeClass(RegExpTerm term, string clazz) { exists(RegExpCharacterClassEscape escape | term = escape | escape.getValue() = clazz) } +/** + * Holds if `term` is a possessive quantifier. + * As javascript's regexes do not support possessive quantifiers, this never holds, but is used by the shared library. + */ +predicate isPossessive(RegExpQuantifier term) { none() } + +/** + * Holds if the regex that `term` is part of is used in a way that ignores any leading prefix of the input it's matched against. + * Not yet implemented for Javascript. + */ +predicate matchesAnyPrefix(RegExpTerm term) { any() } + +/** + * Holds if the regex that `term` is part of is used in a way that ignores any trailing suffix of the input it's matched against. + * Not yet implemented for Javascript. + */ +predicate matchesAnySuffix(RegExpTerm term) { any() } + /** * Holds if the regular expression should not be considered. * diff --git a/javascript/ql/src/CHANGELOG.md b/javascript/ql/src/CHANGELOG.md index a70da925644..0854beff86d 100644 --- a/javascript/ql/src/CHANGELOG.md +++ b/javascript/ql/src/CHANGELOG.md @@ -1,3 +1,10 @@ +## 0.1.2 + +### New Queries + +* The `js/missing-origin-check` query has been added. It highlights "message" event handlers that do not check the origin of the event. + The query previously existed as the experimental `js/missing-postmessageorigin-verification` query. + ## 0.1.1 ### Minor Analysis Improvements diff --git a/javascript/ql/src/Security/CWE-094/ExpressionInjection.ql b/javascript/ql/src/Security/CWE-094/ExpressionInjection.ql index 399c9e4c9bd..03c129711ad 100644 --- a/javascript/ql/src/Security/CWE-094/ExpressionInjection.ql +++ b/javascript/ql/src/Security/CWE-094/ExpressionInjection.ql @@ -6,7 +6,7 @@ * @problem.severity warning * @security-severity 9.3 * @precision high - * @id js/actions/injection + * @id js/actions/command-injection * @tags actions * security * external/cwe/cwe-094 diff --git a/javascript/ql/src/Security/CWE-094/UnsafeCodeConstruction.ql b/javascript/ql/src/Security/CWE-094/UnsafeCodeConstruction.ql index edae41e18ce..ff9b4fc4dd0 100644 --- a/javascript/ql/src/Security/CWE-094/UnsafeCodeConstruction.ql +++ b/javascript/ql/src/Security/CWE-094/UnsafeCodeConstruction.ql @@ -1,5 +1,5 @@ /** - * @name Unsafe code constructed from libary input + * @name Unsafe code constructed from library input * @description Using externally controlled strings to construct code may allow a malicious * user to execute arbitrary code. * @kind path-problem diff --git a/javascript/ql/src/Security/CWE-377/InsecureTemporaryFile.qhelp b/javascript/ql/src/Security/CWE-377/InsecureTemporaryFile.qhelp new file mode 100644 index 00000000000..13bc9514b99 --- /dev/null +++ b/javascript/ql/src/Security/CWE-377/InsecureTemporaryFile.qhelp @@ -0,0 +1,43 @@ + + + + +

    +Temporary files created in the operating system's temporary directory are by default accessible +to other users. In some cases, this can lead to information exposure, or in the worst +case, to remote code execution. +

    +
    + + +

    +Use a well-tested library like tmp +for creating temporary files. These libraries ensure both that the file is inaccessible +to other users and that the file does not already exist. +

    +
    + + +

    +The following example creates a temporary file in the operating system's temporary directory. +

    + + +

    +The file created above is accessible to other users, and there is no guarantee that +the file does not already exist. +

    +

    +The below example uses the tmp library +to securely create a temporary file. +

    + + +
    + + +
  • Mitre.org: CWE-377.
  • +
  • NPM: tmp.
  • +
    + +
    diff --git a/javascript/ql/src/Security/CWE-377/InsecureTemporaryFile.ql b/javascript/ql/src/Security/CWE-377/InsecureTemporaryFile.ql new file mode 100644 index 00000000000..8bfce571835 --- /dev/null +++ b/javascript/ql/src/Security/CWE-377/InsecureTemporaryFile.ql @@ -0,0 +1,21 @@ +/** + * @name Insecure temporary file + * @description Creating a temporary file that is accessible by other users TODO: + * @kind path-problem + * @id js/insecure-temporary-file + * @problem.severity warning + * @security-severity 7.0 + * @precision medium + * @tags external/cwe/cwe-377 + * external/cwe/cwe-378 + * security + */ + +import javascript +import DataFlow::PathGraph +import semmle.javascript.security.dataflow.InsecureTemporaryFileQuery + +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Insecure creation of file in $@.", source.getNode(), + "the os temp dir" diff --git a/javascript/ql/src/Security/CWE-377/examples/insecure-temporary-file.js b/javascript/ql/src/Security/CWE-377/examples/insecure-temporary-file.js new file mode 100644 index 00000000000..af94b4b3972 --- /dev/null +++ b/javascript/ql/src/Security/CWE-377/examples/insecure-temporary-file.js @@ -0,0 +1,6 @@ +const fs = require('fs'); +const os = require('os'); +const path = require('path'); + +const file = path.join(os.tmpdir(), "test-" + (new Date()).getTime() + ".txt"); +fs.writeFileSync(file, "content"); \ No newline at end of file diff --git a/javascript/ql/src/Security/CWE-377/examples/secure-temporary-file.js b/javascript/ql/src/Security/CWE-377/examples/secure-temporary-file.js new file mode 100644 index 00000000000..229f7ec81d1 --- /dev/null +++ b/javascript/ql/src/Security/CWE-377/examples/secure-temporary-file.js @@ -0,0 +1,5 @@ +const fs = require('fs'); +const tmp = require('tmp'); + +const file = tmp.fileSync().name; +fs.writeFileSync(file, "content"); \ No newline at end of file diff --git a/javascript/ql/src/Statements/LoopIterationSkippedDueToShifting.ql b/javascript/ql/src/Statements/LoopIterationSkippedDueToShifting.ql index 719a389fc36..509cce99cf2 100644 --- a/javascript/ql/src/Statements/LoopIterationSkippedDueToShifting.ql +++ b/javascript/ql/src/Statements/LoopIterationSkippedDueToShifting.ql @@ -13,7 +13,7 @@ import javascript /** * An operation that inserts or removes elements from an array while shifting all elements - * occuring after the insertion/removal point. + * occurring after the insertion/removal point. * * Does not include `push` and `pop` since these never shift any elements. */ diff --git a/javascript/ql/src/change-notes/2022-01-18-insecure-temporary-file.md b/javascript/ql/src/change-notes/2022-01-18-insecure-temporary-file.md new file mode 100644 index 00000000000..e8713e94b76 --- /dev/null +++ b/javascript/ql/src/change-notes/2022-01-18-insecure-temporary-file.md @@ -0,0 +1,4 @@ +--- +category: newQuery +--- +* A new query `js/insecure-temporary-file` has been added. The query detects the creation of temporary files that may be accessible by others users. The query is not run by default. diff --git a/javascript/ql/src/change-notes/2022-04-12-postmessage-origin-verification.md b/javascript/ql/src/change-notes/released/0.1.2.md similarity index 75% rename from javascript/ql/src/change-notes/2022-04-12-postmessage-origin-verification.md rename to javascript/ql/src/change-notes/released/0.1.2.md index f59652a8640..345f24ec493 100644 --- a/javascript/ql/src/change-notes/2022-04-12-postmessage-origin-verification.md +++ b/javascript/ql/src/change-notes/released/0.1.2.md @@ -1,5 +1,6 @@ ---- -category: newQuery ---- +## 0.1.2 + +### New Queries + * The `js/missing-origin-check` query has been added. It highlights "message" event handlers that do not check the origin of the event. - The query previously existed as the experimental `js/missing-postmessageorigin-verification` query. \ No newline at end of file + The query previously existed as the experimental `js/missing-postmessageorigin-verification` query. diff --git a/javascript/ql/src/codeql-pack.release.yml b/javascript/ql/src/codeql-pack.release.yml index 92d1505475f..6abd14b1ef8 100644 --- a/javascript/ql/src/codeql-pack.release.yml +++ b/javascript/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.1.1 +lastReleaseVersion: 0.1.2 diff --git a/javascript/ql/src/qlpack.yml b/javascript/ql/src/qlpack.yml index ee8d91927f3..45b11500391 100644 --- a/javascript/ql/src/qlpack.yml +++ b/javascript/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-queries -version: 0.1.2-dev +version: 0.1.3-dev groups: - javascript - queries diff --git a/javascript/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.expected b/javascript/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.expected new file mode 100644 index 00000000000..8952998dd9c --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.expected @@ -0,0 +1,53 @@ +nodes +| insecure-temporary-file.js:7:9:11:5 | tmpLocation | +| insecure-temporary-file.js:7:23:11:5 | path.jo ... )\\n ) | +| insecure-temporary-file.js:8:9:8:45 | os.tmpd ... mpDir() | +| insecure-temporary-file.js:8:21:8:31 | os.tmpdir() | +| insecure-temporary-file.js:8:21:8:31 | os.tmpdir() | +| insecure-temporary-file.js:13:22:13:32 | tmpLocation | +| insecure-temporary-file.js:13:22:13:32 | tmpLocation | +| insecure-temporary-file.js:15:9:15:34 | tmpPath | +| insecure-temporary-file.js:15:19:15:34 | "/tmp/something" | +| insecure-temporary-file.js:15:19:15:34 | "/tmp/something" | +| insecure-temporary-file.js:17:22:17:49 | path.jo ... /foo/") | +| insecure-temporary-file.js:17:22:17:49 | path.jo ... /foo/") | +| insecure-temporary-file.js:17:32:17:38 | tmpPath | +| insecure-temporary-file.js:23:22:23:49 | path.jo ... /foo/") | +| insecure-temporary-file.js:23:22:23:49 | path.jo ... /foo/") | +| insecure-temporary-file.js:23:32:23:38 | tmpPath | +| insecure-temporary-file.js:25:11:25:92 | tmpPath2 | +| insecure-temporary-file.js:25:22:25:92 | path.jo ... )}.md`) | +| insecure-temporary-file.js:25:32:25:42 | os.tmpdir() | +| insecure-temporary-file.js:25:32:25:42 | os.tmpdir() | +| insecure-temporary-file.js:26:22:26:29 | tmpPath2 | +| insecure-temporary-file.js:26:22:26:29 | tmpPath2 | +| insecure-temporary-file.js:28:17:28:24 | tmpPath2 | +| insecure-temporary-file.js:28:17:28:24 | tmpPath2 | +edges +| insecure-temporary-file.js:7:9:11:5 | tmpLocation | insecure-temporary-file.js:13:22:13:32 | tmpLocation | +| insecure-temporary-file.js:7:9:11:5 | tmpLocation | insecure-temporary-file.js:13:22:13:32 | tmpLocation | +| insecure-temporary-file.js:7:23:11:5 | path.jo ... )\\n ) | insecure-temporary-file.js:7:9:11:5 | tmpLocation | +| insecure-temporary-file.js:8:9:8:45 | os.tmpd ... mpDir() | insecure-temporary-file.js:7:23:11:5 | path.jo ... )\\n ) | +| insecure-temporary-file.js:8:21:8:31 | os.tmpdir() | insecure-temporary-file.js:8:9:8:45 | os.tmpd ... mpDir() | +| insecure-temporary-file.js:8:21:8:31 | os.tmpdir() | insecure-temporary-file.js:8:9:8:45 | os.tmpd ... mpDir() | +| insecure-temporary-file.js:15:9:15:34 | tmpPath | insecure-temporary-file.js:17:32:17:38 | tmpPath | +| insecure-temporary-file.js:15:9:15:34 | tmpPath | insecure-temporary-file.js:23:32:23:38 | tmpPath | +| insecure-temporary-file.js:15:19:15:34 | "/tmp/something" | insecure-temporary-file.js:15:9:15:34 | tmpPath | +| insecure-temporary-file.js:15:19:15:34 | "/tmp/something" | insecure-temporary-file.js:15:9:15:34 | tmpPath | +| insecure-temporary-file.js:17:32:17:38 | tmpPath | insecure-temporary-file.js:17:22:17:49 | path.jo ... /foo/") | +| insecure-temporary-file.js:17:32:17:38 | tmpPath | insecure-temporary-file.js:17:22:17:49 | path.jo ... /foo/") | +| insecure-temporary-file.js:23:32:23:38 | tmpPath | insecure-temporary-file.js:23:22:23:49 | path.jo ... /foo/") | +| insecure-temporary-file.js:23:32:23:38 | tmpPath | insecure-temporary-file.js:23:22:23:49 | path.jo ... /foo/") | +| insecure-temporary-file.js:25:11:25:92 | tmpPath2 | insecure-temporary-file.js:26:22:26:29 | tmpPath2 | +| insecure-temporary-file.js:25:11:25:92 | tmpPath2 | insecure-temporary-file.js:26:22:26:29 | tmpPath2 | +| insecure-temporary-file.js:25:11:25:92 | tmpPath2 | insecure-temporary-file.js:28:17:28:24 | tmpPath2 | +| insecure-temporary-file.js:25:11:25:92 | tmpPath2 | insecure-temporary-file.js:28:17:28:24 | tmpPath2 | +| insecure-temporary-file.js:25:22:25:92 | path.jo ... )}.md`) | insecure-temporary-file.js:25:11:25:92 | tmpPath2 | +| insecure-temporary-file.js:25:32:25:42 | os.tmpdir() | insecure-temporary-file.js:25:22:25:92 | path.jo ... )}.md`) | +| insecure-temporary-file.js:25:32:25:42 | os.tmpdir() | insecure-temporary-file.js:25:22:25:92 | path.jo ... )}.md`) | +#select +| insecure-temporary-file.js:13:22:13:32 | tmpLocation | insecure-temporary-file.js:8:21:8:31 | os.tmpdir() | insecure-temporary-file.js:13:22:13:32 | tmpLocation | Insecure creation of file in $@. | insecure-temporary-file.js:8:21:8:31 | os.tmpdir() | the os temp dir | +| insecure-temporary-file.js:17:22:17:49 | path.jo ... /foo/") | insecure-temporary-file.js:15:19:15:34 | "/tmp/something" | insecure-temporary-file.js:17:22:17:49 | path.jo ... /foo/") | Insecure creation of file in $@. | insecure-temporary-file.js:15:19:15:34 | "/tmp/something" | the os temp dir | +| insecure-temporary-file.js:23:22:23:49 | path.jo ... /foo/") | insecure-temporary-file.js:15:19:15:34 | "/tmp/something" | insecure-temporary-file.js:23:22:23:49 | path.jo ... /foo/") | Insecure creation of file in $@. | insecure-temporary-file.js:15:19:15:34 | "/tmp/something" | the os temp dir | +| insecure-temporary-file.js:26:22:26:29 | tmpPath2 | insecure-temporary-file.js:25:32:25:42 | os.tmpdir() | insecure-temporary-file.js:26:22:26:29 | tmpPath2 | Insecure creation of file in $@. | insecure-temporary-file.js:25:32:25:42 | os.tmpdir() | the os temp dir | +| insecure-temporary-file.js:28:17:28:24 | tmpPath2 | insecure-temporary-file.js:25:32:25:42 | os.tmpdir() | insecure-temporary-file.js:28:17:28:24 | tmpPath2 | Insecure creation of file in $@. | insecure-temporary-file.js:25:32:25:42 | os.tmpdir() | the os temp dir | diff --git a/javascript/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.qlref b/javascript/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.qlref new file mode 100644 index 00000000000..68a27dfb269 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.qlref @@ -0,0 +1 @@ +Security/CWE-377/InsecureTemporaryFile.ql diff --git a/javascript/ql/test/query-tests/Security/CWE-377/insecure-temporary-file.js b/javascript/ql/test/query-tests/Security/CWE-377/insecure-temporary-file.js new file mode 100644 index 00000000000..641b89a3ebe --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-377/insecure-temporary-file.js @@ -0,0 +1,30 @@ +const os = require('os'); +const uuid = require('node-uuid'); +const fs = require('fs'); +const path = require('path'); + +(function main() { + var tmpLocation = path.join( + os.tmpdir ? os.tmpdir() : os.tmpDir(), + 'something', + uuid.v4().slice(0, 8) + ); + + fs.writeFileSync(tmpLocation, content); // NOT OK + + var tmpPath = "/tmp/something"; + fs.writeFileSync(path.join("./foo/", tmpPath), content); // OK + fs.writeFileSync(path.join(tmpPath, "./foo/"), content); // NOT OK + + fs.writeFileSync(path.join(tmpPath, "./foo/"), content, {mode: 0o600}); // OK + + fs.writeFileSync(path.join(tmpPath, "./foo/"), content, {mode: mode}); // OK - assumed unknown mode is secure + + fs.writeFileSync(path.join(tmpPath, "./foo/"), content, {mode: 0o666}); // NOT OK - explicitly insecure + + const tmpPath2 = path.join(os.tmpdir(), `tmp_${Math.floor(Math.random() * 1000000)}.md`); + fs.writeFileSync(tmpPath2, content); // NOT OK + + fs.openSync(tmpPath2, 'w'); // NOT OK + fs.openSync(tmpPath2, 'w', 0o600); // OK +}) diff --git a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/PrototypePollutingAssignment.expected b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/PrototypePollutingAssignment.expected index ec2bfb99862..7b4b6e81751 100644 --- a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/PrototypePollutingAssignment.expected +++ b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/PrototypePollutingAssignment.expected @@ -94,6 +94,12 @@ nodes | lib.js:108:3:108:10 | obj[one] | | lib.js:108:3:108:10 | obj[one] | | lib.js:108:7:108:9 | one | +| sublib/sub.js:1:37:1:40 | path | +| sublib/sub.js:1:37:1:40 | path | +| sublib/sub.js:2:3:2:14 | obj[path[0]] | +| sublib/sub.js:2:3:2:14 | obj[path[0]] | +| sublib/sub.js:2:7:2:10 | path | +| sublib/sub.js:2:7:2:13 | path[0] | | tst.js:5:9:5:38 | taint | | tst.js:5:17:5:38 | String( ... y.data) | | tst.js:5:24:5:37 | req.query.data | @@ -230,6 +236,11 @@ edges | lib.js:104:13:104:24 | arguments[1] | lib.js:104:7:104:24 | one | | lib.js:108:7:108:9 | one | lib.js:108:3:108:10 | obj[one] | | lib.js:108:7:108:9 | one | lib.js:108:3:108:10 | obj[one] | +| sublib/sub.js:1:37:1:40 | path | sublib/sub.js:2:7:2:10 | path | +| sublib/sub.js:1:37:1:40 | path | sublib/sub.js:2:7:2:10 | path | +| sublib/sub.js:2:7:2:10 | path | sublib/sub.js:2:7:2:13 | path[0] | +| sublib/sub.js:2:7:2:13 | path[0] | sublib/sub.js:2:3:2:14 | obj[path[0]] | +| sublib/sub.js:2:7:2:13 | path[0] | sublib/sub.js:2:3:2:14 | obj[path[0]] | | tst.js:5:9:5:38 | taint | tst.js:8:12:8:16 | taint | | tst.js:5:9:5:38 | taint | tst.js:9:12:9:16 | taint | | tst.js:5:9:5:38 | taint | tst.js:12:25:12:29 | taint | @@ -284,6 +295,7 @@ edges | lib.js:70:13:70:24 | obj[path[0]] | lib.js:59:18:59:18 | s | lib.js:70:13:70:24 | obj[path[0]] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:59:18:59:18 | s | library input | | lib.js:87:10:87:14 | proto | lib.js:83:14:83:25 | arguments[1] | lib.js:87:10:87:14 | proto | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:83:14:83:25 | arguments[1] | library input | | lib.js:108:3:108:10 | obj[one] | lib.js:104:13:104:24 | arguments[1] | lib.js:108:3:108:10 | obj[one] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:104:13:104:24 | arguments[1] | library input | +| sublib/sub.js:2:3:2:14 | obj[path[0]] | sublib/sub.js:1:37:1:40 | path | sublib/sub.js:2:3:2:14 | obj[path[0]] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | sublib/sub.js:1:37:1:40 | path | library input | | tst.js:8:5:8:17 | object[taint] | tst.js:5:24:5:37 | req.query.data | tst.js:8:5:8:17 | object[taint] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | tst.js:5:24:5:37 | req.query.data | user controlled input | | tst.js:9:5:9:17 | object[taint] | tst.js:5:24:5:37 | req.query.data | tst.js:9:5:9:17 | object[taint] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | tst.js:5:24:5:37 | req.query.data | user controlled input | | tst.js:14:5:14:32 | unsafeG ... taint) | tst.js:5:24:5:37 | req.query.data | tst.js:14:5:14:32 | unsafeG ... taint) | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | tst.js:5:24:5:37 | req.query.data | user controlled input | diff --git a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/sublib/package.json b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/sublib/package.json new file mode 100644 index 00000000000..3f633a4ff71 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/sublib/package.json @@ -0,0 +1,4 @@ +{ + "name": "sublib", + "main": "./sub" +} \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/sublib/sub.js b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/sublib/sub.js new file mode 100644 index 00000000000..d74de12493a --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/sublib/sub.js @@ -0,0 +1,3 @@ +module.exports.set = function (obj, path, value) { + obj[path[0]][path[1]] = value; // NOT OK +} \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/sublib/sub/empty.js b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/sublib/sub/empty.js new file mode 100644 index 00000000000..cc4c41e100b --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/sublib/sub/empty.js @@ -0,0 +1 @@ +console.log("foo"); \ No newline at end of file diff --git a/python/ql/lib/CHANGELOG.md b/python/ql/lib/CHANGELOG.md index ae6636f6f6e..8734a5f89ef 100644 --- a/python/ql/lib/CHANGELOG.md +++ b/python/ql/lib/CHANGELOG.md @@ -1,3 +1,14 @@ +## 0.3.0 + +### Breaking Changes + +* The imports made available from `import python` are no longer exposed under `DataFlow::` after doing `import semmle.python.dataflow.new.DataFlow`, for example using `DataFlow::Add` will now cause a compile error. + +### Minor Analysis Improvements + +* The modeling of `request.files` in Flask has been fixed, so we now properly handle assignments to local variables (such as `files = request.files; files['key'].filename`). +* Added taint propagation for `io.StringIO` and `io.BytesIO`. This addition was originally [submitted as part of an experimental query by @jorgectf](https://github.com/github/codeql/pull/6112). + ## 0.2.0 ### Breaking Changes diff --git a/python/ql/lib/change-notes/2022-03-29-add-taint-for-StringIO.md b/python/ql/lib/change-notes/2022-03-29-add-taint-for-StringIO.md deleted file mode 100644 index 7857e6f9ca6..00000000000 --- a/python/ql/lib/change-notes/2022-03-29-add-taint-for-StringIO.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Added taint propagation for `io.StringIO` and `io.BytesIO`. This addition was originally [submitted as part of an experimental query by @jorgectf](https://github.com/github/codeql/pull/6112). diff --git a/python/ql/lib/change-notes/2022-04-20-export-python-under-DataFlow.md b/python/ql/lib/change-notes/2022-04-20-export-python-under-DataFlow.md deleted file mode 100644 index 2729b834ccf..00000000000 --- a/python/ql/lib/change-notes/2022-04-20-export-python-under-DataFlow.md +++ /dev/null @@ -1,4 +0,0 @@ ---- - category: breaking ---- - * The imports made available from `import python` are no longer exposed under `DataFlow::` after doing `import semmle.python.dataflow.new.DataFlow`, for example using `DataFlow::Add` will now cause a compile error. diff --git a/python/ql/lib/change-notes/2022-05-02-flask-request-files-modeling.md b/python/ql/lib/change-notes/2022-05-02-flask-request-files-modeling.md deleted file mode 100644 index 9b80811a608..00000000000 --- a/python/ql/lib/change-notes/2022-05-02-flask-request-files-modeling.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: minorAnalysis ---- -The modeling of `request.files` in Flask has been fixed, so we now properly handle -assignments to local variables (such as `files = request.files; files['key'].filename`). diff --git a/python/ql/lib/change-notes/released/0.3.0.md b/python/ql/lib/change-notes/released/0.3.0.md new file mode 100644 index 00000000000..15455199e89 --- /dev/null +++ b/python/ql/lib/change-notes/released/0.3.0.md @@ -0,0 +1,10 @@ +## 0.3.0 + +### Breaking Changes + +* The imports made available from `import python` are no longer exposed under `DataFlow::` after doing `import semmle.python.dataflow.new.DataFlow`, for example using `DataFlow::Add` will now cause a compile error. + +### Minor Analysis Improvements + +* The modeling of `request.files` in Flask has been fixed, so we now properly handle assignments to local variables (such as `files = request.files; files['key'].filename`). +* Added taint propagation for `io.StringIO` and `io.BytesIO`. This addition was originally [submitted as part of an experimental query by @jorgectf](https://github.com/github/codeql/pull/6112). diff --git a/python/ql/lib/codeql-pack.release.yml b/python/ql/lib/codeql-pack.release.yml index 5274e27ed52..95f6e3a0ba6 100644 --- a/python/ql/lib/codeql-pack.release.yml +++ b/python/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.2.0 +lastReleaseVersion: 0.3.0 diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml index ca2423b1b94..3e239436c03 100644 --- a/python/ql/lib/qlpack.yml +++ b/python/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-all -version: 0.2.1-dev +version: 0.3.1-dev groups: python dbscheme: semmlecode.python.dbscheme extractor: python diff --git a/python/ql/lib/semmle/python/Import.qll b/python/ql/lib/semmle/python/Import.qll index cd62001b41e..c75ef9f0c91 100644 --- a/python/ql/lib/semmle/python/Import.qll +++ b/python/ql/lib/semmle/python/Import.qll @@ -184,7 +184,7 @@ class Import extends Import_ { * For example, for the import statement `import bar` which * is a relative import in package "foo", this would return * "foo.bar". - * The import statment `from foo import bar` would return + * The import statement `from foo import bar` would return * `foo` and `foo.bar` */ string getAnImportedModuleName() { diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatchPointsTo.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatchPointsTo.qll index 6564d4dc62e..1d50a12364f 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatchPointsTo.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatchPointsTo.qll @@ -172,7 +172,7 @@ module ArgumentPassing { /** * Gets the node representing the argument to `call` that is passed to the parameter at * (zero-based) index `paramN` in `callable`. If this is a positional argument, it must appear - * at an index, `argN`, in `call` wich satisfies `paramN = mapping.getParamN(argN)`. + * at an index, `argN`, in `call` which satisfies `paramN = mapping.getParamN(argN)`. * * `mapping` will be the identity for function calls, but not for method- or constructor calls, * where the first parameter is `self` and the first positional argument is passed to the second positional parameter. diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll index 5bd84566df5..fb773ea89f8 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll index 5bd84566df5..fb773ea89f8 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll index 5bd84566df5..fb773ea89f8 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll index 5bd84566df5..fb773ea89f8 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll index e60505d9248..0079b259260 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll @@ -305,7 +305,7 @@ cached private module Cached { /** * If needed, call this predicate from `DataFlowImplSpecific.qll` in order to - * force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby + * force a stage-dependency on the `DataFlowImplCommon.qll` stage and thereby * collapsing the two stages. */ cached diff --git a/python/ql/lib/semmle/python/dataflow/old/StateTracking.qll b/python/ql/lib/semmle/python/dataflow/old/StateTracking.qll index 71ca8fd0b20..43b2ece1093 100644 --- a/python/ql/lib/semmle/python/dataflow/old/StateTracking.qll +++ b/python/ql/lib/semmle/python/dataflow/old/StateTracking.qll @@ -45,14 +45,14 @@ abstract class TrackableState extends string { /** * Holds if state starts at `f`. * Either this predicate or `startsAt(ControlFlowNode f, Context ctx)` - * should be overriden by sub-classes. + * should be overridden by sub-classes. */ predicate startsAt(ControlFlowNode f) { none() } /** * Holds if state starts at `f` given context `ctx`. * Either this predicate or `startsAt(ControlFlowNode f)` - * should be overriden by sub-classes. + * should be overridden by sub-classes. */ pragma[noinline] predicate startsAt(ControlFlowNode f, Context ctx) { ctx.appliesTo(f) and this.startsAt(f) } @@ -60,14 +60,14 @@ abstract class TrackableState extends string { /** * Holds if state ends at `f`. * Either this predicate or `endsAt(ControlFlowNode f, Context ctx)` - * may be overriden by sub-classes. + * may be overridden by sub-classes. */ predicate endsAt(ControlFlowNode f) { none() } /** * Holds if state ends at `f` given context `ctx`. * Either this predicate or `endsAt(ControlFlowNode f)` - * may be overriden by sub-classes. + * may be overridden by sub-classes. */ pragma[noinline] predicate endsAt(ControlFlowNode f, Context ctx) { ctx.appliesTo(f) and this.endsAt(f) } diff --git a/python/ql/lib/semmle/python/frameworks/Aiomysql.qll b/python/ql/lib/semmle/python/frameworks/Aiomysql.qll index 112dc58d061..fdcf21afc34 100644 --- a/python/ql/lib/semmle/python/frameworks/Aiomysql.qll +++ b/python/ql/lib/semmle/python/frameworks/Aiomysql.qll @@ -25,7 +25,7 @@ private module Aiomysql { /** * Gets a `Connection` that is created when * - the result of `aiomysql.connect()` is awaited. - * - the result of calling `aquire` on a `ConnectionPool` is awaited. + * - the result of calling `acquire` on a `ConnectionPool` is awaited. * See https://aiomysql.readthedocs.io/en/stable/connection.html#connection */ API::Node connection() { @@ -82,7 +82,7 @@ private module Aiomysql { } /** - * Gets an `SAConnection` that is created when the result of calling `aquire` on an `Engine` is awaited. + * Gets an `SAConnection` that is created when the result of calling `acquire` on an `Engine` is awaited. * See https://aiomysql.readthedocs.io/en/stable/sa.html#connection */ API::Node saConnection() { result = engine().getMember("acquire").getReturn().getAwaited() } diff --git a/python/ql/lib/semmle/python/frameworks/Aiopg.qll b/python/ql/lib/semmle/python/frameworks/Aiopg.qll index 1a60c433150..afc553fe04b 100644 --- a/python/ql/lib/semmle/python/frameworks/Aiopg.qll +++ b/python/ql/lib/semmle/python/frameworks/Aiopg.qll @@ -25,7 +25,7 @@ private module Aiopg { /** * Gets a `Connection` that is created when * - the result of `aiopg.connect()` is awaited. - * - the result of calling `aquire` on a `ConnectionPool` is awaited. + * - the result of calling `acquire` on a `ConnectionPool` is awaited. * See https://aiopg.readthedocs.io/en/stable/core.html#connection */ API::Node connection() { @@ -78,7 +78,7 @@ private module Aiopg { } /** - * Gets an `SAConnection` that is created when the result of calling `aquire` on an `Engine` is awaited. + * Gets an `SAConnection` that is created when the result of calling `acquire` on an `Engine` is awaited. * See https://aiopg.readthedocs.io/en/stable/sa.html#connection */ API::Node saConnection() { result = engine().getMember("acquire").getReturn().getAwaited() } diff --git a/python/ql/lib/semmle/python/frameworks/Asyncpg.qll b/python/ql/lib/semmle/python/frameworks/Asyncpg.qll index 48d3e1534ae..81da12a015c 100644 --- a/python/ql/lib/semmle/python/frameworks/Asyncpg.qll +++ b/python/ql/lib/semmle/python/frameworks/Asyncpg.qll @@ -20,7 +20,7 @@ private module Asyncpg { "asyncpg;ConnectionPool;asyncpg;;Member[create_pool].ReturnValue.Awaited", // a `Connection` that is created when // * - the result of `asyncpg.connect()` is awaited. - // * - the result of calling `aquire` on a `ConnectionPool` is awaited. + // * - the result of calling `acquire` on a `ConnectionPool` is awaited. "asyncpg;Connection;asyncpg;;Member[connect].ReturnValue.Awaited", "asyncpg;Connection;asyncpg;ConnectionPool;Member[acquire].ReturnValue.Awaited", // Creating an internal `~Connection` type that contains both `Connection` and `ConnectionPool`. diff --git a/python/ql/lib/semmle/python/objects/TObject.qll b/python/ql/lib/semmle/python/objects/TObject.qll index 67739933ab8..ee6bcb8340d 100644 --- a/python/ql/lib/semmle/python/objects/TObject.qll +++ b/python/ql/lib/semmle/python/objects/TObject.qll @@ -243,7 +243,7 @@ predicate class_method( * Holds if the literal corresponding to the control flow node `n` has class `cls`. * * Helper predicate for `literal_instantiation`. Prevents a bad join with - * `PointsToContext::appliesTo` from occuring. + * `PointsToContext::appliesTo` from occurring. */ pragma[nomagic] private predicate literal_node_class(ControlFlowNode n, ClassObjectInternal cls) { diff --git a/python/ql/lib/semmle/python/security/BadTagFilterQuery.qll b/python/ql/lib/semmle/python/security/BadTagFilterQuery.qll index e22c00ddc47..d935abce37a 100644 --- a/python/ql/lib/semmle/python/security/BadTagFilterQuery.qll +++ b/python/ql/lib/semmle/python/security/BadTagFilterQuery.qll @@ -28,14 +28,14 @@ private module RegexpMatching { * but if `ignorePrefix` is true, it will only match "foo". */ predicate test(string str, boolean ignorePrefix) { - none() // maybe overriden in subclasses + none() // maybe overridden in subclasses } /** * Same as `test(..)`, but where the `fillsCaptureGroup` afterwards tells which capture groups were filled by the given string. */ predicate testWithGroups(string str, boolean ignorePrefix) { - none() // maybe overriden in subclasses + none() // maybe overridden in subclasses } /** diff --git a/python/ql/lib/semmle/python/security/performance/ExponentialBackTracking.qll b/python/ql/lib/semmle/python/security/performance/ExponentialBackTracking.qll index 5e0fe18ea00..99b4062dfdc 100644 --- a/python/ql/lib/semmle/python/security/performance/ExponentialBackTracking.qll +++ b/python/ql/lib/semmle/python/security/performance/ExponentialBackTracking.qll @@ -51,7 +51,7 @@ * either a single character, a set of characters represented by a * character class, or the set of all characters. * * The product automaton is constructed lazily, starting with pair states - * `(q, q)` where `q` is a fork, and proceding along an over-approximate + * `(q, q)` where `q` is a fork, and proceeding along an over-approximate * step relation. * * The over-approximate step relation allows transitions along pairs of * abstract input symbols where the symbols have overlap in the characters they accept. diff --git a/python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll b/python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll index 6f695b5035b..8aa348bf62f 100644 --- a/python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll +++ b/python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll @@ -610,16 +610,23 @@ State after(RegExpTerm t) { or exists(RegExpGroup grp | t = grp.getAChild() | result = after(grp)) or - exists(EffectivelyStar star | t = star.getAChild() | result = before(star)) + exists(EffectivelyStar star | t = star.getAChild() | + not isPossessive(star) and + result = before(star) + ) or exists(EffectivelyPlus plus | t = plus.getAChild() | - result = before(plus) or + not isPossessive(plus) and + result = before(plus) + or result = after(plus) ) or exists(EffectivelyQuestion opt | t = opt.getAChild() | result = after(opt)) or - exists(RegExpRoot root | t = root | result = AcceptAnySuffix(root)) + exists(RegExpRoot root | t = root | + if matchesAnySuffix(root) then result = AcceptAnySuffix(root) else result = Accept(root) + ) } /** @@ -690,7 +697,7 @@ predicate delta(State q1, EdgeLabel lbl, State q2) { lbl = Epsilon() and q2 = Accept(root) ) or - exists(RegExpRoot root | q1 = Match(root, 0) | lbl = Any() and q2 = q1) + exists(RegExpRoot root | q1 = Match(root, 0) | matchesAnyPrefix(root) and lbl = Any() and q2 = q1) or exists(RegExpDollar dollar | q1 = before(dollar) | lbl = Epsilon() and q2 = Accept(getRoot(dollar)) diff --git a/python/ql/lib/semmle/python/security/performance/ReDoSUtilSpecific.qll b/python/ql/lib/semmle/python/security/performance/ReDoSUtilSpecific.qll index 4193fd5a1e5..bc495f88c3c 100644 --- a/python/ql/lib/semmle/python/security/performance/ReDoSUtilSpecific.qll +++ b/python/ql/lib/semmle/python/security/performance/ReDoSUtilSpecific.qll @@ -13,6 +13,24 @@ predicate isEscapeClass(RegExpTerm term, string clazz) { exists(RegExpCharacterClassEscape escape | term = escape | escape.getValue() = clazz) } +/** + * Holds if `term` is a possessive quantifier. + * As python's regexes do not support possessive quantifiers, this never holds, but is used by the shared library. + */ +predicate isPossessive(RegExpQuantifier term) { none() } + +/** + * Holds if the regex that `term` is part of is used in a way that ignores any leading prefix of the input it's matched against. + * Not yet implemented for Python. + */ +predicate matchesAnyPrefix(RegExpTerm term) { any() } + +/** + * Holds if the regex that `term` is part of is used in a way that ignores any trailing suffix of the input it's matched against. + * Not yet implemented for Python. + */ +predicate matchesAnySuffix(RegExpTerm term) { any() } + /** * Holds if the regular expression should not be considered. * diff --git a/python/ql/lib/semmle/python/security/strings/External.qll b/python/ql/lib/semmle/python/security/strings/External.qll index 48b61666143..a5116e42e4e 100644 --- a/python/ql/lib/semmle/python/security/strings/External.qll +++ b/python/ql/lib/semmle/python/security/strings/External.qll @@ -35,7 +35,7 @@ deprecated class ExternalStringSequenceKind extends SequenceKind { } /** - * An hierachical dictionary or list where the entire structure is externally controlled + * An hierarchical dictionary or list where the entire structure is externally controlled * This is typically a parsed JSON object. */ deprecated class ExternalJsonKind extends TaintKind { diff --git a/python/ql/src/CHANGELOG.md b/python/ql/src/CHANGELOG.md index 3b427cfaae9..a0c725aeb08 100644 --- a/python/ql/src/CHANGELOG.md +++ b/python/ql/src/CHANGELOG.md @@ -1,3 +1,11 @@ +## 0.1.2 + +### New Queries + +* "XML external entity expansion" (`py/xxe`). Results will appear by default. This query was based on [an experimental query by @jorgectf](https://github.com/github/codeql/pull/6112). +* "XML internal entity expansion" (`py/xml-bomb`). Results will appear by default. This query was based on [an experimental query by @jorgectf](https://github.com/github/codeql/pull/6112). +* The query "CSRF protection weakened or disabled" (`py/csrf-protection-disabled`) has been implemented. Its results will now appear by default. + ## 0.1.1 ## 0.1.0 diff --git a/python/ql/src/change-notes/2022-03-24-csrf-protection.md b/python/ql/src/change-notes/2022-03-24-csrf-protection.md deleted file mode 100644 index 14a291d5f78..00000000000 --- a/python/ql/src/change-notes/2022-03-24-csrf-protection.md +++ /dev/null @@ -1,4 +0,0 @@ ---- - category: newQuery ---- -* The query "CSRF protection weakened or disabled" (`py/csrf-protection-disabled`) has been implemented. Its results will now appear by default. diff --git a/python/ql/src/change-notes/2022-04-05-add-xxe-and-xmlbomb.md b/python/ql/src/change-notes/released/0.1.2.md similarity index 68% rename from python/ql/src/change-notes/2022-04-05-add-xxe-and-xmlbomb.md rename to python/ql/src/change-notes/released/0.1.2.md index bd867091aea..04e3e8b97af 100644 --- a/python/ql/src/change-notes/2022-04-05-add-xxe-and-xmlbomb.md +++ b/python/ql/src/change-notes/released/0.1.2.md @@ -1,5 +1,7 @@ ---- -category: newQuery ---- +## 0.1.2 + +### New Queries + * "XML external entity expansion" (`py/xxe`). Results will appear by default. This query was based on [an experimental query by @jorgectf](https://github.com/github/codeql/pull/6112). * "XML internal entity expansion" (`py/xml-bomb`). Results will appear by default. This query was based on [an experimental query by @jorgectf](https://github.com/github/codeql/pull/6112). +* The query "CSRF protection weakened or disabled" (`py/csrf-protection-disabled`) has been implemented. Its results will now appear by default. diff --git a/python/ql/src/codeql-pack.release.yml b/python/ql/src/codeql-pack.release.yml index 92d1505475f..6abd14b1ef8 100644 --- a/python/ql/src/codeql-pack.release.yml +++ b/python/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.1.1 +lastReleaseVersion: 0.1.2 diff --git a/python/ql/src/qlpack.yml b/python/ql/src/qlpack.yml index 265e6acebd3..9e43fd7246f 100644 --- a/python/ql/src/qlpack.yml +++ b/python/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-queries -version: 0.1.2-dev +version: 0.1.3-dev groups: - python - queries diff --git a/python/ql/test/TestUtilities/InlineExpectationsTest.qll b/python/ql/test/TestUtilities/InlineExpectationsTest.qll index a4d264b2703..3891fcf13a1 100644 --- a/python/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/python/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -181,7 +181,7 @@ private string expectationCommentPattern() { result = "\\s*\\$((?:[^/]|/[^/])*)( /** * The possible columns in an expectation comment. The `TDefaultColumn` branch represents the first * column in a comment. This column is not precedeeded by a name. `TNamedColumn(name)` represents a - * column containing expected results preceeded by the string `name:`. + * column containing expected results preceded by the string `name:`. */ private newtype TColumn = TDefaultColumn() or diff --git a/python/ql/test/experimental/dataflow/testConfig.qll b/python/ql/test/experimental/dataflow/testConfig.qll index 90bd1d47978..03815e2f7f9 100644 --- a/python/ql/test/experimental/dataflow/testConfig.qll +++ b/python/ql/test/experimental/dataflow/testConfig.qll @@ -8,7 +8,7 @@ * s = SOURCE * SINK(s) * ``` - * `SOURCE` will be a source and the second occurance of `s` will be a sink. + * `SOURCE` will be a source and the second occurrence of `s` will be a sink. * * In order to test literals, alternative sources are defined for each type: * diff --git a/ql/ql/src/codeql_ql/ast/Ast.qll b/ql/ql/src/codeql_ql/ast/Ast.qll index a626bc2e53c..17f8d5142d3 100644 --- a/ql/ql/src/codeql_ql/ast/Ast.qll +++ b/ql/ql/src/codeql_ql/ast/Ast.qll @@ -919,7 +919,7 @@ class NewTypeBranch extends TNewTypeBranch, Predicate, TypeDeclaration { class Call extends TCall, Expr, Formula { /** Gets the `i`th argument of this call. */ Expr getArgument(int i) { - none() // overriden in sublcasses. + none() // overridden in sublcasses. } /** Gets an argument of this call, if any. */ @@ -1901,13 +1901,13 @@ class FunctionSymbol extends string { */ class BinOpExpr extends TBinOpExpr, Expr { /** Gets the left operand of the binary expression. */ - Expr getLeftOperand() { none() } // overriden in subclasses + Expr getLeftOperand() { none() } // overridden in subclasses /** Gets the right operand of the binary expression. */ - Expr getRightOperand() { none() } // overriden in subclasses + Expr getRightOperand() { none() } // overridden in subclasses /** Gets the operator of the binary expression. */ - FunctionSymbol getOperator() { none() } // overriden in subclasses + FunctionSymbol getOperator() { none() } // overridden in subclasses /** Gets an operand of the binary expression. */ final Expr getAnOperand() { result = this.getLeftOperand() or result = this.getRightOperand() } diff --git a/ql/ql/src/codeql_ql/ast/internal/Type.qll b/ql/ql/src/codeql_ql/ast/internal/Type.qll index 4d88cd194d5..a2d9b3f7076 100644 --- a/ql/ql/src/codeql_ql/ast/internal/Type.qll +++ b/ql/ql/src/codeql_ql/ast/internal/Type.qll @@ -32,13 +32,13 @@ class Type extends TType { string getName() { result = "???" } /** - * Gets a supertype of this type. This follows the user-visible type heirarchy, + * Gets a supertype of this type. This follows the user-visible type hierarchy, * and doesn't include internal types like the characteristic and domain types of classes. */ Type getASuperType() { none() } /** - * Gets a supertype of this type in the internal heirarchy, + * Gets a supertype of this type in the internal hierarchy, * which includes the characteristic and domain types of classes. */ Type getAnInternalSuperType() { result = TDontCare() } diff --git a/ql/ql/src/codeql_ql/dataflow/DataFlow.qll b/ql/ql/src/codeql_ql/dataflow/DataFlow.qll index 3f6c4903970..da8bc1da837 100644 --- a/ql/ql/src/codeql_ql/dataflow/DataFlow.qll +++ b/ql/ql/src/codeql_ql/dataflow/DataFlow.qll @@ -212,7 +212,7 @@ class SuperNode extends LocalFlow::TSuperNode { * The node is arbitrary and the caller should not rely on how the node is chosen. * The node is currently chosen such that: * - An `AstNodeNode` is preferred over other nodes. - * - A node occuring earlier is preferred over one occurring later. + * - A node occurring earlier is preferred over one occurring later. */ Node getArbitraryRepr() { result = min(Node n | n = getANode() | n order by getInternalId(n)) } @@ -343,7 +343,7 @@ class Tracker extends GlobalFlow::TEdgeLabelOrTrackerState { /** Holds if this is the starting point, that is, the summary of the empty path. */ predicate start() { this = GlobalFlow::MkNoEdge() } - /** Holds if a call step has been used (possibly preceeded by return steps). */ + /** Holds if a call step has been used (possibly preceded by return steps). */ predicate hasCall() { this = GlobalFlow::MkHasCall() } /** Holds if either `start()` or `hasCall()` holds */ diff --git a/ql/ql/src/codeql_ql/printAstAst.qll b/ql/ql/src/codeql_ql/printAstAst.qll index feb525908d2..a80091ff940 100644 --- a/ql/ql/src/codeql_ql/printAstAst.qll +++ b/ql/ql/src/codeql_ql/printAstAst.qll @@ -25,7 +25,7 @@ class PrintAstConfiguration extends string { /** * Gets the `i`th child of parent. - * The ordering is location based and pretty arbitary. + * The ordering is location based and pretty arbitrary. */ AstNode getAstChild(PrintAstNode parent, int i) { result = diff --git a/ql/ql/src/codeql_ql/printAstGenerated.qll b/ql/ql/src/codeql_ql/printAstGenerated.qll index caee0ab809a..e93c0b38867 100644 --- a/ql/ql/src/codeql_ql/printAstGenerated.qll +++ b/ql/ql/src/codeql_ql/printAstGenerated.qll @@ -28,7 +28,7 @@ class PrintAstConfiguration extends string { /** * Gets the `i`th child of parent. - * The ordering is location based and pretty arbitary. + * The ordering is location based and pretty arbitrary. */ AstNode getAstChild(PrintAstNode parent, int i) { result = diff --git a/ql/ql/src/codeql_ql/style/AcronymsShouldBeCamelCaseQuery.qll b/ql/ql/src/codeql_ql/style/AcronymsShouldBeCamelCaseQuery.qll index 95d67ef47bb..9af28333cfe 100644 --- a/ql/ql/src/codeql_ql/style/AcronymsShouldBeCamelCaseQuery.qll +++ b/ql/ql/src/codeql_ql/style/AcronymsShouldBeCamelCaseQuery.qll @@ -1,35 +1,5 @@ import ql - -/** - * Gets the name for a `node` that defines something in a QL program. - * E.g. a predicate, class, or module definition. - */ -string getName(AstNode node, string kind) { - result = node.(Class).getName() and kind = "class" - or - // not including CharPreds or db relations. The remaining are: classlessPredicate, classPredicate, newTypeBranch. - result = node.(ClasslessPredicate).getName() and - kind = "classlessPredicate" - or - result = node.(ClassPredicate).getName() and - kind = "classPredicate" - or - result = node.(NewTypeBranch).getName() and - kind = "newtypeBranch" - or - result = node.(NewType).getName() and - kind = "newtype" - or - result = node.(VarDecl).getName() and - kind = "variable" and - not node = any(FieldDecl f).getVarDecl() - or - result = node.(FieldDecl).getName() and kind = "field" - or - result = node.(Module).getName() and kind = "module" - or - result = node.(Import).importedAs() and kind = "import" -} +private import NodeName string prettyPluralKind(string kind) { kind = "class" and result = "classes" diff --git a/ql/ql/src/codeql_ql/style/MisspellingQuery.qll b/ql/ql/src/codeql_ql/style/MisspellingQuery.qll new file mode 100644 index 00000000000..3c51df79a00 --- /dev/null +++ b/ql/ql/src/codeql_ql/style/MisspellingQuery.qll @@ -0,0 +1,69 @@ +import ql +private import NodeName +private import TypoDatabase + +predicate misspelling(string wrong, string right, string mistake) { + mistake = "common misspelling" and + (typos(wrong, right) or additional_typos(wrong, right)) + or + mistake = "non-US spelling" and + non_us_spelling(wrong, right) +} + +predicate additional_typos(string wrong, string right) { + wrong = "tranformer" and right = "transformer" +} + +/** + * Holds if `word` is an acceptable spelling that would otherwise be considered + * a mistake by the typo database. + */ +predicate isAllowed(string word) { + word = + [ + "asign", // 'sign of a', not 'assign' + "larg", // 'left argument', not 'large' + "nto", // some comments refer to the variable `nTo` + "thn" // deliberate misspelling of 'then' to avoid using a keyword + ] +} + +predicate non_us_spelling(string wrong, string right) { + exists(string s | + wrong = s.splitAt("/", 0) and + right = s.splitAt("/", 1) and + s = + [ + "colour/color", "authorise/authorize", "authorises/authorizes", "authorised/authorized", + "analyse/analyze", "analysed/analyzed", "behaviour/behavior", "modelling/modeling", + "modelled/modeled" + ] + ) +} + +/** + * Gets a word in the camel-case string `s`. For example, if `s` is + * `"getFooBar"`, it returns `"get"`, `"Foo"`, and `"Bar"`. + */ +bindingset[s] +string getACamelCaseWord(string s) { result = s.regexpFind("(^[a-z]+)|([A-Z][a-z]+)", _, _) } + +bindingset[s] +string getACommentWord(string s) { result = s.regexpFind("\\b\\w+\\b", _, _) } + +string getAWord(AstNode node, string kind) { + result = getACommentWord(node.(QLDoc).getContents()).toLowerCase() and + kind = "QLDoc comment" + or + exists(string nodeKind | + result = getACamelCaseWord(getName(node, nodeKind)).toLowerCase() and + kind = nodeKind + " name" + ) +} + +predicate misspelled_element(AstNode node, string kind, string wrong, string right, string mistake) { + wrong = getAWord(node, kind) and + misspelling(wrong, right, mistake) and + not isAllowed(wrong) and + not node.hasAnnotation("deprecated") +} diff --git a/ql/ql/src/codeql_ql/style/NodeName.qll b/ql/ql/src/codeql_ql/style/NodeName.qll new file mode 100644 index 00000000000..6d02b7bb70c --- /dev/null +++ b/ql/ql/src/codeql_ql/style/NodeName.qll @@ -0,0 +1,32 @@ +import ql + +/** + * Gets the name for a `node` that defines something in a QL program. + * E.g. a predicate, class, or module definition. + */ +string getName(AstNode node, string kind) { + result = node.(Class).getName() and kind = "class" + or + // not including CharPreds or db relations. The remaining are: classlessPredicate, classPredicate, newTypeBranch. + result = node.(ClasslessPredicate).getName() and + kind = "classlessPredicate" + or + result = node.(ClassPredicate).getName() and + kind = "classPredicate" + or + result = node.(NewTypeBranch).getName() and + kind = "newtypeBranch" + or + result = node.(NewType).getName() and + kind = "newtype" + or + result = node.(VarDecl).getName() and + kind = "variable" and + not node = any(FieldDecl f).getVarDecl() + or + result = node.(FieldDecl).getName() and kind = "field" + or + result = node.(Module).getName() and kind = "module" + or + result = node.(Import).importedAs() and kind = "import" +} diff --git a/ql/ql/src/codeql_ql/style/TypoDatabase.qll b/ql/ql/src/codeql_ql/style/TypoDatabase.qll new file mode 100644 index 00000000000..aad43d9d0cc --- /dev/null +++ b/ql/ql/src/codeql_ql/style/TypoDatabase.qll @@ -0,0 +1,9031 @@ +/** + * Holds if `wrong` is a common misspelling of `right`. + * + * This predicate was automatically generated by + * python buildutils-internal/scripts/generate-typos.py + * which uses http://en.wikipedia.org/wiki/Wikipedia:Lists_of_common_misspellings/For_machines (with custom additions) on 2018-01-19. + * + * This file is available under the Creative Commons Attribution-ShareAlike License + * (https://en.wikipedia.org/wiki/Wikipedia:Text_of_Creative_Commons_Attribution-ShareAlike_3.0_Unported_License). + */ +predicate typos(string wrong, string right) { + wrong = "abandonned" and right = "abandoned" + or + wrong = "abbout" and right = "about" + or + wrong = "aberation" and right = "aberration" + or + wrong = "abilityes" and right = "abilities" + or + wrong = "abilties" and right = "abilities" + or + wrong = "abilty" and right = "ability" + or + wrong = "abondon" and right = "abandon" + or + wrong = "abondoned" and right = "abandoned" + or + wrong = "abondoning" and right = "abandoning" + or + wrong = "abondons" and right = "abandons" + or + wrong = "aborigene" and right = "aborigine" + or + wrong = "abortificant" and right = "abortifacient" + or + wrong = "abotu" and right = "about" + or + wrong = "abreviate" and right = "abbreviate" + or + wrong = "abreviated" and right = "abbreviated" + or + wrong = "abreviation" and right = "abbreviation" + or + wrong = "abritrary" and right = "arbitrary" + or + wrong = "absail" and right = "abseil" + or + wrong = "absailing" and right = "abseiling" + or + wrong = "abscence" and right = "absence" + or + wrong = "absense" and right = "absence" + or + wrong = "absolutly" and right = "absolutely" + or + wrong = "absorbsion" and right = "absorption" + or + wrong = "absorbtion" and right = "absorption" + or + wrong = "abudance" and right = "abundance" + or + wrong = "abundacies" and right = "abundances" + or + wrong = "abundancies" and right = "abundances" + or + wrong = "abundunt" and right = "abundant" + or + wrong = "abutts" and right = "abuts" + or + wrong = "acadamy" and right = "academy" + or + wrong = "acadmic" and right = "academic" + or + wrong = "accademic" and right = "academic" + or + wrong = "accademy" and right = "academy" + or + wrong = "acccess" and right = "access" + or + wrong = "acccused" and right = "accused" + or + wrong = "accelleration" and right = "acceleration" + or + wrong = "accension" and right = "accession" + or + wrong = "accension" and right = "ascension" + or + wrong = "acceptence" and right = "acceptance" + or + wrong = "acceptible" and right = "acceptable" + or + wrong = "accesories" and right = "accessories" + or + wrong = "accessable" and right = "accessible" + or + wrong = "accidant" and right = "accident" + or + wrong = "accidentaly" and right = "accidentally" + or + wrong = "accidently" and right = "accidentally" + or + wrong = "acclimitization" and right = "acclimatization" + or + wrong = "accomadate" and right = "accommodate" + or + wrong = "accomadated" and right = "accommodated" + or + wrong = "accomadates" and right = "accommodates" + or + wrong = "accomadating" and right = "accommodating" + or + wrong = "accomadation" and right = "accommodation" + or + wrong = "accomadations" and right = "accommodations" + or + wrong = "accomdate" and right = "accommodate" + or + wrong = "accomodate" and right = "accommodate" + or + wrong = "accomodated" and right = "accommodated" + or + wrong = "accomodates" and right = "accommodates" + or + wrong = "accomodating" and right = "accommodating" + or + wrong = "accomodation" and right = "accommodation" + or + wrong = "accomodations" and right = "accommodations" + or + wrong = "accompanyed" and right = "accompanied" + or + wrong = "accordeon" and right = "accordion" + or + wrong = "accordian" and right = "accordion" + or + wrong = "accoring" and right = "according" + or + wrong = "accoustic" and right = "acoustic" + or + wrong = "accquainted" and right = "acquainted" + or + wrong = "accrediation" and right = "accreditation" + or + wrong = "accredidation" and right = "accreditation" + or + wrong = "accross" and right = "across" + or + wrong = "accussed" and right = "accused" + or + wrong = "acedemic" and right = "academic" + or + wrong = "acheive" and right = "achieve" + or + wrong = "acheived" and right = "achieved" + or + wrong = "acheivement" and right = "achievement" + or + wrong = "acheivements" and right = "achievements" + or + wrong = "acheives" and right = "achieves" + or + wrong = "acheiving" and right = "achieving" + or + wrong = "acheivment" and right = "achievement" + or + wrong = "acheivments" and right = "achievements" + or + wrong = "achievment" and right = "achievement" + or + wrong = "achievments" and right = "achievements" + or + wrong = "achive" and right = "achieve" + or + wrong = "achive" and right = "archive" + or + wrong = "achived" and right = "achieved" + or + wrong = "achived" and right = "archived" + or + wrong = "achivement" and right = "achievement" + or + wrong = "achivements" and right = "achievements" + or + wrong = "acident" and right = "accident" + or + wrong = "acknowldeged" and right = "acknowledged" + or + wrong = "acknowledgeing" and right = "acknowledging" + or + wrong = "ackward" and right = "awkward" + or + wrong = "ackward" and right = "backward" + or + wrong = "acommodate" and right = "accommodate" + or + wrong = "acomplish" and right = "accomplish" + or + wrong = "acomplished" and right = "accomplished" + or + wrong = "acomplishment" and right = "accomplishment" + or + wrong = "acomplishments" and right = "accomplishments" + or + wrong = "acording" and right = "according" + or + wrong = "acordingly" and right = "accordingly" + or + wrong = "acquaintence" and right = "acquaintance" + or + wrong = "acquaintences" and right = "acquaintances" + or + wrong = "acquiantence" and right = "acquaintance" + or + wrong = "acquiantences" and right = "acquaintances" + or + wrong = "acquited" and right = "acquitted" + or + wrong = "activites" and right = "activities" + or + wrong = "activly" and right = "actively" + or + wrong = "actualy" and right = "actually" + or + wrong = "acuracy" and right = "accuracy" + or + wrong = "acused" and right = "accused" + or + wrong = "acustom" and right = "accustom" + or + wrong = "acustommed" and right = "accustomed" + or + wrong = "adapater" and right = "adapter" + or + wrong = "adavanced" and right = "advanced" + or + wrong = "adbandon" and right = "abandon" + or + wrong = "addional" and right = "additional" + or + wrong = "addionally" and right = "additionally" + or + wrong = "additinally" and right = "additionally" + or + wrong = "additionaly" and right = "additionally" + or + wrong = "additonal" and right = "additional" + or + wrong = "additonally" and right = "additionally" + or + wrong = "addmission" and right = "admission" + or + wrong = "addopt" and right = "adopt" + or + wrong = "addopted" and right = "adopted" + or + wrong = "addoptive" and right = "adoptive" + or + wrong = "addres" and right = "adders" + or + wrong = "addres" and right = "address" + or + wrong = "addresable" and right = "addressable" + or + wrong = "addresed" and right = "addressed" + or + wrong = "addresing" and right = "addressing" + or + wrong = "addressess" and right = "addresses" + or + wrong = "addtion" and right = "addition" + or + wrong = "addtional" and right = "additional" + or + wrong = "adecuate" and right = "adequate" + or + wrong = "adequit" and right = "adequate" + or + wrong = "adhearing" and right = "adhering" + or + wrong = "adherance" and right = "adherence" + or + wrong = "admendment" and right = "amendment" + or + wrong = "admininistrative" and right = "administrative" + or + wrong = "adminstered" and right = "administered" + or + wrong = "adminstrate" and right = "administrate" + or + wrong = "adminstration" and right = "administration" + or + wrong = "adminstrative" and right = "administrative" + or + wrong = "adminstrator" and right = "administrator" + or + wrong = "admissability" and right = "admissibility" + or + wrong = "admissable" and right = "admissible" + or + wrong = "admited" and right = "admitted" + or + wrong = "admitedly" and right = "admittedly" + or + wrong = "adn" and right = "and" + or + wrong = "adolecent" and right = "adolescent" + or + wrong = "adquire" and right = "acquire" + or + wrong = "adquired" and right = "acquired" + or + wrong = "adquires" and right = "acquires" + or + wrong = "adquiring" and right = "acquiring" + or + wrong = "adres" and right = "address" + or + wrong = "adresable" and right = "addressable" + or + wrong = "adresing" and right = "addressing" + or + wrong = "adress" and right = "address" + or + wrong = "adressable" and right = "addressable" + or + wrong = "adressed" and right = "addressed" + or + wrong = "adressing" and right = "addressing" + or + wrong = "adressing" and right = "dressing" + or + wrong = "adventrous" and right = "adventurous" + or + wrong = "advertisment" and right = "advertisement" + or + wrong = "advertisments" and right = "advertisements" + or + wrong = "advesary" and right = "adversary" + or + wrong = "adviced" and right = "advised" + or + wrong = "aeriel" and right = "aerial" + or + wrong = "aeriels" and right = "aerials" + or + wrong = "afair" and right = "affair" + or + wrong = "afficianados" and right = "aficionados" + or + wrong = "afficionado" and right = "aficionado" + or + wrong = "afficionados" and right = "aficionados" + or + wrong = "affilate" and right = "affiliate" + or + wrong = "affilliate" and right = "affiliate" + or + wrong = "affort" and right = "afford" + or + wrong = "affort" and right = "effort" + or + wrong = "aforememtioned" and right = "aforementioned" + or + wrong = "againnst" and right = "against" + or + wrong = "agains" and right = "against" + or + wrong = "agaisnt" and right = "against" + or + wrong = "aganist" and right = "against" + or + wrong = "aggaravates" and right = "aggravates" + or + wrong = "aggreed" and right = "agreed" + or + wrong = "aggreement" and right = "agreement" + or + wrong = "aggregious" and right = "egregious" + or + wrong = "aggresive" and right = "aggressive" + or + wrong = "agian" and right = "again" + or + wrong = "agianst" and right = "against" + or + wrong = "agin" and right = "again" + or + wrong = "agina" and right = "again" + or + wrong = "agina" and right = "angina" + or + wrong = "aginst" and right = "against" + or + wrong = "agravate" and right = "aggravate" + or + wrong = "agre" and right = "agree" + or + wrong = "agred" and right = "agreed" + or + wrong = "agreeement" and right = "agreement" + or + wrong = "agreemnt" and right = "agreement" + or + wrong = "agregate" and right = "aggregate" + or + wrong = "agregates" and right = "aggregates" + or + wrong = "agreing" and right = "agreeing" + or + wrong = "agression" and right = "aggression" + or + wrong = "agressive" and right = "aggressive" + or + wrong = "agressively" and right = "aggressively" + or + wrong = "agressor" and right = "aggressor" + or + wrong = "agricultue" and right = "agriculture" + or + wrong = "agriculure" and right = "agriculture" + or + wrong = "agricuture" and right = "agriculture" + or + wrong = "agrieved" and right = "aggrieved" + or + wrong = "agrument" and right = "argument" + or + wrong = "agruments" and right = "arguments" + or + wrong = "ahev" and right = "have" + or + wrong = "ahppen" and right = "happen" + or + wrong = "ahve" and right = "have" + or + wrong = "aicraft" and right = "aircraft" + or + wrong = "aiport" and right = "airport" + or + wrong = "airbourne" and right = "airborne" + or + wrong = "aircaft" and right = "aircraft" + or + wrong = "aircrafts" and right = "aircraft" + or + wrong = "airporta" and right = "airports" + or + wrong = "airrcraft" and right = "aircraft" + or + wrong = "aisian" and right = "asian" + or + wrong = "albiet" and right = "albeit" + or + wrong = "alchohol" and right = "alcohol" + or + wrong = "alchoholic" and right = "alcoholic" + or + wrong = "alchol" and right = "alcohol" + or + wrong = "alcholic" and right = "alcoholic" + or + wrong = "alcohal" and right = "alcohol" + or + wrong = "alcoholical" and right = "alcoholic" + or + wrong = "aledge" and right = "allege" + or + wrong = "aledged" and right = "alleged" + or + wrong = "aledges" and right = "alleges" + or + wrong = "alege" and right = "allege" + or + wrong = "aleged" and right = "alleged" + or + wrong = "alegience" and right = "allegiance" + or + wrong = "algebraical" and right = "algebraic" + or + wrong = "algorhitms" and right = "algorithms" + or + wrong = "algoritm" and right = "algorithm" + or + wrong = "algoritms" and right = "algorithms" + or + wrong = "alientating" and right = "alienating" + or + wrong = "alledge" and right = "allege" + or + wrong = "alledged" and right = "alleged" + or + wrong = "alledgedly" and right = "allegedly" + or + wrong = "alledges" and right = "alleges" + or + wrong = "allegedely" and right = "allegedly" + or + wrong = "allegedy" and right = "allegedly" + or + wrong = "allegely" and right = "allegedly" + or + wrong = "allegence" and right = "allegiance" + or + wrong = "allegience" and right = "allegiance" + or + wrong = "allign" and right = "align" + or + wrong = "alligned" and right = "aligned" + or + wrong = "alliviate" and right = "alleviate" + or + wrong = "allopone" and right = "allophone" + or + wrong = "allopones" and right = "allophones" + or + wrong = "allready" and right = "already" + or + wrong = "allthough" and right = "although" + or + wrong = "alltogether" and right = "altogether" + or + wrong = "almsot" and right = "almost" + or + wrong = "alochol" and right = "alcohol" + or + wrong = "alomst" and right = "almost" + or + wrong = "alot" and right = "allot" + or + wrong = "alotted" and right = "allotted" + or + wrong = "alowed" and right = "allowed" + or + wrong = "alowing" and right = "allowing" + or + wrong = "alreayd" and right = "already" + or + wrong = "alse" and right = "else" + or + wrong = "alsot" and right = "also" + or + wrong = "alternitives" and right = "alternatives" + or + wrong = "altho" and right = "although" + or + wrong = "althought" and right = "although" + or + wrong = "altough" and right = "although" + or + wrong = "alusion" and right = "allusion" + or + wrong = "alusion" and right = "illusion" + or + wrong = "alwasy" and right = "always" + or + wrong = "alwyas" and right = "always" + or + wrong = "amalgomated" and right = "amalgamated" + or + wrong = "amatuer" and right = "amateur" + or + wrong = "amature" and right = "amateur" + or + wrong = "amature" and right = "armature" + or + wrong = "amendmant" and right = "amendment" + or + wrong = "amercia" and right = "america" + or + wrong = "amerliorate" and right = "ameliorate" + or + wrong = "amke" and right = "make" + or + wrong = "amking" and right = "making" + or + wrong = "ammend" and right = "amend" + or + wrong = "ammended" and right = "amended" + or + wrong = "ammendment" and right = "amendment" + or + wrong = "ammendments" and right = "amendments" + or + wrong = "ammount" and right = "amount" + or + wrong = "ammused" and right = "amused" + or + wrong = "amoung" and right = "among" + or + wrong = "amoungst" and right = "amongst" + or + wrong = "amung" and right = "among" + or + wrong = "amunition" and right = "ammunition" + or + wrong = "analagous" and right = "analogous" + or + wrong = "analitic" and right = "analytic" + or + wrong = "analogeous" and right = "analogous" + or + wrong = "anarchim" and right = "anarchism" + or + wrong = "anarchistm" and right = "anarchism" + or + wrong = "anbd" and right = "and" + or + wrong = "ancestory" and right = "ancestry" + or + wrong = "ancilliary" and right = "ancillary" + or + wrong = "andd" and right = "and" + or + wrong = "androgenous" and right = "androgynous" + or + wrong = "androgeny" and right = "androgyny" + or + wrong = "anihilation" and right = "annihilation" + or + wrong = "aniversary" and right = "anniversary" + or + wrong = "annoint" and right = "anoint" + or + wrong = "annointed" and right = "anointed" + or + wrong = "annointing" and right = "anointing" + or + wrong = "annoints" and right = "anoints" + or + wrong = "annouced" and right = "announced" + or + wrong = "annualy" and right = "annually" + or + wrong = "annuled" and right = "annulled" + or + wrong = "anohter" and right = "another" + or + wrong = "anomolies" and right = "anomalies" + or + wrong = "anomolous" and right = "anomalous" + or + wrong = "anomoly" and right = "anomaly" + or + wrong = "anonimity" and right = "anonymity" + or + wrong = "anounced" and right = "announced" + or + wrong = "anouncement" and right = "announcement" + or + wrong = "ansalisation" and right = "nasalisation" + or + wrong = "ansalization" and right = "nasalization" + or + wrong = "ansestors" and right = "ancestors" + or + wrong = "antartic" and right = "antarctic" + or + wrong = "anthromorphization" and right = "anthropomorphization" + or + wrong = "anthropolgist" and right = "anthropologist" + or + wrong = "anthropolgy" and right = "anthropology" + or + wrong = "anual" and right = "annual" + or + wrong = "anulled" and right = "annulled" + or + wrong = "anwsered" and right = "answered" + or + wrong = "anyhwere" and right = "anywhere" + or + wrong = "anytying" and right = "anything" + or + wrong = "aparent" and right = "apparent" + or + wrong = "aparment" and right = "apartment" + or + wrong = "apenines" and right = "apennines" + or + wrong = "aplication" and right = "application" + or + wrong = "aplied" and right = "applied" + or + wrong = "apolegetics" and right = "apologetics" + or + wrong = "apon" and right = "apron" + or + wrong = "apon" and right = "upon" + or + wrong = "apparant" and right = "apparent" + or + wrong = "apparantly" and right = "apparently" + or + wrong = "appart" and right = "apart" + or + wrong = "appartment" and right = "apartment" + or + wrong = "appartments" and right = "apartments" + or + wrong = "appealling" and right = "appalling" + or + wrong = "appealling" and right = "appealing" + or + wrong = "appeareance" and right = "appearance" + or + wrong = "appearence" and right = "appearance" + or + wrong = "appearences" and right = "appearances" + or + wrong = "appenines" and right = "apennines" + or + wrong = "apperance" and right = "appearance" + or + wrong = "apperances" and right = "appearances" + or + wrong = "appereance" and right = "appearance" + or + wrong = "appereances" and right = "appearances" + or + wrong = "applicaiton" and right = "application" + or + wrong = "applicaitons" and right = "applications" + or + wrong = "appologies" and right = "apologies" + or + wrong = "appology" and right = "apology" + or + wrong = "apprearance" and right = "appearance" + or + wrong = "apprieciate" and right = "appreciate" + or + wrong = "approachs" and right = "approaches" + or + wrong = "appropiate" and right = "appropriate" + or + wrong = "appropraite" and right = "appropriate" + or + wrong = "appropropiate" and right = "appropriate" + or + wrong = "approproximate" and right = "approximate" + or + wrong = "approxamately" and right = "approximately" + or + wrong = "approxiately" and right = "approximately" + or + wrong = "approximitely" and right = "approximately" + or + wrong = "aprehensive" and right = "apprehensive" + or + wrong = "apropriate" and right = "appropriate" + or + wrong = "aproval" and right = "approval" + or + wrong = "aproximate" and right = "approximate" + or + wrong = "aproximately" and right = "approximately" + or + wrong = "aquaduct" and right = "aqueduct" + or + wrong = "aquaintance" and right = "acquaintance" + or + wrong = "aquainted" and right = "acquainted" + or + wrong = "aquiantance" and right = "acquaintance" + or + wrong = "aquire" and right = "acquire" + or + wrong = "aquired" and right = "acquired" + or + wrong = "aquiring" and right = "acquiring" + or + wrong = "aquisition" and right = "acquisition" + or + wrong = "aquitted" and right = "acquitted" + or + wrong = "aranged" and right = "arranged" + or + wrong = "arangement" and right = "arrangement" + or + wrong = "arbitarily" and right = "arbitrarily" + or + wrong = "arbitary" and right = "arbitrary" + or + wrong = "archaelogical" and right = "archaeological" + or + wrong = "archaelogists" and right = "archaeologists" + or + wrong = "archaelogy" and right = "archaeology" + or + wrong = "archaoelogy" and right = "archaeology" + or + wrong = "archaoelogy" and right = "archeology" + or + wrong = "archaology" and right = "archaeology" + or + wrong = "archaology" and right = "archeology" + or + wrong = "archeaologist" and right = "archaeologist" + or + wrong = "archeaologist" and right = "archeologist" + or + wrong = "archeaologists" and right = "archaeologists" + or + wrong = "archeaologists" and right = "archeologists" + or + wrong = "archetect" and right = "architect" + or + wrong = "archetects" and right = "architects" + or + wrong = "archetectural" and right = "architectural" + or + wrong = "archetecturally" and right = "architecturally" + or + wrong = "archetecture" and right = "architecture" + or + wrong = "archiac" and right = "archaic" + or + wrong = "archictect" and right = "architect" + or + wrong = "archimedian" and right = "archimedean" + or + wrong = "architecht" and right = "architect" + or + wrong = "architechturally" and right = "architecturally" + or + wrong = "architechture" and right = "architecture" + or + wrong = "architechtures" and right = "architectures" + or + wrong = "architectual" and right = "architectural" + or + wrong = "archtype" and right = "archetype" + or + wrong = "archtypes" and right = "archetypes" + or + wrong = "aready" and right = "already" + or + wrong = "areodynamics" and right = "aerodynamics" + or + wrong = "argubly" and right = "arguably" + or + wrong = "arguement" and right = "argument" + or + wrong = "arguements" and right = "arguments" + or + wrong = "arised" and right = "arose" + or + wrong = "arival" and right = "arrival" + or + wrong = "armamant" and right = "armament" + or + wrong = "armistace" and right = "armistice" + or + wrong = "arogant" and right = "arrogant" + or + wrong = "arogent" and right = "arrogant" + or + wrong = "aroud" and right = "around" + or + wrong = "arrangment" and right = "arrangement" + or + wrong = "arrangments" and right = "arrangements" + or + wrong = "arrengement" and right = "arrangement" + or + wrong = "arrengements" and right = "arrangements" + or + wrong = "arround" and right = "around" + or + wrong = "artcile" and right = "article" + or + wrong = "artical" and right = "article" + or + wrong = "artice" and right = "article" + or + wrong = "articel" and right = "article" + or + wrong = "artifical" and right = "artificial" + or + wrong = "artifically" and right = "artificially" + or + wrong = "artillary" and right = "artillery" + or + wrong = "arund" and right = "around" + or + wrong = "asetic" and right = "ascetic" + or + wrong = "asign" and right = "assign" + or + wrong = "aslo" and right = "also" + or + wrong = "asnyc" and right = "async" + or + wrong = "asociated" and right = "associated" + or + wrong = "asorbed" and right = "absorbed" + or + wrong = "asphyxation" and right = "asphyxiation" + or + wrong = "assasin" and right = "assassin" + or + wrong = "assasinate" and right = "assassinate" + or + wrong = "assasinated" and right = "assassinated" + or + wrong = "assasinates" and right = "assassinates" + or + wrong = "assasination" and right = "assassination" + or + wrong = "assasinations" and right = "assassinations" + or + wrong = "assasined" and right = "assassinated" + or + wrong = "assasins" and right = "assassins" + or + wrong = "assassintation" and right = "assassination" + or + wrong = "assemple" and right = "assemble" + or + wrong = "assertation" and right = "assertion" + or + wrong = "asside" and right = "aside" + or + wrong = "assisnate" and right = "assassinate" + or + wrong = "assit" and right = "assist" + or + wrong = "assitant" and right = "assistant" + or + wrong = "assocation" and right = "association" + or + wrong = "assoicate" and right = "associate" + or + wrong = "assoicated" and right = "associated" + or + wrong = "assoicates" and right = "associates" + or + wrong = "assosication" and right = "assassination" + or + wrong = "asssassans" and right = "assassins" + or + wrong = "assualt" and right = "assault" + or + wrong = "assualted" and right = "assaulted" + or + wrong = "assymetric" and right = "asymmetric" + or + wrong = "assymetrical" and right = "asymmetrical" + or + wrong = "asteriod" and right = "asteroid" + or + wrong = "asthetic" and right = "aesthetic" + or + wrong = "asthetical" and right = "aesthetical" + or + wrong = "asthetically" and right = "aesthetically" + or + wrong = "asume" and right = "assume" + or + wrong = "atain" and right = "attain" + or + wrong = "atempting" and right = "attempting" + or + wrong = "atheistical" and right = "atheistic" + or + wrong = "athenean" and right = "athenian" + or + wrong = "atheneans" and right = "athenians" + or + wrong = "athiesm" and right = "atheism" + or + wrong = "athiest" and right = "atheist" + or + wrong = "atorney" and right = "attorney" + or + wrong = "atribute" and right = "attribute" + or + wrong = "atributed" and right = "attributed" + or + wrong = "atributes" and right = "attributes" + or + wrong = "attaindre" and right = "attainder" + or + wrong = "attaindre" and right = "attained" + or + wrong = "attemp" and right = "attempt" + or + wrong = "attemped" and right = "attempted" + or + wrong = "attemt" and right = "attempt" + or + wrong = "attemted" and right = "attempted" + or + wrong = "attemting" and right = "attempting" + or + wrong = "attemts" and right = "attempts" + or + wrong = "attendence" and right = "attendance" + or + wrong = "attendent" and right = "attendant" + or + wrong = "attendents" and right = "attendants" + or + wrong = "attened" and right = "attended" + or + wrong = "attension" and right = "attention" + or + wrong = "attitide" and right = "attitude" + or + wrong = "attributred" and right = "attributed" + or + wrong = "attrocities" and right = "atrocities" + or + wrong = "audeince" and right = "audience" + or + wrong = "auromated" and right = "automated" + or + wrong = "austrailia" and right = "australia" + or + wrong = "austrailian" and right = "australian" + or + wrong = "auther" and right = "author" + or + wrong = "authobiographic" and right = "autobiographic" + or + wrong = "authobiography" and right = "autobiography" + or + wrong = "authorative" and right = "authoritative" + or + wrong = "authorites" and right = "authorities" + or + wrong = "authorithy" and right = "authority" + or + wrong = "authoritiers" and right = "authorities" + or + wrong = "authoritive" and right = "authoritative" + or + wrong = "authrorities" and right = "authorities" + or + wrong = "autochtonous" and right = "autochthonous" + or + wrong = "autoctonous" and right = "autochthonous" + or + wrong = "automaticly" and right = "automatically" + or + wrong = "automibile" and right = "automobile" + or + wrong = "automonomous" and right = "autonomous" + or + wrong = "autor" and right = "author" + or + wrong = "autority" and right = "authority" + or + wrong = "auxilary" and right = "auxiliary" + or + wrong = "auxillaries" and right = "auxiliaries" + or + wrong = "auxillary" and right = "auxiliary" + or + wrong = "auxilliaries" and right = "auxiliaries" + or + wrong = "auxilliary" and right = "auxiliary" + or + wrong = "availabe" and right = "available" + or + wrong = "availablity" and right = "availability" + or + wrong = "availaible" and right = "available" + or + wrong = "availble" and right = "available" + or + wrong = "availiable" and right = "available" + or + wrong = "availible" and right = "available" + or + wrong = "avalable" and right = "available" + or + wrong = "avalance" and right = "avalanche" + or + wrong = "avaliable" and right = "available" + or + wrong = "avation" and right = "aviation" + or + wrong = "averageed" and right = "averaged" + or + wrong = "avilable" and right = "available" + or + wrong = "awared" and right = "awarded" + or + wrong = "awya" and right = "away" + or + wrong = "baceause" and right = "because" + or + wrong = "backgorund" and right = "background" + or + wrong = "backrounds" and right = "backgrounds" + or + wrong = "bakc" and right = "back" + or + wrong = "banannas" and right = "bananas" + or + wrong = "bandwith" and right = "bandwidth" + or + wrong = "bankrupcy" and right = "bankruptcy" + or + wrong = "banruptcy" and right = "bankruptcy" + or + wrong = "baout" and right = "about" + or + wrong = "baout" and right = "bout" + or + wrong = "basicaly" and right = "basically" + or + wrong = "basicly" and right = "basically" + or + wrong = "bcak" and right = "back" + or + wrong = "beachead" and right = "beachhead" + or + wrong = "beacuse" and right = "because" + or + wrong = "beastiality" and right = "bestiality" + or + wrong = "beatiful" and right = "beautiful" + or + wrong = "beaurocracy" and right = "bureaucracy" + or + wrong = "beaurocratic" and right = "bureaucratic" + or + wrong = "beautyfull" and right = "beautiful" + or + wrong = "becamae" and right = "became" + or + wrong = "becames" and right = "became" + or + wrong = "becames" and right = "becomes" + or + wrong = "becasue" and right = "because" + or + wrong = "beccause" and right = "because" + or + wrong = "becomeing" and right = "becoming" + or + wrong = "becomming" and right = "becoming" + or + wrong = "becouse" and right = "because" + or + wrong = "becuase" and right = "because" + or + wrong = "bedore" and right = "before" + or + wrong = "beeing" and right = "being" + or + wrong = "befoer" and right = "before" + or + wrong = "beggin" and right = "begging" + or + wrong = "beggin" and right = "begin" + or + wrong = "begginer" and right = "beginner" + or + wrong = "begginers" and right = "beginners" + or + wrong = "beggining" and right = "beginning" + or + wrong = "begginings" and right = "beginnings" + or + wrong = "beggins" and right = "begins" + or + wrong = "begining" and right = "beginning" + or + wrong = "beginnig" and right = "beginning" + or + wrong = "behavour" and right = "behavior" + or + wrong = "behavour" and right = "behaviour" + or + wrong = "beleagured" and right = "beleaguered" + or + wrong = "beleif" and right = "belief" + or + wrong = "beleive" and right = "believe" + or + wrong = "beleived" and right = "believed" + or + wrong = "beleives" and right = "believes" + or + wrong = "beleiving" and right = "believing" + or + wrong = "beligum" and right = "belgium" + or + wrong = "belive" and right = "believe" + or + wrong = "belived" and right = "believed" + or + wrong = "belived" and right = "beloved" + or + wrong = "belives" and right = "beliefs" + or + wrong = "belives" and right = "believes" + or + wrong = "belligerant" and right = "belligerent" + or + wrong = "bellweather" and right = "bellwether" + or + wrong = "bemusemnt" and right = "bemusement" + or + wrong = "beneficary" and right = "beneficiary" + or + wrong = "beng" and right = "being" + or + wrong = "benificial" and right = "beneficial" + or + wrong = "benifit" and right = "benefit" + or + wrong = "benifits" and right = "benefits" + or + wrong = "bergamont" and right = "bergamot" + or + wrong = "bernouilli" and right = "bernoulli" + or + wrong = "beseige" and right = "besiege" + or + wrong = "beseiged" and right = "besieged" + or + wrong = "beseiging" and right = "besieging" + or + wrong = "beteen" and right = "between" + or + wrong = "betwen" and right = "between" + or + wrong = "beween" and right = "between" + or + wrong = "bewteen" and right = "between" + or + wrong = "bigining" and right = "beginning" + or + wrong = "biginning" and right = "beginning" + or + wrong = "bilateraly" and right = "bilaterally" + or + wrong = "billingualism" and right = "bilingualism" + or + wrong = "binominal" and right = "binomial" + or + wrong = "bizzare" and right = "bizarre" + or + wrong = "blaim" and right = "blame" + or + wrong = "blaimed" and right = "blamed" + or + wrong = "blessure" and right = "blessing" + or + wrong = "blitzkreig" and right = "blitzkrieg" + or + wrong = "boaut" and right = "about" + or + wrong = "boaut" and right = "boat" + or + wrong = "boaut" and right = "bout" + or + wrong = "bodydbuilder" and right = "bodybuilder" + or + wrong = "bolean" and right = "boolean" + or + wrong = "bombardement" and right = "bombardment" + or + wrong = "bombarment" and right = "bombardment" + or + wrong = "bondary" and right = "boundary" + or + wrong = "bonnano" and right = "bonanno" + or + wrong = "boook" and right = "book" + or + wrong = "borke" and right = "broke" + or + wrong = "boundry" and right = "boundary" + or + wrong = "bouyancy" and right = "buoyancy" + or + wrong = "bouyant" and right = "buoyant" + or + wrong = "boyant" and right = "buoyant" + or + wrong = "bradcast" and right = "broadcast" + or + wrong = "brasillian" and right = "brazilian" + or + wrong = "breakthough" and right = "breakthrough" + or + wrong = "breakthroughts" and right = "breakthroughs" + or + wrong = "breif" and right = "brief" + or + wrong = "breifly" and right = "briefly" + or + wrong = "brethen" and right = "brethren" + or + wrong = "bretheren" and right = "brethren" + or + wrong = "briliant" and right = "brilliant" + or + wrong = "brillant" and right = "brilliant" + or + wrong = "brimestone" and right = "brimstone" + or + wrong = "britian" and right = "britain" + or + wrong = "brittish" and right = "british" + or + wrong = "broacasted" and right = "broadcast" + or + wrong = "broadacasting" and right = "broadcasting" + or + wrong = "broady" and right = "broadly" + or + wrong = "buddah" and right = "buddha" + or + wrong = "buddist" and right = "buddhist" + or + wrong = "buisness" and right = "business" + or + wrong = "buisnessman" and right = "businessman" + or + wrong = "buoancy" and right = "buoyancy" + or + wrong = "buring" and right = "burin" + or + wrong = "buring" and right = "burning" + or + wrong = "buring" and right = "burying" + or + wrong = "buring" and right = "during" + or + wrong = "burried" and right = "buried" + or + wrong = "busines" and right = "business" + or + wrong = "busineses" and right = "business" + or + wrong = "busineses" and right = "businesses" + or + wrong = "busness" and right = "business" + or + wrong = "bussiness" and right = "business" + or + wrong = "caculater" and right = "calculator" + or + wrong = "cacuses" and right = "caucuses" + or + wrong = "cahracters" and right = "characters" + or + wrong = "calaber" and right = "caliber" + or + wrong = "calander" and right = "calendar" + or + wrong = "calander" and right = "calender" + or + wrong = "calander" and right = "colander" + or + wrong = "calculater" and right = "calculator" + or + wrong = "calculs" and right = "calculus" + or + wrong = "calender" and right = "calendar" + or + wrong = "calenders" and right = "calendars" + or + wrong = "caligraphy" and right = "calligraphy" + or + wrong = "caluclate" and right = "calculate" + or + wrong = "caluclated" and right = "calculated" + or + wrong = "caluculate" and right = "calculate" + or + wrong = "caluculated" and right = "calculated" + or + wrong = "calulate" and right = "calculate" + or + wrong = "calulated" and right = "calculated" + or + wrong = "calulater" and right = "calculator" + or + wrong = "cambrige" and right = "cambridge" + or + wrong = "camoflage" and right = "camouflage" + or + wrong = "campagin" and right = "campaign" + or + wrong = "campain" and right = "campaign" + or + wrong = "campains" and right = "campaigns" + or + wrong = "candadate" and right = "candidate" + or + wrong = "candiate" and right = "candidate" + or + wrong = "candidiate" and right = "candidate" + or + wrong = "cannister" and right = "canister" + or + wrong = "cannisters" and right = "canisters" + or + wrong = "cannnot" and right = "cannot" + or + wrong = "cannonical" and right = "canonical" + or + wrong = "cannotation" and right = "connotation" + or + wrong = "cannotations" and right = "connotations" + or + wrong = "caost" and right = "coast" + or + wrong = "caperbility" and right = "capability" + or + wrong = "capible" and right = "capable" + or + wrong = "captial" and right = "capital" + or + wrong = "captued" and right = "captured" + or + wrong = "capturd" and right = "captured" + or + wrong = "carachter" and right = "character" + or + wrong = "caracterized" and right = "characterized" + or + wrong = "carcas" and right = "caracas" + or + wrong = "carcas" and right = "carcass" + or + wrong = "carefull" and right = "careful" + or + wrong = "careing" and right = "caring" + or + wrong = "carismatic" and right = "charismatic" + or + wrong = "carmalite" and right = "carmelite" + or + wrong = "carnagie" and right = "carnegie" + or + wrong = "carnege" and right = "carnage" + or + wrong = "carnege" and right = "carnegie" + or + wrong = "carnige" and right = "carnage" + or + wrong = "carnige" and right = "carnegie" + or + wrong = "carnigie" and right = "carnegie" + or + wrong = "carreer" and right = "career" + or + wrong = "carrers" and right = "careers" + or + wrong = "carribbean" and right = "caribbean" + or + wrong = "carribean" and right = "caribbean" + or + wrong = "carryng" and right = "carrying" + or + wrong = "cartdridge" and right = "cartridge" + or + wrong = "carthagian" and right = "carthaginian" + or + wrong = "carthographer" and right = "cartographer" + or + wrong = "cartilege" and right = "cartilage" + or + wrong = "cartilidge" and right = "cartilage" + or + wrong = "cartrige" and right = "cartridge" + or + wrong = "casette" and right = "cassette" + or + wrong = "casion" and right = "caisson" + or + wrong = "cassawory" and right = "cassowary" + or + wrong = "cassowarry" and right = "cassowary" + or + wrong = "casue" and right = "cause" + or + wrong = "casued" and right = "caused" + or + wrong = "casues" and right = "causes" + or + wrong = "casuing" and right = "causing" + or + wrong = "casulaties" and right = "casualties" + or + wrong = "casulaty" and right = "casualty" + or + wrong = "catagories" and right = "categories" + or + wrong = "catagorized" and right = "categorized" + or + wrong = "catagory" and right = "category" + or + wrong = "cataline" and right = "catalina" + or + wrong = "cataline" and right = "catiline" + or + wrong = "catapillar" and right = "caterpillar" + or + wrong = "catapillars" and right = "caterpillars" + or + wrong = "catapiller" and right = "caterpillar" + or + wrong = "catapillers" and right = "caterpillars" + or + wrong = "catepillar" and right = "caterpillar" + or + wrong = "catepillars" and right = "caterpillars" + or + wrong = "catergorize" and right = "categorize" + or + wrong = "catergorized" and right = "categorized" + or + wrong = "caterpilar" and right = "caterpillar" + or + wrong = "caterpilars" and right = "caterpillars" + or + wrong = "caterpiller" and right = "caterpillar" + or + wrong = "caterpillers" and right = "caterpillars" + or + wrong = "cathlic" and right = "catholic" + or + wrong = "catholocism" and right = "catholicism" + or + wrong = "catterpilar" and right = "caterpillar" + or + wrong = "catterpilars" and right = "caterpillars" + or + wrong = "catterpillar" and right = "caterpillar" + or + wrong = "catterpillars" and right = "caterpillars" + or + wrong = "cattleship" and right = "battleship" + or + wrong = "causalities" and right = "casualties" + or + wrong = "ceasar" and right = "caesar" + or + wrong = "celcius" and right = "celsius" + or + wrong = "cellpading" and right = "cellpadding" + or + wrong = "cementary" and right = "cemetery" + or + wrong = "cemetarey" and right = "cemetery" + or + wrong = "cemetaries" and right = "cemeteries" + or + wrong = "cemetary" and right = "cemetery" + or + wrong = "cencus" and right = "census" + or + wrong = "censur" and right = "censor" + or + wrong = "censur" and right = "censure" + or + wrong = "cententenial" and right = "centennial" + or + wrong = "centruies" and right = "centuries" + or + wrong = "centruy" and right = "century" + or + wrong = "centuties" and right = "centuries" + or + wrong = "centuty" and right = "century" + or + wrong = "ceratin" and right = "certain" + or + wrong = "ceratin" and right = "keratin" + or + wrong = "cerimonial" and right = "ceremonial" + or + wrong = "cerimonies" and right = "ceremonies" + or + wrong = "cerimonious" and right = "ceremonious" + or + wrong = "cerimony" and right = "ceremony" + or + wrong = "ceromony" and right = "ceremony" + or + wrong = "certainity" and right = "certainty" + or + wrong = "certian" and right = "certain" + or + wrong = "cervial" and right = "cervical" + or + wrong = "cervial" and right = "serval" + or + wrong = "cervial" and right = "servile" + or + wrong = "chalenging" and right = "challenging" + or + wrong = "challange" and right = "challenge" + or + wrong = "challanged" and right = "challenged" + or + wrong = "challege" and right = "challenge" + or + wrong = "champange" and right = "champagne" + or + wrong = "changable" and right = "changeable" + or + wrong = "charachter" and right = "character" + or + wrong = "charachters" and right = "characters" + or + wrong = "charactersistic" and right = "characteristic" + or + wrong = "charactor" and right = "character" + or + wrong = "charactors" and right = "characters" + or + wrong = "charasmatic" and right = "charismatic" + or + wrong = "charaterized" and right = "characterized" + or + wrong = "chariman" and right = "chairman" + or + wrong = "charistics" and right = "characteristics" + or + wrong = "chasr" and right = "chase" + or + wrong = "chasr" and right = "chaser" + or + wrong = "cheif" and right = "chief" + or + wrong = "cheifs" and right = "chiefs" + or + wrong = "chemcial" and right = "chemical" + or + wrong = "chemcially" and right = "chemically" + or + wrong = "chemestry" and right = "chemistry" + or + wrong = "chemicaly" and right = "chemically" + or + wrong = "childbird" and right = "childbirth" + or + wrong = "childen" and right = "children" + or + wrong = "choclate" and right = "chocolate" + or + wrong = "choosen" and right = "chosen" + or + wrong = "chracter" and right = "character" + or + wrong = "chuch" and right = "church" + or + wrong = "churchs" and right = "churches" + or + wrong = "cincinatti" and right = "cincinnati" + or + wrong = "cincinnatti" and right = "cincinnati" + or + wrong = "circulaton" and right = "circulation" + or + wrong = "circumsicion" and right = "circumcision" + or + wrong = "circut" and right = "circuit" + or + wrong = "ciricuit" and right = "circuit" + or + wrong = "ciriculum" and right = "curriculum" + or + wrong = "civillian" and right = "civilian" + or + wrong = "claer" and right = "clear" + or + wrong = "claerer" and right = "clearer" + or + wrong = "claerly" and right = "clearly" + or + wrong = "claimes" and right = "claims" + or + wrong = "clas" and right = "class" + or + wrong = "clasic" and right = "classic" + or + wrong = "clasical" and right = "classical" + or + wrong = "clasically" and right = "classically" + or + wrong = "cleareance" and right = "clearance" + or + wrong = "clera" and right = "clear" + or + wrong = "clera" and right = "sclera" + or + wrong = "clincial" and right = "clinical" + or + wrong = "clinicaly" and right = "clinically" + or + wrong = "cmo" and right = "com" + or + wrong = "cmoputer" and right = "computer" + or + wrong = "coctail" and right = "cocktail" + or + wrong = "coform" and right = "conform" + or + wrong = "cognizent" and right = "cognizant" + or + wrong = "coincedentally" and right = "coincidentally" + or + wrong = "colaborations" and right = "collaborations" + or + wrong = "colateral" and right = "collateral" + or + wrong = "colelctive" and right = "collective" + or + wrong = "collaberative" and right = "collaborative" + or + wrong = "collecton" and right = "collection" + or + wrong = "collegue" and right = "colleague" + or + wrong = "collegues" and right = "colleagues" + or + wrong = "collonade" and right = "colonnade" + or + wrong = "collonies" and right = "colonies" + or + wrong = "collony" and right = "colony" + or + wrong = "collosal" and right = "colossal" + or + wrong = "colonizators" and right = "colonizers" + or + wrong = "comander" and right = "commandeer" + or + wrong = "comander" and right = "commander" + or + wrong = "comando" and right = "commando" + or + wrong = "comandos" and right = "commandos" + or + wrong = "comany" and right = "company" + or + wrong = "comapany" and right = "company" + or + wrong = "comback" and right = "comeback" + or + wrong = "combanations" and right = "combinations" + or + wrong = "combinatins" and right = "combinations" + or + wrong = "combusion" and right = "combustion" + or + wrong = "comdemnation" and right = "condemnation" + or + wrong = "comemmorates" and right = "commemorates" + or + wrong = "comemoretion" and right = "commemoration" + or + wrong = "comision" and right = "commission" + or + wrong = "comisioned" and right = "commissioned" + or + wrong = "comisioner" and right = "commissioner" + or + wrong = "comisioning" and right = "commissioning" + or + wrong = "comisions" and right = "commissions" + or + wrong = "comission" and right = "commission" + or + wrong = "comissioned" and right = "commissioned" + or + wrong = "comissioner" and right = "commissioner" + or + wrong = "comissioning" and right = "commissioning" + or + wrong = "comissions" and right = "commissions" + or + wrong = "comited" and right = "committed" + or + wrong = "comiting" and right = "committing" + or + wrong = "comitted" and right = "committed" + or + wrong = "comittee" and right = "committee" + or + wrong = "comitting" and right = "committing" + or + wrong = "commandoes" and right = "commandos" + or + wrong = "commedic" and right = "comedic" + or + wrong = "commemerative" and right = "commemorative" + or + wrong = "commemmorate" and right = "commemorate" + or + wrong = "commemmorating" and right = "commemorating" + or + wrong = "commerical" and right = "commercial" + or + wrong = "commerically" and right = "commercially" + or + wrong = "commericial" and right = "commercial" + or + wrong = "commericially" and right = "commercially" + or + wrong = "commerorative" and right = "commemorative" + or + wrong = "comming" and right = "coming" + or + wrong = "comminication" and right = "communication" + or + wrong = "commision" and right = "commission" + or + wrong = "commisioned" and right = "commissioned" + or + wrong = "commisioner" and right = "commissioner" + or + wrong = "commisioning" and right = "commissioning" + or + wrong = "commisions" and right = "commissions" + or + wrong = "commited" and right = "committed" + or + wrong = "commitee" and right = "committee" + or + wrong = "commiting" and right = "committing" + or + wrong = "committe" and right = "committee" + or + wrong = "committment" and right = "commitment" + or + wrong = "committments" and right = "commitments" + or + wrong = "commmemorated" and right = "commemorated" + or + wrong = "commongly" and right = "commonly" + or + wrong = "commonweath" and right = "commonwealth" + or + wrong = "commuications" and right = "communications" + or + wrong = "commuinications" and right = "communications" + or + wrong = "communciation" and right = "communication" + or + wrong = "communiation" and right = "communication" + or + wrong = "communites" and right = "communities" + or + wrong = "compability" and right = "compatibility" + or + wrong = "comparision" and right = "comparison" + or + wrong = "comparisions" and right = "comparisons" + or + wrong = "comparitive" and right = "comparative" + or + wrong = "comparitively" and right = "comparatively" + or + wrong = "compatabilities" and right = "compatibilities" + or + wrong = "compatability" and right = "compatibility" + or + wrong = "compatable" and right = "compatible" + or + wrong = "compatablities" and right = "compatibilities" + or + wrong = "compatablity" and right = "compatibility" + or + wrong = "compatiable" and right = "compatible" + or + wrong = "compatiblities" and right = "compatibilities" + or + wrong = "compatiblity" and right = "compatibility" + or + wrong = "compeitions" and right = "competitions" + or + wrong = "compensantion" and right = "compensation" + or + wrong = "competance" and right = "competence" + or + wrong = "competant" and right = "competent" + or + wrong = "competative" and right = "competitive" + or + wrong = "competion" and right = "competition" + or + wrong = "competion" and right = "completion" + or + wrong = "competitiion" and right = "competition" + or + wrong = "competive" and right = "competitive" + or + wrong = "competiveness" and right = "competitiveness" + or + wrong = "comphrehensive" and right = "comprehensive" + or + wrong = "compitent" and right = "competent" + or + wrong = "completelyl" and right = "completely" + or + wrong = "completetion" and right = "completion" + or + wrong = "complier" and right = "compiler" + or + wrong = "componant" and right = "component" + or + wrong = "comprable" and right = "comparable" + or + wrong = "comprimise" and right = "compromise" + or + wrong = "compulsary" and right = "compulsory" + or + wrong = "compulsery" and right = "compulsory" + or + wrong = "computarized" and right = "computerized" + or + wrong = "concensus" and right = "consensus" + or + wrong = "concider" and right = "consider" + or + wrong = "concidered" and right = "considered" + or + wrong = "concidering" and right = "considering" + or + wrong = "conciders" and right = "considers" + or + wrong = "concieted" and right = "conceited" + or + wrong = "concieved" and right = "conceived" + or + wrong = "concious" and right = "conscious" + or + wrong = "conciously" and right = "consciously" + or + wrong = "conciousness" and right = "consciousness" + or + wrong = "condamned" and right = "condemned" + or + wrong = "condemmed" and right = "condemned" + or + wrong = "condidtion" and right = "condition" + or + wrong = "condidtions" and right = "conditions" + or + wrong = "conected" and right = "connected" + or + wrong = "conection" and right = "connection" + or + wrong = "conesencus" and right = "consensus" + or + wrong = "confidental" and right = "confidential" + or + wrong = "confidentally" and right = "confidentially" + or + wrong = "confids" and right = "confides" + or + wrong = "configureable" and right = "configurable" + or + wrong = "confortable" and right = "comfortable" + or + wrong = "congradulations" and right = "congratulations" + or + wrong = "congresional" and right = "congressional" + or + wrong = "conived" and right = "connived" + or + wrong = "conjecutre" and right = "conjecture" + or + wrong = "conjuction" and right = "conjunction" + or + wrong = "connectinos" and right = "connections" + or + wrong = "conneticut" and right = "connecticut" + or + wrong = "conotations" and right = "connotations" + or + wrong = "conquerd" and right = "conquered" + or + wrong = "conquerer" and right = "conqueror" + or + wrong = "conquerers" and right = "conquerors" + or + wrong = "conqured" and right = "conquered" + or + wrong = "conscent" and right = "consent" + or + wrong = "consciouness" and right = "consciousness" + or + wrong = "consdider" and right = "consider" + or + wrong = "consdidered" and right = "considered" + or + wrong = "consdiered" and right = "considered" + or + wrong = "consectutive" and right = "consecutive" + or + wrong = "consenquently" and right = "consequently" + or + wrong = "consentrate" and right = "concentrate" + or + wrong = "consentrated" and right = "concentrated" + or + wrong = "consentrates" and right = "concentrates" + or + wrong = "consept" and right = "concept" + or + wrong = "consequentually" and right = "consequently" + or + wrong = "consequeseces" and right = "consequences" + or + wrong = "consern" and right = "concern" + or + wrong = "conserned" and right = "concerned" + or + wrong = "conserning" and right = "concerning" + or + wrong = "conservitive" and right = "conservative" + or + wrong = "consiciousness" and right = "consciousness" + or + wrong = "consicousness" and right = "consciousness" + or + wrong = "considerd" and right = "considered" + or + wrong = "consideres" and right = "considered" + or + wrong = "consious" and right = "conscious" + or + wrong = "consistant" and right = "consistent" + or + wrong = "consistantly" and right = "consistently" + or + wrong = "consituencies" and right = "constituencies" + or + wrong = "consituency" and right = "constituency" + or + wrong = "consituted" and right = "constituted" + or + wrong = "consitution" and right = "constitution" + or + wrong = "consitutional" and right = "constitutional" + or + wrong = "consolodate" and right = "consolidate" + or + wrong = "consolodated" and right = "consolidated" + or + wrong = "consonent" and right = "consonant" + or + wrong = "consonents" and right = "consonants" + or + wrong = "consorcium" and right = "consortium" + or + wrong = "conspiracys" and right = "conspiracies" + or + wrong = "conspiriator" and right = "conspirator" + or + wrong = "consructor" and right = "constructor" + or + wrong = "constaints" and right = "constraints" + or + wrong = "constanly" and right = "constantly" + or + wrong = "constarnation" and right = "consternation" + or + wrong = "constatn" and right = "constant" + or + wrong = "constinually" and right = "continually" + or + wrong = "constituant" and right = "constituent" + or + wrong = "constituants" and right = "constituents" + or + wrong = "constituion" and right = "constitution" + or + wrong = "constituional" and right = "constitutional" + or + wrong = "consttruction" and right = "construction" + or + wrong = "constuction" and right = "construction" + or + wrong = "consulant" and right = "consultant" + or + wrong = "consumate" and right = "consummate" + or + wrong = "consumated" and right = "consummated" + or + wrong = "contaiminate" and right = "contaminate" + or + wrong = "containes" and right = "contains" + or + wrong = "contamporaries" and right = "contemporaries" + or + wrong = "contamporary" and right = "contemporary" + or + wrong = "contempoary" and right = "contemporary" + or + wrong = "contemporaneus" and right = "contemporaneous" + or + wrong = "contempory" and right = "contemporary" + or + wrong = "contendor" and right = "contender" + or + wrong = "contian" and right = "contain" + or + wrong = "contians" and right = "contains" + or + wrong = "contibute" and right = "contribute" + or + wrong = "contibuted" and right = "contributed" + or + wrong = "contibutes" and right = "contributes" + or + wrong = "contigent" and right = "contingent" + or + wrong = "contined" and right = "continued" + or + wrong = "continential" and right = "continental" + or + wrong = "continous" and right = "continuous" + or + wrong = "continously" and right = "continuously" + or + wrong = "continueing" and right = "continuing" + or + wrong = "contravercial" and right = "controversial" + or + wrong = "contraversy" and right = "controversy" + or + wrong = "contributer" and right = "contributor" + or + wrong = "contributers" and right = "contributors" + or + wrong = "contritutions" and right = "contributions" + or + wrong = "controled" and right = "controlled" + or + wrong = "controling" and right = "controlling" + or + wrong = "controll" and right = "control" + or + wrong = "controlls" and right = "controls" + or + wrong = "controvercial" and right = "controversial" + or + wrong = "controvercy" and right = "controversy" + or + wrong = "controveries" and right = "controversies" + or + wrong = "controversal" and right = "controversial" + or + wrong = "controversey" and right = "controversy" + or + wrong = "controvertial" and right = "controversial" + or + wrong = "controvery" and right = "controversy" + or + wrong = "contruction" and right = "construction" + or + wrong = "contructor" and right = "constructor" + or + wrong = "contstruction" and right = "construction" + or + wrong = "conveinent" and right = "convenient" + or + wrong = "convenant" and right = "covenant" + or + wrong = "convential" and right = "conventional" + or + wrong = "convertables" and right = "convertibles" + or + wrong = "convertion" and right = "conversion" + or + wrong = "conviced" and right = "convinced" + or + wrong = "convienient" and right = "convenient" + or + wrong = "coordiantion" and right = "coordination" + or + wrong = "coorperation" and right = "cooperation" + or + wrong = "coorperation" and right = "corporation" + or + wrong = "coorperations" and right = "corporations" + or + wrong = "copmetitors" and right = "competitors" + or + wrong = "coputer" and right = "computer" + or + wrong = "copywrite" and right = "copyright" + or + wrong = "coridal" and right = "cordial" + or + wrong = "cornmitted" and right = "committed" + or + wrong = "corosion" and right = "corrosion" + or + wrong = "corparate" and right = "corporate" + or + wrong = "corperations" and right = "corporations" + or + wrong = "correcters" and right = "correctors" + or + wrong = "correponding" and right = "corresponding" + or + wrong = "correposding" and right = "corresponding" + or + wrong = "correspondant" and right = "correspondent" + or + wrong = "correspondants" and right = "correspondents" + or + wrong = "corridoors" and right = "corridors" + or + wrong = "corrispond" and right = "correspond" + or + wrong = "corrispondant" and right = "correspondent" + or + wrong = "corrispondants" and right = "correspondents" + or + wrong = "corrisponded" and right = "corresponded" + or + wrong = "corrisponding" and right = "corresponding" + or + wrong = "corrisponds" and right = "corresponds" + or + wrong = "costitution" and right = "constitution" + or + wrong = "coucil" and right = "council" + or + wrong = "coudl" and right = "cloud" + or + wrong = "coudl" and right = "could" + or + wrong = "councellor" and right = "councillor" + or + wrong = "councellor" and right = "councilor" + or + wrong = "councellor" and right = "counselor" + or + wrong = "councellors" and right = "councillors" + or + wrong = "councellors" and right = "councilors" + or + wrong = "councellors" and right = "counselors" + or + wrong = "counries" and right = "countries" + or + wrong = "countains" and right = "contains" + or + wrong = "countires" and right = "countries" + or + wrong = "coururier" and right = "courier" + or + wrong = "coururier" and right = "couturier" + or + wrong = "coverted" and right = "converted" + or + wrong = "coverted" and right = "covered" + or + wrong = "coverted" and right = "coveted" + or + wrong = "cpoy" and right = "copy" + or + wrong = "cpoy" and right = "coy" + or + wrong = "creaeted" and right = "created" + or + wrong = "creedence" and right = "credence" + or + wrong = "critereon" and right = "criterion" + or + wrong = "criterias" and right = "criteria" + or + wrong = "criticists" and right = "critics" + or + wrong = "critising" and right = "criticising" + or + wrong = "critising" and right = "criticizing" + or + wrong = "critisising" and right = "criticising" + or + wrong = "critisism" and right = "criticism" + or + wrong = "critisisms" and right = "criticisms" + or + wrong = "critisize" and right = "criticise" + or + wrong = "critisize" and right = "criticize" + or + wrong = "critisized" and right = "criticised" + or + wrong = "critisized" and right = "criticized" + or + wrong = "critisizes" and right = "criticises" + or + wrong = "critisizes" and right = "criticizes" + or + wrong = "critisizing" and right = "criticising" + or + wrong = "critisizing" and right = "criticizing" + or + wrong = "critized" and right = "criticized" + or + wrong = "critizing" and right = "criticizing" + or + wrong = "crockodiles" and right = "crocodiles" + or + wrong = "crowm" and right = "crown" + or + wrong = "crtical" and right = "critical" + or + wrong = "crticised" and right = "criticised" + or + wrong = "crucifiction" and right = "crucifixion" + or + wrong = "crusies" and right = "cruises" + or + wrong = "crutial" and right = "crucial" + or + wrong = "crystalisation" and right = "crystallisation" + or + wrong = "culiminating" and right = "culminating" + or + wrong = "cumulatative" and right = "cumulative" + or + wrong = "curch" and right = "church" + or + wrong = "curcuit" and right = "circuit" + or + wrong = "currenly" and right = "currently" + or + wrong = "curriculem" and right = "curriculum" + or + wrong = "cxan" and right = "cyan" + or + wrong = "cyclinder" and right = "cylinder" + or + wrong = "dacquiri" and right = "daiquiri" + or + wrong = "daed" and right = "dead" + or + wrong = "dael" and right = "dahl" + or + wrong = "dael" and right = "deal" + or + wrong = "dael" and right = "dial" + or + wrong = "dalmation" and right = "dalmatian" + or + wrong = "damenor" and right = "demeanor" + or + wrong = "dammage" and right = "damage" + or + wrong = "dardenelles" and right = "dardanelles" + or + wrong = "daugher" and right = "daughter" + or + wrong = "deafult" and right = "default" + or + wrong = "debateable" and right = "debatable" + or + wrong = "decendant" and right = "descendant" + or + wrong = "decendants" and right = "descendants" + or + wrong = "decendent" and right = "descendant" + or + wrong = "decendents" and right = "descendants" + or + wrong = "decideable" and right = "decidable" + or + wrong = "decidely" and right = "decidedly" + or + wrong = "decieved" and right = "deceived" + or + wrong = "decison" and right = "decision" + or + wrong = "decomissioned" and right = "decommissioned" + or + wrong = "decomposit" and right = "decompose" + or + wrong = "decomposited" and right = "decomposed" + or + wrong = "decompositing" and right = "decomposing" + or + wrong = "decomposits" and right = "decomposes" + or + wrong = "decress" and right = "decrees" + or + wrong = "decribe" and right = "describe" + or + wrong = "decribed" and right = "described" + or + wrong = "decribes" and right = "describes" + or + wrong = "decribing" and right = "describing" + or + wrong = "dectect" and right = "detect" + or + wrong = "defendent" and right = "defendant" + or + wrong = "defendents" and right = "defendants" + or + wrong = "deffensively" and right = "defensively" + or + wrong = "deffine" and right = "define" + or + wrong = "deffined" and right = "defined" + or + wrong = "definance" and right = "defiance" + or + wrong = "definate" and right = "definite" + or + wrong = "definately" and right = "definitely" + or + wrong = "definatly" and right = "definitely" + or + wrong = "definetly" and right = "definitely" + or + wrong = "definining" and right = "defining" + or + wrong = "definit" and right = "definite" + or + wrong = "definitly" and right = "definitely" + or + wrong = "definiton" and right = "definition" + or + wrong = "defintion" and right = "definition" + or + wrong = "defualt" and right = "default" + or + wrong = "defult" and right = "default" + or + wrong = "degrate" and right = "degrade" + or + wrong = "delagates" and right = "delegates" + or + wrong = "delapidated" and right = "dilapidated" + or + wrong = "delerious" and right = "delirious" + or + wrong = "delevopment" and right = "development" + or + wrong = "deliberatly" and right = "deliberately" + or + wrong = "delusionally" and right = "delusively" + or + wrong = "demenor" and right = "demeanor" + or + wrong = "demographical" and right = "demographic" + or + wrong = "demolision" and right = "demolition" + or + wrong = "demorcracy" and right = "democracy" + or + wrong = "demostration" and right = "demonstration" + or + wrong = "denegrating" and right = "denigrating" + or + wrong = "densly" and right = "densely" + or + wrong = "deparment" and right = "department" + or + wrong = "deparmental" and right = "departmental" + or + wrong = "deparments" and right = "departments" + or + wrong = "dependance" and right = "dependence" + or + wrong = "dependancy" and right = "dependency" + or + wrong = "deram" and right = "dram" + or + wrong = "deram" and right = "dream" + or + wrong = "deriviated" and right = "derived" + or + wrong = "derivitive" and right = "derivative" + or + wrong = "derogitory" and right = "derogatory" + or + wrong = "descendands" and right = "descendants" + or + wrong = "descibed" and right = "described" + or + wrong = "desciptors" and right = "descriptors" + or + wrong = "descision" and right = "decision" + or + wrong = "descisions" and right = "decisions" + or + wrong = "descriibes" and right = "describes" + or + wrong = "descripters" and right = "descriptors" + or + wrong = "descripton" and right = "description" + or + wrong = "desctruction" and right = "destruction" + or + wrong = "descuss" and right = "discuss" + or + wrong = "desgined" and right = "designed" + or + wrong = "deside" and right = "decide" + or + wrong = "desigining" and right = "designing" + or + wrong = "desinations" and right = "destinations" + or + wrong = "desintegrated" and right = "disintegrated" + or + wrong = "desintegration" and right = "disintegration" + or + wrong = "desireable" and right = "desirable" + or + wrong = "desitned" and right = "destined" + or + wrong = "desktiop" and right = "desktop" + or + wrong = "desorder" and right = "disorder" + or + wrong = "desoriented" and right = "disoriented" + or + wrong = "desparate" and right = "desperate" + or + wrong = "desparate" and right = "disparate" + or + wrong = "despict" and right = "depict" + or + wrong = "despiration" and right = "desperation" + or + wrong = "dessicated" and right = "desiccated" + or + wrong = "dessigned" and right = "designed" + or + wrong = "destablized" and right = "destabilized" + or + wrong = "destory" and right = "destroy" + or + wrong = "detailled" and right = "detailed" + or + wrong = "detatched" and right = "detached" + or + wrong = "deteoriated" and right = "deteriorated" + or + wrong = "deteriate" and right = "deteriorate" + or + wrong = "deterioriating" and right = "deteriorating" + or + wrong = "determinining" and right = "determining" + or + wrong = "detremental" and right = "detrimental" + or + wrong = "devasted" and right = "devastated" + or + wrong = "develope" and right = "develop" + or + wrong = "developement" and right = "development" + or + wrong = "developped" and right = "developed" + or + wrong = "develpment" and right = "development" + or + wrong = "devels" and right = "delves" + or + wrong = "devestated" and right = "devastated" + or + wrong = "devestating" and right = "devastating" + or + wrong = "devide" and right = "divide" + or + wrong = "devided" and right = "divided" + or + wrong = "devistating" and right = "devastating" + or + wrong = "devolopement" and right = "development" + or + wrong = "diablical" and right = "diabolical" + or + wrong = "diamons" and right = "diamonds" + or + wrong = "diaster" and right = "disaster" + or + wrong = "dichtomy" and right = "dichotomy" + or + wrong = "diconnects" and right = "disconnects" + or + wrong = "dicover" and right = "discover" + or + wrong = "dicovered" and right = "discovered" + or + wrong = "dicovering" and right = "discovering" + or + wrong = "dicovers" and right = "discovers" + or + wrong = "dicovery" and right = "discovery" + or + wrong = "dictionarys" and right = "dictionaries" + or + wrong = "dicussed" and right = "discussed" + or + wrong = "diea" and right = "die" + or + wrong = "diea" and right = "idea" + or + wrong = "dieing" and right = "dyeing" + or + wrong = "dieing" and right = "dying" + or + wrong = "dieties" and right = "deities" + or + wrong = "diety" and right = "deity" + or + wrong = "diferent" and right = "different" + or + wrong = "diferrent" and right = "different" + or + wrong = "differentiatiations" and right = "differentiations" + or + wrong = "differnt" and right = "different" + or + wrong = "difficulity" and right = "difficulty" + or + wrong = "diffrent" and right = "different" + or + wrong = "dificulties" and right = "difficulties" + or + wrong = "dificulty" and right = "difficulty" + or + wrong = "dimenions" and right = "dimensions" + or + wrong = "dimention" and right = "dimension" + or + wrong = "dimentional" and right = "dimensional" + or + wrong = "dimentions" and right = "dimensions" + or + wrong = "dimesnional" and right = "dimensional" + or + wrong = "diminuitive" and right = "diminutive" + or + wrong = "dimunitive" and right = "diminutive" + or + wrong = "diosese" and right = "diocese" + or + wrong = "diphtong" and right = "diphthong" + or + wrong = "diphtongs" and right = "diphthongs" + or + wrong = "diplomancy" and right = "diplomacy" + or + wrong = "dipthong" and right = "diphthong" + or + wrong = "dipthongs" and right = "diphthongs" + or + wrong = "directoty" and right = "directory" + or + wrong = "dirived" and right = "derived" + or + wrong = "disagreeed" and right = "disagreed" + or + wrong = "disapeared" and right = "disappeared" + or + wrong = "disapointing" and right = "disappointing" + or + wrong = "disappearred" and right = "disappeared" + or + wrong = "disaproval" and right = "disapproval" + or + wrong = "disasterous" and right = "disastrous" + or + wrong = "disatisfaction" and right = "dissatisfaction" + or + wrong = "disatisfied" and right = "dissatisfied" + or + wrong = "disatrous" and right = "disastrous" + or + wrong = "discontentment" and right = "discontent" + or + wrong = "discribe" and right = "describe" + or + wrong = "discribed" and right = "described" + or + wrong = "discribes" and right = "describes" + or + wrong = "discribing" and right = "describing" + or + wrong = "disctinction" and right = "distinction" + or + wrong = "disctinctive" and right = "distinctive" + or + wrong = "disemination" and right = "dissemination" + or + wrong = "disenchanged" and right = "disenchanted" + or + wrong = "disiplined" and right = "disciplined" + or + wrong = "disobediance" and right = "disobedience" + or + wrong = "disobediant" and right = "disobedient" + or + wrong = "disolved" and right = "dissolved" + or + wrong = "disover" and right = "discover" + or + wrong = "dispair" and right = "despair" + or + wrong = "disparingly" and right = "disparagingly" + or + wrong = "dispence" and right = "dispense" + or + wrong = "dispenced" and right = "dispensed" + or + wrong = "dispencing" and right = "dispensing" + or + wrong = "dispicable" and right = "despicable" + or + wrong = "dispite" and right = "despite" + or + wrong = "dispostion" and right = "disposition" + or + wrong = "disproportiate" and right = "disproportionate" + or + wrong = "disputandem" and right = "disputandum" + or + wrong = "disricts" and right = "districts" + or + wrong = "dissagreement" and right = "disagreement" + or + wrong = "dissapear" and right = "disappear" + or + wrong = "dissapearance" and right = "disappearance" + or + wrong = "dissapeared" and right = "disappeared" + or + wrong = "dissapearing" and right = "disappearing" + or + wrong = "dissapears" and right = "disappears" + or + wrong = "dissappear" and right = "disappear" + or + wrong = "dissappears" and right = "disappears" + or + wrong = "dissappointed" and right = "disappointed" + or + wrong = "dissarray" and right = "disarray" + or + wrong = "dissobediance" and right = "disobedience" + or + wrong = "dissobediant" and right = "disobedient" + or + wrong = "dissobedience" and right = "disobedience" + or + wrong = "dissobedient" and right = "disobedient" + or + wrong = "distiction" and right = "distinction" + or + wrong = "distingish" and right = "distinguish" + or + wrong = "distingished" and right = "distinguished" + or + wrong = "distingishes" and right = "distinguishes" + or + wrong = "distingishing" and right = "distinguishing" + or + wrong = "distingquished" and right = "distinguished" + or + wrong = "distrubution" and right = "distribution" + or + wrong = "distruction" and right = "destruction" + or + wrong = "distructive" and right = "destructive" + or + wrong = "ditributed" and right = "distributed" + or + wrong = "diversed" and right = "diverged" + or + wrong = "diversed" and right = "diverse" + or + wrong = "divice" and right = "device" + or + wrong = "divinition" and right = "divination" + or + wrong = "divison" and right = "division" + or + wrong = "divisons" and right = "divisions" + or + wrong = "doccument" and right = "document" + or + wrong = "doccumented" and right = "documented" + or + wrong = "doccuments" and right = "documents" + or + wrong = "docrines" and right = "doctrines" + or + wrong = "doctines" and right = "doctrines" + or + wrong = "documenatry" and right = "documentary" + or + wrong = "doens" and right = "does" + or + wrong = "doign" and right = "doing" + or + wrong = "dominaton" and right = "domination" + or + wrong = "dominent" and right = "dominant" + or + wrong = "dominiant" and right = "dominant" + or + wrong = "donig" and right = "doing" + or + wrong = "doub" and right = "daub" + or + wrong = "doub" and right = "doubt" + or + wrong = "doulbe" and right = "double" + or + wrong = "dowloads" and right = "downloads" + or + wrong = "dramtic" and right = "dramatic" + or + wrong = "draughtman" and right = "draughtsman" + or + wrong = "dravadian" and right = "dravidian" + or + wrong = "dreasm" and right = "dreams" + or + wrong = "driectly" and right = "directly" + or + wrong = "drnik" and right = "drink" + or + wrong = "druming" and right = "drumming" + or + wrong = "drummless" and right = "drumless" + or + wrong = "dum" and right = "dumb" + or + wrong = "dupicate" and right = "duplicate" + or + wrong = "durig" and right = "during" + or + wrong = "durring" and right = "during" + or + wrong = "duting" and right = "during" + or + wrong = "dyas" and right = "dryas" + or + wrong = "eahc" and right = "each" + or + wrong = "ealier" and right = "earlier" + or + wrong = "earlies" and right = "earliest" + or + wrong = "earnt" and right = "earned" + or + wrong = "ecclectic" and right = "eclectic" + or + wrong = "eceonomy" and right = "economy" + or + wrong = "ecidious" and right = "deciduous" + or + wrong = "eclispe" and right = "eclipse" + or + wrong = "ecomonic" and right = "economic" + or + wrong = "ect" and right = "etc" + or + wrong = "editting" and right = "editing" + or + wrong = "eearly" and right = "early" + or + wrong = "efel" and right = "evil" + or + wrong = "effeciency" and right = "efficiency" + or + wrong = "effecient" and right = "efficient" + or + wrong = "effeciently" and right = "efficiently" + or + wrong = "efficency" and right = "efficiency" + or + wrong = "efficent" and right = "efficient" + or + wrong = "efficently" and right = "efficiently" + or + wrong = "efford" and right = "afford" + or + wrong = "efford" and right = "effort" + or + wrong = "effords" and right = "affords" + or + wrong = "effords" and right = "efforts" + or + wrong = "effulence" and right = "effluence" + or + wrong = "eigth" and right = "eight" + or + wrong = "eigth" and right = "eighth" + or + wrong = "eiter" and right = "either" + or + wrong = "elction" and right = "election" + or + wrong = "electic" and right = "eclectic" + or + wrong = "electic" and right = "electric" + or + wrong = "electon" and right = "election" + or + wrong = "electon" and right = "electron" + or + wrong = "electrial" and right = "electrical" + or + wrong = "electricly" and right = "electrically" + or + wrong = "electricty" and right = "electricity" + or + wrong = "elementay" and right = "elementary" + or + wrong = "eleminated" and right = "eliminated" + or + wrong = "eleminating" and right = "eliminating" + or + wrong = "eles" and right = "eels" + or + wrong = "eletricity" and right = "electricity" + or + wrong = "elicided" and right = "elicited" + or + wrong = "eligable" and right = "eligible" + or + wrong = "elimentary" and right = "elementary" + or + wrong = "ellected" and right = "elected" + or + wrong = "elphant" and right = "elephant" + or + wrong = "embarass" and right = "embarrass" + or + wrong = "embarassed" and right = "embarrassed" + or + wrong = "embarassing" and right = "embarrassing" + or + wrong = "embarassment" and right = "embarrassment" + or + wrong = "embargos" and right = "embargoes" + or + wrong = "embarras" and right = "embarrass" + or + wrong = "embarrased" and right = "embarrassed" + or + wrong = "embarrasing" and right = "embarrassing" + or + wrong = "embarrasment" and right = "embarrassment" + or + wrong = "embezelled" and right = "embezzled" + or + wrong = "emblamatic" and right = "emblematic" + or + wrong = "eminate" and right = "emanate" + or + wrong = "eminated" and right = "emanated" + or + wrong = "emision" and right = "emission" + or + wrong = "emited" and right = "emitted" + or + wrong = "emiting" and right = "emitting" + or + wrong = "emition" and right = "emission" + or + wrong = "emition" and right = "emotion" + or + wrong = "emmediately" and right = "immediately" + or + wrong = "emmigrated" and right = "emigrated" + or + wrong = "emmigrated" and right = "immigrated" + or + wrong = "emminent" and right = "eminent" + or + wrong = "emminent" and right = "imminent" + or + wrong = "emminently" and right = "eminently" + or + wrong = "emmisaries" and right = "emissaries" + or + wrong = "emmisarries" and right = "emissaries" + or + wrong = "emmisarry" and right = "emissary" + or + wrong = "emmisary" and right = "emissary" + or + wrong = "emmision" and right = "emission" + or + wrong = "emmisions" and right = "emissions" + or + wrong = "emmited" and right = "emitted" + or + wrong = "emmiting" and right = "emitting" + or + wrong = "emmitted" and right = "emitted" + or + wrong = "emmitting" and right = "emitting" + or + wrong = "emnity" and right = "enmity" + or + wrong = "emperical" and right = "empirical" + or + wrong = "emphaised" and right = "emphasised" + or + wrong = "emphsis" and right = "emphasis" + or + wrong = "emphysyma" and right = "emphysema" + or + wrong = "empirial" and right = "empirical" + or + wrong = "empirial" and right = "imperial" + or + wrong = "emporer" and right = "emperor" + or + wrong = "emprisoned" and right = "imprisoned" + or + wrong = "enameld" and right = "enameled" + or + wrong = "enchancement" and right = "enhancement" + or + wrong = "encouraing" and right = "encouraging" + or + wrong = "encryptiion" and right = "encryption" + or + wrong = "encylopedia" and right = "encyclopedia" + or + wrong = "endevors" and right = "endeavors" + or + wrong = "endevour" and right = "endeavour" + or + wrong = "endig" and right = "ending" + or + wrong = "endolithes" and right = "endoliths" + or + wrong = "enduce" and right = "induce" + or + wrong = "ened" and right = "need" + or + wrong = "enforceing" and right = "enforcing" + or + wrong = "engagment" and right = "engagement" + or + wrong = "engeneer" and right = "engineer" + or + wrong = "engeneering" and right = "engineering" + or + wrong = "engieneer" and right = "engineer" + or + wrong = "engieneers" and right = "engineers" + or + wrong = "enlargment" and right = "enlargement" + or + wrong = "enlargments" and right = "enlargements" + or + wrong = "enlish" and right = "english" + or + wrong = "enlish" and right = "enlist" + or + wrong = "enourmous" and right = "enormous" + or + wrong = "enourmously" and right = "enormously" + or + wrong = "ensconsed" and right = "ensconced" + or + wrong = "entaglements" and right = "entanglements" + or + wrong = "enteratinment" and right = "entertainment" + or + wrong = "enthusiatic" and right = "enthusiastic" + or + wrong = "entitity" and right = "entity" + or + wrong = "entitlied" and right = "entitled" + or + wrong = "entrepeneur" and right = "entrepreneur" + or + wrong = "entrepeneurs" and right = "entrepreneurs" + or + wrong = "enviorment" and right = "environment" + or + wrong = "enviormental" and right = "environmental" + or + wrong = "enviormentally" and right = "environmentally" + or + wrong = "enviorments" and right = "environments" + or + wrong = "enviornment" and right = "environment" + or + wrong = "enviornmental" and right = "environmental" + or + wrong = "enviornmentalist" and right = "environmentalist" + or + wrong = "enviornmentally" and right = "environmentally" + or + wrong = "enviornments" and right = "environments" + or + wrong = "enviroment" and right = "environment" + or + wrong = "enviromental" and right = "environmental" + or + wrong = "enviromentalist" and right = "environmentalist" + or + wrong = "enviromentally" and right = "environmentally" + or + wrong = "enviroments" and right = "environments" + or + wrong = "environemnt" and right = "environment" + or + wrong = "envolutionary" and right = "evolutionary" + or + wrong = "envrionments" and right = "environments" + or + wrong = "enxt" and right = "next" + or + wrong = "epidsodes" and right = "episodes" + or + wrong = "epsiode" and right = "episode" + or + wrong = "equialent" and right = "equivalent" + or + wrong = "equilibium" and right = "equilibrium" + or + wrong = "equilibrum" and right = "equilibrium" + or + wrong = "equiped" and right = "equipped" + or + wrong = "equippment" and right = "equipment" + or + wrong = "equitorial" and right = "equatorial" + or + wrong = "equivelant" and right = "equivalent" + or + wrong = "equivelent" and right = "equivalent" + or + wrong = "equivilant" and right = "equivalent" + or + wrong = "equivilent" and right = "equivalent" + or + wrong = "equivlalent" and right = "equivalent" + or + wrong = "erally" and right = "orally" + or + wrong = "erally" and right = "really" + or + wrong = "eratic" and right = "erratic" + or + wrong = "eratically" and right = "erratically" + or + wrong = "eraticly" and right = "erratically" + or + wrong = "erested" and right = "arrested" + or + wrong = "erested" and right = "erected" + or + wrong = "errupted" and right = "erupted" + or + wrong = "esential" and right = "essential" + or + wrong = "esitmated" and right = "estimated" + or + wrong = "esle" and right = "else" + or + wrong = "especialy" and right = "especially" + or + wrong = "essencial" and right = "essential" + or + wrong = "essense" and right = "essence" + or + wrong = "essentail" and right = "essential" + or + wrong = "essentialy" and right = "essentially" + or + wrong = "essentual" and right = "essential" + or + wrong = "essesital" and right = "essential" + or + wrong = "estabishes" and right = "establishes" + or + wrong = "establising" and right = "establishing" + or + wrong = "ethnocentricm" and right = "ethnocentrism" + or + wrong = "ethose" and right = "ethos" + or + wrong = "ethose" and right = "those" + or + wrong = "europian" and right = "european" + or + wrong = "europians" and right = "europeans" + or + wrong = "eurpean" and right = "european" + or + wrong = "eurpoean" and right = "european" + or + wrong = "evenhtually" and right = "eventually" + or + wrong = "eventally" and right = "eventually" + or + wrong = "eventially" and right = "eventually" + or + wrong = "eventualy" and right = "eventually" + or + wrong = "everthing" and right = "everything" + or + wrong = "everyting" and right = "everything" + or + wrong = "eveyr" and right = "every" + or + wrong = "evidentally" and right = "evidently" + or + wrong = "exagerate" and right = "exaggerate" + or + wrong = "exagerated" and right = "exaggerated" + or + wrong = "exagerates" and right = "exaggerates" + or + wrong = "exagerating" and right = "exaggerating" + or + wrong = "exagerrate" and right = "exaggerate" + or + wrong = "exagerrated" and right = "exaggerated" + or + wrong = "exagerrates" and right = "exaggerates" + or + wrong = "exagerrating" and right = "exaggerating" + or + wrong = "examinated" and right = "examined" + or + wrong = "exampt" and right = "exempt" + or + wrong = "exapansion" and right = "expansion" + or + wrong = "excact" and right = "exact" + or + wrong = "excange" and right = "exchange" + or + wrong = "excecute" and right = "execute" + or + wrong = "excecuted" and right = "executed" + or + wrong = "excecutes" and right = "executes" + or + wrong = "excecuting" and right = "executing" + or + wrong = "excecution" and right = "execution" + or + wrong = "excedded" and right = "exceeded" + or + wrong = "excelent" and right = "excellent" + or + wrong = "excell" and right = "excel" + or + wrong = "excellance" and right = "excellence" + or + wrong = "excellant" and right = "excellent" + or + wrong = "excells" and right = "excels" + or + wrong = "excercise" and right = "exercise" + or + wrong = "exchanching" and right = "exchanging" + or + wrong = "excisted" and right = "existed" + or + wrong = "exculsivly" and right = "exclusively" + or + wrong = "execising" and right = "exercising" + or + wrong = "exection" and right = "execution" + or + wrong = "exectued" and right = "executed" + or + wrong = "exeedingly" and right = "exceedingly" + or + wrong = "exelent" and right = "excellent" + or + wrong = "exellent" and right = "excellent" + or + wrong = "exemple" and right = "example" + or + wrong = "exept" and right = "except" + or + wrong = "exeptional" and right = "exceptional" + or + wrong = "exerbate" and right = "exacerbate" + or + wrong = "exerbated" and right = "exacerbated" + or + wrong = "exerciese" and right = "exercises" + or + wrong = "exerpt" and right = "excerpt" + or + wrong = "exerpts" and right = "excerpts" + or + wrong = "exersize" and right = "exercise" + or + wrong = "exerternal" and right = "external" + or + wrong = "exhalted" and right = "exalted" + or + wrong = "exhibtion" and right = "exhibition" + or + wrong = "exibition" and right = "exhibition" + or + wrong = "exibitions" and right = "exhibitions" + or + wrong = "exicting" and right = "exciting" + or + wrong = "exinct" and right = "extinct" + or + wrong = "existance" and right = "existence" + or + wrong = "existant" and right = "existent" + or + wrong = "existince" and right = "existence" + or + wrong = "exliled" and right = "exiled" + or + wrong = "exludes" and right = "excludes" + or + wrong = "exmaple" and right = "example" + or + wrong = "exonorate" and right = "exonerate" + or + wrong = "exoskelaton" and right = "exoskeleton" + or + wrong = "expalin" and right = "explain" + or + wrong = "expatriot" and right = "expatriate" + or + wrong = "expeced" and right = "expected" + or + wrong = "expecially" and right = "especially" + or + wrong = "expeditonary" and right = "expeditionary" + or + wrong = "expeiments" and right = "experiments" + or + wrong = "expell" and right = "expel" + or + wrong = "expells" and right = "expels" + or + wrong = "experiance" and right = "experience" + or + wrong = "experianced" and right = "experienced" + or + wrong = "expession" and right = "expression" + or + wrong = "expessions" and right = "expressions" + or + wrong = "expiditions" and right = "expeditions" + or + wrong = "expierence" and right = "experience" + or + wrong = "explaination" and right = "explanation" + or + wrong = "explaning" and right = "explaining" + or + wrong = "explictly" and right = "explicitly" + or + wrong = "exploititive" and right = "exploitative" + or + wrong = "explotation" and right = "exploitation" + or + wrong = "expropiated" and right = "expropriated" + or + wrong = "expropiation" and right = "expropriation" + or + wrong = "exressed" and right = "expressed" + or + wrong = "extemely" and right = "extremely" + or + wrong = "extened" and right = "extended" + or + wrong = "extention" and right = "extension" + or + wrong = "extentions" and right = "extensions" + or + wrong = "extered" and right = "exerted" + or + wrong = "extermist" and right = "extremist" + or + wrong = "extint" and right = "extant" + or + wrong = "extint" and right = "extinct" + or + wrong = "extracter" and right = "extractor" + or + wrong = "extradiction" and right = "extradition" + or + wrong = "extraterrestial" and right = "extraterrestrial" + or + wrong = "extraterrestials" and right = "extraterrestrials" + or + wrong = "extravagent" and right = "extravagant" + or + wrong = "extrememly" and right = "extremely" + or + wrong = "extremeophile" and right = "extremophile" + or + wrong = "extremly" and right = "extremely" + or + wrong = "extrordinarily" and right = "extraordinarily" + or + wrong = "extrordinary" and right = "extraordinary" + or + wrong = "eyar" and right = "eyas" + or + wrong = "eyar" and right = "year" + or + wrong = "eyars" and right = "eyas" + or + wrong = "eyars" and right = "years" + or + wrong = "eyasr" and right = "eyas" + or + wrong = "eyasr" and right = "years" + or + wrong = "faciliate" and right = "facilitate" + or + wrong = "faciliated" and right = "facilitated" + or + wrong = "faciliates" and right = "facilitates" + or + wrong = "facilites" and right = "facilities" + or + wrong = "facillitate" and right = "facilitate" + or + wrong = "facinated" and right = "fascinated" + or + wrong = "facist" and right = "fascist" + or + wrong = "familes" and right = "families" + or + wrong = "familliar" and right = "familiar" + or + wrong = "famoust" and right = "famous" + or + wrong = "fanatism" and right = "fanaticism" + or + wrong = "farenheit" and right = "fahrenheit" + or + wrong = "fatc" and right = "fact" + or + wrong = "faught" and right = "fought" + or + wrong = "favoutrable" and right = "favourable" + or + wrong = "feasable" and right = "feasible" + or + wrong = "febuary" and right = "february" + or + wrong = "feburary" and right = "february" + or + wrong = "fedreally" and right = "federally" + or + wrong = "femminist" and right = "feminist" + or + wrong = "feromone" and right = "pheromone" + or + wrong = "fertily" and right = "fertility" + or + wrong = "fianite" and right = "finite" + or + wrong = "fianlly" and right = "finally" + or + wrong = "ficticious" and right = "fictitious" + or + wrong = "fictious" and right = "fictitious" + or + wrong = "fidn" and right = "find" + or + wrong = "fiel" and right = "feel" + or + wrong = "fiel" and right = "field" + or + wrong = "fiel" and right = "file" + or + wrong = "fiel" and right = "phial" + or + wrong = "fiels" and right = "feels" + or + wrong = "fiels" and right = "fields" + or + wrong = "fiels" and right = "files" + or + wrong = "fiels" and right = "phials" + or + wrong = "fiercly" and right = "fiercely" + or + wrong = "fightings" and right = "fighting" + or + wrong = "filiament" and right = "filament" + or + wrong = "fimilies" and right = "families" + or + wrong = "finacial" and right = "financial" + or + wrong = "finaly" and right = "finally" + or + wrong = "financialy" and right = "financially" + or + wrong = "firends" and right = "friends" + or + wrong = "firts" and right = "first" + or + wrong = "firts" and right = "flirts" + or + wrong = "fisionable" and right = "fissionable" + or + wrong = "flamable" and right = "flammable" + or + wrong = "flawess" and right = "flawless" + or + wrong = "fleed" and right = "fled" + or + wrong = "fleed" and right = "freed" + or + wrong = "flemmish" and right = "flemish" + or + wrong = "florescent" and right = "fluorescent" + or + wrong = "flourescent" and right = "fluorescent" + or + wrong = "flourine" and right = "fluorine" + or + wrong = "flourishment" and right = "flourishing" + or + wrong = "fluorish" and right = "flourish" + or + wrong = "follwoing" and right = "following" + or + wrong = "folowing" and right = "following" + or + wrong = "fomed" and right = "formed" + or + wrong = "fomr" and right = "form" + or + wrong = "fomr" and right = "from" + or + wrong = "fonetic" and right = "phonetic" + or + wrong = "fontrier" and right = "fontier" + or + wrong = "foootball" and right = "football" + or + wrong = "forbad" and right = "forbade" + or + wrong = "forbiden" and right = "forbidden" + or + wrong = "foreward" and right = "foreword" + or + wrong = "forfiet" and right = "forfeit" + or + wrong = "forhead" and right = "forehead" + or + wrong = "foriegn" and right = "foreign" + or + wrong = "formalhaut" and right = "fomalhaut" + or + wrong = "formallize" and right = "formalize" + or + wrong = "formallized" and right = "formalized" + or + wrong = "formaly" and right = "formally" + or + wrong = "formaly" and right = "formerly" + or + wrong = "formelly" and right = "formerly" + or + wrong = "formidible" and right = "formidable" + or + wrong = "formost" and right = "foremost" + or + wrong = "forsaw" and right = "foresaw" + or + wrong = "forseeable" and right = "foreseeable" + or + wrong = "fortelling" and right = "foretelling" + or + wrong = "forunner" and right = "forerunner" + or + wrong = "foucs" and right = "focus" + or + wrong = "foudn" and right = "found" + or + wrong = "fougth" and right = "fought" + or + wrong = "foundaries" and right = "foundries" + or + wrong = "foundary" and right = "foundry" + or + wrong = "foundland" and right = "newfoundland" + or + wrong = "fourties" and right = "forties" + or + wrong = "fourty" and right = "forty" + or + wrong = "fouth" and right = "fourth" + or + wrong = "foward" and right = "forward" + or + wrong = "framwork" and right = "framework" + or + wrong = "fransiscan" and right = "franciscan" + or + wrong = "fransiscans" and right = "franciscans" + or + wrong = "freind" and right = "friend" + or + wrong = "freindly" and right = "friendly" + or + wrong = "frequentily" and right = "frequently" + or + wrong = "frome" and right = "from" + or + wrong = "fromed" and right = "formed" + or + wrong = "froniter" and right = "frontier" + or + wrong = "fucntion" and right = "function" + or + wrong = "fucntioning" and right = "functioning" + or + wrong = "fufill" and right = "fulfill" + or + wrong = "fufilled" and right = "fulfilled" + or + wrong = "fulfiled" and right = "fulfilled" + or + wrong = "fullfill" and right = "fulfill" + or + wrong = "fullfilled" and right = "fulfilled" + or + wrong = "funcion" and right = "function" + or + wrong = "fundametal" and right = "fundamental" + or + wrong = "fundametals" and right = "fundamentals" + or + wrong = "funguses" and right = "fungi" + or + wrong = "funtion" and right = "function" + or + wrong = "funtions" and right = "functions" + or + wrong = "furuther" and right = "further" + or + wrong = "futher" and right = "further" + or + wrong = "futhermore" and right = "furthermore" + or + wrong = "futhroc" and right = "futhark" + or + wrong = "futhroc" and right = "futhorc" + or + wrong = "gae" and right = "gael" + or + wrong = "gae" and right = "gale" + or + wrong = "gae" and right = "game" + or + wrong = "galatic" and right = "galactic" + or + wrong = "galations" and right = "galatians" + or + wrong = "gallaxies" and right = "galaxies" + or + wrong = "galvinized" and right = "galvanized" + or + wrong = "ganerate" and right = "generate" + or + wrong = "ganes" and right = "games" + or + wrong = "ganster" and right = "gangster" + or + wrong = "garantee" and right = "guarantee" + or + wrong = "garanteed" and right = "guaranteed" + or + wrong = "garantees" and right = "guarantees" + or + wrong = "garnison" and right = "garrison" + or + wrong = "gaurantee" and right = "guarantee" + or + wrong = "gauranteed" and right = "guaranteed" + or + wrong = "gaurantees" and right = "guarantees" + or + wrong = "gaurd" and right = "gourd" + or + wrong = "gaurd" and right = "guard" + or + wrong = "gaurentee" and right = "guarantee" + or + wrong = "gaurenteed" and right = "guaranteed" + or + wrong = "gaurentees" and right = "guarantees" + or + wrong = "geneological" and right = "genealogical" + or + wrong = "geneologies" and right = "genealogies" + or + wrong = "geneology" and right = "genealogy" + or + wrong = "generaly" and right = "generally" + or + wrong = "generatting" and right = "generating" + or + wrong = "genialia" and right = "genitalia" + or + wrong = "geographicial" and right = "geographical" + or + wrong = "geometrician" and right = "geometer" + or + wrong = "geometricians" and right = "geometers" + or + wrong = "gerat" and right = "great" + or + wrong = "ghandi" and right = "gandhi" + or + wrong = "glamourous" and right = "glamorous" + or + wrong = "glight" and right = "flight" + or + wrong = "gnawwed" and right = "gnawed" + or + wrong = "godess" and right = "goddess" + or + wrong = "godesses" and right = "goddesses" + or + wrong = "godounov" and right = "godunov" + or + wrong = "gogin" and right = "gauguin" + or + wrong = "gogin" and right = "going" + or + wrong = "goign" and right = "going" + or + wrong = "gonig" and right = "going" + or + wrong = "gothenberg" and right = "gothenburg" + or + wrong = "gottleib" and right = "gottlieb" + or + wrong = "gouvener" and right = "governor" + or + wrong = "govement" and right = "government" + or + wrong = "govenment" and right = "government" + or + wrong = "govenrment" and right = "government" + or + wrong = "goverance" and right = "governance" + or + wrong = "goverment" and right = "government" + or + wrong = "govermental" and right = "governmental" + or + wrong = "governer" and right = "governor" + or + wrong = "governmnet" and right = "government" + or + wrong = "govorment" and right = "government" + or + wrong = "govormental" and right = "governmental" + or + wrong = "govornment" and right = "government" + or + wrong = "gracefull" and right = "graceful" + or + wrong = "graet" and right = "great" + or + wrong = "grafitti" and right = "graffiti" + or + wrong = "gramatically" and right = "grammatically" + or + wrong = "grammaticaly" and right = "grammatically" + or + wrong = "grammer" and right = "grammar" + or + wrong = "grat" and right = "great" + or + wrong = "gratuitious" and right = "gratuitous" + or + wrong = "greatful" and right = "grateful" + or + wrong = "greatfully" and right = "gratefully" + or + wrong = "greif" and right = "grief" + or + wrong = "gridles" and right = "griddles" + or + wrong = "gropu" and right = "group" + or + wrong = "grwo" and right = "grow" + or + wrong = "guaduloupe" and right = "guadalupe" + or + wrong = "guaduloupe" and right = "guadeloupe" + or + wrong = "guadulupe" and right = "guadalupe" + or + wrong = "guadulupe" and right = "guadeloupe" + or + wrong = "guage" and right = "gauge" + or + wrong = "guarentee" and right = "guarantee" + or + wrong = "guarenteed" and right = "guaranteed" + or + wrong = "guarentees" and right = "guarantees" + or + wrong = "guatamala" and right = "guatemala" + or + wrong = "guatamalan" and right = "guatemalan" + or + wrong = "guerrila" and right = "guerrilla" + or + wrong = "guerrilas" and right = "guerrillas" + or + wrong = "guidence" and right = "guidance" + or + wrong = "guilia" and right = "giulia" + or + wrong = "guilio" and right = "giulio" + or + wrong = "guiness" and right = "guinness" + or + wrong = "guiseppe" and right = "giuseppe" + or + wrong = "gunanine" and right = "guanine" + or + wrong = "gurantee" and right = "guarantee" + or + wrong = "guranteed" and right = "guaranteed" + or + wrong = "gurantees" and right = "guarantees" + or + wrong = "guttaral" and right = "guttural" + or + wrong = "gutteral" and right = "guttural" + or + wrong = "habaeus" and right = "habeas" + or + wrong = "habeus" and right = "habeas" + or + wrong = "habsbourg" and right = "habsburg" + or + wrong = "haemorrage" and right = "haemorrhage" + or + wrong = "haev" and right = "have" + or + wrong = "haev" and right = "heave" + or + wrong = "halarious" and right = "hilarious" + or + wrong = "hallowean" and right = "halloween" + or + wrong = "halp" and right = "help" + or + wrong = "hander" and right = "handler" + or + wrong = "hapen" and right = "happen" + or + wrong = "hapened" and right = "happened" + or + wrong = "hapening" and right = "happening" + or + wrong = "happend" and right = "happened" + or + wrong = "happended" and right = "happened" + or + wrong = "happenned" and right = "happened" + or + wrong = "harased" and right = "harassed" + or + wrong = "harases" and right = "harasses" + or + wrong = "harasment" and right = "harassment" + or + wrong = "harasments" and right = "harassments" + or + wrong = "harassement" and right = "harassment" + or + wrong = "harras" and right = "harass" + or + wrong = "harrased" and right = "harassed" + or + wrong = "harrases" and right = "harasses" + or + wrong = "harrasing" and right = "harassing" + or + wrong = "harrasment" and right = "harassment" + or + wrong = "harrasments" and right = "harassments" + or + wrong = "harrassed" and right = "harassed" + or + wrong = "harrasses" and right = "harassed" + or + wrong = "harrassing" and right = "harassing" + or + wrong = "harrassment" and right = "harassment" + or + wrong = "harrassments" and right = "harassments" + or + wrong = "hatian" and right = "haitian" + or + wrong = "haviest" and right = "heaviest" + or + wrong = "headquarer" and right = "headquarter" + or + wrong = "headquater" and right = "headquarter" + or + wrong = "headquatered" and right = "headquartered" + or + wrong = "headquaters" and right = "headquarters" + or + wrong = "healthercare" and right = "healthcare" + or + wrong = "heared" and right = "heard" + or + wrong = "heathy" and right = "healthy" + or + wrong = "heidelburg" and right = "heidelberg" + or + wrong = "heigher" and right = "higher" + or + wrong = "heirarchy" and right = "hierarchy" + or + wrong = "heiroglyphics" and right = "hieroglyphics" + or + wrong = "helment" and right = "helmet" + or + wrong = "helpfull" and right = "helpful" + or + wrong = "helpped" and right = "helped" + or + wrong = "hemmorhage" and right = "hemorrhage" + or + wrong = "herad" and right = "heard" + or + wrong = "herad" and right = "hera" + or + wrong = "heridity" and right = "heredity" + or + wrong = "heroe" and right = "hero" + or + wrong = "heros" and right = "heroes" + or + wrong = "hertiage" and right = "heritage" + or + wrong = "hertzs" and right = "hertz" + or + wrong = "hesistant" and right = "hesitant" + or + wrong = "heterogenous" and right = "heterogeneous" + or + wrong = "hieght" and right = "height" + or + wrong = "hierachical" and right = "hierarchical" + or + wrong = "hierachies" and right = "hierarchies" + or + wrong = "hierachy" and right = "hierarchy" + or + wrong = "hierarcical" and right = "hierarchical" + or + wrong = "hierarcy" and right = "hierarchy" + or + wrong = "hieroglph" and right = "hieroglyph" + or + wrong = "hieroglphs" and right = "hieroglyphs" + or + wrong = "higer" and right = "higher" + or + wrong = "higest" and right = "highest" + or + wrong = "higway" and right = "highway" + or + wrong = "hillarious" and right = "hilarious" + or + wrong = "himselv" and right = "himself" + or + wrong = "hinderance" and right = "hindrance" + or + wrong = "hinderence" and right = "hindrance" + or + wrong = "hindrence" and right = "hindrance" + or + wrong = "hipopotamus" and right = "hippopotamus" + or + wrong = "hismelf" and right = "himself" + or + wrong = "histocompatability" and right = "histocompatibility" + or + wrong = "historicians" and right = "historians" + or + wrong = "holf" and right = "hold" + or + wrong = "holliday" and right = "holiday" + or + wrong = "homogeneize" and right = "homogenize" + or + wrong = "homogeneized" and right = "homogenized" + or + wrong = "honory" and right = "honorary" + or + wrong = "horrifing" and right = "horrifying" + or + wrong = "hosited" and right = "hoisted" + or + wrong = "hospitible" and right = "hospitable" + or + wrong = "hounour" and right = "honour" + or + wrong = "housr" and right = "hours" + or + wrong = "housr" and right = "house" + or + wrong = "howver" and right = "however" + or + wrong = "hsitorians" and right = "historians" + or + wrong = "hstory" and right = "history" + or + wrong = "hten" and right = "hen" + or + wrong = "hten" and right = "the" + or + wrong = "hten" and right = "then" + or + wrong = "htere" and right = "here" + or + wrong = "htere" and right = "there" + or + wrong = "htey" and right = "they" + or + wrong = "htikn" and right = "think" + or + wrong = "hting" and right = "thing" + or + wrong = "htink" and right = "think" + or + wrong = "htis" and right = "this" + or + wrong = "humer" and right = "humor" + or + wrong = "humer" and right = "humour" + or + wrong = "humerous" and right = "humerus" + or + wrong = "humerous" and right = "humorous" + or + wrong = "huminoid" and right = "humanoid" + or + wrong = "humoural" and right = "humoral" + or + wrong = "humurous" and right = "humorous" + or + wrong = "husban" and right = "husband" + or + wrong = "hvae" and right = "have" + or + wrong = "hvaing" and right = "having" + or + wrong = "hvea" and right = "have" + or + wrong = "hvea" and right = "heave" + or + wrong = "hwihc" and right = "which" + or + wrong = "hwile" and right = "while" + or + wrong = "hwole" and right = "whole" + or + wrong = "hydogen" and right = "hydrogen" + or + wrong = "hydropile" and right = "hydrophile" + or + wrong = "hydropilic" and right = "hydrophilic" + or + wrong = "hydropobe" and right = "hydrophobe" + or + wrong = "hydropobic" and right = "hydrophobic" + or + wrong = "hygeine" and right = "hygiene" + or + wrong = "hyjack" and right = "hijack" + or + wrong = "hyjacking" and right = "hijacking" + or + wrong = "hypocracy" and right = "hypocrisy" + or + wrong = "hypocrasy" and right = "hypocrisy" + or + wrong = "hypocricy" and right = "hypocrisy" + or + wrong = "hypocrit" and right = "hypocrite" + or + wrong = "hypocrits" and right = "hypocrites" + or + wrong = "iconclastic" and right = "iconoclastic" + or + wrong = "idaeidae" and right = "idea" + or + wrong = "idaes" and right = "ideas" + or + wrong = "idealogies" and right = "ideologies" + or + wrong = "idealogy" and right = "ideology" + or + wrong = "identicial" and right = "identical" + or + wrong = "identifers" and right = "identifiers" + or + wrong = "ideosyncratic" and right = "idiosyncratic" + or + wrong = "idesa" and right = "ideas" + or + wrong = "idesa" and right = "ides" + or + wrong = "idiosyncracy" and right = "idiosyncrasy" + or + wrong = "ihaca" and right = "ithaca" + or + wrong = "illegimacy" and right = "illegitimacy" + or + wrong = "illegitmate" and right = "illegitimate" + or + wrong = "illess" and right = "illness" + or + wrong = "illiegal" and right = "illegal" + or + wrong = "illution" and right = "illusion" + or + wrong = "ilness" and right = "illness" + or + wrong = "ilogical" and right = "illogical" + or + wrong = "imagenary" and right = "imaginary" + or + wrong = "imagin" and right = "imagine" + or + wrong = "imaginery" and right = "imagery" + or + wrong = "imaginery" and right = "imaginary" + or + wrong = "imanent" and right = "eminent" + or + wrong = "imanent" and right = "imminent" + or + wrong = "imcomplete" and right = "incomplete" + or + wrong = "imediately" and right = "immediately" + or + wrong = "imense" and right = "immense" + or + wrong = "imigrant" and right = "emigrant" + or + wrong = "imigrant" and right = "immigrant" + or + wrong = "imigrated" and right = "emigrated" + or + wrong = "imigrated" and right = "immigrated" + or + wrong = "imigration" and right = "emigration" + or + wrong = "imigration" and right = "immigration" + or + wrong = "iminent" and right = "eminent" + or + wrong = "iminent" and right = "immanent" + or + wrong = "iminent" and right = "imminent" + or + wrong = "immediatley" and right = "immediately" + or + wrong = "immediatly" and right = "immediately" + or + wrong = "immidately" and right = "immediately" + or + wrong = "immidiately" and right = "immediately" + or + wrong = "immitate" and right = "imitate" + or + wrong = "immitated" and right = "imitated" + or + wrong = "immitating" and right = "imitating" + or + wrong = "immitator" and right = "imitator" + or + wrong = "immunosupressant" and right = "immunosuppressant" + or + wrong = "impecabbly" and right = "impeccably" + or + wrong = "impedence" and right = "impedance" + or + wrong = "implamenting" and right = "implementing" + or + wrong = "impliment" and right = "implement" + or + wrong = "implimented" and right = "implemented" + or + wrong = "imploys" and right = "employs" + or + wrong = "importamt" and right = "important" + or + wrong = "impressario" and right = "impresario" + or + wrong = "imprioned" and right = "imprisoned" + or + wrong = "imprisonned" and right = "imprisoned" + or + wrong = "improvision" and right = "improvisation" + or + wrong = "improvments" and right = "improvements" + or + wrong = "inablility" and right = "inability" + or + wrong = "inaccessable" and right = "inaccessible" + or + wrong = "inadiquate" and right = "inadequate" + or + wrong = "inadquate" and right = "inadequate" + or + wrong = "inadvertant" and right = "inadvertent" + or + wrong = "inadvertantly" and right = "inadvertently" + or + wrong = "inagurated" and right = "inaugurated" + or + wrong = "inaguration" and right = "inauguration" + or + wrong = "inappropiate" and right = "inappropriate" + or + wrong = "inaugures" and right = "inaugurates" + or + wrong = "inbalance" and right = "imbalance" + or + wrong = "inbalanced" and right = "imbalanced" + or + wrong = "inbetween" and right = "between" + or + wrong = "incarcirated" and right = "incarcerated" + or + wrong = "incidentially" and right = "incidentally" + or + wrong = "incidently" and right = "incidentally" + or + wrong = "inclreased" and right = "increased" + or + wrong = "includ" and right = "include" + or + wrong = "includng" and right = "including" + or + wrong = "incompatabilities" and right = "incompatibilities" + or + wrong = "incompatability" and right = "incompatibility" + or + wrong = "incompatable" and right = "incompatible" + or + wrong = "incompatablities" and right = "incompatibilities" + or + wrong = "incompatablity" and right = "incompatibility" + or + wrong = "incompatiblities" and right = "incompatibilities" + or + wrong = "incompatiblity" and right = "incompatibility" + or + wrong = "incompetance" and right = "incompetence" + or + wrong = "incompetant" and right = "incompetent" + or + wrong = "incomptable" and right = "incompatible" + or + wrong = "incomptetent" and right = "incompetent" + or + wrong = "inconsistant" and right = "inconsistent" + or + wrong = "incoroporated" and right = "incorporated" + or + wrong = "incorperation" and right = "incorporation" + or + wrong = "incorportaed" and right = "incorporated" + or + wrong = "incorprates" and right = "incorporates" + or + wrong = "incorruptable" and right = "incorruptible" + or + wrong = "incramentally" and right = "incrementally" + or + wrong = "increadible" and right = "incredible" + or + wrong = "incredable" and right = "incredible" + or + wrong = "inctroduce" and right = "introduce" + or + wrong = "inctroduced" and right = "introduced" + or + wrong = "incuding" and right = "including" + or + wrong = "incunabla" and right = "incunabula" + or + wrong = "indefinately" and right = "indefinitely" + or + wrong = "indefineable" and right = "undefinable" + or + wrong = "indefinitly" and right = "indefinitely" + or + wrong = "indentical" and right = "identical" + or + wrong = "indepedantly" and right = "independently" + or + wrong = "indepedence" and right = "independence" + or + wrong = "independance" and right = "independence" + or + wrong = "independant" and right = "independent" + or + wrong = "independantly" and right = "independently" + or + wrong = "independece" and right = "independence" + or + wrong = "independendet" and right = "independent" + or + wrong = "indespensable" and right = "indispensable" + or + wrong = "indespensible" and right = "indispensable" + or + wrong = "indictement" and right = "indictment" + or + wrong = "indigineous" and right = "indigenous" + or + wrong = "indipendence" and right = "independence" + or + wrong = "indipendent" and right = "independent" + or + wrong = "indipendently" and right = "independently" + or + wrong = "indispensible" and right = "indispensable" + or + wrong = "indisputible" and right = "indisputable" + or + wrong = "indisputibly" and right = "indisputably" + or + wrong = "indite" and right = "indict" + or + wrong = "individualy" and right = "individually" + or + wrong = "indpendent" and right = "independent" + or + wrong = "indpendently" and right = "independently" + or + wrong = "indulgue" and right = "indulge" + or + wrong = "indutrial" and right = "industrial" + or + wrong = "indviduals" and right = "individuals" + or + wrong = "inefficienty" and right = "inefficiently" + or + wrong = "inevatible" and right = "inevitable" + or + wrong = "inevitible" and right = "inevitable" + or + wrong = "inevititably" and right = "inevitably" + or + wrong = "infalability" and right = "infallibility" + or + wrong = "infallable" and right = "infallible" + or + wrong = "infectuous" and right = "infectious" + or + wrong = "infered" and right = "inferred" + or + wrong = "infilitrate" and right = "infiltrate" + or + wrong = "infilitrated" and right = "infiltrated" + or + wrong = "infilitration" and right = "infiltration" + or + wrong = "infinit" and right = "infinite" + or + wrong = "inflamation" and right = "inflammation" + or + wrong = "influencial" and right = "influential" + or + wrong = "influented" and right = "influenced" + or + wrong = "infomation" and right = "information" + or + wrong = "informtion" and right = "information" + or + wrong = "infrantryman" and right = "infantryman" + or + wrong = "infrigement" and right = "infringement" + or + wrong = "ingenius" and right = "ingenious" + or + wrong = "ingreediants" and right = "ingredients" + or + wrong = "inhabitans" and right = "inhabitants" + or + wrong = "inherantly" and right = "inherently" + or + wrong = "inheritage" and right = "heritage" + or + wrong = "inheritage" and right = "inheritance" + or + wrong = "inheritence" and right = "inheritance" + or + wrong = "inital" and right = "initial" + or + wrong = "initalize" and right = "initialize" + or + wrong = "initally" and right = "initially" + or + wrong = "initation" and right = "initiation" + or + wrong = "initiaitive" and right = "initiative" + or + wrong = "inlcuding" and right = "including" + or + wrong = "inmigrant" and right = "immigrant" + or + wrong = "inmigrants" and right = "immigrants" + or + wrong = "innoculated" and right = "inoculated" + or + wrong = "inocence" and right = "innocence" + or + wrong = "inofficial" and right = "unofficial" + or + wrong = "inot" and right = "into" + or + wrong = "inpeach" and right = "impeach" + or + wrong = "inpending" and right = "impending" + or + wrong = "inpenetrable" and right = "impenetrable" + or + wrong = "inpolite" and right = "impolite" + or + wrong = "inprisonment" and right = "imprisonment" + or + wrong = "inproving" and right = "improving" + or + wrong = "insectiverous" and right = "insectivorous" + or + wrong = "insensative" and right = "insensitive" + or + wrong = "inseperable" and right = "inseparable" + or + wrong = "insistance" and right = "insistence" + or + wrong = "insitution" and right = "institution" + or + wrong = "insitutions" and right = "institutions" + or + wrong = "inspite" and right = "inspire" + or + wrong = "instade" and right = "instead" + or + wrong = "instatance" and right = "instance" + or + wrong = "institue" and right = "institute" + or + wrong = "instuction" and right = "instruction" + or + wrong = "instuments" and right = "instruments" + or + wrong = "instutionalized" and right = "institutionalized" + or + wrong = "instutions" and right = "intuitions" + or + wrong = "insurence" and right = "insurance" + or + wrong = "intelectual" and right = "intellectual" + or + wrong = "inteligence" and right = "intelligence" + or + wrong = "inteligent" and right = "intelligent" + or + wrong = "intenational" and right = "international" + or + wrong = "intented" and right = "indented" + or + wrong = "intented" and right = "intended" + or + wrong = "intepretation" and right = "interpretation" + or + wrong = "intepretator" and right = "interpretor" + or + wrong = "interational" and right = "international" + or + wrong = "interbread" and right = "interbred" + or + wrong = "interbread" and right = "interbreed" + or + wrong = "interchangable" and right = "interchangeable" + or + wrong = "interchangably" and right = "interchangeably" + or + wrong = "intercontinential" and right = "intercontinental" + or + wrong = "intercontinetal" and right = "intercontinental" + or + wrong = "intered" and right = "interned" + or + wrong = "intered" and right = "interred" + or + wrong = "interelated" and right = "interrelated" + or + wrong = "interferance" and right = "interference" + or + wrong = "interfereing" and right = "interfering" + or + wrong = "intergrated" and right = "integrated" + or + wrong = "intergration" and right = "integration" + or + wrong = "interm" and right = "interim" + or + wrong = "internation" and right = "international" + or + wrong = "interpet" and right = "interpret" + or + wrong = "interrim" and right = "interim" + or + wrong = "interrugum" and right = "interregnum" + or + wrong = "intertaining" and right = "entertaining" + or + wrong = "interupt" and right = "interrupt" + or + wrong = "intervines" and right = "intervenes" + or + wrong = "intevene" and right = "intervene" + or + wrong = "intial" and right = "initial" + or + wrong = "intialize" and right = "initialize" + or + wrong = "intialized" and right = "initialized" + or + wrong = "intially" and right = "initially" + or + wrong = "intrduced" and right = "introduced" + or + wrong = "intrest" and right = "interest" + or + wrong = "introdued" and right = "introduced" + or + wrong = "intruduced" and right = "introduced" + or + wrong = "intrument" and right = "instrument" + or + wrong = "intrumental" and right = "instrumental" + or + wrong = "intruments" and right = "instruments" + or + wrong = "intrusted" and right = "entrusted" + or + wrong = "intutive" and right = "intuitive" + or + wrong = "intutively" and right = "intuitively" + or + wrong = "inudstry" and right = "industry" + or + wrong = "inumerable" and right = "enumerable" + or + wrong = "inumerable" and right = "innumerable" + or + wrong = "inventer" and right = "inventor" + or + wrong = "invertibrates" and right = "invertebrates" + or + wrong = "investingate" and right = "investigate" + or + wrong = "involvment" and right = "involvement" + or + wrong = "irelevent" and right = "irrelevant" + or + wrong = "iresistable" and right = "irresistible" + or + wrong = "iresistably" and right = "irresistibly" + or + wrong = "iresistible" and right = "irresistible" + or + wrong = "iresistibly" and right = "irresistibly" + or + wrong = "iritable" and right = "irritable" + or + wrong = "iritated" and right = "irritated" + or + wrong = "ironicly" and right = "ironically" + or + wrong = "irregardless" and right = "regardless" + or + wrong = "irrelevent" and right = "irrelevant" + or + wrong = "irreplacable" and right = "irreplaceable" + or + wrong = "irresistable" and right = "irresistible" + or + wrong = "irresistably" and right = "irresistibly" + or + wrong = "israelies" and right = "israelis" + or + wrong = "issueing" and right = "issuing" + or + wrong = "itnroduced" and right = "introduced" + or + wrong = "iunior" and right = "junior" + or + wrong = "iwll" and right = "will" + or + wrong = "iwth" and right = "with" + or + wrong = "janurary" and right = "january" + or + wrong = "januray" and right = "january" + or + wrong = "japanes" and right = "japanese" + or + wrong = "jaques" and right = "jacques" + or + wrong = "jeapardy" and right = "jeopardy" + or + wrong = "jewllery" and right = "jewellery" + or + wrong = "johanine" and right = "johannine" + or + wrong = "jorunal" and right = "journal" + or + wrong = "jospeh" and right = "joseph" + or + wrong = "jouney" and right = "journey" + or + wrong = "journied" and right = "journeyed" + or + wrong = "journies" and right = "journeys" + or + wrong = "jstu" and right = "just" + or + wrong = "jsut" and right = "just" + or + wrong = "juadaism" and right = "judaism" + or + wrong = "juadism" and right = "judaism" + or + wrong = "judical" and right = "judicial" + or + wrong = "judisuary" and right = "judiciary" + or + wrong = "juducial" and right = "judicial" + or + wrong = "juristiction" and right = "jurisdiction" + or + wrong = "juristictions" and right = "jurisdictions" + or + wrong = "kindergarden" and right = "kindergarten" + or + wrong = "klenex" and right = "kleenex" + or + wrong = "knifes" and right = "knives" + or + wrong = "knive" and right = "knife" + or + wrong = "knowlege" and right = "knowledge" + or + wrong = "knowlegeable" and right = "knowledgeable" + or + wrong = "knwo" and right = "know" + or + wrong = "knwos" and right = "knows" + or + wrong = "konw" and right = "know" + or + wrong = "konws" and right = "knows" + or + wrong = "kwno" and right = "know" + or + wrong = "labatory" and right = "laboratory" + or + wrong = "labatory" and right = "lavatory" + or + wrong = "labled" and right = "labeled" + or + wrong = "labled" and right = "labelled" + or + wrong = "labratory" and right = "laboratory" + or + wrong = "laguage" and right = "language" + or + wrong = "laguages" and right = "languages" + or + wrong = "langage" and right = "language" + or + wrong = "langauge" and right = "language" + or + wrong = "larg" and right = "large" + or + wrong = "largst" and right = "largest" + or + wrong = "larrry" and right = "larry" + or + wrong = "lastr" and right = "last" + or + wrong = "lattitude" and right = "latitude" + or + wrong = "launchs" and right = "launch" + or + wrong = "launchs" and right = "launches" + or + wrong = "launhed" and right = "launched" + or + wrong = "lavae" and right = "larvae" + or + wrong = "layed" and right = "laid" + or + wrong = "lazyness" and right = "laziness" + or + wrong = "leage" and right = "league" + or + wrong = "leanr" and right = "lean" + or + wrong = "leanr" and right = "leaner" + or + wrong = "leanr" and right = "learn" + or + wrong = "leathal" and right = "lethal" + or + wrong = "lefted" and right = "left" + or + wrong = "legitamate" and right = "legitimate" + or + wrong = "legitmate" and right = "legitimate" + or + wrong = "leibnitz" and right = "leibniz" + or + wrong = "lengh" and right = "length" + or + wrong = "lenght" and right = "length" + or + wrong = "lengt" and right = "length" + or + wrong = "lenth" and right = "length" + or + wrong = "leran" and right = "learn" + or + wrong = "lerans" and right = "learns" + or + wrong = "leutenant" and right = "lieutenant" + or + wrong = "levetate" and right = "levitate" + or + wrong = "levetated" and right = "levitated" + or + wrong = "levetates" and right = "levitates" + or + wrong = "levetating" and right = "levitating" + or + wrong = "levle" and right = "level" + or + wrong = "liasion" and right = "liaison" + or + wrong = "liason" and right = "liaison" + or + wrong = "liasons" and right = "liaisons" + or + wrong = "libaries" and right = "libraries" + or + wrong = "libary" and right = "library" + or + wrong = "libell" and right = "libel" + or + wrong = "libguistic" and right = "linguistic" + or + wrong = "libguistics" and right = "linguistics" + or + wrong = "libitarianisn" and right = "libertarianism" + or + wrong = "lible" and right = "liable" + or + wrong = "lible" and right = "libel" + or + wrong = "lieing" and right = "lying" + or + wrong = "liek" and right = "like" + or + wrong = "liekd" and right = "liked" + or + wrong = "liesure" and right = "leisure" + or + wrong = "lieuenant" and right = "lieutenant" + or + wrong = "lieved" and right = "lived" + or + wrong = "liftime" and right = "lifetime" + or + wrong = "likelyhood" and right = "likelihood" + or + wrong = "linnaena" and right = "linnaean" + or + wrong = "lippizaner" and right = "lipizzaner" + or + wrong = "liquify" and right = "liquefy" + or + wrong = "liscense" and right = "licence" + or + wrong = "liscense" and right = "license" + or + wrong = "lisence" and right = "licence" + or + wrong = "lisence" and right = "license" + or + wrong = "lisense" and right = "licence" + or + wrong = "lisense" and right = "license" + or + wrong = "listners" and right = "listeners" + or + wrong = "litature" and right = "literature" + or + wrong = "literaly" and right = "literally" + or + wrong = "literture" and right = "literature" + or + wrong = "littel" and right = "little" + or + wrong = "litterally" and right = "literally" + or + wrong = "liuke" and right = "like" + or + wrong = "livley" and right = "lively" + or + wrong = "lmits" and right = "limits" + or + wrong = "loev" and right = "love" + or + wrong = "lonelyness" and right = "loneliness" + or + wrong = "longitudonal" and right = "longitudinal" + or + wrong = "lonley" and right = "lonely" + or + wrong = "lonly" and right = "lonely" + or + wrong = "lonly" and right = "only" + or + wrong = "loosing" and right = "losing" + or + wrong = "lotharingen" and right = "lothringen" + or + wrong = "lsat" and right = "last" + or + wrong = "lukid" and right = "likud" + or + wrong = "lveo" and right = "love" + or + wrong = "lvoe" and right = "love" + or + wrong = "lybia" and right = "libya" + or + wrong = "maching" and right = "machine" + or + wrong = "maching" and right = "marching" + or + wrong = "maching" and right = "matching" + or + wrong = "mackeral" and right = "mackerel" + or + wrong = "magasine" and right = "magazine" + or + wrong = "magincian" and right = "magician" + or + wrong = "magisine" and right = "magazine" + or + wrong = "magizine" and right = "magazine" + or + wrong = "magnificient" and right = "magnificent" + or + wrong = "magolia" and right = "magnolia" + or + wrong = "mailny" and right = "mainly" + or + wrong = "maintainance" and right = "maintenance" + or + wrong = "maintainence" and right = "maintenance" + or + wrong = "maintance" and right = "maintenance" + or + wrong = "maintenence" and right = "maintenance" + or + wrong = "maintinaing" and right = "maintaining" + or + wrong = "maintioned" and right = "mentioned" + or + wrong = "majoroty" and right = "majority" + or + wrong = "maked" and right = "made" + or + wrong = "maked" and right = "marked" + or + wrong = "makse" and right = "makes" + or + wrong = "malcom" and right = "malcolm" + or + wrong = "maltesian" and right = "maltese" + or + wrong = "mamal" and right = "mammal" + or + wrong = "mamalian" and right = "mammalian" + or + wrong = "managable" and right = "manageable" + or + wrong = "managable" and right = "manageably" + or + wrong = "managment" and right = "management" + or + wrong = "maneouvre" and right = "manoeuvre" + or + wrong = "maneouvred" and right = "manoeuvred" + or + wrong = "maneouvres" and right = "manoeuvres" + or + wrong = "maneouvring" and right = "manoeuvring" + or + wrong = "manisfestations" and right = "manifestations" + or + wrong = "manoeuverability" and right = "maneuverability" + or + wrong = "manouver" and right = "maneuver" + or + wrong = "manouver" and right = "manoeuvre" + or + wrong = "manouverability" and right = "maneuverability" + or + wrong = "manouverability" and right = "manoeuverability" + or + wrong = "manouverability" and right = "manoeuvrability" + or + wrong = "manouverable" and right = "maneuverable" + or + wrong = "manouverable" and right = "manoeuvrable" + or + wrong = "manouvers" and right = "maneuvers" + or + wrong = "manouvers" and right = "manoeuvres" + or + wrong = "mantained" and right = "maintained" + or + wrong = "manuever" and right = "maneuver" + or + wrong = "manuever" and right = "manoeuvre" + or + wrong = "manuevers" and right = "maneuvers" + or + wrong = "manuevers" and right = "manoeuvres" + or + wrong = "manufacturedd" and right = "manufactured" + or + wrong = "manufature" and right = "manufacture" + or + wrong = "manufatured" and right = "manufactured" + or + wrong = "manufaturing" and right = "manufacturing" + or + wrong = "manuver" and right = "maneuver" + or + wrong = "mariage" and right = "marriage" + or + wrong = "marjority" and right = "majority" + or + wrong = "markes" and right = "marks" + or + wrong = "marketting" and right = "marketing" + or + wrong = "marmelade" and right = "marmalade" + or + wrong = "marrage" and right = "marriage" + or + wrong = "marraige" and right = "marriage" + or + wrong = "marrtyred" and right = "martyred" + or + wrong = "marryied" and right = "married" + or + wrong = "massachussets" and right = "massachusetts" + or + wrong = "massachussetts" and right = "massachusetts" + or + wrong = "masterbation" and right = "masturbation" + or + wrong = "mataphysical" and right = "metaphysical" + or + wrong = "materalists" and right = "materialist" + or + wrong = "mathamatics" and right = "mathematics" + or + wrong = "mathematican" and right = "mathematician" + or + wrong = "mathematicas" and right = "mathematics" + or + wrong = "matheticians" and right = "mathematicians" + or + wrong = "mathmatically" and right = "mathematically" + or + wrong = "mathmatician" and right = "mathematician" + or + wrong = "mathmaticians" and right = "mathematicians" + or + wrong = "mccarthyst" and right = "mccarthyist" + or + wrong = "mchanics" and right = "mechanics" + or + wrong = "meaninng" and right = "meaning" + or + wrong = "mear" and right = "mare" + or + wrong = "mear" and right = "mere" + or + wrong = "mear" and right = "wear" + or + wrong = "mechandise" and right = "merchandise" + or + wrong = "medacine" and right = "medicine" + or + wrong = "medeival" and right = "medieval" + or + wrong = "medevial" and right = "medieval" + or + wrong = "mediciney" and right = "mediciny" + or + wrong = "medievel" and right = "medieval" + or + wrong = "mediterainnean" and right = "mediterranean" + or + wrong = "mediteranean" and right = "mediterranean" + or + wrong = "meerkrat" and right = "meerkat" + or + wrong = "melieux" and right = "milieux" + or + wrong = "membranaphone" and right = "membranophone" + or + wrong = "memeber" and right = "member" + or + wrong = "menally" and right = "mentally" + or + wrong = "meranda" and right = "miranda" + or + wrong = "meranda" and right = "veranda" + or + wrong = "mercentile" and right = "mercantile" + or + wrong = "mesage" and right = "message" + or + wrong = "messanger" and right = "messenger" + or + wrong = "messenging" and right = "messaging" + or + wrong = "messsage" and right = "message" + or + wrong = "metalic" and right = "metallic" + or + wrong = "metalurgic" and right = "metallurgic" + or + wrong = "metalurgical" and right = "metallurgical" + or + wrong = "metalurgy" and right = "metallurgy" + or + wrong = "metamorphysis" and right = "metamorphosis" + or + wrong = "metaphoricial" and right = "metaphorical" + or + wrong = "meterologist" and right = "meteorologist" + or + wrong = "meterology" and right = "meteorology" + or + wrong = "methaphor" and right = "metaphor" + or + wrong = "methaphors" and right = "metaphors" + or + wrong = "michagan" and right = "michigan" + or + wrong = "micoscopy" and right = "microscopy" + or + wrong = "midwifes" and right = "midwives" + or + wrong = "mileau" and right = "milieu" + or + wrong = "milennia" and right = "millennia" + or + wrong = "milennium" and right = "millennium" + or + wrong = "mileu" and right = "milieu" + or + wrong = "miliary" and right = "military" + or + wrong = "miligram" and right = "milligram" + or + wrong = "milion" and right = "million" + or + wrong = "miliraty" and right = "military" + or + wrong = "millenia" and right = "millennia" + or + wrong = "millenial" and right = "millennial" + or + wrong = "millenialism" and right = "millennialism" + or + wrong = "millenium" and right = "millennium" + or + wrong = "millepede" and right = "millipede" + or + wrong = "millioniare" and right = "millionaire" + or + wrong = "millitant" and right = "militant" + or + wrong = "millitary" and right = "military" + or + wrong = "millon" and right = "million" + or + wrong = "miltary" and right = "military" + or + wrong = "minature" and right = "miniature" + or + wrong = "minerial" and right = "mineral" + or + wrong = "ministery" and right = "ministry" + or + wrong = "minsitry" and right = "ministry" + or + wrong = "minstries" and right = "ministries" + or + wrong = "minstry" and right = "ministry" + or + wrong = "minumum" and right = "minimum" + or + wrong = "mirrorred" and right = "mirrored" + or + wrong = "miscelaneous" and right = "miscellaneous" + or + wrong = "miscellanious" and right = "miscellaneous" + or + wrong = "miscellanous" and right = "miscellaneous" + or + wrong = "mischeivous" and right = "mischievous" + or + wrong = "mischevious" and right = "mischievous" + or + wrong = "mischievious" and right = "mischievous" + or + wrong = "misdameanor" and right = "misdemeanor" + or + wrong = "misdameanors" and right = "misdemeanors" + or + wrong = "misdemenor" and right = "misdemeanor" + or + wrong = "misdemenors" and right = "misdemeanors" + or + wrong = "misfourtunes" and right = "misfortunes" + or + wrong = "misile" and right = "missile" + or + wrong = "misouri" and right = "missouri" + or + wrong = "mispell" and right = "misspell" + or + wrong = "mispelled" and right = "misspelled" + or + wrong = "mispelling" and right = "misspelling" + or + wrong = "missen" and right = "mizzen" + or + wrong = "missisipi" and right = "mississippi" + or + wrong = "missisippi" and right = "mississippi" + or + wrong = "missle" and right = "missile" + or + wrong = "missonary" and right = "missionary" + or + wrong = "misterious" and right = "mysterious" + or + wrong = "mistery" and right = "mystery" + or + wrong = "misteryous" and right = "mysterious" + or + wrong = "mkae" and right = "make" + or + wrong = "mkaes" and right = "makes" + or + wrong = "mkaing" and right = "making" + or + wrong = "mkea" and right = "make" + or + wrong = "moderm" and right = "modem" + or + wrong = "modle" and right = "model" + or + wrong = "moent" and right = "moment" + or + wrong = "moeny" and right = "money" + or + wrong = "mohammedans" and right = "muslims" + or + wrong = "moil" and right = "mohel" + or + wrong = "moil" and right = "soil" + or + wrong = "moleclues" and right = "molecules" + or + wrong = "momento" and right = "memento" + or + wrong = "monestaries" and right = "monasteries" + or + wrong = "monestary" and right = "monastery" + or + wrong = "monestary" and right = "monetary" + or + wrong = "monickers" and right = "monikers" + or + wrong = "monolite" and right = "monolithic" + or + wrong = "monserrat" and right = "montserrat" + or + wrong = "montains" and right = "mountains" + or + wrong = "montanous" and right = "mountainous" + or + wrong = "montnana" and right = "montana" + or + wrong = "monts" and right = "months" + or + wrong = "montypic" and right = "monotypic" + or + wrong = "moreso" and right = "more" + or + wrong = "morgage" and right = "mortgage" + or + wrong = "morisette" and right = "morissette" + or + wrong = "morrisette" and right = "morissette" + or + wrong = "morroccan" and right = "moroccan" + or + wrong = "morrocco" and right = "morocco" + or + wrong = "morroco" and right = "morocco" + or + wrong = "mortage" and right = "mortgage" + or + wrong = "mosture" and right = "moisture" + or + wrong = "motiviated" and right = "motivated" + or + wrong = "mounth" and right = "month" + or + wrong = "movei" and right = "movie" + or + wrong = "movment" and right = "movement" + or + wrong = "mroe" and right = "more" + or + wrong = "mucuous" and right = "mucous" + or + wrong = "muder" and right = "murder" + or + wrong = "mudering" and right = "murdering" + or + wrong = "muhammadan" and right = "muslim" + or + wrong = "multicultralism" and right = "multiculturalism" + or + wrong = "multipled" and right = "multiplied" + or + wrong = "multiplers" and right = "multipliers" + or + wrong = "munbers" and right = "numbers" + or + wrong = "muncipalities" and right = "municipalities" + or + wrong = "muncipality" and right = "municipality" + or + wrong = "munnicipality" and right = "municipality" + or + wrong = "muscels" and right = "muscles" + or + wrong = "muscels" and right = "mussels" + or + wrong = "muscial" and right = "musical" + or + wrong = "muscician" and right = "musician" + or + wrong = "muscicians" and right = "musicians" + or + wrong = "mutiliated" and right = "mutilated" + or + wrong = "mutiple" and right = "multiple" + or + wrong = "myraid" and right = "myriad" + or + wrong = "mysef" and right = "myself" + or + wrong = "mysogynist" and right = "misogynist" + or + wrong = "mysogyny" and right = "misogyny" + or + wrong = "mysterous" and right = "mysterious" + or + wrong = "mythraic" and right = "mithraic" + or + wrong = "naieve" and right = "naive" + or + wrong = "naploeon" and right = "napoleon" + or + wrong = "napolean" and right = "napoleon" + or + wrong = "napoleonian" and right = "napoleonic" + or + wrong = "naturaly" and right = "naturally" + or + wrong = "naturely" and right = "naturally" + or + wrong = "naturual" and right = "natural" + or + wrong = "naturually" and right = "naturally" + or + wrong = "nazereth" and right = "nazareth" + or + wrong = "neccesarily" and right = "necessarily" + or + wrong = "neccesary" and right = "necessary" + or + wrong = "neccessarily" and right = "necessarily" + or + wrong = "neccessary" and right = "necessary" + or + wrong = "neccessities" and right = "necessities" + or + wrong = "necesarily" and right = "necessarily" + or + wrong = "necesary" and right = "necessary" + or + wrong = "necessiate" and right = "necessitate" + or + wrong = "neglible" and right = "negligible" + or + wrong = "negligable" and right = "negligible" + or + wrong = "negociate" and right = "negotiate" + or + wrong = "negociation" and right = "negotiation" + or + wrong = "negociations" and right = "negotiations" + or + wrong = "negotation" and right = "negotiation" + or + wrong = "neice" and right = "nice" + or + wrong = "neice" and right = "niece" + or + wrong = "neigborhood" and right = "neighborhood" + or + wrong = "neigbour" and right = "neighbor" + or + wrong = "neigbour" and right = "neighbour" + or + wrong = "neigbourhood" and right = "neighbourhood" + or + wrong = "neigbouring" and right = "neighboring" + or + wrong = "neigbouring" and right = "neighbouring" + or + wrong = "neigbours" and right = "neighbors" + or + wrong = "neigbours" and right = "neighbours" + or + wrong = "neolitic" and right = "neolithic" + or + wrong = "nessasarily" and right = "necessarily" + or + wrong = "nessecary" and right = "necessary" + or + wrong = "nestin" and right = "nesting" + or + wrong = "neverthless" and right = "nevertheless" + or + wrong = "newletters" and right = "newsletters" + or + wrong = "nickle" and right = "nickel" + or + wrong = "nightime" and right = "nighttime" + or + wrong = "nineth" and right = "ninth" + or + wrong = "ninteenth" and right = "nineteenth" + or + wrong = "ninty" and right = "ninety" + or + wrong = "nkow" and right = "know" + or + wrong = "nkwo" and right = "know" + or + wrong = "nmae" and right = "name" + or + wrong = "noncombatents" and right = "noncombatants" + or + wrong = "nonsence" and right = "nonsense" + or + wrong = "nontheless" and right = "nonetheless" + or + wrong = "norhern" and right = "northern" + or + wrong = "northen" and right = "northern" + or + wrong = "northereastern" and right = "northeastern" + or + wrong = "notabley" and right = "notably" + or + wrong = "noteable" and right = "notable" + or + wrong = "noteably" and right = "notably" + or + wrong = "noteriety" and right = "notoriety" + or + wrong = "noth" and right = "north" + or + wrong = "nothern" and right = "northern" + or + wrong = "noticable" and right = "noticeable" + or + wrong = "noticably" and right = "noticeably" + or + wrong = "notications" and right = "notifications" + or + wrong = "noticeing" and right = "noticing" + or + wrong = "noticible" and right = "noticeable" + or + wrong = "notwhithstanding" and right = "notwithstanding" + or + wrong = "noveau" and right = "nouveau" + or + wrong = "novermber" and right = "november" + or + wrong = "nowdays" and right = "nowadays" + or + wrong = "nowe" and right = "now" + or + wrong = "nto" and right = "not" + or + wrong = "nubmer" and right = "number" + or + wrong = "nucular" and right = "nuclear" + or + wrong = "nuculear" and right = "nuclear" + or + wrong = "nuisanse" and right = "nuisance" + or + wrong = "nullabour" and right = "nullarbor" + or + wrong = "numberous" and right = "numerous" + or + wrong = "nuremburg" and right = "nuremberg" + or + wrong = "nusance" and right = "nuisance" + or + wrong = "nutritent" and right = "nutrient" + or + wrong = "nutritents" and right = "nutrients" + or + wrong = "nuturing" and right = "nurturing" + or + wrong = "obect" and right = "object" + or + wrong = "obediance" and right = "obedience" + or + wrong = "obediant" and right = "obedient" + or + wrong = "obejct" and right = "object" + or + wrong = "obession" and right = "obsession" + or + wrong = "obssessed" and right = "obsessed" + or + wrong = "obstacal" and right = "obstacle" + or + wrong = "obstancles" and right = "obstacles" + or + wrong = "obstruced" and right = "obstructed" + or + wrong = "ocasion" and right = "occasion" + or + wrong = "ocasional" and right = "occasional" + or + wrong = "ocasionally" and right = "occasionally" + or + wrong = "ocasionaly" and right = "occasionally" + or + wrong = "ocasioned" and right = "occasioned" + or + wrong = "ocasions" and right = "occasions" + or + wrong = "ocassion" and right = "occasion" + or + wrong = "ocassional" and right = "occasional" + or + wrong = "ocassionally" and right = "occasionally" + or + wrong = "ocassionaly" and right = "occasionally" + or + wrong = "ocassioned" and right = "occasioned" + or + wrong = "ocassions" and right = "occasions" + or + wrong = "occaison" and right = "occasion" + or + wrong = "occassion" and right = "occasion" + or + wrong = "occassional" and right = "occasional" + or + wrong = "occassionally" and right = "occasionally" + or + wrong = "occassionaly" and right = "occasionally" + or + wrong = "occassioned" and right = "occasioned" + or + wrong = "occassions" and right = "occasions" + or + wrong = "occationally" and right = "occasionally" + or + wrong = "occour" and right = "occur" + or + wrong = "occurance" and right = "occurrence" + or + wrong = "occurances" and right = "occurrences" + or + wrong = "occured" and right = "occurred" + or + wrong = "occurence" and right = "occurrence" + or + wrong = "occurences" and right = "occurrences" + or + wrong = "occuring" and right = "occurring" + or + wrong = "occurr" and right = "occur" + or + wrong = "occurrance" and right = "occurrence" + or + wrong = "occurrances" and right = "occurrences" + or + wrong = "octohedra" and right = "octahedra" + or + wrong = "octohedral" and right = "octahedral" + or + wrong = "octohedron" and right = "octahedron" + or + wrong = "ocuntries" and right = "countries" + or + wrong = "ocuntry" and right = "country" + or + wrong = "ocurr" and right = "occur" + or + wrong = "ocurrance" and right = "occurrence" + or + wrong = "ocurred" and right = "occurred" + or + wrong = "ocurrence" and right = "occurrence" + or + wrong = "offcers" and right = "officers" + or + wrong = "offcially" and right = "officially" + or + wrong = "offereings" and right = "offerings" + or + wrong = "offical" and right = "official" + or + wrong = "offically" and right = "officially" + or + wrong = "officals" and right = "officials" + or + wrong = "officaly" and right = "officially" + or + wrong = "officialy" and right = "officially" + or + wrong = "offred" and right = "offered" + or + wrong = "oftenly" and right = "often" + or + wrong = "oging" and right = "going" + or + wrong = "oging" and right = "ogling" + or + wrong = "oject" and right = "object" + or + wrong = "omision" and right = "omission" + or + wrong = "omited" and right = "omitted" + or + wrong = "omiting" and right = "omitting" + or + wrong = "omlette" and right = "omelette" + or + wrong = "ommision" and right = "omission" + or + wrong = "ommited" and right = "omitted" + or + wrong = "ommiting" and right = "omitting" + or + wrong = "ommitted" and right = "omitted" + or + wrong = "ommitting" and right = "omitting" + or + wrong = "omniverous" and right = "omnivorous" + or + wrong = "omniverously" and right = "omnivorously" + or + wrong = "omre" and right = "more" + or + wrong = "onot" and right = "not" + or + wrong = "onot" and right = "note" + or + wrong = "onyl" and right = "only" + or + wrong = "openess" and right = "openness" + or + wrong = "oponent" and right = "opponent" + or + wrong = "oportunity" and right = "opportunity" + or + wrong = "opose" and right = "oppose" + or + wrong = "oposite" and right = "opposite" + or + wrong = "oposition" and right = "opposition" + or + wrong = "oppenly" and right = "openly" + or + wrong = "oppinion" and right = "opinion" + or + wrong = "opponant" and right = "opponent" + or + wrong = "oppononent" and right = "opponent" + or + wrong = "oppositition" and right = "opposition" + or + wrong = "oppossed" and right = "opposed" + or + wrong = "opprotunity" and right = "opportunity" + or + wrong = "opression" and right = "oppression" + or + wrong = "opressive" and right = "oppressive" + or + wrong = "opthalmic" and right = "ophthalmic" + or + wrong = "opthalmologist" and right = "ophthalmologist" + or + wrong = "opthalmology" and right = "ophthalmology" + or + wrong = "opthamologist" and right = "ophthalmologist" + or + wrong = "optmizations" and right = "optimizations" + or + wrong = "optomism" and right = "optimism" + or + wrong = "orded" and right = "ordered" + or + wrong = "organim" and right = "organism" + or + wrong = "organistion" and right = "organisation" + or + wrong = "organiztion" and right = "organization" + or + wrong = "orgin" and right = "organ" + or + wrong = "orgin" and right = "origin" + or + wrong = "orginal" and right = "original" + or + wrong = "orginally" and right = "originally" + or + wrong = "orginize" and right = "organise" + or + wrong = "oridinarily" and right = "ordinarily" + or + wrong = "origanaly" and right = "originally" + or + wrong = "originall" and right = "original" + or + wrong = "originall" and right = "originally" + or + wrong = "originaly" and right = "originally" + or + wrong = "originially" and right = "originally" + or + wrong = "originnally" and right = "originally" + or + wrong = "origional" and right = "original" + or + wrong = "orignally" and right = "originally" + or + wrong = "orignially" and right = "originally" + or + wrong = "otehr" and right = "other" + or + wrong = "oublisher" and right = "publisher" + or + wrong = "ouevre" and right = "oeuvre" + or + wrong = "ouput" and right = "output" + or + wrong = "oustanding" and right = "outstanding" + or + wrong = "overriden" and right = "overridden" + or + wrong = "overshaddowed" and right = "overshadowed" + or + wrong = "overwelming" and right = "overwhelming" + or + wrong = "overwheliming" and right = "overwhelming" + or + wrong = "owrk" and right = "work" + or + wrong = "owudl" and right = "would" + or + wrong = "oxigen" and right = "oxygen" + or + wrong = "oximoron" and right = "oxymoron" + or + wrong = "p0enis" and right = "penis" + or + wrong = "paide" and right = "paid" + or + wrong = "paitience" and right = "patience" + or + wrong = "palce" and right = "palace" + or + wrong = "palce" and right = "place" + or + wrong = "paleolitic" and right = "paleolithic" + or + wrong = "paliamentarian" and right = "parliamentarian" + or + wrong = "palistian" and right = "palestinian" + or + wrong = "palistinian" and right = "palestinian" + or + wrong = "palistinians" and right = "palestinians" + or + wrong = "pallete" and right = "palette" + or + wrong = "pamflet" and right = "pamphlet" + or + wrong = "pamplet" and right = "pamphlet" + or + wrong = "pantomine" and right = "pantomime" + or + wrong = "papanicalou" and right = "papanicolaou" + or + wrong = "paralel" and right = "parallel" + or + wrong = "paralell" and right = "parallel" + or + wrong = "paralelly" and right = "parallelly" + or + wrong = "paralely" and right = "parallelly" + or + wrong = "parallely" and right = "parallelly" + or + wrong = "paramater" and right = "parameter" + or + wrong = "paramters" and right = "parameters" + or + wrong = "paranthesis" and right = "parenthesis" + or + wrong = "paraphenalia" and right = "paraphernalia" + or + wrong = "parellels" and right = "parallels" + or + wrong = "parisitic" and right = "parasitic" + or + wrong = "parituclar" and right = "particular" + or + wrong = "parliment" and right = "parliament" + or + wrong = "parrakeets" and right = "parakeets" + or + wrong = "parralel" and right = "parallel" + or + wrong = "parrallel" and right = "parallel" + or + wrong = "parrallell" and right = "parallel" + or + wrong = "parrallelly" and right = "parallelly" + or + wrong = "parrallely" and right = "parallelly" + or + wrong = "partialy" and right = "partially" + or + wrong = "particually" and right = "particularly" + or + wrong = "particualr" and right = "particular" + or + wrong = "particuarly" and right = "particularly" + or + wrong = "particularily" and right = "particularly" + or + wrong = "particulary" and right = "particularly" + or + wrong = "pary" and right = "party" + or + wrong = "pased" and right = "passed" + or + wrong = "pasengers" and right = "passengers" + or + wrong = "passerbys" and right = "passersby" + or + wrong = "pasttime" and right = "pastime" + or + wrong = "pastural" and right = "pastoral" + or + wrong = "paticular" and right = "particular" + or + wrong = "pattented" and right = "patented" + or + wrong = "pavillion" and right = "pavilion" + or + wrong = "payed" and right = "paid" + or + wrong = "pblisher" and right = "publisher" + or + wrong = "pbulisher" and right = "publisher" + or + wrong = "peageant" and right = "pageant" + or + wrong = "peaple" and right = "people" + or + wrong = "peaples" and right = "peoples" + or + wrong = "peculure" and right = "peculiar" + or + wrong = "pedestrain" and right = "pedestrian" + or + wrong = "peformed" and right = "performed" + or + wrong = "peice" and right = "piece" + or + wrong = "peloponnes" and right = "peloponnesus" + or + wrong = "penatly" and right = "penalty" + or + wrong = "penerator" and right = "penetrator" + or + wrong = "penisula" and right = "peninsula" + or + wrong = "penisular" and right = "peninsular" + or + wrong = "penninsula" and right = "peninsula" + or + wrong = "penninsular" and right = "peninsular" + or + wrong = "pennisula" and right = "peninsula" + or + wrong = "pennyslvania" and right = "pennsylvania" + or + wrong = "pensinula" and right = "peninsula" + or + wrong = "pensle" and right = "pencil" + or + wrong = "peom" and right = "poem" + or + wrong = "peoms" and right = "poems" + or + wrong = "peopel" and right = "people" + or + wrong = "peopels" and right = "peoples" + or + wrong = "peotry" and right = "poetry" + or + wrong = "perade" and right = "parade" + or + wrong = "percepted" and right = "perceived" + or + wrong = "percieve" and right = "perceive" + or + wrong = "percieved" and right = "perceived" + or + wrong = "perenially" and right = "perennially" + or + wrong = "peretrator" and right = "perpetrator" + or + wrong = "perfomance" and right = "performance" + or + wrong = "perfomers" and right = "performers" + or + wrong = "performence" and right = "performance" + or + wrong = "performes" and right = "performed" + or + wrong = "performes" and right = "performs" + or + wrong = "perhasp" and right = "perhaps" + or + wrong = "perheaps" and right = "perhaps" + or + wrong = "perhpas" and right = "perhaps" + or + wrong = "peripathetic" and right = "peripatetic" + or + wrong = "peristent" and right = "persistent" + or + wrong = "perjery" and right = "perjury" + or + wrong = "perjorative" and right = "pejorative" + or + wrong = "permanant" and right = "permanent" + or + wrong = "permenant" and right = "permanent" + or + wrong = "permenantly" and right = "permanently" + or + wrong = "permissable" and right = "permissible" + or + wrong = "perogative" and right = "prerogative" + or + wrong = "peronal" and right = "personal" + or + wrong = "perosnality" and right = "personality" + or + wrong = "perpertrated" and right = "perpetrated" + or + wrong = "perphas" and right = "perhaps" + or + wrong = "perpindicular" and right = "perpendicular" + or + wrong = "persan" and right = "person" + or + wrong = "perseverence" and right = "perseverance" + or + wrong = "persistance" and right = "persistence" + or + wrong = "persistant" and right = "persistent" + or + wrong = "personel" and right = "personal" + or + wrong = "personel" and right = "personnel" + or + wrong = "personell" and right = "personnel" + or + wrong = "personnell" and right = "personnel" + or + wrong = "persuded" and right = "persuaded" + or + wrong = "persue" and right = "pursue" + or + wrong = "persued" and right = "pursued" + or + wrong = "persuing" and right = "pursuing" + or + wrong = "persuit" and right = "pursuit" + or + wrong = "persuits" and right = "pursuits" + or + wrong = "pertubation" and right = "perturbation" + or + wrong = "pertubations" and right = "perturbations" + or + wrong = "pessiary" and right = "pessary" + or + wrong = "petetion" and right = "petition" + or + wrong = "pharoah" and right = "pharaoh" + or + wrong = "phenomenom" and right = "phenomenon" + or + wrong = "phenomenonal" and right = "phenomenal" + or + wrong = "phenomenonly" and right = "phenomenally" + or + wrong = "phenomonenon" and right = "phenomenon" + or + wrong = "phenomonon" and right = "phenomenon" + or + wrong = "phenonmena" and right = "phenomena" + or + wrong = "philipines" and right = "philippines" + or + wrong = "philisopher" and right = "philosopher" + or + wrong = "philisophical" and right = "philosophical" + or + wrong = "philisophy" and right = "philosophy" + or + wrong = "phillipine" and right = "philippine" + or + wrong = "phillipines" and right = "philippines" + or + wrong = "phillippines" and right = "philippines" + or + wrong = "phillosophically" and right = "philosophically" + or + wrong = "philospher" and right = "philosopher" + or + wrong = "philosphies" and right = "philosophies" + or + wrong = "philosphy" and right = "philosophy" + or + wrong = "phonecian" and right = "phoenecian" + or + wrong = "phongraph" and right = "phonograph" + or + wrong = "phylosophical" and right = "philosophical" + or + wrong = "physicaly" and right = "physically" + or + wrong = "piblisher" and right = "publisher" + or + wrong = "pich" and right = "pitch" + or + wrong = "pilgrimmage" and right = "pilgrimage" + or + wrong = "pilgrimmages" and right = "pilgrimages" + or + wrong = "pinapple" and right = "pineapple" + or + wrong = "pinnaple" and right = "pineapple" + or + wrong = "pinoneered" and right = "pioneered" + or + wrong = "plagarism" and right = "plagiarism" + or + wrong = "planation" and right = "plantation" + or + wrong = "planed" and right = "planned" + or + wrong = "plantiff" and right = "plaintiff" + or + wrong = "plateu" and right = "plateau" + or + wrong = "plausable" and right = "plausible" + or + wrong = "playright" and right = "playwright" + or + wrong = "playwrite" and right = "playwright" + or + wrong = "playwrites" and right = "playwrights" + or + wrong = "pleasent" and right = "pleasant" + or + wrong = "plebicite" and right = "plebiscite" + or + wrong = "plesant" and right = "pleasant" + or + wrong = "poenis" and right = "penis" + or + wrong = "poeoples" and right = "peoples" + or + wrong = "poety" and right = "poetry" + or + wrong = "poisin" and right = "poison" + or + wrong = "polical" and right = "political" + or + wrong = "polinator" and right = "pollinator" + or + wrong = "polinators" and right = "pollinators" + or + wrong = "politican" and right = "politician" + or + wrong = "politicans" and right = "politicians" + or + wrong = "poltical" and right = "political" + or + wrong = "polute" and right = "pollute" + or + wrong = "poluted" and right = "polluted" + or + wrong = "polutes" and right = "pollutes" + or + wrong = "poluting" and right = "polluting" + or + wrong = "polution" and right = "pollution" + or + wrong = "polyphonyic" and right = "polyphonic" + or + wrong = "polysaccaride" and right = "polysaccharide" + or + wrong = "polysaccharid" and right = "polysaccharide" + or + wrong = "pomegranite" and right = "pomegranate" + or + wrong = "pomotion" and right = "promotion" + or + wrong = "poportional" and right = "proportional" + or + wrong = "popoulation" and right = "population" + or + wrong = "popularaty" and right = "popularity" + or + wrong = "populare" and right = "popular" + or + wrong = "populer" and right = "popular" + or + wrong = "porshan" and right = "portion" + or + wrong = "porshon" and right = "portion" + or + wrong = "portait" and right = "portrait" + or + wrong = "portayed" and right = "portrayed" + or + wrong = "portraing" and right = "portraying" + or + wrong = "portugese" and right = "portuguese" + or + wrong = "portuguease" and right = "portuguese" + or + wrong = "portugues" and right = "portuguese" + or + wrong = "posess" and right = "possess" + or + wrong = "posessed" and right = "possessed" + or + wrong = "posesses" and right = "possesses" + or + wrong = "posessing" and right = "possessing" + or + wrong = "posession" and right = "possession" + or + wrong = "posessions" and right = "possessions" + or + wrong = "posion" and right = "poison" + or + wrong = "positon" and right = "position" + or + wrong = "positon" and right = "positron" + or + wrong = "possable" and right = "possible" + or + wrong = "possably" and right = "possibly" + or + wrong = "posseses" and right = "possesses" + or + wrong = "possesing" and right = "possessing" + or + wrong = "possesion" and right = "possession" + or + wrong = "possessess" and right = "possesses" + or + wrong = "possibile" and right = "possible" + or + wrong = "possibilty" and right = "possibility" + or + wrong = "possiblility" and right = "possibility" + or + wrong = "possiblilty" and right = "possibility" + or + wrong = "possiblities" and right = "possibilities" + or + wrong = "possiblity" and right = "possibility" + or + wrong = "possition" and right = "position" + or + wrong = "postdam" and right = "potsdam" + or + wrong = "posthomous" and right = "posthumous" + or + wrong = "postion" and right = "position" + or + wrong = "postive" and right = "positive" + or + wrong = "potatos" and right = "potatoes" + or + wrong = "potrait" and right = "portrait" + or + wrong = "potrayed" and right = "portrayed" + or + wrong = "poulations" and right = "populations" + or + wrong = "poverful" and right = "powerful" + or + wrong = "poweful" and right = "powerful" + or + wrong = "powerfull" and right = "powerful" + or + wrong = "ppublisher" and right = "publisher" + or + wrong = "practial" and right = "practical" + or + wrong = "practially" and right = "practically" + or + wrong = "practicaly" and right = "practically" + or + wrong = "practicioner" and right = "practitioner" + or + wrong = "practicioners" and right = "practitioners" + or + wrong = "practicly" and right = "practically" + or + wrong = "practioner" and right = "practitioner" + or + wrong = "practioners" and right = "practitioners" + or + wrong = "prairy" and right = "prairie" + or + wrong = "prarie" and right = "prairie" + or + wrong = "praries" and right = "prairies" + or + wrong = "pratice" and right = "practice" + or + wrong = "preample" and right = "preamble" + or + wrong = "precedessor" and right = "predecessor" + or + wrong = "preceed" and right = "precede" + or + wrong = "preceeded" and right = "preceded" + or + wrong = "preceeding" and right = "preceding" + or + wrong = "preceeds" and right = "precedes" + or + wrong = "precendence" and right = "precedence" + or + wrong = "precentage" and right = "percentage" + or + wrong = "precice" and right = "precise" + or + wrong = "precisly" and right = "precisely" + or + wrong = "precurser" and right = "precursor" + or + wrong = "predecesors" and right = "predecessors" + or + wrong = "predicatble" and right = "predictable" + or + wrong = "predicitons" and right = "predictions" + or + wrong = "predomiantly" and right = "predominately" + or + wrong = "prefered" and right = "preferred" + or + wrong = "prefering" and right = "preferring" + or + wrong = "preferrably" and right = "preferably" + or + wrong = "pregancies" and right = "pregnancies" + or + wrong = "preiod" and right = "period" + or + wrong = "preliferation" and right = "proliferation" + or + wrong = "premeire" and right = "premiere" + or + wrong = "premeired" and right = "premiered" + or + wrong = "premillenial" and right = "premillennial" + or + wrong = "preminence" and right = "preeminence" + or + wrong = "premission" and right = "permission" + or + wrong = "premonasterians" and right = "premonstratensians" + or + wrong = "preocupation" and right = "preoccupation" + or + wrong = "prepair" and right = "prepare" + or + wrong = "prepartion" and right = "preparation" + or + wrong = "prepatory" and right = "preparatory" + or + wrong = "preperation" and right = "preparation" + or + wrong = "preperations" and right = "preparations" + or + wrong = "preriod" and right = "period" + or + wrong = "presedential" and right = "presidential" + or + wrong = "presense" and right = "presence" + or + wrong = "presidenital" and right = "presidential" + or + wrong = "presidental" and right = "presidential" + or + wrong = "presitgious" and right = "prestigious" + or + wrong = "prespective" and right = "perspective" + or + wrong = "prestigeous" and right = "prestigious" + or + wrong = "prestigous" and right = "prestigious" + or + wrong = "presumabely" and right = "presumably" + or + wrong = "presumibly" and right = "presumably" + or + wrong = "pretection" and right = "protection" + or + wrong = "prevelant" and right = "prevalent" + or + wrong = "preverse" and right = "perverse" + or + wrong = "previvous" and right = "previous" + or + wrong = "pricipal" and right = "principal" + or + wrong = "priciple" and right = "principle" + or + wrong = "priestood" and right = "priesthood" + or + wrong = "primarly" and right = "primarily" + or + wrong = "primative" and right = "primitive" + or + wrong = "primatively" and right = "primitively" + or + wrong = "primatives" and right = "primitives" + or + wrong = "primordal" and right = "primordial" + or + wrong = "principaly" and right = "principality" + or + wrong = "principial" and right = "principal" + or + wrong = "principlaity" and right = "principality" + or + wrong = "principly" and right = "principally" + or + wrong = "prinicipal" and right = "principal" + or + wrong = "privalege" and right = "privilege" + or + wrong = "privaleges" and right = "privileges" + or + wrong = "priveledges" and right = "privileges" + or + wrong = "privelege" and right = "privilege" + or + wrong = "priveleged" and right = "privileged" + or + wrong = "priveleges" and right = "privileges" + or + wrong = "privelige" and right = "privilege" + or + wrong = "priveliged" and right = "privileged" + or + wrong = "priveliges" and right = "privileges" + or + wrong = "privelleges" and right = "privileges" + or + wrong = "privilage" and right = "privilege" + or + wrong = "priviledge" and right = "privilege" + or + wrong = "priviledges" and right = "privileges" + or + wrong = "privledge" and right = "privilege" + or + wrong = "privte" and right = "private" + or + wrong = "probabilaty" and right = "probability" + or + wrong = "probablistic" and right = "probabilistic" + or + wrong = "probablly" and right = "probably" + or + wrong = "probalibity" and right = "probability" + or + wrong = "probaly" and right = "probably" + or + wrong = "probelm" and right = "problem" + or + wrong = "proccess" and right = "process" + or + wrong = "proccessing" and right = "processing" + or + wrong = "procede" and right = "precede" + or + wrong = "procede" and right = "proceed" + or + wrong = "proceded" and right = "preceded" + or + wrong = "proceded" and right = "proceeded" + or + wrong = "procedes" and right = "precedes" + or + wrong = "procedes" and right = "proceeds" + or + wrong = "procedger" and right = "procedure" + or + wrong = "proceding" and right = "preceding" + or + wrong = "proceding" and right = "proceeding" + or + wrong = "procedings" and right = "proceedings" + or + wrong = "proceedure" and right = "procedure" + or + wrong = "proces" and right = "process" + or + wrong = "procesed" and right = "processed" + or + wrong = "processer" and right = "processor" + or + wrong = "proclaimation" and right = "proclamation" + or + wrong = "proclamed" and right = "proclaimed" + or + wrong = "proclaming" and right = "proclaiming" + or + wrong = "proclomation" and right = "proclamation" + or + wrong = "profesion" and right = "profession" + or + wrong = "profesion" and right = "profusion" + or + wrong = "profesor" and right = "professor" + or + wrong = "professer" and right = "professor" + or + wrong = "proffesed" and right = "professed" + or + wrong = "proffesion" and right = "profession" + or + wrong = "proffesional" and right = "professional" + or + wrong = "proffesor" and right = "professor" + or + wrong = "profilic" and right = "prolific" + or + wrong = "progessed" and right = "progressed" + or + wrong = "progidy" and right = "prodigy" + or + wrong = "programable" and right = "programmable" + or + wrong = "progrom" and right = "pogrom" + or + wrong = "progrom" and right = "program" + or + wrong = "progroms" and right = "pogroms" + or + wrong = "progroms" and right = "programs" + or + wrong = "prohabition" and right = "prohibition" + or + wrong = "prologomena" and right = "prolegomena" + or + wrong = "prominance" and right = "prominence" + or + wrong = "prominant" and right = "prominent" + or + wrong = "prominantly" and right = "prominently" + or + wrong = "prominately" and right = "predominately" + or + wrong = "prominately" and right = "prominently" + or + wrong = "promiscous" and right = "promiscuous" + or + wrong = "promotted" and right = "promoted" + or + wrong = "pronomial" and right = "pronominal" + or + wrong = "pronouced" and right = "pronounced" + or + wrong = "pronounched" and right = "pronounced" + or + wrong = "pronounciation" and right = "pronunciation" + or + wrong = "proove" and right = "prove" + or + wrong = "prooved" and right = "proved" + or + wrong = "prophacy" and right = "prophecy" + or + wrong = "propietary" and right = "proprietary" + or + wrong = "propmted" and right = "prompted" + or + wrong = "propoganda" and right = "propaganda" + or + wrong = "propogate" and right = "propagate" + or + wrong = "propogates" and right = "propagates" + or + wrong = "propogation" and right = "propagation" + or + wrong = "propostion" and right = "proposition" + or + wrong = "propotions" and right = "proportions" + or + wrong = "propper" and right = "proper" + or + wrong = "propperly" and right = "properly" + or + wrong = "proprietory" and right = "proprietary" + or + wrong = "proseletyzing" and right = "proselytizing" + or + wrong = "protaganist" and right = "protagonist" + or + wrong = "protaganists" and right = "protagonists" + or + wrong = "protocal" and right = "protocol" + or + wrong = "protoganist" and right = "protagonist" + or + wrong = "prototpe" and right = "prototype" + or + wrong = "protoype" and right = "prototype" + or + wrong = "protrayed" and right = "portrayed" + or + wrong = "protruberance" and right = "protuberance" + or + wrong = "protruberances" and right = "protuberances" + or + wrong = "prouncements" and right = "pronouncements" + or + wrong = "provacative" and right = "provocative" + or + wrong = "provded" and right = "provided" + or + wrong = "provicial" and right = "provincial" + or + wrong = "provinicial" and right = "provincial" + or + wrong = "provisiosn" and right = "provision" + or + wrong = "provisonal" and right = "provisional" + or + wrong = "proximty" and right = "proximity" + or + wrong = "pseudononymous" and right = "pseudonymous" + or + wrong = "pseudonyn" and right = "pseudonym" + or + wrong = "psuedo" and right = "pseudo" + or + wrong = "psycology" and right = "psychology" + or + wrong = "psyhic" and right = "psychic" + or + wrong = "pubilsher" and right = "publisher" + or + wrong = "pubisher" and right = "publisher" + or + wrong = "publiaher" and right = "publisher" + or + wrong = "publically" and right = "publicly" + or + wrong = "publicaly" and right = "publicly" + or + wrong = "publicher" and right = "publisher" + or + wrong = "publihser" and right = "publisher" + or + wrong = "publisehr" and right = "publisher" + or + wrong = "publiser" and right = "publisher" + or + wrong = "publisger" and right = "publisher" + or + wrong = "publisheed" and right = "published" + or + wrong = "publisherr" and right = "publisher" + or + wrong = "publishher" and right = "publisher" + or + wrong = "publishor" and right = "publisher" + or + wrong = "publishre" and right = "publisher" + or + wrong = "publissher" and right = "publisher" + or + wrong = "publlisher" and right = "publisher" + or + wrong = "publsiher" and right = "publisher" + or + wrong = "publusher" and right = "publisher" + or + wrong = "puchasing" and right = "purchasing" + or + wrong = "pucini" and right = "puccini" + or + wrong = "pulisher" and right = "publisher" + or + wrong = "pumkin" and right = "pumpkin" + or + wrong = "puplisher" and right = "publisher" + or + wrong = "puritannical" and right = "puritanical" + or + wrong = "purposedly" and right = "purposely" + or + wrong = "purpotedly" and right = "purportedly" + or + wrong = "pursuade" and right = "persuade" + or + wrong = "pursuaded" and right = "persuaded" + or + wrong = "pursuades" and right = "persuades" + or + wrong = "pususading" and right = "persuading" + or + wrong = "puting" and right = "putting" + or + wrong = "pwoer" and right = "power" + or + wrong = "pyscic" and right = "psychic" + or + wrong = "qtuie" and right = "quiet" + or + wrong = "qtuie" and right = "quite" + or + wrong = "quantaty" and right = "quantity" + or + wrong = "quantitiy" and right = "quantity" + or + wrong = "quarantaine" and right = "quarantine" + or + wrong = "queenland" and right = "queensland" + or + wrong = "questonable" and right = "questionable" + or + wrong = "quicklyu" and right = "quickly" + or + wrong = "quinessential" and right = "quintessential" + or + wrong = "quitted" and right = "quit" + or + wrong = "quizes" and right = "quizzes" + or + wrong = "qutie" and right = "quiet" + or + wrong = "qutie" and right = "quite" + or + wrong = "rabinnical" and right = "rabbinical" + or + wrong = "racaus" and right = "raucous" + or + wrong = "radiactive" and right = "radioactive" + or + wrong = "radify" and right = "ratify" + or + wrong = "raelly" and right = "really" + or + wrong = "rarified" and right = "rarefied" + or + wrong = "reaccurring" and right = "recurring" + or + wrong = "reacing" and right = "reaching" + or + wrong = "reacll" and right = "recall" + or + wrong = "readmition" and right = "readmission" + or + wrong = "realitvely" and right = "relatively" + or + wrong = "realsitic" and right = "realistic" + or + wrong = "realtions" and right = "relations" + or + wrong = "realy" and right = "really" + or + wrong = "realyl" and right = "really" + or + wrong = "reasearch" and right = "research" + or + wrong = "rebiulding" and right = "rebuilding" + or + wrong = "rebllions" and right = "rebellions" + or + wrong = "rebounce" and right = "rebound" + or + wrong = "reccomend" and right = "recommend" + or + wrong = "reccomendations" and right = "recommendations" + or + wrong = "reccomended" and right = "recommended" + or + wrong = "reccomending" and right = "recommending" + or + wrong = "reccommend" and right = "recommend" + or + wrong = "reccommended" and right = "recommended" + or + wrong = "reccommending" and right = "recommending" + or + wrong = "reccuring" and right = "recurring" + or + wrong = "receeded" and right = "receded" + or + wrong = "receeding" and right = "receding" + or + wrong = "recepient" and right = "recipient" + or + wrong = "recepients" and right = "recipients" + or + wrong = "receving" and right = "receiving" + or + wrong = "rechargable" and right = "rechargeable" + or + wrong = "reched" and right = "reached" + or + wrong = "recide" and right = "reside" + or + wrong = "recided" and right = "resided" + or + wrong = "recident" and right = "resident" + or + wrong = "recidents" and right = "residents" + or + wrong = "reciding" and right = "residing" + or + wrong = "reciepents" and right = "recipients" + or + wrong = "reciept" and right = "receipt" + or + wrong = "recieve" and right = "receive" + or + wrong = "recieved" and right = "received" + or + wrong = "reciever" and right = "receiver" + or + wrong = "recievers" and right = "receivers" + or + wrong = "recieves" and right = "receives" + or + wrong = "recieving" and right = "receiving" + or + wrong = "recipiant" and right = "recipient" + or + wrong = "recipiants" and right = "recipients" + or + wrong = "recived" and right = "received" + or + wrong = "recivership" and right = "receivership" + or + wrong = "recogise" and right = "recognise" + or + wrong = "recogize" and right = "recognize" + or + wrong = "recomend" and right = "recommend" + or + wrong = "recomended" and right = "recommended" + or + wrong = "recomending" and right = "recommending" + or + wrong = "recomends" and right = "recommends" + or + wrong = "recommedations" and right = "recommendations" + or + wrong = "recompence" and right = "recompense" + or + wrong = "reconaissance" and right = "reconnaissance" + or + wrong = "reconcilation" and right = "reconciliation" + or + wrong = "reconized" and right = "recognized" + or + wrong = "reconnaisance" and right = "reconnaissance" + or + wrong = "reconnaissence" and right = "reconnaissance" + or + wrong = "recontructed" and right = "reconstructed" + or + wrong = "recquired" and right = "required" + or + wrong = "recrational" and right = "recreational" + or + wrong = "recrod" and right = "record" + or + wrong = "recuiting" and right = "recruiting" + or + wrong = "recuring" and right = "recurring" + or + wrong = "recurrance" and right = "recurrence" + or + wrong = "rediculous" and right = "ridiculous" + or + wrong = "reedeming" and right = "redeeming" + or + wrong = "reenforced" and right = "reinforced" + or + wrong = "refect" and right = "reflect" + or + wrong = "refedendum" and right = "referendum" + or + wrong = "referal" and right = "referral" + or + wrong = "referece" and right = "reference" + or + wrong = "refereces" and right = "references" + or + wrong = "refered" and right = "referred" + or + wrong = "referemce" and right = "reference" + or + wrong = "referemces" and right = "references" + or + wrong = "referencs" and right = "references" + or + wrong = "referenece" and right = "reference" + or + wrong = "refereneced" and right = "referenced" + or + wrong = "refereneces" and right = "references" + or + wrong = "referiang" and right = "referring" + or + wrong = "refering" and right = "referring" + or + wrong = "refernce" and right = "reference" + or + wrong = "refernce" and right = "references" + or + wrong = "refernces" and right = "references" + or + wrong = "referrence" and right = "reference" + or + wrong = "referrences" and right = "references" + or + wrong = "referrs" and right = "refers" + or + wrong = "reffered" and right = "referred" + or + wrong = "refference" and right = "reference" + or + wrong = "reffering" and right = "referring" + or + wrong = "refrence" and right = "reference" + or + wrong = "refrences" and right = "references" + or + wrong = "refrers" and right = "refers" + or + wrong = "refridgeration" and right = "refrigeration" + or + wrong = "refridgerator" and right = "refrigerator" + or + wrong = "refromist" and right = "reformist" + or + wrong = "refusla" and right = "refusal" + or + wrong = "regardes" and right = "regards" + or + wrong = "regluar" and right = "regular" + or + wrong = "reguarly" and right = "regularly" + or + wrong = "regulaion" and right = "regulation" + or + wrong = "regulaotrs" and right = "regulators" + or + wrong = "regularily" and right = "regularly" + or + wrong = "rehersal" and right = "rehearsal" + or + wrong = "reicarnation" and right = "reincarnation" + or + wrong = "reigining" and right = "reigning" + or + wrong = "reknown" and right = "renown" + or + wrong = "reknowned" and right = "renowned" + or + wrong = "rela" and right = "real" + or + wrong = "relaly" and right = "really" + or + wrong = "relatiopnship" and right = "relationship" + or + wrong = "relativly" and right = "relatively" + or + wrong = "relected" and right = "reelected" + or + wrong = "releive" and right = "relieve" + or + wrong = "releived" and right = "relieved" + or + wrong = "releiver" and right = "reliever" + or + wrong = "releses" and right = "releases" + or + wrong = "relevence" and right = "relevance" + or + wrong = "relevent" and right = "relevant" + or + wrong = "reliablity" and right = "reliability" + or + wrong = "relient" and right = "reliant" + or + wrong = "religeous" and right = "religious" + or + wrong = "religous" and right = "religious" + or + wrong = "religously" and right = "religiously" + or + wrong = "relinqushment" and right = "relinquishment" + or + wrong = "relitavely" and right = "relatively" + or + wrong = "relized" and right = "realised" + or + wrong = "relized" and right = "realized" + or + wrong = "relpacement" and right = "replacement" + or + wrong = "remaing" and right = "remaining" + or + wrong = "remeber" and right = "remember" + or + wrong = "rememberable" and right = "memorable" + or + wrong = "rememberance" and right = "remembrance" + or + wrong = "remembrence" and right = "remembrance" + or + wrong = "remenant" and right = "remnant" + or + wrong = "remenicent" and right = "reminiscent" + or + wrong = "reminent" and right = "remnant" + or + wrong = "reminescent" and right = "reminiscent" + or + wrong = "reminscent" and right = "reminiscent" + or + wrong = "reminsicent" and right = "reminiscent" + or + wrong = "rendevous" and right = "rendezvous" + or + wrong = "rendezous" and right = "rendezvous" + or + wrong = "renedered" and right = "rende" + or + wrong = "renewl" and right = "renewal" + or + wrong = "rennovate" and right = "renovate" + or + wrong = "rennovated" and right = "renovated" + or + wrong = "rennovating" and right = "renovating" + or + wrong = "rennovation" and right = "renovation" + or + wrong = "rentors" and right = "renters" + or + wrong = "reoccurrence" and right = "recurrence" + or + wrong = "reorganision" and right = "reorganisation" + or + wrong = "repatition" and right = "repartition" + or + wrong = "repatition" and right = "repetition" + or + wrong = "repblic" and right = "republic" + or + wrong = "repblican" and right = "republican" + or + wrong = "repblicans" and right = "republicans" + or + wrong = "repblics" and right = "republics" + or + wrong = "repectively" and right = "respectively" + or + wrong = "repeition" and right = "repetition" + or + wrong = "repentence" and right = "repentance" + or + wrong = "repentent" and right = "repentant" + or + wrong = "repeteadly" and right = "repeatedly" + or + wrong = "repetion" and right = "repetition" + or + wrong = "repid" and right = "rapid" + or + wrong = "reponse" and right = "response" + or + wrong = "reponsible" and right = "responsible" + or + wrong = "reportadly" and right = "reportedly" + or + wrong = "represantative" and right = "representative" + or + wrong = "representive" and right = "representative" + or + wrong = "representives" and right = "representatives" + or + wrong = "reproducable" and right = "reproducible" + or + wrong = "reprtoire" and right = "repertoire" + or + wrong = "repsectively" and right = "respectively" + or + wrong = "reptition" and right = "repetition" + or + wrong = "repubic" and right = "republic" + or + wrong = "repubican" and right = "republican" + or + wrong = "repubicans" and right = "republicans" + or + wrong = "repubics" and right = "republics" + or + wrong = "republi" and right = "republic" + or + wrong = "republian" and right = "republican" + or + wrong = "republians" and right = "republicans" + or + wrong = "republis" and right = "republics" + or + wrong = "repulic" and right = "republic" + or + wrong = "repulican" and right = "republican" + or + wrong = "repulicans" and right = "republicans" + or + wrong = "repulics" and right = "republics" + or + wrong = "requirment" and right = "requirement" + or + wrong = "requred" and right = "required" + or + wrong = "resaurant" and right = "restaurant" + or + wrong = "resembelance" and right = "resemblance" + or + wrong = "resembes" and right = "resembles" + or + wrong = "resemblence" and right = "resemblance" + or + wrong = "resevoir" and right = "reservoir" + or + wrong = "residental" and right = "residential" + or + wrong = "resignement" and right = "resignment" + or + wrong = "resistable" and right = "resistible" + or + wrong = "resistence" and right = "resistance" + or + wrong = "resistent" and right = "resistant" + or + wrong = "respectivly" and right = "respectively" + or + wrong = "responce" and right = "response" + or + wrong = "responibilities" and right = "responsibilities" + or + wrong = "responisble" and right = "responsible" + or + wrong = "responnsibilty" and right = "responsibility" + or + wrong = "responsability" and right = "responsibility" + or + wrong = "responsibile" and right = "responsible" + or + wrong = "responsibilites" and right = "responsibilities" + or + wrong = "responsiblities" and right = "responsibilities" + or + wrong = "responsiblity" and right = "responsibility" + or + wrong = "ressemblance" and right = "resemblance" + or + wrong = "ressemble" and right = "resemble" + or + wrong = "ressembled" and right = "resembled" + or + wrong = "ressemblence" and right = "resemblance" + or + wrong = "ressembling" and right = "resembling" + or + wrong = "resssurecting" and right = "resurrecting" + or + wrong = "ressurect" and right = "resurrect" + or + wrong = "ressurected" and right = "resurrected" + or + wrong = "ressurection" and right = "resurrection" + or + wrong = "ressurrection" and right = "resurrection" + or + wrong = "restarant" and right = "restaurant" + or + wrong = "restarants" and right = "restaurants" + or + wrong = "restaraunt" and right = "restaurant" + or + wrong = "restaraunteur" and right = "restaurateur" + or + wrong = "restaraunteurs" and right = "restaurateurs" + or + wrong = "restaraunts" and right = "restaurants" + or + wrong = "restauranteurs" and right = "restaurateurs" + or + wrong = "restauration" and right = "restoration" + or + wrong = "restauraunt" and right = "restaurant" + or + wrong = "resteraunt" and right = "restaurant" + or + wrong = "resteraunts" and right = "restaurants" + or + wrong = "resticted" and right = "restricted" + or + wrong = "restraunt" and right = "restaurant" + or + wrong = "restraunt" and right = "restraint" + or + wrong = "resturant" and right = "restaurant" + or + wrong = "resturants" and right = "restaurants" + or + wrong = "resturaunt" and right = "restaurant" + or + wrong = "resturaunts" and right = "restaurants" + or + wrong = "resurecting" and right = "resurrecting" + or + wrong = "retalitated" and right = "retaliated" + or + wrong = "retalitation" and right = "retaliation" + or + wrong = "retreive" and right = "retrieve" + or + wrong = "retrive" and right = "retrieve" + or + wrong = "returnd" and right = "returned" + or + wrong = "revaluated" and right = "reevaluated" + or + wrong = "reveiw" and right = "review" + or + wrong = "reveral" and right = "reversal" + or + wrong = "reversable" and right = "reversible" + or + wrong = "revolutionar" and right = "revolutionary" + or + wrong = "rewitten" and right = "rewritten" + or + wrong = "rewriet" and right = "rewrite" + or + wrong = "rference" and right = "reference" + or + wrong = "rferences" and right = "references" + or + wrong = "rhymme" and right = "rhyme" + or + wrong = "rhythem" and right = "rhythm" + or + wrong = "rhythim" and right = "rhythm" + or + wrong = "rhytmic" and right = "rhythmic" + or + wrong = "rigeur" and right = "rigor" + or + wrong = "rigeur" and right = "rigour" + or + wrong = "rigeur" and right = "rigueur" + or + wrong = "rigourous" and right = "rigorous" + or + wrong = "rininging" and right = "ringing" + or + wrong = "rised" and right = "raised" + or + wrong = "rised" and right = "rose" + or + wrong = "rockerfeller" and right = "rockefeller" + or + wrong = "rococco" and right = "rococo" + or + wrong = "rocord" and right = "record" + or + wrong = "roomate" and right = "roommate" + or + wrong = "rougly" and right = "roughly" + or + wrong = "rucuperate" and right = "recuperate" + or + wrong = "rudimentatry" and right = "rudimentary" + or + wrong = "rulle" and right = "rule" + or + wrong = "runing" and right = "running" + or + wrong = "runnung" and right = "running" + or + wrong = "russina" and right = "russian" + or + wrong = "russion" and right = "russian" + or + wrong = "rwite" and right = "write" + or + wrong = "rythem" and right = "rhythm" + or + wrong = "rythim" and right = "rhythm" + or + wrong = "rythm" and right = "rhythm" + or + wrong = "rythmic" and right = "rhythmic" + or + wrong = "rythyms" and right = "rhythms" + or + wrong = "sacrafice" and right = "sacrifice" + or + wrong = "sacreligious" and right = "sacrilegious" + or + wrong = "sacremento" and right = "sacramento" + or + wrong = "sacrifical" and right = "sacrificial" + or + wrong = "saftey" and right = "safety" + or + wrong = "safty" and right = "safety" + or + wrong = "salery" and right = "salary" + or + wrong = "sanctionning" and right = "sanctioning" + or + wrong = "sandwhich" and right = "sandwich" + or + wrong = "sanhedrim" and right = "sanhedrin" + or + wrong = "santioned" and right = "sanctioned" + or + wrong = "sargant" and right = "sergeant" + or + wrong = "sargeant" and right = "sergeant" + or + wrong = "sasy" and right = "sassy" + or + wrong = "sasy" and right = "says" + or + wrong = "satelite" and right = "satellite" + or + wrong = "satelites" and right = "satellites" + or + wrong = "saterday" and right = "saturday" + or + wrong = "saterdays" and right = "saturdays" + or + wrong = "satisfactority" and right = "satisfactorily" + or + wrong = "satric" and right = "satiric" + or + wrong = "satrical" and right = "satirical" + or + wrong = "satrically" and right = "satirically" + or + wrong = "sattelite" and right = "satellite" + or + wrong = "sattelites" and right = "satellites" + or + wrong = "saught" and right = "sought" + or + wrong = "saveing" and right = "saving" + or + wrong = "saxaphone" and right = "saxophone" + or + wrong = "scaleable" and right = "scalable" + or + wrong = "scandanavia" and right = "scandinavia" + or + wrong = "scaricity" and right = "scarcity" + or + wrong = "scavanged" and right = "scavenged" + or + wrong = "schedual" and right = "schedule" + or + wrong = "scholarhip" and right = "scholarship" + or + wrong = "scholarstic" and right = "scholarly" + or + wrong = "scholarstic" and right = "scholastic" + or + wrong = "scientfic" and right = "scientific" + or + wrong = "scientifc" and right = "scientific" + or + wrong = "scientis" and right = "scientist" + or + wrong = "scince" and right = "science" + or + wrong = "scinece" and right = "science" + or + wrong = "scirpt" and right = "script" + or + wrong = "scoll" and right = "scroll" + or + wrong = "screenwrighter" and right = "screenwriter" + or + wrong = "scrutinity" and right = "scrutiny" + or + wrong = "scuptures" and right = "sculptures" + or + wrong = "seach" and right = "search" + or + wrong = "seached" and right = "searched" + or + wrong = "seaches" and right = "searches" + or + wrong = "secceeded" and right = "seceded" + or + wrong = "secceeded" and right = "succeeded" + or + wrong = "seceed" and right = "secede" + or + wrong = "seceed" and right = "succeed" + or + wrong = "seceeded" and right = "seceded" + or + wrong = "seceeded" and right = "succeeded" + or + wrong = "secratary" and right = "secretary" + or + wrong = "secretery" and right = "secretary" + or + wrong = "sedereal" and right = "sidereal" + or + wrong = "seeked" and right = "sought" + or + wrong = "segementation" and right = "segmentation" + or + wrong = "seguoys" and right = "segues" + or + wrong = "seige" and right = "siege" + or + wrong = "seing" and right = "seeing" + or + wrong = "seinor" and right = "senior" + or + wrong = "seldomly" and right = "seldom" + or + wrong = "senarios" and right = "scenarios" + or + wrong = "sence" and right = "sense" + or + wrong = "sence" and right = "since" + or + wrong = "senstive" and right = "sensitive" + or + wrong = "sensure" and right = "censure" + or + wrong = "seperate" and right = "separate" + or + wrong = "seperated" and right = "separated" + or + wrong = "seperately" and right = "separately" + or + wrong = "seperates" and right = "separates" + or + wrong = "seperating" and right = "separating" + or + wrong = "seperation" and right = "separation" + or + wrong = "seperatism" and right = "separatism" + or + wrong = "seperatist" and right = "separatist" + or + wrong = "seperator" and right = "separator" + or + wrong = "sepina" and right = "subpoena" + or + wrong = "sepulchure" and right = "sepulcher" + or + wrong = "sepulchure" and right = "sepulchre" + or + wrong = "sepulcre" and right = "sepulcher" + or + wrong = "sepulcre" and right = "sepulchre" + or + wrong = "sergent" and right = "sergeant" + or + wrong = "settelement" and right = "settlement" + or + wrong = "settlment" and right = "settlement" + or + wrong = "settting" and right = "setting" + or + wrong = "severeal" and right = "several" + or + wrong = "severley" and right = "severely" + or + wrong = "severly" and right = "severely" + or + wrong = "sevice" and right = "service" + or + wrong = "shadasloo" and right = "shadaloo" + or + wrong = "shaddow" and right = "shadow" + or + wrong = "shadoloo" and right = "shadaloo" + or + wrong = "shamen" and right = "shaman" + or + wrong = "shamen" and right = "shamans" + or + wrong = "sheat" and right = "cheat" + or + wrong = "sheat" and right = "sheath" + or + wrong = "sheat" and right = "sheet" + or + wrong = "sheild" and right = "shield" + or + wrong = "sherif" and right = "sheriff" + or + wrong = "shineing" and right = "shining" + or + wrong = "shiped" and right = "shipped" + or + wrong = "shiping" and right = "shipping" + or + wrong = "shopkeeepers" and right = "shopkeepers" + or + wrong = "shorly" and right = "shortly" + or + wrong = "shoudl" and right = "should" + or + wrong = "shoudln" and right = "should" + or + wrong = "shreak" and right = "shriek" + or + wrong = "shrinked" and right = "shrunk" + or + wrong = "sicne" and right = "since" + or + wrong = "sideral" and right = "sidereal" + or + wrong = "sieze" and right = "seize" + or + wrong = "sieze" and right = "size" + or + wrong = "siezed" and right = "seized" + or + wrong = "siezed" and right = "sized" + or + wrong = "siezing" and right = "seizing" + or + wrong = "siezing" and right = "sizing" + or + wrong = "siezure" and right = "seizure" + or + wrong = "siezures" and right = "seizures" + or + wrong = "siginificant" and right = "significant" + or + wrong = "signficant" and right = "significant" + or + wrong = "signficiant" and right = "significant" + or + wrong = "signfies" and right = "signifies" + or + wrong = "signifantly" and right = "significantly" + or + wrong = "significently" and right = "significantly" + or + wrong = "signifigant" and right = "significant" + or + wrong = "signifigantly" and right = "significantly" + or + wrong = "signitories" and right = "signatories" + or + wrong = "signitory" and right = "signatory" + or + wrong = "similarily" and right = "similarly" + or + wrong = "similiar" and right = "similar" + or + wrong = "similiarity" and right = "similarity" + or + wrong = "similiarly" and right = "similarly" + or + wrong = "simmilar" and right = "similar" + or + wrong = "simpley" and right = "simply" + or + wrong = "simplier" and right = "simpler" + or + wrong = "simultanous" and right = "simultaneous" + or + wrong = "simultanously" and right = "simultaneously" + or + wrong = "sincerley" and right = "sincerely" + or + wrong = "singsog" and right = "singsong" + or + wrong = "sinse" and right = "since" + or + wrong = "sinse" and right = "sines" + or + wrong = "sionist" and right = "zionist" + or + wrong = "sionists" and right = "zionists" + or + wrong = "sixtin" and right = "sistine" + or + wrong = "skagerak" and right = "skagerrak" + or + wrong = "skateing" and right = "skating" + or + wrong = "slaugterhouses" and right = "slaughterhouses" + or + wrong = "slighly" and right = "slightly" + or + wrong = "slippy" and right = "slippery" + or + wrong = "slowy" and right = "slowly" + or + wrong = "smae" and right = "same" + or + wrong = "smealting" and right = "smelting" + or + wrong = "smoe" and right = "some" + or + wrong = "sneeks" and right = "sneaks" + or + wrong = "snese" and right = "sneeze" + or + wrong = "socalism" and right = "socialism" + or + wrong = "socities" and right = "societies" + or + wrong = "soem" and right = "some" + or + wrong = "sofware" and right = "software" + or + wrong = "sohw" and right = "show" + or + wrong = "soilders" and right = "soldiers" + or + wrong = "solatary" and right = "solitary" + or + wrong = "soley" and right = "solely" + or + wrong = "soliders" and right = "soldiers" + or + wrong = "soliliquy" and right = "soliloquy" + or + wrong = "soluable" and right = "soluble" + or + wrong = "somene" and right = "someone" + or + wrong = "somtimes" and right = "sometimes" + or + wrong = "somwhere" and right = "somewhere" + or + wrong = "sophicated" and right = "sophisticated" + or + wrong = "sophmore" and right = "sophomore" + or + wrong = "sorceror" and right = "sorcerer" + or + wrong = "sorrounding" and right = "surrounding" + or + wrong = "sotry" and right = "story" + or + wrong = "sotyr" and right = "satyr" + or + wrong = "sotyr" and right = "story" + or + wrong = "soudn" and right = "sound" + or + wrong = "soudns" and right = "sounds" + or + wrong = "sould" and right = "could" + or + wrong = "sould" and right = "should" + or + wrong = "sould" and right = "sold" + or + wrong = "sould" and right = "soul" + or + wrong = "sountrack" and right = "soundtrack" + or + wrong = "sourth" and right = "south" + or + wrong = "sourthern" and right = "southern" + or + wrong = "souvenier" and right = "souvenir" + or + wrong = "souveniers" and right = "souvenirs" + or + wrong = "soveits" and right = "soviets" + or + wrong = "sovereignity" and right = "sovereignty" + or + wrong = "soverign" and right = "sovereign" + or + wrong = "soverignity" and right = "sovereignty" + or + wrong = "soverignty" and right = "sovereignty" + or + wrong = "spainish" and right = "spanish" + or + wrong = "speach" and right = "speech" + or + wrong = "specfic" and right = "specific" + or + wrong = "speciallized" and right = "specialised" + or + wrong = "speciallized" and right = "specialized" + or + wrong = "specif" and right = "specific" + or + wrong = "specif" and right = "specify" + or + wrong = "specifiying" and right = "specifying" + or + wrong = "speciman" and right = "specimen" + or + wrong = "spectauclar" and right = "spectacular" + or + wrong = "spectaulars" and right = "spectaculars" + or + wrong = "spects" and right = "aspects" + or + wrong = "spects" and right = "expects" + or + wrong = "spectum" and right = "spectrum" + or + wrong = "speices" and right = "species" + or + wrong = "spendour" and right = "splendour" + or + wrong = "spermatozoan" and right = "spermatozoon" + or + wrong = "spoace" and right = "space" + or + wrong = "sponser" and right = "sponsor" + or + wrong = "sponsered" and right = "sponsored" + or + wrong = "spontanous" and right = "spontaneous" + or + wrong = "sponzored" and right = "sponsored" + or + wrong = "spoonfulls" and right = "spoonfuls" + or + wrong = "sppeches" and right = "speeches" + or + wrong = "spreaded" and right = "spread" + or + wrong = "sprech" and right = "speech" + or + wrong = "spred" and right = "spread" + or + wrong = "spriritual" and right = "spiritual" + or + wrong = "spritual" and right = "spiritual" + or + wrong = "sqaure" and right = "square" + or + wrong = "sring" and right = "string" + or + wrong = "stablility" and right = "stability" + or + wrong = "stainlees" and right = "stainless" + or + wrong = "staion" and right = "station" + or + wrong = "standars" and right = "standards" + or + wrong = "stange" and right = "strange" + or + wrong = "startegic" and right = "strategic" + or + wrong = "startegies" and right = "strategies" + or + wrong = "startegy" and right = "strategy" + or + wrong = "stateman" and right = "statesman" + or + wrong = "statememts" and right = "statements" + or + wrong = "statment" and right = "statement" + or + wrong = "steriods" and right = "steroids" + or + wrong = "sterotypes" and right = "stereotypes" + or + wrong = "stilus" and right = "stylus" + or + wrong = "stingent" and right = "stringent" + or + wrong = "stiring" and right = "stirring" + or + wrong = "stirrs" and right = "stirs" + or + wrong = "stlye" and right = "style" + or + wrong = "stomache" and right = "stomach" + or + wrong = "stong" and right = "strong" + or + wrong = "stopry" and right = "story" + or + wrong = "storeis" and right = "stories" + or + wrong = "storise" and right = "stories" + or + wrong = "stornegst" and right = "strongest" + or + wrong = "stoyr" and right = "story" + or + wrong = "stpo" and right = "stop" + or + wrong = "stradegies" and right = "strategies" + or + wrong = "stradegy" and right = "strategy" + or + wrong = "strat" and right = "start" + or + wrong = "strat" and right = "strata" + or + wrong = "stratagically" and right = "strategically" + or + wrong = "streemlining" and right = "streamlining" + or + wrong = "stregth" and right = "strength" + or + wrong = "strenghen" and right = "strengthen" + or + wrong = "strenghened" and right = "strengthened" + or + wrong = "strenghening" and right = "strengthening" + or + wrong = "strenght" and right = "strength" + or + wrong = "strenghten" and right = "strengthen" + or + wrong = "strenghtened" and right = "strengthened" + or + wrong = "strenghtening" and right = "strengthening" + or + wrong = "strengtened" and right = "strengthened" + or + wrong = "strenous" and right = "strenuous" + or + wrong = "strictist" and right = "strictest" + or + wrong = "strikely" and right = "strikingly" + or + wrong = "strnad" and right = "strand" + or + wrong = "stroy" and right = "destroy" + or + wrong = "stroy" and right = "story" + or + wrong = "structual" and right = "structural" + or + wrong = "stubborness" and right = "stubbornness" + or + wrong = "stucture" and right = "structure" + or + wrong = "stuctured" and right = "structured" + or + wrong = "studdy" and right = "study" + or + wrong = "studing" and right = "studying" + or + wrong = "stuggling" and right = "struggling" + or + wrong = "sturcture" and right = "structure" + or + wrong = "subcatagories" and right = "subcategories" + or + wrong = "subcatagory" and right = "subcategory" + or + wrong = "subconsiously" and right = "subconsciously" + or + wrong = "subjudgation" and right = "subjugation" + or + wrong = "submachne" and right = "submachine" + or + wrong = "subpecies" and right = "subspecies" + or + wrong = "subsidary" and right = "subsidiary" + or + wrong = "subsiduary" and right = "subsidiary" + or + wrong = "subsquent" and right = "subsequent" + or + wrong = "subsquently" and right = "subsequently" + or + wrong = "substace" and right = "substance" + or + wrong = "substancial" and right = "substantial" + or + wrong = "substatial" and right = "substantial" + or + wrong = "substituded" and right = "substituted" + or + wrong = "substract" and right = "subtract" + or + wrong = "substracted" and right = "subtracted" + or + wrong = "substracting" and right = "subtracting" + or + wrong = "substraction" and right = "subtraction" + or + wrong = "substracts" and right = "subtracts" + or + wrong = "subtances" and right = "substances" + or + wrong = "subterranian" and right = "subterranean" + or + wrong = "suburburban" and right = "suburban" + or + wrong = "succceeded" and right = "succeeded" + or + wrong = "succcesses" and right = "successes" + or + wrong = "succedded" and right = "succeeded" + or + wrong = "succeded" and right = "succeeded" + or + wrong = "succeds" and right = "succeeds" + or + wrong = "succesful" and right = "successful" + or + wrong = "succesfully" and right = "successfully" + or + wrong = "succesfuly" and right = "successfully" + or + wrong = "succesion" and right = "succession" + or + wrong = "succesive" and right = "successive" + or + wrong = "successfull" and right = "successful" + or + wrong = "successully" and right = "successfully" + or + wrong = "succsess" and right = "success" + or + wrong = "succsessfull" and right = "successful" + or + wrong = "suceed" and right = "succeed" + or + wrong = "suceeded" and right = "succeeded" + or + wrong = "suceeding" and right = "succeeding" + or + wrong = "suceeds" and right = "succeeds" + or + wrong = "sucesful" and right = "successful" + or + wrong = "sucesfully" and right = "successfully" + or + wrong = "sucesfuly" and right = "successfully" + or + wrong = "sucesion" and right = "succession" + or + wrong = "sucess" and right = "success" + or + wrong = "sucesses" and right = "successes" + or + wrong = "sucessful" and right = "successful" + or + wrong = "sucessfull" and right = "successful" + or + wrong = "sucessfully" and right = "successfully" + or + wrong = "sucessfuly" and right = "successfully" + or + wrong = "sucession" and right = "succession" + or + wrong = "sucessive" and right = "successive" + or + wrong = "sucessor" and right = "successor" + or + wrong = "sucessot" and right = "successor" + or + wrong = "sucide" and right = "suicide" + or + wrong = "sucidial" and right = "suicidal" + or + wrong = "sudent" and right = "student" + or + wrong = "sudents" and right = "students" + or + wrong = "sufferage" and right = "suffrage" + or + wrong = "sufferred" and right = "suffered" + or + wrong = "sufferring" and right = "suffering" + or + wrong = "sufficent" and right = "sufficient" + or + wrong = "sufficently" and right = "sufficiently" + or + wrong = "sumary" and right = "summary" + or + wrong = "sunglases" and right = "sunglasses" + or + wrong = "suop" and right = "soup" + or + wrong = "superceeded" and right = "superseded" + or + wrong = "superintendant" and right = "superintendent" + or + wrong = "suphisticated" and right = "sophisticated" + or + wrong = "suplimented" and right = "supplemented" + or + wrong = "suported" and right = "supported" + or + wrong = "supose" and right = "suppose" + or + wrong = "suposed" and right = "supposed" + or + wrong = "suposedly" and right = "supposedly" + or + wrong = "suposes" and right = "supposes" + or + wrong = "suposing" and right = "supposing" + or + wrong = "supplamented" and right = "supplemented" + or + wrong = "suppliementing" and right = "supplementing" + or + wrong = "suppoed" and right = "supposed" + or + wrong = "supposingly" and right = "supposedly" + or + wrong = "suppy" and right = "supply" + or + wrong = "suprassing" and right = "surpassing" + or + wrong = "supress" and right = "suppress" + or + wrong = "supressed" and right = "suppressed" + or + wrong = "supresses" and right = "suppresses" + or + wrong = "supressing" and right = "suppressing" + or + wrong = "suprise" and right = "surprise" + or + wrong = "suprised" and right = "surprised" + or + wrong = "suprising" and right = "surprising" + or + wrong = "suprisingly" and right = "surprisingly" + or + wrong = "suprize" and right = "surprise" + or + wrong = "suprized" and right = "surprised" + or + wrong = "suprizing" and right = "surprising" + or + wrong = "suprizingly" and right = "surprisingly" + or + wrong = "surfce" and right = "surface" + or + wrong = "surley" and right = "surely" + or + wrong = "surley" and right = "surly" + or + wrong = "suround" and right = "surround" + or + wrong = "surounded" and right = "surrounded" + or + wrong = "surounding" and right = "surrounding" + or + wrong = "suroundings" and right = "surroundings" + or + wrong = "surounds" and right = "surrounds" + or + wrong = "surplanted" and right = "supplanted" + or + wrong = "surpress" and right = "suppress" + or + wrong = "surpressed" and right = "suppressed" + or + wrong = "surprize" and right = "surprise" + or + wrong = "surprized" and right = "surprised" + or + wrong = "surprizing" and right = "surprising" + or + wrong = "surprizingly" and right = "surprisingly" + or + wrong = "surrended" and right = "surrendered" + or + wrong = "surrended" and right = "surrounded" + or + wrong = "surrepetitious" and right = "surreptitious" + or + wrong = "surrepetitiously" and right = "surreptitiously" + or + wrong = "surreptious" and right = "surreptitious" + or + wrong = "surreptiously" and right = "surreptitiously" + or + wrong = "surronded" and right = "surrounded" + or + wrong = "surrouded" and right = "surrounded" + or + wrong = "surrouding" and right = "surrounding" + or + wrong = "surrundering" and right = "surrendering" + or + wrong = "surveilence" and right = "surveillance" + or + wrong = "surveill" and right = "surveil" + or + wrong = "surveyer" and right = "surveyor" + or + wrong = "surviver" and right = "survivor" + or + wrong = "survivers" and right = "survivors" + or + wrong = "survivied" and right = "survived" + or + wrong = "suseptable" and right = "susceptible" + or + wrong = "suseptible" and right = "susceptible" + or + wrong = "suspention" and right = "suspension" + or + wrong = "swaer" and right = "swear" + or + wrong = "swaers" and right = "swears" + or + wrong = "swepth" and right = "swept" + or + wrong = "swiming" and right = "swimming" + or + wrong = "syas" and right = "says" + or + wrong = "symetrical" and right = "symmetrical" + or + wrong = "symetrically" and right = "symmetrically" + or + wrong = "symetry" and right = "symmetry" + or + wrong = "symettric" and right = "symmetric" + or + wrong = "symmetral" and right = "symmetric" + or + wrong = "symmetricaly" and right = "symmetrically" + or + wrong = "synagouge" and right = "synagogue" + or + wrong = "syncronization" and right = "synchronization" + or + wrong = "synonomous" and right = "synonymous" + or + wrong = "synonymns" and right = "synonyms" + or + wrong = "synphony" and right = "symphony" + or + wrong = "syphyllis" and right = "syphilis" + or + wrong = "sypmtoms" and right = "symptoms" + or + wrong = "syrap" and right = "syrup" + or + wrong = "sysmatically" and right = "systematically" + or + wrong = "sytem" and right = "system" + or + wrong = "sytle" and right = "style" + or + wrong = "tabacco" and right = "tobacco" + or + wrong = "tahn" and right = "than" + or + wrong = "taht" and right = "that" + or + wrong = "talekd" and right = "talked" + or + wrong = "targetted" and right = "targeted" + or + wrong = "targetting" and right = "targeting" + or + wrong = "tast" and right = "taste" + or + wrong = "tath" and right = "that" + or + wrong = "tatoo" and right = "tattoo" + or + wrong = "tattooes" and right = "tattoos" + or + wrong = "taxanomic" and right = "taxonomic" + or + wrong = "taxanomy" and right = "taxonomy" + or + wrong = "teached" and right = "taught" + or + wrong = "techician" and right = "technician" + or + wrong = "techicians" and right = "technicians" + or + wrong = "techiniques" and right = "techniques" + or + wrong = "technitian" and right = "technician" + or + wrong = "technnology" and right = "technology" + or + wrong = "technolgy" and right = "technology" + or + wrong = "teh" and right = "the" + or + wrong = "tehy" and right = "they" + or + wrong = "telelevision" and right = "television" + or + wrong = "televsion" and right = "television" + or + wrong = "telphony" and right = "telephony" + or + wrong = "temerature" and right = "temperature" + or + wrong = "tempalte" and right = "template" + or + wrong = "tempaltes" and right = "templates" + or + wrong = "temparate" and right = "temperate" + or + wrong = "temperarily" and right = "temporarily" + or + wrong = "temperment" and right = "temperament" + or + wrong = "tempertaure" and right = "temperature" + or + wrong = "temperture" and right = "temperature" + or + wrong = "temprary" and right = "temporary" + or + wrong = "tenacle" and right = "tentacle" + or + wrong = "tenacles" and right = "tentacles" + or + wrong = "tendacy" and right = "tendency" + or + wrong = "tendancies" and right = "tendencies" + or + wrong = "tendancy" and right = "tendency" + or + wrong = "tepmorarily" and right = "temporarily" + or + wrong = "terrestial" and right = "terrestrial" + or + wrong = "terriories" and right = "territories" + or + wrong = "terriory" and right = "territory" + or + wrong = "territorist" and right = "terrorist" + or + wrong = "territoy" and right = "territory" + or + wrong = "terroist" and right = "terrorist" + or + wrong = "testiclular" and right = "testicular" + or + wrong = "testomony" and right = "testimony" + or + wrong = "tghe" and right = "the" + or + wrong = "thast" and right = "that" + or + wrong = "theather" and right = "theater" + or + wrong = "theese" and right = "these" + or + wrong = "theif" and right = "thief" + or + wrong = "theives" and right = "thieves" + or + wrong = "themselfs" and right = "themselves" + or + wrong = "themslves" and right = "themselves" + or + wrong = "ther" and right = "the" + or + wrong = "ther" and right = "their" + or + wrong = "ther" and right = "there" + or + wrong = "therafter" and right = "thereafter" + or + wrong = "therby" and right = "thereby" + or + wrong = "theri" and right = "their" + or + wrong = "thgat" and right = "that" + or + wrong = "thge" and right = "the" + or + wrong = "thier" and right = "their" + or + wrong = "thign" and right = "thing" + or + wrong = "thigns" and right = "things" + or + wrong = "thigsn" and right = "things" + or + wrong = "thikn" and right = "think" + or + wrong = "thikning" and right = "thickening" + or + wrong = "thikning" and right = "thinking" + or + wrong = "thikns" and right = "thinks" + or + wrong = "thiunk" and right = "think" + or + wrong = "thn" and right = "then" + or + wrong = "thna" and right = "than" + or + wrong = "thne" and right = "then" + or + wrong = "thnig" and right = "thing" + or + wrong = "thnigs" and right = "things" + or + wrong = "thoughout" and right = "throughout" + or + wrong = "threatend" and right = "threatened" + or + wrong = "threatning" and right = "threatening" + or + wrong = "threee" and right = "three" + or + wrong = "threshhold" and right = "threshold" + or + wrong = "thrid" and right = "third" + or + wrong = "throrough" and right = "thorough" + or + wrong = "throughly" and right = "thoroughly" + or + wrong = "throught" and right = "thought" + or + wrong = "throught" and right = "through" + or + wrong = "throught" and right = "throughout" + or + wrong = "througout" and right = "throughout" + or + wrong = "thru" and right = "through" + or + wrong = "thsi" and right = "this" + or + wrong = "thsoe" and right = "those" + or + wrong = "thta" and right = "that" + or + wrong = "thyat" and right = "that" + or + wrong = "tiem" and right = "tim" + or + wrong = "tiem" and right = "time" + or + wrong = "tihkn" and right = "think" + or + wrong = "tihs" and right = "this" + or + wrong = "timne" and right = "time" + or + wrong = "tiome" and right = "time" + or + wrong = "tiome" and right = "tome" + or + wrong = "tje" and right = "the" + or + wrong = "tjhe" and right = "the" + or + wrong = "tjpanishad" and right = "upanishad" + or + wrong = "tkae" and right = "take" + or + wrong = "tkaes" and right = "takes" + or + wrong = "tkaing" and right = "taking" + or + wrong = "tlaking" and right = "talking" + or + wrong = "tobbaco" and right = "tobacco" + or + wrong = "todya" and right = "today" + or + wrong = "toghether" and right = "together" + or + wrong = "toke" and right = "took" + or + wrong = "tolerence" and right = "tolerance" + or + wrong = "tolkein" and right = "tolkien" + or + wrong = "tomatos" and right = "tomatoes" + or + wrong = "tommorow" and right = "tomorrow" + or + wrong = "tommorrow" and right = "tomorrow" + or + wrong = "tongiht" and right = "tonight" + or + wrong = "toriodal" and right = "toroidal" + or + wrong = "tormenters" and right = "tormentors" + or + wrong = "tornadoe" and right = "tornado" + or + wrong = "torpeados" and right = "torpedoes" + or + wrong = "torpedos" and right = "torpedoes" + or + wrong = "tortise" and right = "tortoise" + or + wrong = "toubles" and right = "troubles" + or + wrong = "tounge" and right = "tongue" + or + wrong = "tourch" and right = "torch" + or + wrong = "tourch" and right = "touch" + or + wrong = "towords" and right = "towards" + or + wrong = "towrad" and right = "toward" + or + wrong = "tradionally" and right = "traditionally" + or + wrong = "traditionaly" and right = "traditionally" + or + wrong = "traditionnal" and right = "traditional" + or + wrong = "traditition" and right = "tradition" + or + wrong = "tradtionally" and right = "traditionally" + or + wrong = "trafficed" and right = "trafficked" + or + wrong = "trafficing" and right = "trafficking" + or + wrong = "trafic" and right = "traffic" + or + wrong = "trancendent" and right = "transcendent" + or + wrong = "trancending" and right = "transcending" + or + wrong = "tranform" and right = "transform" + or + wrong = "tranformed" and right = "transformed" + or + wrong = "transcendance" and right = "transcendence" + or + wrong = "transcendant" and right = "transcendent" + or + wrong = "transcendentational" and right = "transcendental" + or + wrong = "transcripting" and right = "transcribing" + or + wrong = "transcripting" and right = "transcription" + or + wrong = "transending" and right = "transcending" + or + wrong = "transesxuals" and right = "transsexuals" + or + wrong = "transfered" and right = "transferred" + or + wrong = "transfering" and right = "transferring" + or + wrong = "transformaton" and right = "transformation" + or + wrong = "transistion" and right = "transition" + or + wrong = "translater" and right = "translator" + or + wrong = "translaters" and right = "translators" + or + wrong = "transmissable" and right = "transmissible" + or + wrong = "transporation" and right = "transportation" + or + wrong = "tremelo" and right = "tremolo" + or + wrong = "tremelos" and right = "tremolos" + or + wrong = "treshold" and right = "threshold" + or + wrong = "triguered" and right = "triggered" + or + wrong = "triology" and right = "trilogy" + or + wrong = "troling" and right = "trolling" + or + wrong = "troup" and right = "troupe" + or + wrong = "troups" and right = "troops" + or + wrong = "troups" and right = "troupes" + or + wrong = "truely" and right = "truly" + or + wrong = "trustworthyness" and right = "trustworthiness" + or + wrong = "turnk" and right = "trunk" + or + wrong = "turnk" and right = "turnkey" + or + wrong = "tuscon" and right = "tucson" + or + wrong = "tust" and right = "trust" + or + wrong = "twelth" and right = "twelfth" + or + wrong = "twon" and right = "town" + or + wrong = "twpo" and right = "two" + or + wrong = "tyhat" and right = "that" + or + wrong = "tyhe" and right = "they" + or + wrong = "typcial" and right = "typical" + or + wrong = "typicaly" and right = "typically" + or + wrong = "tyranies" and right = "tyrannies" + or + wrong = "tyrany" and right = "tyranny" + or + wrong = "tyrranies" and right = "tyrannies" + or + wrong = "tyrrany" and right = "tyranny" + or + wrong = "ubiquitious" and right = "ubiquitous" + or + wrong = "ublisher" and right = "publisher" + or + wrong = "udpate" and right = "update" + or + wrong = "uise" and right = "use" + or + wrong = "ukranian" and right = "ukrainian" + or + wrong = "ultimely" and right = "ultimately" + or + wrong = "unacompanied" and right = "unaccompanied" + or + wrong = "unahppy" and right = "unhappy" + or + wrong = "unanymous" and right = "unanimous" + or + wrong = "unathorised" and right = "unauthorised" + or + wrong = "unavailible" and right = "unavailable" + or + wrong = "unballance" and right = "unbalance" + or + wrong = "unbeknowst" and right = "unbeknownst" + or + wrong = "unbeleivable" and right = "unbelievable" + or + wrong = "uncertainity" and right = "uncertainty" + or + wrong = "unchallengable" and right = "unchallengeable" + or + wrong = "unchangable" and right = "unchangeable" + or + wrong = "uncompetive" and right = "uncompetitive" + or + wrong = "unconcious" and right = "unconscious" + or + wrong = "unconciousness" and right = "unconsciousness" + or + wrong = "unconfortability" and right = "discomfort" + or + wrong = "uncontitutional" and right = "unconstitutional" + or + wrong = "unconvential" and right = "unconventional" + or + wrong = "undecideable" and right = "undecidable" + or + wrong = "understoon" and right = "understood" + or + wrong = "undesireable" and right = "undesirable" + or + wrong = "undetecable" and right = "undetectable" + or + wrong = "undoubtely" and right = "undoubtedly" + or + wrong = "undreground" and right = "underground" + or + wrong = "uneccesary" and right = "unnecessary" + or + wrong = "unecessary" and right = "unnecessary" + or + wrong = "unequalities" and right = "inequalities" + or + wrong = "unforetunately" and right = "unfortunately" + or + wrong = "unforgetable" and right = "unforgettable" + or + wrong = "unforgiveable" and right = "unforgivable" + or + wrong = "unforseen" and right = "unforeseen" + or + wrong = "unfortunatley" and right = "unfortunately" + or + wrong = "unfortunatly" and right = "unfortunately" + or + wrong = "unfourtunately" and right = "unfortunately" + or + wrong = "unihabited" and right = "uninhabited" + or + wrong = "unilateraly" and right = "unilaterally" + or + wrong = "unilatreal" and right = "unilateral" + or + wrong = "unilatreally" and right = "unilaterally" + or + wrong = "uninterruped" and right = "uninterrupted" + or + wrong = "uninterupted" and right = "uninterrupted" + or + wrong = "unintialized" and right = "uninitialized" + or + wrong = "unitesstates" and right = "unitedstates" + or + wrong = "univeral" and right = "universal" + or + wrong = "univeristies" and right = "universities" + or + wrong = "univeristy" and right = "university" + or + wrong = "univerity" and right = "university" + or + wrong = "universtiy" and right = "university" + or + wrong = "univesities" and right = "universities" + or + wrong = "univesity" and right = "university" + or + wrong = "unkown" and right = "unknown" + or + wrong = "unlikey" and right = "unlikely" + or + wrong = "unmanouverable" and right = "unmaneuverable" + or + wrong = "unmanouverable" and right = "unmanoeuvrable" + or + wrong = "unmistakeably" and right = "unmistakably" + or + wrong = "unneccesarily" and right = "unnecessarily" + or + wrong = "unneccesary" and right = "unnecessary" + or + wrong = "unneccessarily" and right = "unnecessarily" + or + wrong = "unneccessary" and right = "unnecessary" + or + wrong = "unnecesarily" and right = "unnecessarily" + or + wrong = "unnecesary" and right = "unnecessary" + or + wrong = "unoffical" and right = "unofficial" + or + wrong = "unoperational" and right = "nonoperational" + or + wrong = "unoticeable" and right = "unnoticeable" + or + wrong = "unplease" and right = "displease" + or + wrong = "unplesant" and right = "unpleasant" + or + wrong = "unprecendented" and right = "unprecedented" + or + wrong = "unprecidented" and right = "unprecedented" + or + wrong = "unrepentent" and right = "unrepentant" + or + wrong = "unrepetant" and right = "unrepentant" + or + wrong = "unrepetent" and right = "unrepentant" + or + wrong = "unsed" and right = "unsaid" + or + wrong = "unsed" and right = "unused" + or + wrong = "unsed" and right = "used" + or + wrong = "unsubstanciated" and right = "unsubstantiated" + or + wrong = "unsuccesful" and right = "unsuccessful" + or + wrong = "unsuccesfully" and right = "unsuccessfully" + or + wrong = "unsuccessfull" and right = "unsuccessful" + or + wrong = "unsucesful" and right = "unsuccessful" + or + wrong = "unsucesfuly" and right = "unsuccessfully" + or + wrong = "unsucessful" and right = "unsuccessful" + or + wrong = "unsucessfull" and right = "unsuccessful" + or + wrong = "unsucessfully" and right = "unsuccessfully" + or + wrong = "unsuprised" and right = "unsurprised" + or + wrong = "unsuprising" and right = "unsurprising" + or + wrong = "unsuprisingly" and right = "unsurprisingly" + or + wrong = "unsuprized" and right = "unsurprised" + or + wrong = "unsuprizing" and right = "unsurprising" + or + wrong = "unsuprizingly" and right = "unsurprisingly" + or + wrong = "unsurprized" and right = "unsurprised" + or + wrong = "unsurprizing" and right = "unsurprising" + or + wrong = "unsurprizingly" and right = "unsurprisingly" + or + wrong = "untill" and right = "until" + or + wrong = "untranslateable" and right = "untranslatable" + or + wrong = "unuseable" and right = "unusable" + or + wrong = "unusuable" and right = "unusable" + or + wrong = "unviersity" and right = "university" + or + wrong = "unwarrented" and right = "unwarranted" + or + wrong = "unweildly" and right = "unwieldy" + or + wrong = "unwieldly" and right = "unwieldy" + or + wrong = "upcomming" and right = "upcoming" + or + wrong = "upgradded" and right = "upgraded" + or + wrong = "usally" and right = "usually" + or + wrong = "useage" and right = "usage" + or + wrong = "usefull" and right = "useful" + or + wrong = "usefuly" and right = "usefully" + or + wrong = "useing" and right = "using" + or + wrong = "usualy" and right = "usually" + or + wrong = "ususally" and right = "usually" + or + wrong = "vaccum" and right = "vacuum" + or + wrong = "vaccume" and right = "vacuum" + or + wrong = "vacinity" and right = "vicinity" + or + wrong = "vaguaries" and right = "vagaries" + or + wrong = "vaieties" and right = "varieties" + or + wrong = "vailidty" and right = "validity" + or + wrong = "valetta" and right = "valletta" + or + wrong = "valuble" and right = "valuable" + or + wrong = "valueable" and right = "valuable" + or + wrong = "varations" and right = "variations" + or + wrong = "varient" and right = "variant" + or + wrong = "variey" and right = "variety" + or + wrong = "varing" and right = "varying" + or + wrong = "varities" and right = "varieties" + or + wrong = "varity" and right = "variety" + or + wrong = "vasall" and right = "vassal" + or + wrong = "vasalls" and right = "vassals" + or + wrong = "vaule" and right = "value" + or + wrong = "vegatarian" and right = "vegetarian" + or + wrong = "vegitable" and right = "vegetable" + or + wrong = "vegitables" and right = "vegetables" + or + wrong = "vegtable" and right = "vegetable" + or + wrong = "vehicule" and right = "vehicle" + or + wrong = "vell" and right = "well" + or + wrong = "venemous" and right = "venomous" + or + wrong = "vengance" and right = "vengeance" + or + wrong = "vengence" and right = "vengeance" + or + wrong = "verfication" and right = "verification" + or + wrong = "verison" and right = "version" + or + wrong = "verisons" and right = "versions" + or + wrong = "vermillion" and right = "vermilion" + or + wrong = "versitilaty" and right = "versatility" + or + wrong = "versitlity" and right = "versatility" + or + wrong = "vetween" and right = "between" + or + wrong = "veyr" and right = "very" + or + wrong = "vigeur" and right = "vigor" + or + wrong = "vigeur" and right = "vigour" + or + wrong = "vigeur" and right = "vigueur" + or + wrong = "vigilence" and right = "vigilance" + or + wrong = "vigourous" and right = "vigorous" + or + wrong = "villian" and right = "villain" + or + wrong = "villification" and right = "vilification" + or + wrong = "villify" and right = "vilify" + or + wrong = "villin" and right = "villain" + or + wrong = "villin" and right = "villein" + or + wrong = "villin" and right = "villi" + or + wrong = "vincinity" and right = "vicinity" + or + wrong = "violentce" and right = "violence" + or + wrong = "virtualy" and right = "virtually" + or + wrong = "virutal" and right = "virtual" + or + wrong = "virutally" and right = "virtually" + or + wrong = "visable" and right = "visible" + or + wrong = "visably" and right = "visibly" + or + wrong = "visting" and right = "visiting" + or + wrong = "vistors" and right = "visitors" + or + wrong = "vitories" and right = "victories" + or + wrong = "volcanoe" and right = "volcano" + or + wrong = "voleyball" and right = "volleyball" + or + wrong = "volontary" and right = "voluntary" + or + wrong = "volonteer" and right = "volunteer" + or + wrong = "volonteered" and right = "volunteered" + or + wrong = "volonteering" and right = "volunteering" + or + wrong = "volonteers" and right = "volunteers" + or + wrong = "volounteer" and right = "volunteer" + or + wrong = "volounteered" and right = "volunteered" + or + wrong = "volounteering" and right = "volunteering" + or + wrong = "volounteers" and right = "volunteers" + or + wrong = "volumne" and right = "volume" + or + wrong = "vreity" and right = "variety" + or + wrong = "vrey" and right = "very" + or + wrong = "vriety" and right = "variety" + or + wrong = "vulnerablility" and right = "vulnerability" + or + wrong = "vyer" and right = "very" + or + wrong = "vyre" and right = "very" + or + wrong = "waht" and right = "what" + or + wrong = "warantee" and right = "warranty" + or + wrong = "wardobe" and right = "wardrobe" + or + wrong = "warrent" and right = "warrant" + or + wrong = "warrriors" and right = "warriors" + or + wrong = "wass" and right = "was" + or + wrong = "watn" and right = "want" + or + wrong = "wayword" and right = "wayward" + or + wrong = "weaponary" and right = "weaponry" + or + wrong = "weas" and right = "was" + or + wrong = "wehn" and right = "when" + or + wrong = "weild" and right = "wield" + or + wrong = "weild" and right = "wild" + or + wrong = "weilded" and right = "wielded" + or + wrong = "wendsay" and right = "wednesday" + or + wrong = "wensday" and right = "wednesday" + or + wrong = "wereabouts" and right = "whereabouts" + or + wrong = "whant" and right = "want" + or + wrong = "whants" and right = "wants" + or + wrong = "whcih" and right = "which" + or + wrong = "wheras" and right = "whereas" + or + wrong = "wherease" and right = "whereas" + or + wrong = "whereever" and right = "wherever" + or + wrong = "whic" and right = "which" + or + wrong = "whihc" and right = "which" + or + wrong = "whith" and right = "with" + or + wrong = "whlch" and right = "which" + or + wrong = "whn" and right = "when" + or + wrong = "wholey" and right = "wholly" + or + wrong = "wholy" and right = "holy" + or + wrong = "wholy" and right = "wholly" + or + wrong = "whta" and right = "what" + or + wrong = "whther" and right = "whether" + or + wrong = "wich" and right = "which" + or + wrong = "wich" and right = "witch" + or + wrong = "widesread" and right = "widespread" + or + wrong = "wief" and right = "wife" + or + wrong = "wierd" and right = "weird" + or + wrong = "wiew" and right = "view" + or + wrong = "wih" and right = "with" + or + wrong = "wiht" and right = "with" + or + wrong = "wille" and right = "will" + or + wrong = "willingless" and right = "willingness" + or + wrong = "willk" and right = "will" + or + wrong = "wirting" and right = "writing" + or + wrong = "withdrawl" and right = "withdraw" + or + wrong = "withdrawl" and right = "withdrawal" + or + wrong = "witheld" and right = "withheld" + or + wrong = "withh" and right = "with" + or + wrong = "withing" and right = "within" + or + wrong = "withold" and right = "withhold" + or + wrong = "witht" and right = "with" + or + wrong = "witn" and right = "with" + or + wrong = "wiull" and right = "will" + or + wrong = "wnat" and right = "want" + or + wrong = "wnated" and right = "wanted" + or + wrong = "wnats" and right = "wants" + or + wrong = "wohle" and right = "whole" + or + wrong = "wokr" and right = "work" + or + wrong = "wokring" and right = "working" + or + wrong = "wonderfull" and right = "wonderful" + or + wrong = "wordlwide" and right = "worldwide" + or + wrong = "workststion" and right = "workstation" + or + wrong = "worls" and right = "world" + or + wrong = "worstened" and right = "worsened" + or + wrong = "woudl" and right = "would" + or + wrong = "wresters" and right = "wrestlers" + or + wrong = "wriet" and right = "write" + or + wrong = "writen" and right = "written" + or + wrong = "wroet" and right = "wrote" + or + wrong = "wrok" and right = "work" + or + wrong = "wroking" and right = "working" + or + wrong = "wtih" and right = "with" + or + wrong = "wupport" and right = "support" + or + wrong = "xenophoby" and right = "xenophobia" + or + wrong = "yaching" and right = "yachting" + or + wrong = "yaer" and right = "year" + or + wrong = "yaerly" and right = "yearly" + or + wrong = "yaers" and right = "years" + or + wrong = "yatch" and right = "yacht" + or + wrong = "yearm" and right = "year" + or + wrong = "yeasr" and right = "years" + or + wrong = "yeild" and right = "yield" + or + wrong = "yeilding" and right = "yielding" + or + wrong = "yementite" and right = "yemeni" + or + wrong = "yementite" and right = "yemenite" + or + wrong = "yera" and right = "year" + or + wrong = "yeras" and right = "years" + or + wrong = "yersa" and right = "years" + or + wrong = "yotube" and right = "youtube" + or + wrong = "youseff" and right = "yousef" + or + wrong = "youself" and right = "yourself" + or + wrong = "yrea" and right = "year" + or + wrong = "ytou" and right = "you" + or + wrong = "yuo" and right = "you" + or + wrong = "zeebra" and right = "zebra" +} diff --git a/ql/ql/src/codeql_ql/style/docs/NonUSSpellingQuery.qll b/ql/ql/src/codeql_ql/style/docs/NonUSSpellingQuery.qll deleted file mode 100644 index 43036ed53c3..00000000000 --- a/ql/ql/src/codeql_ql/style/docs/NonUSSpellingQuery.qll +++ /dev/null @@ -1,24 +0,0 @@ -predicate non_us_word(string wrong, string right) { - exists(string s | - wrong = s.splitAt("/", 0) and - right = s.splitAt("/", 1) and - s = - [ - "colour/color", "authorise/authorize", "analyse/analyze", "behaviour/behavior", - "modelling/modeling", "modelled/modeled" - ] - ) -} - -bindingset[s] -predicate contains_non_us_spelling(string s, string wrong, string right) { - non_us_word(wrong, right) and - ( - s.matches("%" + wrong + "%") and - wrong != "analyse" - or - // analyses (as a noun) is fine - s.regexpReplaceAll("[\\r\\n]", " ").regexpMatch(".*analyse[^s].*") and - wrong = "analyse" - ) -} diff --git a/ql/ql/src/queries/style/Misspelling.ql b/ql/ql/src/queries/style/Misspelling.ql new file mode 100644 index 00000000000..2d7860513d8 --- /dev/null +++ b/ql/ql/src/queries/style/Misspelling.ql @@ -0,0 +1,18 @@ +/** + * @name Misspelling + * @description Names and comments in QL should use US spelling and avoid common misspellings. + * @kind problem + * @problem.severity warning + * @id ql/misspelling + * @tags maintainability + * @precision very-high + */ + +import ql +import codeql_ql.style.MisspellingQuery + +from AstNode node, string nodeKind, string wrong, string right, string mistake +where misspelled_element(node, nodeKind, wrong, right, mistake) +select node, + "This " + nodeKind + " contains the " + mistake + " '" + wrong + "', which should instead be '" + + right + "'." diff --git a/ql/ql/src/queries/style/NameCasing.ql b/ql/ql/src/queries/style/NameCasing.ql index 330933149f4..e9cfb46c145 100644 --- a/ql/ql/src/queries/style/NameCasing.ql +++ b/ql/ql/src/queries/style/NameCasing.ql @@ -10,14 +10,15 @@ import ql import codeql_ql.style.AcronymsShouldBeCamelCaseQuery as AcronymsQuery +import codeql_ql.style.NodeName as NodeName predicate shouldBeUpperCase(AstNode node, string name, string kind) { - name = AcronymsQuery::getName(node, kind) and + name = NodeName::getName(node, kind) and kind = ["class", "newtypeBranch", "newtype", "module", "import"] } predicate shouldBeLowerCase(AstNode node, string name, string kind) { - name = AcronymsQuery::getName(node, kind) and + name = NodeName::getName(node, kind) and not shouldBeUpperCase(node, name, kind) } diff --git a/ql/ql/src/queries/style/OverridingParameterName.ql b/ql/ql/src/queries/style/OverridingParameterName.ql index 6973c046ae0..5d61072abc4 100644 --- a/ql/ql/src/queries/style/OverridingParameterName.ql +++ b/ql/ql/src/queries/style/OverridingParameterName.ql @@ -1,5 +1,5 @@ /** - * @name Using a different paramater name than used in the super-predicate. + * @name Using a different parameter name than used in the super-predicate. * @description Using another parameter can be an indication of copy-pasted code, or a mistake. * @kind problem * @problem.severity warning diff --git a/ql/ql/src/queries/style/docs/NonUSSpelling.ql b/ql/ql/src/queries/style/docs/NonUSSpelling.ql deleted file mode 100644 index 8d71eeaed74..00000000000 --- a/ql/ql/src/queries/style/docs/NonUSSpelling.ql +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @name Non US spelling - * @description QLDocs shold use US spelling. - * @kind problem - * @problem.severity warning - * @id ql/non-us-spelling - * @tags maintainability - * @precision very-high - */ - -import ql -import codeql_ql.style.docs.NonUSSpellingQuery - -from QLDoc doc, string wrong, string right -where contains_non_us_spelling(doc.getContents().toLowerCase(), wrong, right) -select doc, - "This QLDoc comment contains the non-US spelling '" + wrong + "', which should instead be '" + - right + "'." diff --git a/ql/ql/test/TestUtilities/InlineExpectationsTest.qll b/ql/ql/test/TestUtilities/InlineExpectationsTest.qll index a4d264b2703..3891fcf13a1 100644 --- a/ql/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/ql/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -181,7 +181,7 @@ private string expectationCommentPattern() { result = "\\s*\\$((?:[^/]|/[^/])*)( /** * The possible columns in an expectation comment. The `TDefaultColumn` branch represents the first * column in a comment. This column is not precedeeded by a name. `TNamedColumn(name)` represents a - * column containing expected results preceeded by the string `name:`. + * column containing expected results preceded by the string `name:`. */ private newtype TColumn = TDefaultColumn() or diff --git a/ql/ql/test/queries/performance/VarUnusedInDisjunct/Test.qll b/ql/ql/test/queries/performance/VarUnusedInDisjunct/Test.qll index 9fde97a3544..2a1bc76711e 100644 --- a/ql/ql/test/queries/performance/VarUnusedInDisjunct/Test.qll +++ b/ql/ql/test/queries/performance/VarUnusedInDisjunct/Test.qll @@ -69,7 +69,7 @@ predicate mixed1(Big good, Small small) { good = any(Big bad | small.toString().matches("%foo") and - // the use of good is fine, the comparison futher up binds it. + // the use of good is fine, the comparison further up binds it. // the same is not true for bad. (bad.toString().matches("%foo") or good.toString().regexpMatch("foo.*")) and small.toString().regexpMatch(".*foo") diff --git a/ql/ql/test/queries/style/Misspelling/Misspelling.expected b/ql/ql/test/queries/style/Misspelling/Misspelling.expected new file mode 100644 index 00000000000..dc028c412d8 --- /dev/null +++ b/ql/ql/test/queries/style/Misspelling/Misspelling.expected @@ -0,0 +1,6 @@ +| Test.qll:1:1:3:3 | QLDoc | This QLDoc comment contains the common misspelling 'mispelled', which should instead be 'misspelled'. | +| Test.qll:4:1:11:1 | Class PublicallyAccessible | This class name contains the common misspelling 'publically', which should instead be 'publicly'. | +| Test.qll:5:3:5:20 | FieldDecl | This field name contains the common misspelling 'occurences', which should instead be 'occurrences'. | +| Test.qll:10:3:10:36 | ClassPredicate hasAgrument | This classPredicate name contains the common misspelling 'agrument', which should instead be 'argument'. | +| Test.qll:13:1:16:3 | QLDoc | This QLDoc comment contains the non-US spelling 'colour', which should instead be 'color'. | +| Test.qll:17:1:22:1 | Class AnalysedInt | This class name contains the non-US spelling 'analysed', which should instead be 'analyzed'. | diff --git a/ql/ql/test/queries/style/Misspelling/Misspelling.qlref b/ql/ql/test/queries/style/Misspelling/Misspelling.qlref new file mode 100644 index 00000000000..afbcaf951f3 --- /dev/null +++ b/ql/ql/test/queries/style/Misspelling/Misspelling.qlref @@ -0,0 +1 @@ +queries/style/Misspelling.ql \ No newline at end of file diff --git a/ql/ql/test/queries/style/Misspelling/Test.qll b/ql/ql/test/queries/style/Misspelling/Test.qll new file mode 100644 index 00000000000..f49f4633c6b --- /dev/null +++ b/ql/ql/test/queries/style/Misspelling/Test.qll @@ -0,0 +1,22 @@ +/** + * A string that's deliberately mispelled (and so is that last word). + */ +class PublicallyAccessible extends string { + int numOccurences; // should be 'occurrences' + + PublicallyAccessible() { this = "publically" and numOccurences = 123 } + + // should be argument + predicate hasAgrument() { none() } +} + +/** + * A class whose name contains a British-English spelling. + * And here's the word 'colour'. + */ +class AnalysedInt extends int { + AnalysedInt() { this = 7 } + + // 'analyses' should not be flagged + int numAnalyses() { result = 1 } +} diff --git a/ruby/Cargo.lock b/ruby/Cargo.lock index 75db597d564..8d539255d93 100644 Binary files a/ruby/Cargo.lock and b/ruby/Cargo.lock differ diff --git a/ruby/extractor/Cargo.toml b/ruby/extractor/Cargo.toml index 56afbacc031..9375f47a42a 100644 --- a/ruby/extractor/Cargo.toml +++ b/ruby/extractor/Cargo.toml @@ -11,7 +11,7 @@ flate2 = "1.0" node-types = { path = "../node-types" } tree-sitter = "0.19" tree-sitter-embedded-template = "0.19" -tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "1a3936a3545c0bd9344a0bf983fafc7e17443e39" } +tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "6334d6ab3d04a5672da695d3b155ca3301511f8d" } clap = "3.0" tracing = "0.1" tracing-subscriber = { version = "0.3.3", features = ["env-filter"] } diff --git a/ruby/generator/Cargo.toml b/ruby/generator/Cargo.toml index 4f7824e22ea..63d980f709d 100644 --- a/ruby/generator/Cargo.toml +++ b/ruby/generator/Cargo.toml @@ -12,4 +12,4 @@ node-types = { path = "../node-types" } tracing = "0.1" tracing-subscriber = { version = "0.3.3", features = ["env-filter"] } tree-sitter-embedded-template = "0.19" -tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "1a3936a3545c0bd9344a0bf983fafc7e17443e39" } +tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "6334d6ab3d04a5672da695d3b155ca3301511f8d" } diff --git a/ruby/ql/lib/CHANGELOG.md b/ruby/ql/lib/CHANGELOG.md index bc171ff917b..c9f38d77c7d 100644 --- a/ruby/ql/lib/CHANGELOG.md +++ b/ruby/ql/lib/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.2.1 + +### Bug Fixes + +* The Tree-sitter Ruby grammar has been updated; this fixes several issues where Ruby code was parsed incorrectly. + ## 0.2.0 ### Breaking Changes diff --git a/ruby/ql/lib/change-notes/2022-04-30-update-grammar.md b/ruby/ql/lib/change-notes/2022-04-30-update-grammar.md deleted file mode 100644 index a5190ee7368..00000000000 --- a/ruby/ql/lib/change-notes/2022-04-30-update-grammar.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: fix ---- -The Tree-sitter Ruby grammar has been updated; this fixes several issues where Ruby code was parsed incorrectly. diff --git a/ruby/ql/lib/change-notes/2022-05-01-safe-navigation-operator.md b/ruby/ql/lib/change-notes/2022-05-01-safe-navigation-operator.md new file mode 100644 index 00000000000..bed3c7869e8 --- /dev/null +++ b/ruby/ql/lib/change-notes/2022-05-01-safe-navigation-operator.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +Support of the safe navigation operator (`&.`) has been added; there is a new predicate `MethodCall.isSafeNavigation()`. diff --git a/ruby/ql/lib/change-notes/released/0.2.1.md b/ruby/ql/lib/change-notes/released/0.2.1.md new file mode 100644 index 00000000000..177cf4094e8 --- /dev/null +++ b/ruby/ql/lib/change-notes/released/0.2.1.md @@ -0,0 +1,5 @@ +## 0.2.1 + +### Bug Fixes + +* The Tree-sitter Ruby grammar has been updated; this fixes several issues where Ruby code was parsed incorrectly. diff --git a/ruby/ql/lib/codeql-pack.release.yml b/ruby/ql/lib/codeql-pack.release.yml index 5274e27ed52..df29a726bcc 100644 --- a/ruby/ql/lib/codeql-pack.release.yml +++ b/ruby/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.2.0 +lastReleaseVersion: 0.2.1 diff --git a/ruby/ql/lib/codeql/ruby/ast/Call.qll b/ruby/ql/lib/codeql/ruby/ast/Call.qll index ef5ba8aa9cd..5339f080564 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Call.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Call.qll @@ -105,6 +105,14 @@ class MethodCall extends Call instanceof MethodCallImpl { */ final Block getBlock() { result = super.getBlockImpl() } + /** + * Holds if the safe nagivation operator (`&.`) is used in this call. + * ```rb + * foo&.empty? + * ``` + */ + final predicate isSafeNavigation() { super.isSafeNavigationImpl() } + override string toString() { result = "call to " + this.getMethodName() } override AstNode getAChild(string pred) { diff --git a/ruby/ql/lib/codeql/ruby/ast/Control.qll b/ruby/ql/lib/codeql/ruby/ast/Control.qll index b4b8ce19c34..23d28980149 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Control.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Control.qll @@ -111,10 +111,10 @@ class IfExpr extends ConditionalExpr, TIfExpr { } } -private class If extends IfExpr, TIf { +private class IfReal extends IfExpr, TIfReal { private Ruby::If g; - If() { this = TIf(g) } + IfReal() { this = TIfReal(g) } final override Expr getCondition() { toGenerated(result) = g.getCondition() } @@ -125,6 +125,18 @@ private class If extends IfExpr, TIf { final override string toString() { result = "if ..." } } +private class IfSynth extends IfExpr, TIfSynth { + IfSynth() { this = TIfSynth(_, _) } + + final override Expr getCondition() { synthChild(this, 0, result) } + + final override Stmt getThen() { synthChild(this, 1, result) } + + final override Stmt getElse() { synthChild(this, 2, result) } + + final override string toString() { result = "if ..." } +} + private class Elsif extends IfExpr, TElsif { private Ruby::Elsif g; diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll b/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll index 11499454a75..7d35c51ffbb 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll @@ -162,7 +162,8 @@ private module Cached { } or THereDoc(Ruby::HeredocBeginning g) or TIdentifierMethodCall(Ruby::Identifier g) { isIdentifierMethodCall(g) } or - TIf(Ruby::If g) or + TIfReal(Ruby::If g) or + TIfSynth(AST::AstNode parent, int i) { mkSynthChild(IfKind(), parent, i) } or TIfModifierExpr(Ruby::IfModifier g) or TInClause(Ruby::InClause g) or TInstanceVariableAccessReal(Ruby::InstanceVariable g, AST::InstanceVariable v) { @@ -214,7 +215,8 @@ private module Cached { TMulExprSynth(AST::AstNode parent, int i) { mkSynthChild(MulExprKind(), parent, i) } or TNEExpr(Ruby::Binary g) { g instanceof @ruby_binary_bangequal } or TNextStmt(Ruby::Next g) or - TNilLiteral(Ruby::Nil g) or + TNilLiteralReal(Ruby::Nil g) or + TNilLiteralSynth(AST::AstNode parent, int i) { mkSynthChild(NilLiteralKind(), parent, i) } or TNoRegExpMatchExpr(Ruby::Binary g) { g instanceof @ruby_binary_bangtilde } or TNotExpr(Ruby::Unary g) { g instanceof @ruby_unary_bang or g instanceof @ruby_unary_not } or TOptionalParameter(Ruby::OptionalParameter g) or @@ -347,35 +349,36 @@ private module Cached { TFalseLiteral or TFile or TFindPattern or TFloatLiteral or TForExpr or TForwardParameter or TForwardArgument or TGEExpr or TGTExpr or TGlobalVariableAccessReal or THashKeySymbolLiteral or THashLiteral or THashPattern or THashSplatExpr or - THashSplatNilParameter or THashSplatParameter or THereDoc or TIdentifierMethodCall or TIf or - TIfModifierExpr or TInClause or TInstanceVariableAccessReal or TIntegerLiteralReal or - TKeywordParameter or TLEExpr or TLShiftExprReal or TLTExpr or TLambda or - TLeftAssignmentList or TLine or TLocalVariableAccessReal or TLogicalAndExprReal or - TLogicalOrExprReal or TMethod or TModuleDeclaration or TModuloExprReal or TMulExprReal or - TNEExpr or TNextStmt or TNilLiteral or TNoRegExpMatchExpr or TNotExpr or - TOptionalParameter or TPair or TParenthesizedExpr or TParenthesizedPattern or - TRShiftExprReal or TRangeLiteralReal or TRationalLiteral or TRedoStmt or TRegExpLiteral or - TRegExpMatchExpr or TRegularArrayLiteral or TRegularMethodCall or TRegularStringLiteral or - TRegularSuperCall or TRescueClause or TRescueModifierExpr or TRetryStmt or TReturnStmt or - TScopeResolutionConstantAccess or TSelfReal or TSimpleParameterReal or - TSimpleSymbolLiteral or TSingletonClass or TSingletonMethod or TSpaceshipExpr or - TSplatExprReal or TSplatParameter or TStringArrayLiteral or TStringConcatenation or - TStringEscapeSequenceComponent or TStringInterpolationComponent or TStringTextComponent or - TSubExprReal or TSubshellLiteral or TSymbolArrayLiteral or TTernaryIfExpr or TThen or - TTokenConstantAccess or TTokenMethodName or TTokenSuperCall or TToplevel or TTrueLiteral or - TUnaryMinusExpr or TUnaryPlusExpr or TUndefStmt or TUnlessExpr or TUnlessModifierExpr or - TUntilExpr or TUntilModifierExpr or TReferencePattern or TWhenClause or TWhileExpr or + THashSplatNilParameter or THashSplatParameter or THereDoc or TIdentifierMethodCall or + TIfReal or TIfModifierExpr or TInClause or TInstanceVariableAccessReal or + TIntegerLiteralReal or TKeywordParameter or TLEExpr or TLShiftExprReal or TLTExpr or + TLambda or TLeftAssignmentList or TLine or TLocalVariableAccessReal or + TLogicalAndExprReal or TLogicalOrExprReal or TMethod or TModuleDeclaration or + TModuloExprReal or TMulExprReal or TNEExpr or TNextStmt or TNilLiteralReal or + TNoRegExpMatchExpr or TNotExpr or TOptionalParameter or TPair or TParenthesizedExpr or + TParenthesizedPattern or TRShiftExprReal or TRangeLiteralReal or TRationalLiteral or + TRedoStmt or TRegExpLiteral or TRegExpMatchExpr or TRegularArrayLiteral or + TRegularMethodCall or TRegularStringLiteral or TRegularSuperCall or TRescueClause or + TRescueModifierExpr or TRetryStmt or TReturnStmt or TScopeResolutionConstantAccess or + TSelfReal or TSimpleParameterReal or TSimpleSymbolLiteral or TSingletonClass or + TSingletonMethod or TSpaceshipExpr or TSplatExprReal or TSplatParameter or + TStringArrayLiteral or TStringConcatenation or TStringEscapeSequenceComponent or + TStringInterpolationComponent or TStringTextComponent or TSubExprReal or TSubshellLiteral or + TSymbolArrayLiteral or TTernaryIfExpr or TThen or TTokenConstantAccess or + TTokenMethodName or TTokenSuperCall or TToplevel or TTrueLiteral or TUnaryMinusExpr or + TUnaryPlusExpr or TUndefStmt or TUnlessExpr or TUnlessModifierExpr or TUntilExpr or + TUntilModifierExpr or TReferencePattern or TWhenClause or TWhileExpr or TWhileModifierExpr or TYieldCall; class TAstNodeSynth = TAddExprSynth or TAssignExprSynth or TBitwiseAndExprSynth or TBitwiseOrExprSynth or TBitwiseXorExprSynth or TBraceBlockSynth or TClassVariableAccessSynth or TConstantReadAccessSynth or TDivExprSynth or TExponentExprSynth or - TGlobalVariableAccessSynth or TInstanceVariableAccessSynth or TIntegerLiteralSynth or - TLShiftExprSynth or TLocalVariableAccessSynth or TLogicalAndExprSynth or - TLogicalOrExprSynth or TMethodCallSynth or TModuloExprSynth or TMulExprSynth or - TRShiftExprSynth or TRangeLiteralSynth or TSelfSynth or TSimpleParameterSynth or - TSplatExprSynth or TStmtSequenceSynth or TSubExprSynth; + TGlobalVariableAccessSynth or TIfSynth or TInstanceVariableAccessSynth or + TIntegerLiteralSynth or TLShiftExprSynth or TLocalVariableAccessSynth or + TLogicalAndExprSynth or TLogicalOrExprSynth or TMethodCallSynth or TModuloExprSynth or + TMulExprSynth or TNilLiteralSynth or TRShiftExprSynth or TRangeLiteralSynth or TSelfSynth or + TSimpleParameterSynth or TSplatExprSynth or TStmtSequenceSynth or TSubExprSynth; /** * Gets the underlying TreeSitter entity for a given AST node. This does not @@ -457,7 +460,7 @@ private module Cached { n = THereDoc(result) or n = TIdentifierMethodCall(result) or n = TIfModifierExpr(result) or - n = TIf(result) or + n = TIfReal(result) or n = TInClause(result) or n = TInstanceVariableAccessReal(result, _) or n = TIntegerLiteralReal(result) or @@ -477,7 +480,7 @@ private module Cached { n = TMulExprReal(result) or n = TNEExpr(result) or n = TNextStmt(result) or - n = TNilLiteral(result) or + n = TNilLiteralReal(result) or n = TNoRegExpMatchExpr(result) or n = TNotExpr(result) or n = TOptionalParameter(result) or @@ -568,6 +571,8 @@ private module Cached { or result = TGlobalVariableAccessSynth(parent, i, _) or + result = TIfSynth(parent, i) + or result = TInstanceVariableAccessSynth(parent, i, _) or result = TIntegerLiteralSynth(parent, i, _) @@ -586,6 +591,8 @@ private module Cached { or result = TMulExprSynth(parent, i) or + result = TNilLiteralSynth(parent, i) + or result = TRangeLiteralSynth(parent, i, _) or result = TRShiftExprSynth(parent, i) @@ -672,6 +679,8 @@ class TControlExpr = TConditionalExpr or TCaseExpr or TCaseMatch or TLoop; class TConditionalExpr = TIfExpr or TUnlessExpr or TIfModifierExpr or TUnlessModifierExpr or TTernaryIfExpr; +class TIf = TIfReal or TIfSynth; + class TIfExpr = TIf or TElsif; class TConditionalLoop = TWhileExpr or TUntilExpr or TWhileModifierExpr or TUntilModifierExpr; @@ -695,6 +704,8 @@ class TStmtSequence = class TBodyStmt = TBeginExpr or TModuleBase or TMethod or TLambda or TDoBlock or TSingletonMethod; +class TNilLiteral = TNilLiteralReal or TNilLiteralSynth; + class TLiteral = TEncoding or TFile or TLine or TNumericLiteral or TNilLiteral or TBooleanLiteral or TStringlikeLiteral or TCharacterLiteral or TArrayLiteral or THashLiteral or TRangeLiteral or diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Call.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Call.qll index 25f2e2a305a..9a1d41b097d 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Call.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Call.qll @@ -28,6 +28,8 @@ abstract class MethodCallImpl extends CallImpl, TMethodCall { abstract string getMethodNameImpl(); abstract Block getBlockImpl(); + + predicate isSafeNavigationImpl() { none() } } class MethodCallSynth extends MethodCallImpl, TMethodCallSynth { @@ -89,6 +91,10 @@ class RegularMethodCall extends MethodCallImpl, TRegularMethodCall { final override int getNumberOfArgumentsImpl() { result = count(g.getArguments().getChild(_)) } final override Block getBlockImpl() { toGenerated(result) = g.getBlock() } + + final override predicate isSafeNavigationImpl() { + g.getOperator().(Ruby::Token).getValue() = "&." + } } class ElementReferenceImpl extends MethodCallImpl, TElementReference { diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Literal.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Literal.qll index cbdd65a19ca..e9936d1e48c 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Literal.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Literal.qll @@ -111,12 +111,18 @@ class ComplexLiteralImpl extends Expr, TComplexLiteral { } } -class NilLiteralImpl extends Expr, TNilLiteral { +abstract class NilLiteralImpl extends Expr, TNilLiteral { + final override string toString() { result = "nil" } +} + +class NilLiteralReal extends NilLiteralImpl, TNilLiteralReal { private Ruby::Nil g; - NilLiteralImpl() { this = TNilLiteral(g) } + NilLiteralReal() { this = TNilLiteralReal(g) } +} - final override string toString() { result = g.getValue() } +class NilLiteralSynth extends NilLiteralImpl, TNilLiteralSynth { + NilLiteralSynth() { this = TNilLiteralSynth(_, _) } } abstract class BooleanLiteralImpl extends Expr, TBooleanLiteral { diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll index 3641eb981e2..0b1137faeb7 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll @@ -21,6 +21,7 @@ newtype SynthKind = DivExprKind() or ExponentExprKind() or GlobalVariableAccessKind(GlobalVariable v) or + IfKind() or InstanceVariableAccessKind(InstanceVariable v) or IntegerLiteralKind(int i) { i in [-1000 .. 1000] } or LShiftExprKind() or @@ -33,6 +34,7 @@ newtype SynthKind = } or ModuloExprKind() or MulExprKind() or + NilLiteralKind() or RangeLiteralKind(boolean inclusive) { inclusive in [false, true] } or RShiftExprKind() or SimpleParameterKind() or @@ -1083,3 +1085,123 @@ private module AnonymousBlockParameterSynth { } } } + +private module SafeNavigationCallDesugar { + /** + * ```rb + * receiver&.method(args) { ... } + * ``` + * desugars to + * + * ```rb + * __synth__0 = receiver + * if nil == __synth__0 then nil else __synth__0.method(args) {...} end + * ``` + */ + pragma[nomagic] + private predicate safeNavigationCallSynthesis(AstNode parent, int i, Child child) { + exists(RegularMethodCall call, LocalVariableAccessSynthKind local | + call.isSafeNavigationImpl() and + local = LocalVariableAccessSynthKind(TLocalVariableSynth(call.getReceiverImpl(), 0)) + | + parent = call and + i = -1 and + child = SynthChild(StmtSequenceKind()) + or + exists(TStmtSequenceSynth seq | seq = TStmtSequenceSynth(call, -1) | + parent = seq and + ( + child = SynthChild(AssignExprKind()) and i = 0 + or + child = SynthChild(IfKind()) and i = 1 + ) + or + parent = TAssignExprSynth(seq, 0) and + ( + child = SynthChild(local) and + i = 0 + or + child = childRef(call.getReceiverImpl()) and i = 1 + ) + or + exists(TIfSynth ifExpr | ifExpr = TIfSynth(seq, 1) | + parent = ifExpr and + ( + child = SynthChild(MethodCallKind("==", false, 2)) and + i = 0 + or + child = SynthChild(NilLiteralKind()) and i = 1 + or + child = + SynthChild(MethodCallKind(call.getMethodNameImpl(), false, + call.getNumberOfArgumentsImpl())) and + i = 2 + ) + or + parent = TMethodCallSynth(ifExpr, 0, _, _, _) and + ( + child = SynthChild(NilLiteralKind()) and i = 0 + or + child = SynthChild(local) and + i = 1 + ) + or + parent = TMethodCallSynth(ifExpr, 2, _, _, _) and + ( + i = 0 and + child = SynthChild(local) + or + child = childRef(call.getArgumentImpl(i - 1)) + or + child = childRef(call.getBlockImpl()) and i = -2 + ) + ) + ) + ) + } + + private class SafeNavigationCallSynthesis extends Synthesis { + final override predicate child(AstNode parent, int i, Child child) { + safeNavigationCallSynthesis(parent, i, child) + } + + final override predicate methodCall(string name, boolean setter, int arity) { + exists(RegularMethodCall call | + call.isSafeNavigationImpl() and + name = call.getMethodNameImpl() and + setter = false and + arity = call.getNumberOfArgumentsImpl() + ) + or + name = "==" and setter = false and arity = 2 + } + + final override predicate localVariable(AstNode n, int i) { + i = 0 and n = any(RegularMethodCall c | c.isSafeNavigationImpl()).getReceiverImpl() + } + + override predicate location(AstNode n, Location l) { + exists(RegularMethodCall call, StmtSequence seq | + call.isSafeNavigationImpl() and seq = call.getDesugared() + | + n = seq.getStmt(0) and + hasLocation(call.getReceiverImpl(), l) + or + n = seq.getStmt(1) and + l = toGenerated(call).(Ruby::Call).getOperator().getLocation() + or + n = seq.getStmt(1).(IfExpr).getCondition().(MethodCall).getArgument(0) and + hasLocation(call.getReceiverImpl(), l) + or + n = seq.getStmt(1).(IfExpr).getThen() and + hasLocation(call.getReceiverImpl(), l) + or + n = seq.getStmt(1).(IfExpr).getElse() and + hasLocation(call, l) + or + n = seq.getStmt(1).(IfExpr).getElse().(MethodCall).getReceiver() and + hasLocation(call.getReceiverImpl(), l) + ) + } + } +} diff --git a/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll b/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll index 435097900f8..e07cb1b419f 100644 --- a/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll +++ b/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll @@ -371,7 +371,9 @@ module Trees { CallTree() { // Logical operations are handled separately not this instanceof UnaryLogicalOperation and - not this instanceof BinaryLogicalOperation + not this instanceof BinaryLogicalOperation and + // Calls with the `&.` operator are desugared + not this.(MethodCall).isSafeNavigation() } override ControlFlowTree getChildElement(int i) { result = this.getArgument(i) } @@ -1256,7 +1258,7 @@ module Trees { private class SimpleParameterTree extends NonDefaultValueParameterTree, SimpleParameter { } - // Corner case: For duplicated '_' parameters, only the first occurence has a defining + // Corner case: For duplicated '_' parameters, only the first occurrence has a defining // access. For subsequent parameters we simply include the parameter itself in the CFG private class SimpleParameterTreeDupUnderscore extends LeafTree, SimpleParameter { SimpleParameterTreeDupUnderscore() { not exists(this.getDefiningAccess()) } diff --git a/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll b/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll index e7ae2e489a2..47fcd24883c 100644 --- a/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll +++ b/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll @@ -744,7 +744,7 @@ cached private module Cached { /** * If needed, call this predicate from `ControlFlowGraphImplSpecific.qll` in order to - * force a stage-dependency on the `ControlFlowGraphImplShared.qll` stage and therby + * force a stage-dependency on the `ControlFlowGraphImplShared.qll` stage and thereby * collapsing the two stages. */ cached diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll index 5bd84566df5..fb773ea89f8 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll index 5bd84566df5..fb773ea89f8 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplCommon.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplCommon.qll index e60505d9248..0079b259260 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplCommon.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplCommon.qll @@ -305,7 +305,7 @@ cached private module Cached { /** * If needed, call this predicate from `DataFlowImplSpecific.qll` in order to - * force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby + * force a stage-dependency on the `DataFlowImplCommon.qll` stage and thereby * collapsing the two stages. */ cached diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll index 5bd84566df5..fb773ea89f8 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll @@ -170,6 +170,14 @@ abstract class Configuration extends string { */ int explorationLimit() { none() } + /** + * Holds if hidden nodes should be included in the data flow graph. + * + * This feature should only be used for debugging or when the data flow graph + * is not visualized (for example in a `path-problem` query). + */ + predicate includeHiddenNodes() { none() } + /** * Holds if there is a partial data flow path from `source` to `node`. The * approximate distance between `node` and the closest source is `dist` and @@ -3653,7 +3661,7 @@ private newtype TPathNode = * of dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. */ -abstract private class AccessPath extends TAccessPath { +private class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ abstract TypedContent getHead(); @@ -3868,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode { abstract NodeEx getNodeEx(); predicate isHidden() { - hiddenNode(this.getNodeEx().asNode()) and - not this.isSource() and - not this instanceof PathNodeSink - or - this.getNodeEx() instanceof TNodeImplicitRead + not this.getConfiguration().includeHiddenNodes() and + ( + hiddenNode(this.getNodeEx().asNode()) and + not this.isSource() and + not this instanceof PathNodeSink + or + this.getNodeEx() instanceof TNodeImplicitRead + ) } private string ppAp() { diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActionDispatch.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActionDispatch.qll index a00e8293fd2..bd16ef3796e 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/ActionDispatch.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/ActionDispatch.qll @@ -279,7 +279,7 @@ module ActionDispatch { * ```rb * get "/photos", to: "photos#index" * ``` - * or via a convenience method like `resources`, which defines mutiple routes at once: + * or via a convenience method like `resources`, which defines multiple routes at once: * ```rb * resources :photos * ``` diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll index 4681c2b91a5..127d9ca5122 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll @@ -59,7 +59,7 @@ * A `(package,type)` pair may refer to a static type or a synthetic type name used internally in the model. * Synthetic type names can be used to reuse intermediate sub-paths, when there are multiple ways to access the same * element. - * See `ModelsAsData.qll` for the langauge-specific interpretation of packages and static type names. + * See `ModelsAsData.qll` for the language-specific interpretation of packages and static type names. * * By convention, if one wants to avoid clashes with static types from the package, the type name * should be prefixed with a tilde character (`~`). For example, `(foo, ~Bar)` can be used to indicate that @@ -396,7 +396,7 @@ predicate isValidTokenNameInIdentifyingAccessPath(string name) { } /** - * Holds if `name` is a valid name for an access path token with no arguments, occuring + * Holds if `name` is a valid name for an access path token with no arguments, occurring * in an identifying access path. */ bindingset[name] diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModelsSpecific.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModelsSpecific.qll index 381623d557e..e4e9b9cfc44 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModelsSpecific.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModelsSpecific.qll @@ -163,7 +163,7 @@ predicate isExtraValidTokenNameInIdentifyingAccessPath(string name) { } /** - * Holds if `name` is a valid name for an access path token with no arguments, occuring + * Holds if `name` is a valid name for an access path token with no arguments, occurring * in an identifying access path. */ predicate isExtraValidNoArgumentTokenInIdentifyingAccessPath(string name) { diff --git a/ruby/ql/lib/codeql/ruby/security/BadTagFilterQuery.qll b/ruby/ql/lib/codeql/ruby/security/BadTagFilterQuery.qll index e22c00ddc47..d935abce37a 100644 --- a/ruby/ql/lib/codeql/ruby/security/BadTagFilterQuery.qll +++ b/ruby/ql/lib/codeql/ruby/security/BadTagFilterQuery.qll @@ -28,14 +28,14 @@ private module RegexpMatching { * but if `ignorePrefix` is true, it will only match "foo". */ predicate test(string str, boolean ignorePrefix) { - none() // maybe overriden in subclasses + none() // maybe overridden in subclasses } /** * Same as `test(..)`, but where the `fillsCaptureGroup` afterwards tells which capture groups were filled by the given string. */ predicate testWithGroups(string str, boolean ignorePrefix) { - none() // maybe overriden in subclasses + none() // maybe overridden in subclasses } /** diff --git a/ruby/ql/lib/codeql/ruby/security/performance/ExponentialBackTracking.qll b/ruby/ql/lib/codeql/ruby/security/performance/ExponentialBackTracking.qll index 5e0fe18ea00..99b4062dfdc 100644 --- a/ruby/ql/lib/codeql/ruby/security/performance/ExponentialBackTracking.qll +++ b/ruby/ql/lib/codeql/ruby/security/performance/ExponentialBackTracking.qll @@ -51,7 +51,7 @@ * either a single character, a set of characters represented by a * character class, or the set of all characters. * * The product automaton is constructed lazily, starting with pair states - * `(q, q)` where `q` is a fork, and proceding along an over-approximate + * `(q, q)` where `q` is a fork, and proceeding along an over-approximate * step relation. * * The over-approximate step relation allows transitions along pairs of * abstract input symbols where the symbols have overlap in the characters they accept. diff --git a/ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll b/ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll index 6f695b5035b..8aa348bf62f 100644 --- a/ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll +++ b/ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll @@ -610,16 +610,23 @@ State after(RegExpTerm t) { or exists(RegExpGroup grp | t = grp.getAChild() | result = after(grp)) or - exists(EffectivelyStar star | t = star.getAChild() | result = before(star)) + exists(EffectivelyStar star | t = star.getAChild() | + not isPossessive(star) and + result = before(star) + ) or exists(EffectivelyPlus plus | t = plus.getAChild() | - result = before(plus) or + not isPossessive(plus) and + result = before(plus) + or result = after(plus) ) or exists(EffectivelyQuestion opt | t = opt.getAChild() | result = after(opt)) or - exists(RegExpRoot root | t = root | result = AcceptAnySuffix(root)) + exists(RegExpRoot root | t = root | + if matchesAnySuffix(root) then result = AcceptAnySuffix(root) else result = Accept(root) + ) } /** @@ -690,7 +697,7 @@ predicate delta(State q1, EdgeLabel lbl, State q2) { lbl = Epsilon() and q2 = Accept(root) ) or - exists(RegExpRoot root | q1 = Match(root, 0) | lbl = Any() and q2 = q1) + exists(RegExpRoot root | q1 = Match(root, 0) | matchesAnyPrefix(root) and lbl = Any() and q2 = q1) or exists(RegExpDollar dollar | q1 = before(dollar) | lbl = Epsilon() and q2 = Accept(getRoot(dollar)) diff --git a/ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtilSpecific.qll b/ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtilSpecific.qll index de125f4a9db..8d6b14607e0 100644 --- a/ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtilSpecific.qll +++ b/ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtilSpecific.qll @@ -33,6 +33,24 @@ predicate isExcluded(RegExpParent parent) { parent.(RegExpTerm).getRegExp().(AST::RegExpLiteral).hasFreeSpacingFlag() // exclude free-spacing mode regexes } +/** + * Holds if `term` is a possessive quantifier. + * Not currently implemented, but is used by the shared library. + */ +predicate isPossessive(RegExpQuantifier term) { none() } + +/** + * Holds if the regex that `term` is part of is used in a way that ignores any leading prefix of the input it's matched against. + * Not yet implemented for Ruby. + */ +predicate matchesAnyPrefix(RegExpTerm term) { any() } + +/** + * Holds if the regex that `term` is part of is used in a way that ignores any trailing suffix of the input it's matched against. + * Not yet implemented for Ruby. + */ +predicate matchesAnySuffix(RegExpTerm term) { any() } + /** * A module containing predicates for determining which flags a regular expression have. */ diff --git a/ruby/ql/lib/qlpack.yml b/ruby/ql/lib/qlpack.yml index cd407edd0a8..037c4dddc63 100644 --- a/ruby/ql/lib/qlpack.yml +++ b/ruby/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-all -version: 0.2.1-dev +version: 0.2.2-dev groups: ruby extractor: ruby dbscheme: ruby.dbscheme diff --git a/ruby/ql/src/CHANGELOG.md b/ruby/ql/src/CHANGELOG.md index 72bf3f42e84..be4af4786d1 100644 --- a/ruby/ql/src/CHANGELOG.md +++ b/ruby/ql/src/CHANGELOG.md @@ -1,3 +1,5 @@ +## 0.1.2 + ## 0.1.1 ### New Queries diff --git a/ruby/ql/src/change-notes/released/0.1.2.md b/ruby/ql/src/change-notes/released/0.1.2.md new file mode 100644 index 00000000000..66bd49d11eb --- /dev/null +++ b/ruby/ql/src/change-notes/released/0.1.2.md @@ -0,0 +1 @@ +## 0.1.2 diff --git a/ruby/ql/src/codeql-pack.release.yml b/ruby/ql/src/codeql-pack.release.yml index 92d1505475f..6abd14b1ef8 100644 --- a/ruby/ql/src/codeql-pack.release.yml +++ b/ruby/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.1.1 +lastReleaseVersion: 0.1.2 diff --git a/ruby/ql/src/qlpack.yml b/ruby/ql/src/qlpack.yml index c4fbe058d06..3e176887075 100644 --- a/ruby/ql/src/qlpack.yml +++ b/ruby/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-queries -version: 0.1.2-dev +version: 0.1.3-dev groups: - ruby - queries diff --git a/ruby/ql/test/TestUtilities/InlineExpectationsTest.qll b/ruby/ql/test/TestUtilities/InlineExpectationsTest.qll index a4d264b2703..3891fcf13a1 100644 --- a/ruby/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/ruby/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -181,7 +181,7 @@ private string expectationCommentPattern() { result = "\\s*\\$((?:[^/]|/[^/])*)( /** * The possible columns in an expectation comment. The `TDefaultColumn` branch represents the first * column in a comment. This column is not precedeeded by a name. `TNamedColumn(name)` represents a - * column containing expected results preceeded by the string `name:`. + * column containing expected results preceded by the string `name:`. */ private newtype TColumn = TDefaultColumn() or diff --git a/ruby/ql/test/library-tests/ast/Ast.expected b/ruby/ql/test/library-tests/ast/Ast.expected index a8e67da4ec6..6f0242dd1c3 100644 --- a/ruby/ql/test/library-tests/ast/Ast.expected +++ b/ruby/ql/test/library-tests/ast/Ast.expected @@ -739,6 +739,24 @@ calls/calls.rb: # 356| getStmt: [LocalVariableAccess] y # 357| getStmt: [MethodCall] call to unknown_call # 357| getReceiver: [SelfVariableAccess] self +# 361| getStmt: [MethodCall] call to empty? +# 361| getReceiver: [MethodCall] call to list +# 361| getReceiver: [SelfVariableAccess] self +# 362| getStmt: [MethodCall] call to empty? +# 362| getReceiver: [MethodCall] call to list +# 362| getReceiver: [SelfVariableAccess] self +# 363| getStmt: [MethodCall] call to empty? +# 363| getReceiver: [MethodCall] call to list +# 363| getReceiver: [SelfVariableAccess] self +# 364| getStmt: [MethodCall] call to bar +# 364| getReceiver: [MethodCall] call to foo +# 364| getReceiver: [SelfVariableAccess] self +# 364| getArgument: [IntegerLiteral] 1 +# 364| getArgument: [IntegerLiteral] 2 +# 364| getBlock: [BraceBlock] { ... } +# 364| getParameter: [SimpleParameter] x +# 364| getDefiningAccess: [LocalVariableAccess] x +# 364| getStmt: [LocalVariableAccess] x control/cases.rb: # 1| [Toplevel] cases.rb # 2| getStmt: [AssignExpr] ... = ... diff --git a/ruby/ql/test/library-tests/ast/AstDesugar.expected b/ruby/ql/test/library-tests/ast/AstDesugar.expected index 0c8a602058a..7a5d5e0c85c 100644 --- a/ruby/ql/test/library-tests/ast/AstDesugar.expected +++ b/ruby/ql/test/library-tests/ast/AstDesugar.expected @@ -279,6 +279,38 @@ calls/calls.rb: # 340| getArgument: [IntegerLiteral] 4 # 340| getArgument: [IntegerLiteral] 5 # 340| getArgument: [IntegerLiteral] 6 +# 362| [MethodCall] call to empty? +# 362| getDesugared: [StmtSequence] ... +# 362| getStmt: [AssignExpr] ... = ... +# 362| getAnOperand/getRightOperand: [MethodCall] call to list +# 362| getReceiver: [SelfVariableAccess] self +# 362| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1 +# 362| getStmt: [IfExpr] if ... +# 362| getBranch/getElse: [MethodCall] call to empty? +# 362| getReceiver: [LocalVariableAccess] __synth__0__1 +# 362| getBranch/getThen: [NilLiteral] nil +# 362| getCondition: [MethodCall] call to == +# 362| getArgument: [LocalVariableAccess] __synth__0__1 +# 362| getReceiver: [NilLiteral] nil +# 364| [MethodCall] call to bar +# 364| getDesugared: [StmtSequence] ... +# 364| getStmt: [AssignExpr] ... = ... +# 364| getAnOperand/getRightOperand: [MethodCall] call to foo +# 364| getReceiver: [SelfVariableAccess] self +# 364| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1 +# 364| getStmt: [IfExpr] if ... +# 364| getBranch/getElse: [MethodCall] call to bar +# 364| getReceiver: [LocalVariableAccess] __synth__0__1 +# 364| getArgument: [IntegerLiteral] 1 +# 364| getArgument: [IntegerLiteral] 2 +# 364| getBlock: [BraceBlock] { ... } +# 364| getParameter: [SimpleParameter] x +# 364| getDefiningAccess: [LocalVariableAccess] x +# 364| getStmt: [LocalVariableAccess] x +# 364| getBranch/getThen: [NilLiteral] nil +# 364| getCondition: [MethodCall] call to == +# 364| getArgument: [LocalVariableAccess] __synth__0__1 +# 364| getReceiver: [NilLiteral] nil control/cases.rb: # 90| [ArrayLiteral] %w(...) # 90| getDesugared: [MethodCall] call to [] diff --git a/ruby/ql/test/library-tests/ast/TreeSitter.expected b/ruby/ql/test/library-tests/ast/TreeSitter.expected index 64cdabc5a46..0a2ecda8d28 100644 --- a/ruby/ql/test/library-tests/ast/TreeSitter.expected +++ b/ruby/ql/test/library-tests/ast/TreeSitter.expected @@ -1269,6 +1269,36 @@ calls/calls.rb: # 356| 2: [Identifier] y # 357| 3: [Identifier] unknown_call # 358| 4: [ReservedWord] end +# 361| 117: [Call] Call +# 361| 0: [Identifier] list +# 361| 1: [ReservedWord] . +# 361| 2: [Identifier] empty? +# 362| 118: [Call] Call +# 362| 0: [Identifier] list +# 362| 1: [ReservedWord] &. +# 362| 2: [Identifier] empty? +# 363| 119: [Call] Call +# 363| 0: [Identifier] list +# 363| 1: [ReservedWord] :: +# 363| 2: [Identifier] empty? +# 364| 120: [Call] Call +# 364| 0: [Identifier] foo +# 364| 1: [ReservedWord] &. +# 364| 2: [Identifier] bar +# 364| 3: [ArgumentList] ArgumentList +# 364| 0: [ReservedWord] ( +# 364| 1: [Integer] 1 +# 364| 2: [ReservedWord] , +# 364| 3: [Integer] 2 +# 364| 4: [ReservedWord] ) +# 364| 4: [Block] Block +# 364| 0: [ReservedWord] { +# 364| 1: [BlockParameters] BlockParameters +# 364| 0: [ReservedWord] | +# 364| 1: [Identifier] x +# 364| 2: [ReservedWord] | +# 364| 2: [Identifier] x +# 364| 3: [ReservedWord] } # 1| [Comment] # call with no receiver, arguments, or block # 4| [Comment] # call whose name is a scope resolution # 7| [Comment] # call whose name is a global scope resolution @@ -1342,6 +1372,7 @@ calls/calls.rb: # 330| [Comment] # forward parameter and forwarded arguments # 339| [Comment] # for loop over nested array # 349| [Comment] # calls inside lambdas +# 360| [Comment] # calls with various call operators constants/constants.rb: # 1| [Program] Program # 1| 0: [Module] Module diff --git a/ruby/ql/test/library-tests/ast/ValueText.expected b/ruby/ql/test/library-tests/ast/ValueText.expected index 949e95ac423..6225b1b2e90 100644 --- a/ruby/ql/test/library-tests/ast/ValueText.expected +++ b/ruby/ql/test/library-tests/ast/ValueText.expected @@ -74,6 +74,12 @@ exprValue | calls/calls.rb:346:8:346:9 | 42 | 42 | int | | calls/calls.rb:347:5:347:5 | :X | :X | symbol | | calls/calls.rb:350:5:350:5 | 1 | 1 | int | +| calls/calls.rb:362:1:362:4 | nil | nil | nil | +| calls/calls.rb:362:5:362:6 | nil | nil | nil | +| calls/calls.rb:364:1:364:3 | nil | nil | nil | +| calls/calls.rb:364:4:364:5 | nil | nil | nil | +| calls/calls.rb:364:10:364:10 | 1 | 1 | int | +| calls/calls.rb:364:12:364:12 | 2 | 2 | int | | constants/constants.rb:3:19:3:27 | "const_a" | const_a | string | | constants/constants.rb:6:15:6:23 | "const_b" | const_b | string | | constants/constants.rb:17:12:17:18 | "Hello" | Hello | string | @@ -963,6 +969,12 @@ exprCfgNodeValue | calls/calls.rb:346:8:346:9 | 42 | 42 | int | | calls/calls.rb:347:5:347:5 | :X | :X | symbol | | calls/calls.rb:350:5:350:5 | 1 | 1 | int | +| calls/calls.rb:362:1:362:4 | nil | nil | nil | +| calls/calls.rb:362:5:362:6 | nil | nil | nil | +| calls/calls.rb:364:1:364:3 | nil | nil | nil | +| calls/calls.rb:364:4:364:5 | nil | nil | nil | +| calls/calls.rb:364:10:364:10 | 1 | 1 | int | +| calls/calls.rb:364:12:364:12 | 2 | 2 | int | | constants/constants.rb:3:19:3:27 | "const_a" | const_a | string | | constants/constants.rb:6:15:6:23 | "const_b" | const_b | string | | constants/constants.rb:17:12:17:18 | "Hello" | Hello | string | diff --git a/ruby/ql/test/library-tests/ast/calls/calls.expected b/ruby/ql/test/library-tests/ast/calls/calls.expected index 750ceb88ed0..b56cbd61f37 100644 --- a/ruby/ql/test/library-tests/ast/calls/calls.expected +++ b/ruby/ql/test/library-tests/ast/calls/calls.expected @@ -114,6 +114,12 @@ callsWithArguments | calls.rb:346:1:346:10 | call to foo | foo | 0 | calls.rb:346:5:346:9 | Pair | | calls.rb:347:1:347:7 | call to foo | foo | 0 | calls.rb:347:5:347:6 | Pair | | calls.rb:352:13:352:17 | call to foo | foo | 0 | calls.rb:352:17:352:17 | x | +| calls.rb:362:5:362:6 | call to == | == | 0 | calls.rb:362:1:362:4 | __synth__0__1 | +| calls.rb:364:1:364:23 | call to bar | bar | 0 | calls.rb:364:10:364:10 | 1 | +| calls.rb:364:1:364:23 | call to bar | bar | 0 | calls.rb:364:10:364:10 | 1 | +| calls.rb:364:1:364:23 | call to bar | bar | 1 | calls.rb:364:12:364:12 | 2 | +| calls.rb:364:1:364:23 | call to bar | bar | 1 | calls.rb:364:12:364:12 | 2 | +| calls.rb:364:4:364:5 | call to == | == | 0 | calls.rb:364:1:364:3 | __synth__0__1 | callsWithReceiver | calls.rb:2:1:2:5 | call to foo | calls.rb:2:1:2:5 | self | | calls.rb:5:1:5:10 | call to bar | calls.rb:5:1:5:3 | Foo | @@ -372,6 +378,18 @@ callsWithReceiver | calls.rb:352:13:352:17 | call to foo | calls.rb:352:13:352:17 | self | | calls.rb:353:13:353:24 | call to unknown_call | calls.rb:353:13:353:24 | self | | calls.rb:357:3:357:14 | call to unknown_call | calls.rb:357:3:357:14 | self | +| calls.rb:361:1:361:4 | call to list | calls.rb:361:1:361:4 | self | +| calls.rb:361:1:361:11 | call to empty? | calls.rb:361:1:361:4 | call to list | +| calls.rb:362:1:362:4 | call to list | calls.rb:362:1:362:4 | self | +| calls.rb:362:1:362:12 | call to empty? | calls.rb:362:1:362:4 | __synth__0__1 | +| calls.rb:362:1:362:12 | call to empty? | calls.rb:362:1:362:4 | call to list | +| calls.rb:362:5:362:6 | call to == | calls.rb:362:5:362:6 | nil | +| calls.rb:363:1:363:4 | call to list | calls.rb:363:1:363:4 | self | +| calls.rb:363:1:363:12 | call to empty? | calls.rb:363:1:363:4 | call to list | +| calls.rb:364:1:364:3 | call to foo | calls.rb:364:1:364:3 | self | +| calls.rb:364:1:364:23 | call to bar | calls.rb:364:1:364:3 | __synth__0__1 | +| calls.rb:364:1:364:23 | call to bar | calls.rb:364:1:364:3 | call to foo | +| calls.rb:364:4:364:5 | call to == | calls.rb:364:4:364:5 | nil | callsWithBlock | calls.rb:17:1:17:17 | call to foo | calls.rb:17:5:17:17 | { ... } | | calls.rb:20:1:22:3 | call to foo | calls.rb:20:5:22:3 | do ... end | @@ -385,6 +403,8 @@ callsWithBlock | calls.rb:292:5:292:30 | call to super | calls.rb:292:16:292:30 | { ... } | | calls.rb:293:5:293:33 | call to super | calls.rb:293:16:293:33 | do ... end | | calls.rb:340:1:342:3 | call to each | calls.rb:340:1:342:3 | { ... } | +| calls.rb:364:1:364:23 | call to bar | calls.rb:364:15:364:23 | { ... } | +| calls.rb:364:1:364:23 | call to bar | calls.rb:364:15:364:23 | { ... } | yieldCalls | calls.rb:31:3:31:7 | yield ... | | calls.rb:36:3:36:16 | yield ... | @@ -424,3 +444,6 @@ setterCalls | calls.rb:318:1:318:10 | call to count= | | calls.rb:319:1:319:6 | call to []= | | calls.rb:320:1:320:32 | call to []= | +callsWithSafeNavigationOperator +| calls.rb:362:1:362:12 | call to empty? | +| calls.rb:364:1:364:23 | call to bar | diff --git a/ruby/ql/test/library-tests/ast/calls/calls.ql b/ruby/ql/test/library-tests/ast/calls/calls.ql index 4d244c2cf4c..93bef27efb4 100644 --- a/ruby/ql/test/library-tests/ast/calls/calls.ql +++ b/ruby/ql/test/library-tests/ast/calls/calls.ql @@ -31,3 +31,5 @@ query predicate superCallsWithArguments(SuperCall c, int n, Expr argN) { argN = query predicate superCallsWithBlock(SuperCall c, Block b) { b = c.getBlock() } query predicate setterCalls(SetterMethodCall c) { any() } + +query predicate callsWithSafeNavigationOperator(MethodCall c) { c.isSafeNavigation() } diff --git a/ruby/ql/test/library-tests/ast/calls/calls.rb b/ruby/ql/test/library-tests/ast/calls/calls.rb index 46815457f17..361b245745f 100644 --- a/ruby/ql/test/library-tests/ast/calls/calls.rb +++ b/ruby/ql/test/library-tests/ast/calls/calls.rb @@ -356,3 +356,9 @@ h = -> (x) do y unknown_call end + +# calls with various call operators +list.empty? +list&.empty? +list::empty? +foo&.bar(1,2) { |x| x } \ No newline at end of file diff --git a/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected b/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected index fd7921fbd35..d190d853634 100644 --- a/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected +++ b/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected @@ -3593,7 +3593,7 @@ cfg.rb: #-----| -> do ... end # 202| call to times -#-----| -> exit cfg.rb (normal) +#-----| -> __synth__0__1 # 202| do ... end #-----| -> call to times @@ -3621,6 +3621,66 @@ cfg.rb: # 202| c #-----| -> call to puts +# 205| ... = ... +#-----| -> nil + +# 205| __synth__0__1 +#-----| -> self + +# 205| __synth__0__1 +#-----| -> call to == + +# 205| __synth__0__1 +#-----| -> 1 + +# 205| call to foo +#-----| -> ... = ... + +# 205| nil +#-----| -> if ... + +# 205| self +#-----| -> call to foo + +# 205| ... +#-----| -> exit cfg.rb (normal) + +# 205| call to bar +#-----| -> if ... + +# 205| call to == +#-----| false -> __synth__0__1 +#-----| true -> nil + +# 205| if ... +#-----| -> ... + +# 205| nil +#-----| -> __synth__0__1 + +# 205| 1 +#-----| -> 2 + +# 205| 2 +#-----| -> { ... } + +# 205| enter { ... } +#-----| -> x + +# 205| exit { ... } + +# 205| exit { ... } (normal) +#-----| -> exit { ... } + +# 205| { ... } +#-----| -> call to bar + +# 205| x +#-----| -> x + +# 205| x +#-----| -> exit { ... } (normal) + desugar.rb: # 1| enter m1 #-----| -> x diff --git a/ruby/ql/test/library-tests/controlflow/graph/Nodes.expected b/ruby/ql/test/library-tests/controlflow/graph/Nodes.expected index 73dfb482093..2701f9d7a0f 100644 --- a/ruby/ql/test/library-tests/controlflow/graph/Nodes.expected +++ b/ruby/ql/test/library-tests/controlflow/graph/Nodes.expected @@ -41,6 +41,7 @@ callsWithNoArguments | cfg.rb:194:1:194:23 | call to run_block | | cfg.rb:200:1:200:32 | call to times | | cfg.rb:202:1:202:35 | call to times | +| cfg.rb:205:1:205:3 | call to foo | | desugar.rb:6:3:6:7 | call to foo | | desugar.rb:10:3:10:7 | call to foo | | desugar.rb:14:3:14:7 | call to foo | @@ -203,6 +204,9 @@ positionalArguments | cfg.rb:197:3:197:13 | call to bar | cfg.rb:197:10:197:12 | ... | | cfg.rb:200:18:200:30 | call to puts | cfg.rb:200:30:200:30 | a | | cfg.rb:202:19:202:31 | call to puts | cfg.rb:202:31:202:31 | c | +| cfg.rb:205:1:205:23 | call to bar | cfg.rb:205:10:205:10 | 1 | +| cfg.rb:205:1:205:23 | call to bar | cfg.rb:205:12:205:12 | 2 | +| cfg.rb:205:4:205:5 | call to == | cfg.rb:205:1:205:3 | __synth__0__1 | | desugar.rb:2:5:2:6 | ... + ... | desugar.rb:2:8:2:8 | 1 | | desugar.rb:6:3:6:13 | call to count= | desugar.rb:6:17:6:17 | ... = ... | | desugar.rb:10:3:10:10 | call to []= | desugar.rb:10:9:10:9 | 0 | diff --git a/ruby/ql/test/library-tests/controlflow/graph/cfg.rb b/ruby/ql/test/library-tests/controlflow/graph/cfg.rb index 28cda8bc4ed..0e6ebcc0c5a 100644 --- a/ruby/ql/test/library-tests/controlflow/graph/cfg.rb +++ b/ruby/ql/test/library-tests/controlflow/graph/cfg.rb @@ -201,6 +201,9 @@ end 2.times do |c; d| Kernel.puts c end +# A call with a safe navigation operator +foo&.bar(1,2) { |x| x } + __END__ Some ignored nonsense diff --git a/swift/codegen/cppgen.py b/swift/codegen/cppgen.py index 623621e3559..dcda56fd5f2 100644 --- a/swift/codegen/cppgen.py +++ b/swift/codegen/cppgen.py @@ -66,7 +66,7 @@ def generate(opts, renderer): processor = Processor({cls.name: cls for cls in schema.load(opts.schema).classes}, opts.trap_affix) out = opts.cpp_output renderer.render(cpp.ClassList(processor.get_classes(), opts.cpp_namespace, opts.trap_affix, - opts.cpp_include_dir), out / f"{opts.trap_affix}Classes.h") + opts.cpp_include_dir, opts.schema), out / f"{opts.trap_affix}Classes.h") tags = ("cpp", "schema") diff --git a/swift/codegen/lib/cpp.py b/swift/codegen/lib/cpp.py index 71bb364b74b..f93ff00b027 100644 --- a/swift/codegen/lib/cpp.py +++ b/swift/codegen/lib/cpp.py @@ -104,6 +104,7 @@ class TrapList: namespace: str trap_affix: str include_dir: str + source: str @dataclass @@ -112,6 +113,7 @@ class TagList: tags: List[Tag] namespace: str + source: str @dataclass @@ -150,3 +152,4 @@ class ClassList: namespace: str trap_affix: str include_dir: str + source: str diff --git a/swift/codegen/lib/options.py b/swift/codegen/lib/options.py index 13f173d8dbd..501b7cc73d1 100644 --- a/swift/codegen/lib/options.py +++ b/swift/codegen/lib/options.py @@ -21,7 +21,7 @@ def _init_options(): Option("--cpp-output", tags=["cpp"], type=_abspath, required=True) Option("--cpp-namespace", tags=["cpp"], default="codeql") Option("--trap-affix", tags=["cpp"], default="Trap") - Option("--cpp-include-dir", tags=["cpp"], required=True) + Option("--cpp-include-dir", tags=["cpp"], default="swift/extractor/trap") def _abspath(x): diff --git a/swift/codegen/templates/cpp_classes.mustache b/swift/codegen/templates/cpp_classes.mustache index fdaf52e3efe..758febe966f 100644 --- a/swift/codegen/templates/cpp_classes.mustache +++ b/swift/codegen/templates/cpp_classes.mustache @@ -1,4 +1,4 @@ -// generated by {{generator}} +// generated by {{generator}} from {{source}} // clang-format off #pragma once diff --git a/swift/codegen/templates/trap_tags.mustache b/swift/codegen/templates/trap_tags.mustache index 2c1631d1765..48bae6bb153 100644 --- a/swift/codegen/templates/trap_tags.mustache +++ b/swift/codegen/templates/trap_tags.mustache @@ -1,4 +1,4 @@ -// generated by {{generator}} +// generated by {{generator}} from {{source}} // clang-format off #pragma once diff --git a/swift/codegen/templates/trap_traps.mustache b/swift/codegen/templates/trap_traps.mustache index a6b75a597d8..0e17131e1dc 100644 --- a/swift/codegen/templates/trap_traps.mustache +++ b/swift/codegen/templates/trap_traps.mustache @@ -1,4 +1,4 @@ -// generated by {{generator}} +// generated by {{generator}} from {{source}} // clang-format off #pragma once @@ -29,12 +29,5 @@ inline std::ostream &operator<<(std::ostream &out, const {{name}}{{trap_affix}} << {{#get_streamer}}e.{{field_name}}{{/get_streamer}}{{/fields}} << ")"; return out; } -{{#id}} - -template <> -struct TagToBindingTrapFunctor { - using type = {{name}}{{trap_affix}}; -}; -{{/id}} {{/traps}} } diff --git a/swift/codegen/trapgen.py b/swift/codegen/trapgen.py index ed2fef4373b..2dbb961f837 100755 --- a/swift/codegen/trapgen.py +++ b/swift/codegen/trapgen.py @@ -68,7 +68,7 @@ def generate(opts, renderer): for d in e.rhs: tag_graph.setdefault(d.type, set()).add(e.lhs) - renderer.render(cpp.TrapList(traps, opts.cpp_namespace, opts.trap_affix, opts.cpp_include_dir), + renderer.render(cpp.TrapList(traps, opts.cpp_namespace, opts.trap_affix, opts.cpp_include_dir, opts.dbscheme), out / f"{opts.trap_affix}Entries.h") tags = [] @@ -79,7 +79,7 @@ def generate(opts, renderer): index=index, id=tag, )) - renderer.render(cpp.TagList(tags, opts.cpp_namespace), out / f"{opts.trap_affix}Tags.h") + renderer.render(cpp.TagList(tags, opts.cpp_namespace, opts.dbscheme), out / f"{opts.trap_affix}Tags.h") tags = ("cpp", "dbscheme") diff --git a/swift/extractor/BUILD.bazel b/swift/extractor/BUILD.bazel index 011183d8dac..7c7a1571ee1 100644 --- a/swift/extractor/BUILD.bazel +++ b/swift/extractor/BUILD.bazel @@ -6,7 +6,15 @@ swift_cc_binary( "SwiftExtractor.cpp", "SwiftExtractor.h", "SwiftExtractorConfiguration.h", + "SwiftDispatcher.h", + "SwiftTagTraits.h", "main.cpp", + "SwiftVisitor.h", + "visitors/DeclVisitor.h", + "visitors/ExprVisitor.h", + "visitors/StmtVisitor.h", + "visitors/TypeVisitor.h", + "visitors/PatternVisitor.h", ], visibility = ["//swift:__pkg__"], deps = [ diff --git a/swift/extractor/SwiftDispatcher.h b/swift/extractor/SwiftDispatcher.h new file mode 100644 index 00000000000..a3803777425 --- /dev/null +++ b/swift/extractor/SwiftDispatcher.h @@ -0,0 +1,183 @@ +#pragma once + +#include "swift/extractor/trap/TrapArena.h" +#include "swift/extractor/trap/TrapLabelStore.h" +#include "swift/extractor/trap/generated/TrapClasses.h" +#include "swift/extractor/SwiftTagTraits.h" +#include +#include +#include + +namespace codeql { + +namespace detail { + +// The following `getKindName`s are used within "TBD" TRAP entries to visually mark an AST node as +// not properly emitted yet. +// TODO: To be replaced with QL counterpart +template +inline std::string getKindName(Kind kind) { + return Parent::getKindName(kind).str(); +} + +template <> +inline std::string getKindName(swift::TypeKind kind) { + switch (kind) { +#define TYPE(CLASS, PARENT) \ + case swift::TypeKind::CLASS: \ + return #CLASS; +#include "swift/AST/TypeNodes.def" + default: + return "Unknown"; + } +} + +template <> +std::string inline getKindName(swift::TypeReprKind kind) { + switch (kind) { +#define TYPEREPR(CLASS, PARENT) \ + case swift::TypeReprKind::CLASS: \ + return #CLASS; +#include "swift/AST/TypeReprNodes.def" + default: + return "Unknown"; + } +} + +} // namespace detail + +// The main responsibilities of the SwiftDispatcher are as follows: +// * redirect specific AST node emission to a corresponding visitor (statements, expressions, etc.) +// * storing TRAP labels for emitted AST nodes (in the TrapLabelStore) to avoid re-emission +// Since SwiftDispatcher sees all the AST nodes, it also attaches a location to every 'locatable' +// node (AST nodes that are not types: declarations, statements, expressions, etc.). +class SwiftDispatcher { + public: + // sourceManager, arena, and trap are supposed to outlive the SwiftDispatcher + SwiftDispatcher(const swift::SourceManager& sourceManager, TrapArena& arena, TrapOutput& trap) + : sourceManager{sourceManager}, arena{arena}, trap{trap} {} + + // This is a helper method to emit TRAP entries for AST nodes that we don't fully support yet. + template + void TBD(Child* entity, const std::string& suffix) { + using namespace std::string_literals; + auto label = assignNewLabel(entity); + auto kind = detail::getKindName(static_cast(entity)->getKind()); + auto name = "TBD ("s + kind + suffix + ")"; + if constexpr (std::is_same_v) { + trap.emit(UnknownTypesTrap{label, name}); + } else { + trap.emit(UnknownAstNodesTrap{label, name}); + } + } + + private: + // types to be supported by assignNewLabel/fetchLabel need to be listed here + using Store = TrapLabelStore; + + // This method gives a TRAP label for already emitted AST node. + // If the AST node was not emitted yet, then the emission is dispatched to a corresponding + // visitor (see `visit(T *)` methods below). + template + TrapLabelOf fetchLabel(E* e) { + // this is required so we avoid any recursive loop: a `fetchLabel` during the visit of `e` might + // end up calling `fetchLabel` on `e` itself, so we want the visit of `e` to call `fetchLabel` + // only after having called `assignNewLabel` on `e`. + assert(holds_alternative(waitingForNewLabel) && + "fetchLabel called before assignNewLabel"); + if (auto l = store.get(e)) { + return *l; + } + waitingForNewLabel = e; + visit(e); + if (auto l = store.get(e)) { + if constexpr (!std::is_base_of_v) { + attachLocation(e, *l); + } + return *l; + } + assert(!"assignNewLabel not called during visit"); + return {}; + } + + // Due to the lazy emission approach, we must assign a label to a corresponding AST node before + // it actually gets emitted to handle recursive cases such as recursive calls, or recursive type + // declarations + template + TrapLabelOf assignNewLabel(E* e) { + assert(waitingForNewLabel == Store::Handle{e} && "assignNewLabel called on wrong entity"); + auto label = getLabel>(); + trap.assignStar(label); + store.insert(e, label); + waitingForNewLabel = std::monostate{}; + return label; + } + + template + TrapLabel getLabel() { + return arena.allocateLabel(); + } + + template + void attachLocation(Locatable locatable, TrapLabel locatableLabel) { + attachLocation(&locatable, locatableLabel); + } + + // Emits a Location TRAP entry and attaches it to an AST node + template + void attachLocation(Locatable* locatable, TrapLabel locatableLabel) { + auto start = locatable->getStartLoc(); + auto end = locatable->getEndLoc(); + if (!start.isValid() || !end.isValid()) { + // invalid locations seem to come from entities synthesized by the compiler + return; + } + std::string filepath = getFilepath(start); + auto fileLabel = arena.allocateLabel(); + trap.assignKey(fileLabel, filepath); + // TODO: do not emit duplicate trap entries for Files + trap.emit(FilesTrap{fileLabel, filepath}); + auto [startLine, startColumn] = sourceManager.getLineAndColumnInBuffer(start); + auto [endLine, endColumn] = sourceManager.getLineAndColumnInBuffer(end); + auto locLabel = arena.allocateLabel(); + trap.assignKey(locLabel, '{', fileLabel, "}:", startLine, ':', startColumn, ':', endLine, ':', + endColumn); + trap.emit(LocationsTrap{locLabel, fileLabel, startLine, startColumn, endLine, endColumn}); + trap.emit(LocatablesTrap{locatableLabel, locLabel}); + } + + std::string getFilepath(swift::SourceLoc loc) { + // TODO: this needs more testing + // TODO: check canonicaliztion of names on a case insensitive filesystems + // TODO: make symlink resolution conditional on CODEQL_PRESERVE_SYMLINKS=true + auto displayName = sourceManager.getDisplayNameForLoc(loc); + llvm::SmallString realPath; + if (std::error_code ec = llvm::sys::fs::real_path(displayName, realPath)) { + std::cerr << "Cannot get real path: '" << displayName.str() << "': " << ec.message() << "\n"; + return {}; + } + return realPath.str().str(); + } + + // TODO: The following methods are supposed to redirect TRAP emission to correpsonding visitors, + // which are to be introduced in follow-up PRs + virtual void visit(swift::Decl* decl) = 0; + virtual void visit(swift::Stmt* stmt) = 0; + virtual void visit(swift::Expr* expr) = 0; + virtual void visit(swift::Pattern* pattern) = 0; + virtual void visit(swift::TypeRepr* type) = 0; + virtual void visit(swift::TypeBase* type) = 0; + + const swift::SourceManager& sourceManager; + TrapArena& arena; + TrapOutput& trap; + Store store; + Store::Handle waitingForNewLabel{std::monostate{}}; +}; + +} // namespace codeql diff --git a/swift/extractor/SwiftExtractor.cpp b/swift/extractor/SwiftExtractor.cpp index f07b956e4a8..692822c3e5e 100644 --- a/swift/extractor/SwiftExtractor.cpp +++ b/swift/extractor/SwiftExtractor.cpp @@ -12,13 +12,15 @@ #include #include -#include "swift/extractor/trap/TrapClasses.h" -#include "swift/extractor/trap/TrapArena.h" +#include "swift/extractor/trap/generated/TrapClasses.h" #include "swift/extractor/trap/TrapOutput.h" +#include "swift/extractor/SwiftVisitor.h" using namespace codeql; -static void extractFile(const SwiftExtractorConfiguration& config, swift::SourceFile& file) { +static void extractFile(const SwiftExtractorConfiguration& config, + swift::CompilerInstance& compiler, + swift::SourceFile& file) { if (std::error_code ec = llvm::sys::fs::create_directories(config.trapDir)) { std::cerr << "Cannot create TRAP directory: " << ec.message() << "\n"; return; @@ -79,12 +81,17 @@ static void extractFile(const SwiftExtractorConfiguration& config, swift::Source TrapOutput trap{trapStream}; TrapArena arena{}; - auto label = arena.allocateLabel(); - trap.assignStar(label); - File f{}; - f.id = label; - f.name = srcFilePath.str().str(); - trap.emit(f); + + // In the case of emtpy files, the dispatcher is not called, but we still want to 'record' the + // fact that the file was extracted + auto fileLabel = arena.allocateLabel(); + trap.assignKey(fileLabel, srcFilePath.str().str()); + trap.emit(FilesTrap{fileLabel, srcFilePath.str().str()}); + + SwiftVisitor visitor(compiler.getSourceMgr(), arena, trap); + for (swift::Decl* decl : file.getTopLevelDecls()) { + visitor.extract(decl); + } // TODO: Pick a better name to avoid collisions std::string trapName = file.getFilename().str() + ".trap"; @@ -108,11 +115,11 @@ void codeql::extractSwiftFiles(const SwiftExtractorConfiguration& config, module->getFiles().front()->getKind() == swift::FileUnitKind::Source) { // We can only call getMainSourceFile if the first file is of a Source kind swift::SourceFile& file = module->getMainSourceFile(); - extractFile(config, file); + extractFile(config, compiler, file); } } else { for (auto s : compiler.getPrimarySourceFiles()) { - extractFile(config, *s); + extractFile(config, compiler, *s); } } } diff --git a/swift/extractor/SwiftTagTraits.h b/swift/extractor/SwiftTagTraits.h new file mode 100644 index 00000000000..bc8886bfaea --- /dev/null +++ b/swift/extractor/SwiftTagTraits.h @@ -0,0 +1,72 @@ +#pragma once + +// This file implements the mapping needed by the API defined in the TrapTagTraits.h, so that +// TrapTagOf/TrapLabelOf provide the tags/labels for specific swift entity types. +#include +#include "swift/extractor/trap/TrapTagTraits.h" +#include "swift/extractor/trap/generated/TrapTags.h" + +namespace codeql { + +// codegen goes with QL acronym convention (Sil instead of SIL), we need to remap it to Swift's +// convention +using SILBlockStorageTypeTag = SilBlockStorageTypeTag; +using SILBoxTypeTag = SilBoxTypeTag; +using SILFunctionTypeTag = SilFunctionTypeTag; +using SILTokenTypeTag = SilTokenTypeTag; + +#define MAP_TYPE_TO_TAG(TYPE, TAG) \ + template <> \ + struct detail::ToTagFunctor { \ + using type = TAG; \ + } +#define MAP_TAG(TYPE) MAP_TYPE_TO_TAG(TYPE, TYPE##Tag) +#define MAP_SUBTAG(TYPE, PARENT) \ + MAP_TAG(TYPE); \ + static_assert(std::is_base_of_v, \ + #PARENT "Tag must be a base of " #TYPE "Tag"); + +#define OVERRIDE_TAG(TYPE, TAG) \ + template <> \ + struct detail::ToTagOverride { \ + using type = TAG; \ + }; \ + static_assert(std::is_base_of_v, "override is not a subtag"); + +MAP_TAG(Stmt); +#define ABSTRACT_STMT(CLASS, PARENT) MAP_SUBTAG(CLASS##Stmt, PARENT) +#define STMT(CLASS, PARENT) ABSTRACT_STMT(CLASS, PARENT) +#include "swift/AST/StmtNodes.def" + +MAP_TAG(Expr); +#define ABSTRACT_EXPR(CLASS, PARENT) MAP_SUBTAG(CLASS##Expr, PARENT) +#define EXPR(CLASS, PARENT) ABSTRACT_EXPR(CLASS, PARENT) +#include "swift/AST/ExprNodes.def" + +MAP_TAG(Decl); +#define ABSTRACT_DECL(CLASS, PARENT) MAP_SUBTAG(CLASS##Decl, PARENT) +#define DECL(CLASS, PARENT) ABSTRACT_DECL(CLASS, PARENT) +#include "swift/AST/DeclNodes.def" + +MAP_TAG(Pattern); +#define ABSTRACT_PATTERN(CLASS, PARENT) MAP_SUBTAG(CLASS##Pattern, PARENT) +#define PATTERN(CLASS, PARENT) ABSTRACT_PATTERN(CLASS, PARENT) +#include "swift/AST/PatternNodes.def" + +MAP_TAG(TypeRepr); +MAP_TYPE_TO_TAG(TypeBase, TypeTag); +#define ABSTRACT_TYPE(CLASS, PARENT) MAP_SUBTAG(CLASS##Type, PARENT) +#define TYPE(CLASS, PARENT) ABSTRACT_TYPE(CLASS, PARENT) +#include "swift/AST/TypeNodes.def" + +OVERRIDE_TAG(FuncDecl, ConcreteFuncDeclTag); +OVERRIDE_TAG(VarDecl, ConcreteVarDeclTag); + +#undef MAP_TAG +#undef MAP_SUBTAG +#undef MAP_TYPE_TO_TAG +#undef OVERRIDE_TAG + +// All the other macros defined here are undefined by the .def files + +} // namespace codeql diff --git a/swift/extractor/SwiftVisitor.h b/swift/extractor/SwiftVisitor.h new file mode 100644 index 00000000000..bc766ce1278 --- /dev/null +++ b/swift/extractor/SwiftVisitor.h @@ -0,0 +1,36 @@ +#pragma once + +#include "swift/extractor/SwiftDispatcher.h" +#include "swift/extractor/visitors/DeclVisitor.h" +#include "swift/extractor/visitors/ExprVisitor.h" +#include "swift/extractor/visitors/StmtVisitor.h" +#include "swift/extractor/visitors/TypeVisitor.h" +#include "swift/extractor/visitors/PatternVisitor.h" + +namespace codeql { + +class SwiftVisitor : private SwiftDispatcher { + public: + using SwiftDispatcher::SwiftDispatcher; + + template + void extract(T* entity) { + fetchLabel(entity); + } + + private: + void visit(swift::Decl* decl) override { declVisitor.visit(decl); } + void visit(swift::Stmt* stmt) override { stmtVisitor.visit(stmt); } + void visit(swift::Expr* expr) override { exprVisitor.visit(expr); } + void visit(swift::Pattern* pattern) override { patternVisitor.visit(pattern); } + void visit(swift::TypeRepr* type) override { TBD(type, "TypeRepr"); } + void visit(swift::TypeBase* type) override { typeVisitor.visit(type); } + + DeclVisitor declVisitor{*this}; + ExprVisitor exprVisitor{*this}; + StmtVisitor stmtVisitor{*this}; + TypeVisitor typeVisitor{*this}; + PatternVisitor patternVisitor{*this}; +}; + +} // namespace codeql diff --git a/swift/extractor/trap/BUILD.bazel b/swift/extractor/trap/BUILD.bazel index be611f3ddc6..5a3beca1ba8 100644 --- a/swift/extractor/trap/BUILD.bazel +++ b/swift/extractor/trap/BUILD.bazel @@ -2,14 +2,14 @@ genrule( name = "trapgen", srcs = ["//swift:dbscheme"], outs = [ - "TrapEntries.h", - "TrapTags.h", + "generated/TrapEntries.h", + "generated/TrapTags.h", ], cmd = " ".join([ "$(location //swift/codegen:trapgen)", "--dbscheme $<", "--cpp-include-dir " + package_name(), - "--cpp-output $(RULEDIR)", + "--cpp-output $(RULEDIR)/generated", ]), exec_tools = ["//swift/codegen:trapgen"], ) @@ -21,13 +21,13 @@ genrule( "//swift/codegen:schema_includes", ], outs = [ - "TrapClasses.h", + "generated/TrapClasses.h", ], cmd = " ".join([ "$(location //swift/codegen:cppgen)", "--schema $(location //swift/codegen:schema)", "--cpp-include-dir " + package_name(), - "--cpp-output $(RULEDIR)", + "--cpp-output $(RULEDIR)/generated", ]), exec_tools = ["//swift/codegen:cppgen"], ) diff --git a/swift/extractor/trap/TrapLabel.h b/swift/extractor/trap/TrapLabel.h index 83ca2ab6568..fb710fc8625 100644 --- a/swift/extractor/trap/TrapLabel.h +++ b/swift/extractor/trap/TrapLabel.h @@ -4,8 +4,7 @@ #include #include -#include "swift/extractor/trap/TrapTagTraits.h" -#include "swift/extractor/trap/TrapTags.h" +#include "swift/extractor/trap/generated/TrapTags.h" namespace codeql { @@ -13,6 +12,8 @@ class UntypedTrapLabel { uint64_t id_; friend class std::hash; + template + friend class TrapLabel; protected: UntypedTrapLabel() : id_{0xffffffffffffffff} {} @@ -41,6 +42,7 @@ class TrapLabel : public UntypedTrapLabel { // The caller is responsible for ensuring ID uniqueness. static TrapLabel unsafeCreateFromExplicitId(uint64_t id) { return {id}; } + static TrapLabel unsafeCreateFromUntyped(UntypedTrapLabel label) { return {label.id_}; } template TrapLabel(const TrapLabel& other) : UntypedTrapLabel(other) { diff --git a/swift/extractor/trap/TrapLabelStore.h b/swift/extractor/trap/TrapLabelStore.h new file mode 100644 index 00000000000..93ca4212185 --- /dev/null +++ b/swift/extractor/trap/TrapLabelStore.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +#include +#include + +#include + +#include "swift/extractor/trap/TrapLabel.h" +#include "swift/extractor/trap/TrapTagTraits.h" +#include "swift/extractor/trap/generated/TrapTags.h" + +namespace codeql { + +// The extraction is done in a lazy/on-demand fashion: +// Each emitted TRAP entry for an AST node gets a TRAP label assigned to it. +// To avoid re-emission, we store the "AST node <> label" entry in the TrapLabelStore. +// The template parameters `Ts...` indicate to what entity types we restrict the storage +template +class TrapLabelStore { + public: + using Handle = std::variant; + + template + std::optional> get(const T* e) { + if (auto found = store_.find(e); found != store_.end()) { + return TrapLabelOf::unsafeCreateFromUntyped(found->second); + } + return std::nullopt; + } + + template + void insert(const T* e, TrapLabelOf l) { + auto [_, inserted] = store_.emplace(e, l); + assert(inserted && "already inserted"); + } + + private: + std::unordered_map store_; +}; + +} // namespace codeql diff --git a/swift/extractor/trap/TrapTagTraits.h b/swift/extractor/trap/TrapTagTraits.h index 930127403ac..359951f6810 100644 --- a/swift/extractor/trap/TrapTagTraits.h +++ b/swift/extractor/trap/TrapTagTraits.h @@ -1,21 +1,24 @@ #pragma once +// This file defines functors that can be specialized to define a mapping from arbitrary types to +// label tags + #include namespace codeql { +namespace detail { template struct ToTagFunctor; template struct ToTagOverride : ToTagFunctor {}; -template -using ToTag = typename ToTagOverride>::type; +} // namespace detail template -struct TagToBindingTrapFunctor; +using TrapTagOf = typename detail::ToTagOverride>::type; -template -using TagToBindingTrap = typename TagToBindingTrapFunctor::type; +template +using TrapLabelOf = TrapLabel>; } // namespace codeql diff --git a/swift/extractor/visitors/DeclVisitor.h b/swift/extractor/visitors/DeclVisitor.h new file mode 100644 index 00000000000..536239f93f7 --- /dev/null +++ b/swift/extractor/visitors/DeclVisitor.h @@ -0,0 +1,22 @@ +#pragma once + +#include "swift/extractor/SwiftDispatcher.h" +#include + +namespace codeql { + +class DeclVisitor : public swift::DeclVisitor { + public: + // SwiftDispatcher should outlive the DeclVisitor + DeclVisitor(SwiftDispatcher& dispatcher) : dispatcher(dispatcher) {} + + template + void visitDecl(E* decl) { + dispatcher.TBD(decl, "Decl"); + } + + private: + SwiftDispatcher& dispatcher; +}; + +} // namespace codeql diff --git a/swift/extractor/visitors/ExprVisitor.h b/swift/extractor/visitors/ExprVisitor.h new file mode 100644 index 00000000000..68eeadba6a6 --- /dev/null +++ b/swift/extractor/visitors/ExprVisitor.h @@ -0,0 +1,22 @@ +#pragma once + +#include "swift/extractor/SwiftDispatcher.h" +#include + +namespace codeql { + +class ExprVisitor : public swift::ExprVisitor { + public: + // SwiftDispatcher should outlive the ExprVisitor + ExprVisitor(SwiftDispatcher& dispatcher) : dispatcher(dispatcher) {} + + template + void visitExpr(E* expr) { + dispatcher.TBD(expr, "Expr"); + } + + private: + SwiftDispatcher& dispatcher; +}; + +} // namespace codeql diff --git a/swift/extractor/visitors/PatternVisitor.h b/swift/extractor/visitors/PatternVisitor.h new file mode 100644 index 00000000000..d51500a413f --- /dev/null +++ b/swift/extractor/visitors/PatternVisitor.h @@ -0,0 +1,38 @@ +#pragma once + +#include "swift/extractor/SwiftDispatcher.h" +#include + +namespace codeql { + +namespace detail { +// swift code lacks default implementations of visitor for some entities. We can add those here +// while we do not have yet all implemented. This is a simplified version of the corresponding Expr +// code in swift/AST/ASTVisitor.h +template +class PatchedPatternVisitor : public swift::PatternVisitor { + public: +#define PATTERN(CLASS, PARENT) \ + void visit##CLASS##Pattern(swift::CLASS##Pattern* E) { \ + return static_cast(this)->visit##PARENT(E); \ + } +#include "swift/AST/PatternNodes.def" +}; + +} // namespace detail + +class PatternVisitor : public detail::PatchedPatternVisitor { + public: + // SwiftDispatcher should outlive the PatternVisitor + PatternVisitor(SwiftDispatcher& dispatcher) : dispatcher(dispatcher) {} + + template + void visitPattern(E* pattern) { + dispatcher.TBD(pattern, "Pattern"); + } + + private: + SwiftDispatcher& dispatcher; +}; + +} // namespace codeql diff --git a/swift/extractor/visitors/StmtVisitor.h b/swift/extractor/visitors/StmtVisitor.h new file mode 100644 index 00000000000..dd6e9d468a9 --- /dev/null +++ b/swift/extractor/visitors/StmtVisitor.h @@ -0,0 +1,39 @@ +#pragma once + +#include "swift/extractor/SwiftDispatcher.h" +#include + +namespace codeql { + +namespace detail { +// swift code lacks default implementations of visitor for some entities. We can add those here +// while we do not have yet all implemented. This is a simplified version of the corresponding Expr +// code in swift/AST/ASTVisitor.h +template +class PatchedStmtVisitor : public swift::StmtVisitor { + public: +#define ABSTRACT_STMT(CLASS, PARENT) \ + void visit##CLASS##Stmt(swift::CLASS##Stmt* E) { \ + return static_cast(this)->visit##PARENT(E); \ + } +#define STMT(CLASS, PARENT) ABSTRACT_STMT(CLASS, PARENT) +#include "swift/AST/StmtNodes.def" +}; + +} // namespace detail + +class StmtVisitor : public detail::PatchedStmtVisitor { + public: + // SwiftDispatcher should outlive the StmtVisitor + StmtVisitor(SwiftDispatcher& dispatcher) : dispatcher(dispatcher) {} + + template + void visitStmt(E* stmt) { + dispatcher.TBD(stmt, "Stmt"); + } + + private: + SwiftDispatcher& dispatcher; +}; + +} // namespace codeql diff --git a/swift/extractor/visitors/TypeVisitor.h b/swift/extractor/visitors/TypeVisitor.h new file mode 100644 index 00000000000..982f875e8c2 --- /dev/null +++ b/swift/extractor/visitors/TypeVisitor.h @@ -0,0 +1,22 @@ +#pragma once + +#include "swift/extractor/SwiftDispatcher.h" +#include + +namespace codeql { + +class TypeVisitor : public swift::TypeVisitor { + public: + // SwiftDispatcher should outlive the TypeVisitor + TypeVisitor(SwiftDispatcher& dispatcher) : dispatcher(dispatcher) {} + + template + void visitType(E* type) { + dispatcher.TBD(type, "Type"); + } + + private: + SwiftDispatcher& dispatcher; +}; + +} // namespace codeql diff --git a/swift/ql/lib/codeql/swift/elements/Location.qll b/swift/ql/lib/codeql/swift/elements/Location.qll index 00537c94872..f5943426e58 100644 --- a/swift/ql/lib/codeql/swift/elements/Location.qll +++ b/swift/ql/lib/codeql/swift/elements/Location.qll @@ -1,4 +1,11 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.Location -class Location extends LocationBase { } +class Location extends LocationBase { + predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { + path = getFile().getFullName() and + sl = getStartLine() and + sc = getStartColumn() and + el = getEndLine() and + ec = getEndColumn() + } +} diff --git a/swift/ql/lib/codeql/swift/elements/UnknownAstNode.qll b/swift/ql/lib/codeql/swift/elements/UnknownAstNode.qll index 950390f022d..7314e01d4b6 100644 --- a/swift/ql/lib/codeql/swift/elements/UnknownAstNode.qll +++ b/swift/ql/lib/codeql/swift/elements/UnknownAstNode.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.UnknownAstNode -class UnknownAstNode extends UnknownAstNodeBase { } +class UnknownAstNode extends UnknownAstNodeBase { + override string toString() { result = getName() } +} diff --git a/swift/ql/test/extractor-tests/declarations/test.expected b/swift/ql/test/extractor-tests/declarations/test.expected new file mode 100644 index 00000000000..1f9979f5b54 --- /dev/null +++ b/swift/ql/test/extractor-tests/declarations/test.expected @@ -0,0 +1,2 @@ +| test.swift:1:1:1:9 | TBD (TopLevelCodeDecl) | +| test.swift:1:5:1:5 | TBD (VarDecl) | diff --git a/swift/ql/test/extractor-tests/declarations/test.ql b/swift/ql/test/extractor-tests/declarations/test.ql new file mode 100644 index 00000000000..5fb02dedbca --- /dev/null +++ b/swift/ql/test/extractor-tests/declarations/test.ql @@ -0,0 +1,4 @@ +import swift + +from Decl decl +select decl diff --git a/swift/ql/test/extractor-tests/declarations/test.swift b/swift/ql/test/extractor-tests/declarations/test.swift new file mode 100644 index 00000000000..f9ead9d36ae --- /dev/null +++ b/swift/ql/test/extractor-tests/declarations/test.swift @@ -0,0 +1,2 @@ +let x = 42 +